Now using OpenLayer version 2.14.dev.bf1bdb1.
authorphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Fri, 9 Dec 2016 21:00:28 +0000 (21:00 +0000)
committerphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Fri, 9 Dec 2016 21:00:28 +0000 (21:00 +0000)
git-svn-id: http://www.winterrodeln.org/svn/servermediawiki/mediawiki_extensions/wrmap/trunk@2578 7aebc617-e5e2-0310-91dc-80fb5f6d2477

openlayers/OpenLayers.js
openlayers/OpenLayers.min.js

index 3ab927311766054abc660c675401221f40cd2301..8d47f6dc06ce5d8132c7cb738d7c72d8e672fc13 100644 (file)
@@ -2,14 +2,14 @@
 
   OpenLayers.js -- OpenLayers Map Viewer Library
 
-  Copyright (c) 2006-2013 by OpenLayers Contributors
+  Copyright (c) 2006-2015 by OpenLayers Contributors
   Published under the 2-clause BSD license.
-  See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
+  See https://raw.githubusercontent.com/openlayers/ol2/master/license.txt for the full text of the license, and https://raw.githubusercontent.com/openlayers/ol2/master/authors.txt for full list of contributors.
 
   Includes compressed code under the following licenses:
 
   (For uncompressed versions of the code used, please see the
-  OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
+  OpenLayers Github repository: <https://github.com/openlayers/ol2>)
 
 */
 
  * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
  * Copyright (c) 2006, Yahoo! Inc.
  * All rights reserved.
- * 
+ *
  * Redistribution and use of this software in source and binary forms, with or
  * without modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * * Redistributions of source code must retain the above copyright notice,
  *   this list of conditions and the following disclaimer.
- * 
+ *
  * * Redistributions in binary form must reproduce the above copyright notice,
  *   this list of conditions and the following disclaimer in the documentation
  *   and/or other materials provided with the distribution.
- * 
+ *
  * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
  *   used to endorse or promote products derived from this software without
  *   specific prior written permission of Yahoo! Inc.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 /* ======================================================================
     OpenLayers/SingleFile.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -68,7 +68,7 @@ var OpenLayers = {
     /**
      * Constant: VERSION_NUMBER
      */
-    VERSION_NUMBER: "Release 2.13.1",
+    VERSION_NUMBER: "Release 2.14 dev",
 
     /**
      * Constant: singleFile
@@ -137,11 +137,136 @@ var OpenLayers = {
      */
     ImgPath : ''
 };
+/* ======================================================================
+    OpenLayers/BaseTypes/Class.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/SingleFile.js
+ */
+
+/**
+ * Constructor: OpenLayers.Class
+ * Base class used to construct all other classes. Includes support for 
+ *     multiple inheritance. 
+ *     
+ * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
+ *     syntax for creating classes and dealing with inheritance 
+ *     will be removed.
+ * 
+ * To create a new OpenLayers-style class, use the following syntax:
+ * (code)
+ *     var MyClass = OpenLayers.Class(prototype);
+ * (end)
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ *     following syntax:
+ * (code)
+ *     var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ * (end)
+ * 
+ * Note that instanceof reflection will only reveal Class1 as superclass.
+ *
+ */
+OpenLayers.Class = function() {
+    var len = arguments.length;
+    var P = arguments[0];
+    var F = arguments[len-1];
+
+    var C = typeof F.initialize == "function" ?
+        F.initialize :
+        function(){ P.prototype.initialize.apply(this, arguments); };
+
+    if (len > 1) {
+        var newArgs = [C, P].concat(
+                Array.prototype.slice.call(arguments).slice(1, len-1), F);
+        OpenLayers.inherit.apply(null, newArgs);
+    } else {
+        C.prototype = F;
+    }
+    return C;
+};
+
+/**
+ * Function: OpenLayers.inherit
+ *
+ * Parameters:
+ * C - {Object} the class that inherits
+ * P - {Object} the superclass to inherit from
+ *
+ * In addition to the mandatory C and P parameters, an arbitrary number of
+ * objects can be passed, which will extend C.
+ */
+OpenLayers.inherit = function(C, P) {
+   var F = function() {};
+   F.prototype = P.prototype;
+   C.prototype = new F;
+   var i, l, o;
+   for(i=2, l=arguments.length; i<l; i++) {
+       o = arguments[i];
+       if(typeof o === "function") {
+           o = o.prototype;
+       }
+       OpenLayers.Util.extend(C.prototype, o);
+   }
+};
+
+/**
+ * APIFunction: extend
+ * Copy all properties of a source object to a destination object.  Modifies
+ *     the passed in destination object.  Any properties on the source object
+ *     that are set to undefined will not be (re)set on the destination object.
+ *
+ * Parameters:
+ * destination - {Object} The object that will be modified
+ * source - {Object} The object with properties to be set on the destination
+ *
+ * Returns:
+ * {Object} The destination object.
+ */
+OpenLayers.Util = OpenLayers.Util || {};
+OpenLayers.Util.extend = function(destination, source) {
+    destination = destination || {};
+    if (source) {
+        for (var property in source) {
+            var value = source[property];
+            if (value !== undefined) {
+                destination[property] = value;
+            }
+        }
+
+        /**
+         * IE doesn't include the toString property when iterating over an object's
+         * properties with the for(property in object) syntax.  Explicitly check if
+         * the source has its own toString property.
+         */
+
+        /*
+         * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
+         * prototype object" when calling hawOwnProperty if the source object
+         * is an instance of window.Event.
+         */
+
+        var sourceIsEvt = typeof window.Event == "function"
+                          && source instanceof window.Event;
+
+        if (!sourceIsEvt
+           && source.hasOwnProperty && source.hasOwnProperty("toString")) {
+            destination.toString = source.toString;
+        }
+    }
+    return destination;
+};
 /* ======================================================================
     OpenLayers/BaseTypes.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -480,12 +605,12 @@ OpenLayers.Function = {
      */
     bind: function(func, object) {
         // create a reference to all arguments past the second one
-        var args = Array.prototype.slice.apply(arguments, [2]);
+        var args = Array.prototype.slice.call(arguments, 2);
         return function() {
             // Push on any additional arguments from the actual function call.
             // These will come after those sent to the bind call.
             var newArgs = args.concat(
-                Array.prototype.slice.apply(arguments, [0])
+                Array.prototype.slice.call(arguments, 0)
             );
             return func.apply(object, newArgs);
         };
@@ -604,136 +729,11 @@ OpenLayers.Array = {
     }
     
 };
-/* ======================================================================
-    OpenLayers/BaseTypes/Class.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/SingleFile.js
- */
-
-/**
- * Constructor: OpenLayers.Class
- * Base class used to construct all other classes. Includes support for 
- *     multiple inheritance. 
- *     
- * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
- *     syntax for creating classes and dealing with inheritance 
- *     will be removed.
- * 
- * To create a new OpenLayers-style class, use the following syntax:
- * (code)
- *     var MyClass = OpenLayers.Class(prototype);
- * (end)
- *
- * To create a new OpenLayers-style class with multiple inheritance, use the
- *     following syntax:
- * (code)
- *     var MyClass = OpenLayers.Class(Class1, Class2, prototype);
- * (end)
- * 
- * Note that instanceof reflection will only reveal Class1 as superclass.
- *
- */
-OpenLayers.Class = function() {
-    var len = arguments.length;
-    var P = arguments[0];
-    var F = arguments[len-1];
-
-    var C = typeof F.initialize == "function" ?
-        F.initialize :
-        function(){ P.prototype.initialize.apply(this, arguments); };
-
-    if (len > 1) {
-        var newArgs = [C, P].concat(
-                Array.prototype.slice.call(arguments).slice(1, len-1), F);
-        OpenLayers.inherit.apply(null, newArgs);
-    } else {
-        C.prototype = F;
-    }
-    return C;
-};
-
-/**
- * Function: OpenLayers.inherit
- *
- * Parameters:
- * C - {Object} the class that inherits
- * P - {Object} the superclass to inherit from
- *
- * In addition to the mandatory C and P parameters, an arbitrary number of
- * objects can be passed, which will extend C.
- */
-OpenLayers.inherit = function(C, P) {
-   var F = function() {};
-   F.prototype = P.prototype;
-   C.prototype = new F;
-   var i, l, o;
-   for(i=2, l=arguments.length; i<l; i++) {
-       o = arguments[i];
-       if(typeof o === "function") {
-           o = o.prototype;
-       }
-       OpenLayers.Util.extend(C.prototype, o);
-   }
-};
-
-/**
- * APIFunction: extend
- * Copy all properties of a source object to a destination object.  Modifies
- *     the passed in destination object.  Any properties on the source object
- *     that are set to undefined will not be (re)set on the destination object.
- *
- * Parameters:
- * destination - {Object} The object that will be modified
- * source - {Object} The object with properties to be set on the destination
- *
- * Returns:
- * {Object} The destination object.
- */
-OpenLayers.Util = OpenLayers.Util || {};
-OpenLayers.Util.extend = function(destination, source) {
-    destination = destination || {};
-    if (source) {
-        for (var property in source) {
-            var value = source[property];
-            if (value !== undefined) {
-                destination[property] = value;
-            }
-        }
-
-        /**
-         * IE doesn't include the toString property when iterating over an object's
-         * properties with the for(property in object) syntax.  Explicitly check if
-         * the source has its own toString property.
-         */
-
-        /*
-         * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
-         * prototype object" when calling hawOwnProperty if the source object
-         * is an instance of window.Event.
-         */
-
-        var sourceIsEvt = typeof window.Event == "function"
-                          && source instanceof window.Event;
-
-        if (!sourceIsEvt
-           && source.hasOwnProperty && source.hasOwnProperty("toString")) {
-            destination.toString = source.toString;
-        }
-    }
-    return destination;
-};
 /* ======================================================================
     OpenLayers/BaseTypes/Bounds.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -899,7 +899,7 @@ OpenLayers.Bounds = OpenLayers.Class({
      * Returns a boundingbox-string representation of the bounds object.
      * 
      * Parameters:
-     * decimal - {Integer} How many significant digits in the bbox coords?
+     * decimal - {Integer} How many decimal places in the bbox coords?
      *                     Default is 6
      * reverseAxisOrder - {Boolean} Should we reverse the axis order?
      * 
@@ -1574,7 +1574,7 @@ OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
     OpenLayers/BaseTypes/Element.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -1767,7 +1767,7 @@ OpenLayers.Element = {
     OpenLayers/BaseTypes/LonLat.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -1986,7 +1986,7 @@ OpenLayers.LonLat.fromArray = function(arr) {
     OpenLayers/BaseTypes/Pixel.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -2133,7 +2133,7 @@ OpenLayers.Pixel = OpenLayers.Class({
     OpenLayers/BaseTypes/Size.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -2226,7 +2226,7 @@ OpenLayers.Size = OpenLayers.Class({
     OpenLayers/Console.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -2244,7 +2244,7 @@ OpenLayers.Size = OpenLayers.Class({
  * cross-browser debugging Firebug style.
  *
  * Note:
- * Note that behavior will differ with the Firebug extention and Firebug Lite.
+ * Note that behavior will differ with the Firebug extension and Firebug Lite.
  * Most notably, the Firebug Lite console does not currently allow for
  * hyperlinks to code or for clicking on object to explore their properties.
  * 
@@ -2480,7 +2480,7 @@ OpenLayers.Console = {
     OpenLayers/Lang.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -2618,7 +2618,7 @@ OpenLayers.i18n = OpenLayers.Lang.translate;
     OpenLayers/Util.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -4391,11 +4391,37 @@ OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
     return str;
 };
 
+/**
+ * Function: getConstructor
+ * Take an OpenLayers style CLASS_NAME and return a constructor.
+ *
+ * Parameters:
+ * className - {String} The dot delimited class name (e.g. 'OpenLayers.Foo').
+ * 
+ * Returns:
+ * {Function} The constructor.
+ */
+OpenLayers.Util.getConstructor = function(className) {
+    var Constructor;
+    var parts = className.split('.');
+    if (parts[0] === "OpenLayers") {
+        Constructor = OpenLayers;
+    } else {
+        // someone extended our base class and used their own namespace
+        // this will not work when the library is evaluated in a closure
+        // but it is the best we can do (until we ourselves provide a global)
+        Constructor = window[parts[0]];
+    }
+    for (var i = 1, ii = parts.length; i < ii; ++i) {
+        Constructor = Constructor[parts[i]];
+    }
+    return Constructor;
+};
 /* ======================================================================
     OpenLayers/Events.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -4521,6 +4547,23 @@ OpenLayers.Event = {
         return event.touches && event.touches.length > 1;
     },
 
+    /**
+     * Method: isTouchEvent
+     * Determine whether the event was triggered by a touch
+     * 
+     * Parameters:
+     * evt - {Event}
+     * 
+     * Returns:
+     * {Boolean}
+     */
+    isTouchEvent: function(evt) {
+        return ("" + evt.type).indexOf("touch") === 0 || (
+                "pointerType" in evt && (
+                     evt.pointerType === evt.MSPOINTER_TYPE_TOUCH /*IE10 pointer*/ ||
+                     evt.pointerType === "touch" /*W3C pointer*/));
+    },
+
     /**
      * Method: isLeftClick
      * Determine whether event was caused by a left click. 
@@ -4804,6 +4847,24 @@ OpenLayers.Events = OpenLayers.Class({
         "touchstart", "touchmove", "touchend",
         "keydown"
     ],
+    
+    /**
+     * Constant: standard pointer model
+     * {string}
+     */
+    TOUCH_MODEL_POINTER: "pointer",
+
+    /**
+     * Constant: prefixed pointer model (IE10)
+     * {string}
+     */
+    TOUCH_MODEL_MSPOINTER: "MSPointer",
+
+    /**
+     * Constant: legacy touch model
+     * {string}
+     */
+    TOUCH_MODEL_TOUCH: "touch",
 
     /** 
      * Property: listeners 
@@ -4963,7 +5024,7 @@ OpenLayers.Events = OpenLayers.Class({
         this.listeners  = {};
         this.extensions = {};
         this.extensionCount = {};
-        this._msTouches = [];
+        this._pointerTouches = [];
         
         // if a dom element is specified, add a listeners list 
         // for browser events on the element and register them
@@ -5030,15 +5091,17 @@ OpenLayers.Events = OpenLayers.Class({
             );
         }
         this.element = element;
-        var msTouch = !!window.navigator.msMaxTouchPoints;
+        var touchModel = this.getTouchModel();
         var type;
         for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) {
             type = this.BROWSER_EVENTS[i];
             // register the event cross-browser
             OpenLayers.Event.observe(element, type, this.eventHandler
             );
-            if (msTouch && type.indexOf('touch') === 0) {
-                this.addMsTouchListener(element, type, this.eventHandler);
+            if ((touchModel === this.TOUCH_MODEL_POINTER ||
+                    touchModel === this.TOUCH_MODEL_MSPOINTER) &&
+                    type.indexOf('touch') === 0) {
+                this.addPointerTouchListener(element, type, this.eventHandler);
             }
         }
         // disable dragstart in IE so that mousedown/move/up works normally
@@ -5418,18 +5481,38 @@ OpenLayers.Events = OpenLayers.Class({
     },
 
     /**
-     * Method: addMsTouchListener
+     * Method: getTouchModel
+     * Get the touch model currently in use.
+     * 
+     * This is cached on OpenLayers.Events as _TOUCH_MODEL 
+     * 
+     * Returns:
+     * {string} The current touch model (TOUCH_MODEL_xxx), null if none
+     */
+    getTouchModel: function() {
+        if (!("_TOUCH_MODEL" in OpenLayers.Events)) {
+            OpenLayers.Events._TOUCH_MODEL =
+                    (window.PointerEvent && "pointer") ||
+                    (window.MSPointerEvent && "MSPointer") ||
+                    (("ontouchdown" in document) && "touch") ||
+                    null;
+        }
+        return OpenLayers.Events._TOUCH_MODEL;
+    },
+
+    /**
+     * Method: addPointerTouchListener
      *
      * Parameters:
      * element - {DOMElement} The DOM element to register the listener on
      * type - {String} The event type
      * handler - {Function} the handler
      */
-    addMsTouchListener: function (element, type, handler) {
+    addPointerTouchListener: function (element, type, handler) {
         var eventHandler = this.eventHandler;
-        var touches = this._msTouches;
+        var touches = this._pointerTouches;
 
-        function msHandler(evt) {
+        function pointerHandler(evt) {
             handler(OpenLayers.Util.applyDefaults({
                 stopPropagation: function() {
                     for (var i=touches.length-1; i>=0; --i) {
@@ -5447,29 +5530,34 @@ OpenLayers.Events = OpenLayers.Class({
 
         switch (type) {
             case 'touchstart':
-                return this.addMsTouchListenerStart(element, type, msHandler);
+                return this.addPointerTouchListenerStart(element, type, pointerHandler);
             case 'touchend':
-                return this.addMsTouchListenerEnd(element, type, msHandler);
+                return this.addPointerTouchListenerEnd(element, type, pointerHandler);
             case 'touchmove':
-                return this.addMsTouchListenerMove(element, type, msHandler);
+                return this.addPointerTouchListenerMove(element, type, pointerHandler);
             default:
                 throw 'Unknown touch event type';
         }
     },
 
     /**
-     * Method: addMsTouchListenerStart
+     * Method: addPointerTouchListenerStart
      *
      * Parameters:
      * element - {DOMElement} The DOM element to register the listener on
      * type - {String} The event type
      * handler - {Function} the handler
      */
-    addMsTouchListenerStart: function(element, type, handler) {
-        var touches = this._msTouches;
+    addPointerTouchListenerStart: function(element, type, handler) {
+        var touches = this._pointerTouches;
 
         var cb = function(e) {
 
+            // pointer could be mouse or pen
+            if (!OpenLayers.Event.isTouchEvent(e)) {
+                return;
+            }
+
             var alreadyInArray = false;
             for (var i=0, ii=touches.length; i<ii; ++i) {
                 if (touches[i].pointerId == e.pointerId) {
@@ -5485,35 +5573,52 @@ OpenLayers.Events = OpenLayers.Class({
             handler(e);
         };
 
-        OpenLayers.Event.observe(element, 'MSPointerDown', cb);
+        OpenLayers.Event.observe(element,
+                this.getTouchModel() === this.TOUCH_MODEL_MSPOINTER ?
+                        'MSPointerDown' : 'pointerdown',
+                cb);
+        
+        // the pointerId only needs to be removed from the _pointerTouches array
+        // when the pointer has left its element
+        var internalCb = function (e) {
 
-        // Need to also listen for end events to keep the _msTouches list
-        // accurate
-        var internalCb = function(e) {
-            for (var i=0, ii=touches.length; i<ii; ++i) {
+            // pointer could be mouse or pen
+            if (!OpenLayers.Event.isTouchEvent(e)) {
+               return;
+            }
+
+            var up = false;
+            for (var i = 0, ii = touches.length; i < ii; ++i) {
                 if (touches[i].pointerId == e.pointerId) {
-                    touches.splice(i, 1);
+                    if (this.clientWidth != 0 && this.clientHeight != 0) {
+                        if ((Math.ceil(e.clientX) >= this.clientWidth || Math.ceil(e.clientY) >= this.clientHeight)) {
+                            touches.splice(i, 1);
+                        }
+                    }
                     break;
                 }
             }
         };
-        OpenLayers.Event.observe(element, 'MSPointerUp', internalCb);
+        OpenLayers.Event.observe(element,
+                this.getTouchModel() === this.TOUCH_MODEL_MSPOINTER ?
+                        'MSPointerOut' : 'pointerout',
+                internalCb);
     },
 
     /**
-     * Method: addMsTouchListenerMove
+     * Method: addPointerTouchListenerMove
      *
      * Parameters:
      * element - {DOMElement} The DOM element to register the listener on
      * type - {String} The event type
      * handler - {Function} the handler
      */
-    addMsTouchListenerMove: function (element, type, handler) {
-        var touches = this._msTouches;
+    addPointerTouchListenerMove: function (element, type, handler) {
+        var touches = this._pointerTouches;
         var cb = function(e) {
 
-            //Don't fire touch moves when mouse isn't down
-            if (e.pointerType == e.MSPOINTER_TYPE_MOUSE && e.buttons == 0) {
+            // pointer could be mouse or pen
+            if (!OpenLayers.Event.isTouchEvent(e)) {
                 return;
             }
 
@@ -5533,22 +5638,30 @@ OpenLayers.Events = OpenLayers.Class({
             handler(e);
         };
 
-        OpenLayers.Event.observe(element, 'MSPointerMove', cb);
+        OpenLayers.Event.observe(element,
+                this.getTouchModel() === this.TOUCH_MODEL_MSPOINTER ?
+                        'MSPointerMove' : 'pointermove',
+                cb);
     },
 
     /**
-     * Method: addMsTouchListenerEnd
+     * Method: addPointerTouchListenerEnd
      *
      * Parameters:
      * element - {DOMElement} The DOM element to register the listener on
      * type - {String} The event type
      * handler - {Function} the handler
      */
-    addMsTouchListenerEnd: function (element, type, handler) {
-        var touches = this._msTouches;
+    addPointerTouchListenerEnd: function (element, type, handler) {
+        var touches = this._pointerTouches;
 
         var cb = function(e) {
 
+            // pointer could be mouse or pen
+            if (!OpenLayers.Event.isTouchEvent(e)) {
+               return;
+            }
+
             for (var i=0, ii=touches.length; i<ii; ++i) {
                 if (touches[i].pointerId == e.pointerId) {
                     touches.splice(i, 1);
@@ -5560,372 +5673,657 @@ OpenLayers.Events = OpenLayers.Class({
             handler(e);
         };
 
-        OpenLayers.Event.observe(element, 'MSPointerUp', cb);
+        OpenLayers.Event.observe(element,
+                this.getTouchModel() === this.TOUCH_MODEL_MSPOINTER ?
+                        'MSPointerUp' : 'pointerup',
+                cb);
     },
 
     CLASS_NAME: "OpenLayers.Events"
 });
 /* ======================================================================
-    OpenLayers/Events/buttonclick.js
+    OpenLayers/Icon.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
 
 /**
- * @requires OpenLayers/Events.js
+ * @requires OpenLayers/BaseTypes/Class.js
  */
 
 /**
- * Class: OpenLayers.Events.buttonclick
- * Extension event type for handling buttons on top of a dom element. This
- *     event type fires "buttonclick" on its <target> when a button was
- *     clicked. Buttons are detected by the "olButton" class.
- *
- * This event type makes sure that button clicks do not interfere with other
- *     events that are registered on the same <element>.
+ * Class: OpenLayers.Icon
+ * 
+ * The icon represents a graphical icon on the screen.  Typically used in
+ * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
  *
- * Event types provided by this extension:
- * - *buttonclick* Triggered when a button is clicked. Listeners receive an
- *     object with a *buttonElement* property referencing the dom element of
- *     the clicked button, and an *buttonXY* property with the click position
- *     relative to the button.
+ * An icon has a url, size and position.  It also contains an offset which 
+ * allows the center point to be represented correctly.  This can be
+ * provided either as a fixed offset or a function provided to calculate
+ * the desired offset. 
+ * 
  */
-OpenLayers.Events.buttonclick = OpenLayers.Class({
-    
-    /**
-     * Property: target
-     * {<OpenLayers.Events>} The events instance that the buttonclick event will
-     * be triggered on.
-     */
-    target: null,
+OpenLayers.Icon = OpenLayers.Class({
     
-    /**
-     * Property: events
-     * {Array} Events to observe and conditionally stop from propagating when
-     *     an element with the olButton class (or its olAlphaImg child) is
-     *     clicked.
+    /** 
+     * Property: url 
+     * {String}  image url
      */
-    events: [
-        'mousedown', 'mouseup', 'click', 'dblclick',
-        'touchstart', 'touchmove', 'touchend', 'keydown'
-    ],
+    url: null,
     
-    /**
-     * Property: startRegEx
-     * {RegExp} Regular expression to test Event.type for events that start
-     *     a buttonclick sequence.
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>|Object} An OpenLayers.Size or
+     * an object with a 'w' and 'h' properties.
      */
-    startRegEx: /^mousedown|touchstart$/,
+    size: null,
 
-    /**
-     * Property: cancelRegEx
-     * {RegExp} Regular expression to test Event.type for events that cancel
-     *     a buttonclick sequence.
+    /** 
+     * Property: offset 
+     * {<OpenLayers.Pixel>|Object} distance in pixels to offset the
+     * image when being rendered. An OpenLayers.Pixel or an object
+     * with a 'x' and 'y' properties.
      */
-    cancelRegEx: /^touchmove$/,
-
-    /**
-     * Property: completeRegEx
-     * {RegExp} Regular expression to test Event.type for events that complete
-     *     a buttonclick sequence.
+    offset: null,    
+    
+    /** 
+     * Property: calculateOffset 
+     * {Function} Function to calculate the offset (based on the size)
      */
-    completeRegEx: /^mouseup|touchend$/,
+    calculateOffset: null,    
     
-    /**
-     * Property: startEvt
-     * {Event} The event that started the click sequence
+    /** 
+     * Property: imageDiv 
+     * {DOMElement} 
+     */
+    imageDiv: null,
+
+    /** 
+     * Property: px 
+     * {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object
+     * with a 'x' and 'y' properties.
      */
+    px: null,
     
-    /**
-     * Constructor: OpenLayers.Events.buttonclick
-     * Construct a buttonclick event type. Applications are not supposed to
-     *     create instances of this class - they are created on demand by
-     *     <OpenLayers.Events> instances.
+    /** 
+     * Constructor: OpenLayers.Icon
+     * Creates an icon, which is an image tag in a div.  
      *
-     * Parameters:
-     * target - {<OpenLayers.Events>} The events instance that the buttonclick
-     *     event will be triggered on.
+     * url - {String} 
+     * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or an
+     *                                   object with a 'w' and 'h'
+     *                                   properties.
+     * offset - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an
+     *                                      object with a 'x' and 'y'
+     *                                      properties.
+     * calculateOffset - {Function} 
      */
-    initialize: function(target) {
-        this.target = target;
-        for (var i=this.events.length-1; i>=0; --i) {
-            this.target.register(this.events[i], this, this.buttonClick, {
-                extension: true
-            });
-        }
+    initialize: function(url, size, offset, calculateOffset) {
+        this.url = url;
+        this.size = size || {w: 20, h: 20};
+        this.offset = offset || {x: -(this.size.w/2), y: -(this.size.h/2)};
+        this.calculateOffset = calculateOffset;
+
+        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
     },
     
-    /**
+    /** 
      * Method: destroy
+     * Nullify references and remove event listeners to prevent circular 
+     * references and memory leaks
      */
     destroy: function() {
-        for (var i=this.events.length-1; i>=0; --i) {
-            this.target.unregister(this.events[i], this, this.buttonClick);
-        }
-        delete this.target;
+        // erase any drawn elements
+        this.erase();
+
+        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); 
+        this.imageDiv.innerHTML = "";
+        this.imageDiv = null;
     },
 
-    /**
-     * Method: getPressedButton
-     * Get the pressed button, if any. Returns undefined if no button
-     * was pressed.
-     *
-     * Arguments:
-     * element - {DOMElement} The event target.
-     *
+    /** 
+     * Method: clone
+     * 
      * Returns:
-     * {DOMElement} The button element, or undefined.
+     * {<OpenLayers.Icon>} A fresh copy of the icon.
      */
-    getPressedButton: function(element) {
-        var depth = 3, // limit the search depth
-            button;
-        do {
-            if(OpenLayers.Element.hasClass(element, "olButton")) {
-                // hit!
-                button = element;
-                break;
-            }
-            element = element.parentNode;
-        } while(--depth > 0 && element);
-        return button;
+    clone: function() {
+        return new OpenLayers.Icon(this.url, 
+                                   this.size, 
+                                   this.offset, 
+                                   this.calculateOffset);
     },
     
     /**
-     * Method: ignore
-     * Check for event target elements that should be ignored by OpenLayers.
-     *
+     * Method: setSize
+     * 
      * Parameters:
-     * element - {DOMElement} The event target.
+     * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or
+     * an object with a 'w' and 'h' properties.
      */
-    ignore: function(element) {
-        var depth = 3,
-            ignore = false;
-        do {
-            if (element.nodeName.toLowerCase() === 'a') {
-                ignore = true;
-                break;
-            }
-            element = element.parentNode;
-        } while (--depth > 0 && element);
-        return ignore;
+    setSize: function(size) {
+        if (size != null) {
+            this.size = size;
+        }
+        this.draw();
     },
-
+    
     /**
-     * Method: buttonClick
-     * Check if a button was clicked, and fire the buttonclick event
-     *
+     * Method: setUrl
+     * 
      * Parameters:
-     * evt - {Event}
+     * url - {String} 
      */
-    buttonClick: function(evt) {
-        var propagate = true,
-            element = OpenLayers.Event.element(evt);
-        if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) {
-            // was a button pressed?
-            var button = this.getPressedButton(element);
-            if (button) {
-                if (evt.type === "keydown") {
-                    switch (evt.keyCode) {
-                    case OpenLayers.Event.KEY_RETURN:
-                    case OpenLayers.Event.KEY_SPACE:
-                        this.target.triggerEvent("buttonclick", {
-                            buttonElement: button
-                        });
-                        OpenLayers.Event.stop(evt);
-                        propagate = false;
-                        break;
-                    }
-                } else if (this.startEvt) {
-                    if (this.completeRegEx.test(evt.type)) {
-                        var pos = OpenLayers.Util.pagePosition(button);
-                        var viewportElement = OpenLayers.Util.getViewportElement();
-                        var scrollTop = window.pageYOffset || viewportElement.scrollTop;
-                        var scrollLeft = window.pageXOffset || viewportElement.scrollLeft;
-                        pos[0] = pos[0] - scrollLeft;
-                        pos[1] = pos[1] - scrollTop;
-                        
-                        this.target.triggerEvent("buttonclick", {
-                            buttonElement: button,
-                            buttonXY: {
-                                x: this.startEvt.clientX - pos[0],
-                                y: this.startEvt.clientY - pos[1]
-                            }
-                        });
-                    }
-                    if (this.cancelRegEx.test(evt.type)) {
-                        delete this.startEvt;
-                    }
-                    OpenLayers.Event.stop(evt);
-                    propagate = false;
-                }
-                if (this.startRegEx.test(evt.type)) {
-                    this.startEvt = evt;
-                    OpenLayers.Event.stop(evt);
-                    propagate = false;
-                }
-            } else {
-                propagate = !this.ignore(OpenLayers.Event.element(evt));
-                delete this.startEvt;
-            }
+    setUrl: function(url) {
+        if (url != null) {
+            this.url = url;
         }
-        return propagate;
-    }
-    
-});
-/* ======================================================================
-    OpenLayers/Util/vendorPrefix.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/SingleFile.js
- */
-
-OpenLayers.Util = OpenLayers.Util || {};
-/**
- * Namespace: OpenLayers.Util.vendorPrefix
- * A collection of utility functions to detect vendor prefixed features
- */
-OpenLayers.Util.vendorPrefix = (function() {
-    "use strict";
-    
-    var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"],
-        divStyle = document.createElement("div").style,
-        cssCache = {},
-        jsCache = {};
+        this.draw();
+    },
 
-    
-    /**
-     * Function: domToCss
-     * Converts a upper camel case DOM style property name to a CSS property
-     *      i.e. transformOrigin -> transform-origin
-     *      or   WebkitTransformOrigin -> -webkit-transform-origin
-     *
+    /** 
+     * Method: draw
+     * Move the div to the given pixel.
+     * 
      * Parameters:
-     * prefixedDom - {String} The property to convert
-     *
+     * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an
+     *                                  object with a 'x' and 'y' properties.
+     * 
      * Returns:
-     * {String} The CSS property
+     * {DOMElement} A new DOM Image of this icon set at the location passed-in
      */
-    function domToCss(prefixedDom) {
-        if (!prefixedDom) { return null; }
-        return prefixedDom.
-            replace(/([A-Z])/g, function(c) { return "-" + c.toLowerCase(); }).
-            replace(/^ms-/, "-ms-");
-    }
+    draw: function(px) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, 
+                                            null, 
+                                            null, 
+                                            this.size, 
+                                            this.url, 
+                                            "absolute");
+        this.moveTo(px);
+        return this.imageDiv;
+    }, 
 
-    /**
-     * APIMethod: css
-     * Detect which property is used for a CSS property
+    /** 
+     * Method: erase
+     * Erase the underlying image element.
+     */
+    erase: function() {
+        if (this.imageDiv != null && this.imageDiv.parentNode != null) {
+            OpenLayers.Element.remove(this.imageDiv);
+        }
+    }, 
+    
+    /** 
+     * Method: setOpacity
+     * Change the icon's opacity
      *
      * Parameters:
-     * property - {String} The standard (unprefixed) CSS property name
-     *
-     * Returns:
-     * {String} The standard CSS property, prefixed property or null if not
-     *          supported
+     * opacity - {float} 
      */
-    function css(property) {
-        if (cssCache[property] === undefined) {
-            var domProperty = property.
-                replace(/(-[\s\S])/g, function(c) { return c.charAt(1).toUpperCase(); });
-            var prefixedDom = style(domProperty);
-            cssCache[property] = domToCss(prefixedDom);
-        }
-        return cssCache[property];
-    }
+    setOpacity: function(opacity) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, 
+                                            null, null, null, null, opacity);
 
+    },
+    
     /**
-     * APIMethod: js
-     * Detect which property is used for a JS property/method
+     * Method: moveTo
+     * move icon to passed in px.
      *
      * Parameters:
-     * obj - {Object} The object to test on
-     * property - {String} The standard (unprefixed) JS property name
-     *
-     * Returns:
-     * {String} The standard JS property, prefixed property or null if not
-     *          supported
+     * px - {<OpenLayers.Pixel>|Object} the pixel position to move to.
+     * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.
      */
-    function js(obj, property) {
-        if (jsCache[property] === undefined) {
-            var tmpProp,
-                i = 0,
-                l = VENDOR_PREFIXES.length,
-                prefix,
-                isStyleObj = (typeof obj.cssText !== "undefined");
-
-            jsCache[property] = null;
-            for(; i<l; i++) {
-                prefix = VENDOR_PREFIXES[i];
-                if(prefix) {
-                    if (!isStyleObj) {
-                        // js prefix should be lower-case, while style
-                        // properties have upper case on first character
-                        prefix = prefix.toLowerCase();
-                    }
-                    tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);
-                } else {
-                    tmpProp = property;
-                }
+    moveTo: function (px) {
+        //if no px passed in, use stored location
+        if (px != null) {
+            this.px = px;
+        }
 
-                if(obj[tmpProp] !== undefined) {
-                    jsCache[property] = tmpProp;
-                    break;
+        if (this.imageDiv != null) {
+            if (this.px == null) {
+                this.display(false);
+            } else {
+                if (this.calculateOffset) {
+                    this.offset = this.calculateOffset(this.size);  
                 }
+                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {
+                    x: this.px.x + this.offset.x,
+                    y: this.px.y + this.offset.y
+                });
             }
         }
-        return jsCache[property];
-    }
+    },
     
-    /**
-     * APIMethod: style
-     * Detect which property is used for a DOM style property
+    /** 
+     * Method: display
+     * Hide or show the icon
      *
      * Parameters:
-     * property - {String} The standard (unprefixed) style property name
-     *
-     * Returns:
-     * {String} The standard style property, prefixed property or null if not
-     *          supported
+     * display - {Boolean} 
      */
-    function style(property) {
-        return js(divStyle, property);
-    }
+    display: function(display) {
+        this.imageDiv.style.display = (display) ? "" : "none"; 
+    },
     
-    return {
-        css:      css,
-        js:       js,
-        style:    style,
-        
-        // used for testing
-        cssCache:       cssCache,
-        jsCache:        jsCache
-    };
-}());
+
+    /**
+     * APIMethod: isDrawn
+     * 
+     * Returns:
+     * {Boolean} Whether or not the icon is drawn.
+     */
+    isDrawn: function() {
+        // nodeType 11 for ie, whose nodes *always* have a parentNode
+        // (of type document fragment)
+        var isDrawn = (this.imageDiv && this.imageDiv.parentNode && 
+                       (this.imageDiv.parentNode.nodeType != 11));    
+
+        return isDrawn;   
+    },
+
+    CLASS_NAME: "OpenLayers.Icon"
+});
 /* ======================================================================
-    OpenLayers/Animation.js
+    OpenLayers/Marker.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
 
-/**
- * @requires OpenLayers/SingleFile.js
- * @requires OpenLayers/Util/vendorPrefix.js
- */
 
 /**
- * Namespace: OpenLayers.Animation
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Icon.js
+ */
+
+/**
+ * Class: OpenLayers.Marker
+ * Instances of OpenLayers.Marker are a combination of a 
+ * <OpenLayers.LonLat> and an <OpenLayers.Icon>.  
+ *
+ * Markers are generally added to a special layer called
+ * <OpenLayers.Layer.Markers>.
+ *
+ * Example:
+ * (code)
+ * var markers = new OpenLayers.Layer.Markers( "Markers" );
+ * map.addLayer(markers);
+ *
+ * var size = new OpenLayers.Size(21,25);
+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
+ * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
+ *
+ * (end)
+ *
+ * Note that if you pass an icon into the Marker constructor, it will take
+ * that icon and use it. This means that you should not share icons between
+ * markers -- you use them once, but you should clone() for any additional
+ * markers using that same icon.
+ */
+OpenLayers.Marker = OpenLayers.Class({
+    
+    /** 
+     * Property: icon 
+     * {<OpenLayers.Icon>} The icon used by this marker.
+     */
+    icon: null,
+
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} location of object
+     */
+    lonlat: null,
+    
+    /** 
+     * Property: events 
+     * {<OpenLayers.Events>} the event handler.
+     */
+    events: null,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} the map this marker is attached to
+     */
+    map: null,
+    
+    /** 
+     * Constructor: OpenLayers.Marker
+     *
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>} the position of this marker
+     * icon - {<OpenLayers.Icon>}  the icon for this marker
+     */
+    initialize: function(lonlat, icon) {
+        this.lonlat = lonlat;
+        
+        var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
+        if (this.icon == null) {
+            this.icon = newIcon;
+        } else {
+            this.icon.url = newIcon.url;
+            this.icon.size = newIcon.size;
+            this.icon.offset = newIcon.offset;
+            this.icon.calculateOffset = newIcon.calculateOffset;
+        }
+        this.events = new OpenLayers.Events(this, this.icon.imageDiv);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Destroy the marker. You must first remove the marker from any 
+     * layer which it has been added to, or you will get buggy behavior.
+     * (This can not be done within the marker since the marker does not
+     * know which layer it is attached to.)
+     */
+    destroy: function() {
+        // erase any drawn features
+        this.erase();
+
+        this.map = null;
+
+        this.events.destroy();
+        this.events = null;
+
+        if (this.icon != null) {
+            this.icon.destroy();
+            this.icon = null;
+        }
+    },
+    
+    /** 
+    * Method: draw
+    * Calls draw on the icon, and returns that output.
+    * 
+    * Parameters:
+    * px - {<OpenLayers.Pixel>}
+    * 
+    * Returns:
+    * {DOMElement} A new DOM Image with this marker's icon set at the 
+    * location passed-in
+    */
+    draw: function(px) {
+        return this.icon.draw(px);
+    }, 
+
+    /** 
+    * Method: erase
+    * Erases any drawn elements for this marker.
+    */
+    erase: function() {
+        if (this.icon != null) {
+            this.icon.erase();
+        }
+    }, 
+
+    /**
+    * Method: moveTo
+    * Move the marker to the new location.
+    *
+    * Parameters:
+    * px - {<OpenLayers.Pixel>|Object} the pixel position to move to.
+    * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.
+    */
+    moveTo: function (px) {
+        if ((px != null) && (this.icon != null)) {
+            this.icon.moveTo(px);
+        }           
+        this.lonlat = this.map.getLonLatFromLayerPx(px);
+    },
+
+    /**
+     * APIMethod: isDrawn
+     * 
+     * Returns:
+     * {Boolean} Whether or not the marker is drawn.
+     */
+    isDrawn: function() {
+        var isDrawn = (this.icon && this.icon.isDrawn());
+        return isDrawn;   
+    },
+
+    /**
+     * Method: onScreen
+     *
+     * Returns:
+     * {Boolean} Whether or not the marker is currently visible on screen.
+     */
+    onScreen:function() {
+        
+        var onScreen = false;
+        if (this.map) {
+            var screenBounds = this.map.getExtent();
+            onScreen = screenBounds.containsLonLat(this.lonlat);
+        }    
+        return onScreen;
+    },
+    
+    /**
+     * Method: inflate
+     * Englarges the markers icon by the specified ratio.
+     *
+     * Parameters:
+     * inflate - {float} the ratio to enlarge the marker by (passing 2
+     *                   will double the size).
+     */
+    inflate: function(inflate) {
+        if (this.icon) {
+            this.icon.setSize({
+                w: this.icon.size.w * inflate,
+                h: this.icon.size.h * inflate
+            });
+        }        
+    },
+    
+    /** 
+     * Method: setOpacity
+     * Change the opacity of the marker by changin the opacity of 
+     *   its icon
+     * 
+     * Parameters:
+     * opacity - {float}  Specified as fraction (0.4, etc)
+     */
+    setOpacity: function(opacity) {
+        this.icon.setOpacity(opacity);
+    },
+
+    /**
+     * Method: setUrl
+     * Change URL of the Icon Image.
+     * 
+     * url - {String} 
+     */
+    setUrl: function(url) {
+        this.icon.setUrl(url);
+    },    
+
+    /** 
+     * Method: display
+     * Hide or show the icon
+     * 
+     * display - {Boolean} 
+     */
+    display: function(display) {
+        this.icon.display(display);
+    },
+
+    CLASS_NAME: "OpenLayers.Marker"
+});
+
+
+/**
+ * Function: defaultIcon
+ * Creates a default <OpenLayers.Icon>.
+ * 
+ * Returns:
+ * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
+ */
+OpenLayers.Marker.defaultIcon = function() {
+    return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),
+                               {w: 21, h: 25}, {x: -10.5, y: -25});
+};
+    
+
+/* ======================================================================
+    OpenLayers/Util/vendorPrefix.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/SingleFile.js
+ */
+
+OpenLayers.Util = OpenLayers.Util || {};
+/**
+ * Namespace: OpenLayers.Util.vendorPrefix
+ * A collection of utility functions to detect vendor prefixed features
+ */
+OpenLayers.Util.vendorPrefix = (function() {
+    "use strict";
+    
+    var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"],
+        divStyle = document.createElement("div").style,
+        cssCache = {},
+        jsCache = {};
+
+    
+    /**
+     * Function: domToCss
+     * Converts a upper camel case DOM style property name to a CSS property
+     *      i.e. transformOrigin -> transform-origin
+     *      or   WebkitTransformOrigin -> -webkit-transform-origin
+     *
+     * Parameters:
+     * prefixedDom - {String} The property to convert
+     *
+     * Returns:
+     * {String} The CSS property
+     */
+    function domToCss(prefixedDom) {
+        if (!prefixedDom) { return null; }
+        return prefixedDom.
+            replace(/([A-Z])/g, function(c) { return "-" + c.toLowerCase(); }).
+            replace(/^ms-/, "-ms-");
+    }
+
+    /**
+     * APIMethod: css
+     * Detect which property is used for a CSS property
+     *
+     * Parameters:
+     * property - {String} The standard (unprefixed) CSS property name
+     *
+     * Returns:
+     * {String} The standard CSS property, prefixed property or null if not
+     *          supported
+     */
+    function css(property) {
+        if (cssCache[property] === undefined) {
+            var domProperty = property.
+                replace(/(-[\s\S])/g, function(c) { return c.charAt(1).toUpperCase(); });
+            var prefixedDom = style(domProperty);
+            cssCache[property] = domToCss(prefixedDom);
+        }
+        return cssCache[property];
+    }
+
+    /**
+     * APIMethod: js
+     * Detect which property is used for a JS property/method
+     *
+     * Parameters:
+     * obj - {Object} The object to test on
+     * property - {String} The standard (unprefixed) JS property name
+     *
+     * Returns:
+     * {String} The standard JS property, prefixed property or null if not
+     *          supported
+     */
+    function js(obj, property) {
+        if (jsCache[property] === undefined) {
+            var tmpProp,
+                i = 0,
+                l = VENDOR_PREFIXES.length,
+                prefix,
+                isStyleObj = (typeof obj.cssText !== "undefined");
+
+            jsCache[property] = null;
+            for(; i<l; i++) {
+                prefix = VENDOR_PREFIXES[i];
+                if(prefix) {
+                    if (!isStyleObj) {
+                        // js prefix should be lower-case, while style
+                        // properties have upper case on first character
+                        prefix = prefix.toLowerCase();
+                    }
+                    tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);
+                } else {
+                    tmpProp = property;
+                }
+
+                if(obj[tmpProp] !== undefined) {
+                    jsCache[property] = tmpProp;
+                    break;
+                }
+            }
+        }
+        return jsCache[property];
+    }
+    
+    /**
+     * APIMethod: style
+     * Detect which property is used for a DOM style property
+     *
+     * Parameters:
+     * property - {String} The standard (unprefixed) style property name
+     *
+     * Returns:
+     * {String} The standard style property, prefixed property or null if not
+     *          supported
+     */
+    function style(property) {
+        return js(divStyle, property);
+    }
+    
+    return {
+        css:      css,
+        js:       js,
+        style:    style,
+        
+        // used for testing
+        cssCache:       cssCache,
+        jsCache:        jsCache
+    };
+}());
+/* ======================================================================
+    OpenLayers/Animation.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/SingleFile.js
+ * @requires OpenLayers/Util/vendorPrefix.js
+ */
+
+/**
+ * Namespace: OpenLayers.Animation
  * A collection of utility functions for executing methods that repaint a 
  *     portion of the browser window.  These methods take advantage of the
  *     browser's scheduled repaints where requestAnimationFrame is available.
@@ -6020,7 +6418,7 @@ OpenLayers.Animation = (function(window) {
     OpenLayers/Tween.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -6385,7 +6783,7 @@ OpenLayers.Easing.Quad = {
     OpenLayers/Projection.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -6491,7 +6889,7 @@ OpenLayers.Projection = OpenLayers.Class({
     /**
      * Method: equals
      * Test equality of two projection instances.  Determines equality based
-     *     soley on the projection code.
+     *     solely on the projection code.
      *
      * Returns:
      * {Boolean} The two projections are equivalent.
@@ -6553,23 +6951,27 @@ OpenLayers.Projection.transforms = {};
  * APIProperty: defaults
  * {Object} Defaults for the SRS codes known to OpenLayers (currently
  * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,
- * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,
- * maxExtent (the validity extent for the SRS) and yx (true if this SRS is
- * known to have a reverse axis order).
+ * EPSG:102113, EPSG:102100 and OSGEO:41001). Keys are the SRS code, values are
+ * units, maxExtent (the validity extent for the SRS in projected coordinates),
+ * worldExtent (the world's extent in EPSG:4326) and yx (true if this SRS
+ * is known to have a reverse axis order).
  */
 OpenLayers.Projection.defaults = {
     "EPSG:4326": {
         units: "degrees",
         maxExtent: [-180, -90, 180, 90],
+        worldExtent: [-180, -90, 180, 90],
         yx: true
     },
     "CRS:84": {
         units: "degrees",
-        maxExtent: [-180, -90, 180, 90]
+        maxExtent: [-180, -90, 180, 90],
+        worldExtent: [-180, -90, 180, 90]
     },
     "EPSG:900913": {
         units: "m",
-        maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]
+        maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34],
+        worldExtent: [-180, -89, 180, 89]
     }
 };
 
@@ -6653,9 +7055,9 @@ OpenLayers.Projection.nullTransform = function(point) {
 
 /**
  * Note: Transforms for web mercator <-> geographic
- * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
- * OpenLayers originally started referring to EPSG:900913 as web mercator.
- * The EPSG has declared EPSG:3857 to be web mercator.
+ * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113, EPSG:102100 and 
+ * OSGEO:41001. OpenLayers originally started referring to EPSG:900913 as web
+ * mercator. The EPSG has declared EPSG:3857 to be web mercator.
  * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as
  * equivalent.  See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084.
  * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and
@@ -6696,7 +7098,7 @@ OpenLayers.Projection.nullTransform = function(point) {
     }
     
     // list of equivalent codes for web mercator
-    var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"],
+    var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100", "OSGEO:41001"],
         geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"],
         i;
     for (i=mercator.length-1; i>=0; --i) {
@@ -6711,7 +7113,7 @@ OpenLayers.Projection.nullTransform = function(point) {
     OpenLayers/Map.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -6795,6 +7197,9 @@ OpenLayers.Map = OpenLayers.Class({
      *     zoom has changed.
      * move - triggered after each drag, pan, or zoom
      * moveend - triggered after a drag, pan, or zoom completes
+     * zoomstart - triggered when a zoom starts. Listeners receive an object
+     *     with *center* and *zoom* properties, for the target center and zoom
+     *     level.
      * zoomend - triggered after a zoom completes
      * mouseover - triggered after mouseover the map
      * mouseout - triggered after mouseout the map
@@ -7221,10 +7626,6 @@ OpenLayers.Map = OpenLayers.Class({
      *     Note that if an ArgParser/Permalink control is present,
      *     and the querystring contains a zoom level, zoom will be set
      *     by that, and this option will be ignored.
-     * extent - {<OpenLayers.Bounds>|Array} The initial extent of the map.
-     *     If provided as an array, the array should consist of
-     *     four values (left, bottom, right, top).
-     *     Only specify if <center> and <zoom> are not provided.
      * 
      * Examples:
      * (code)
@@ -7259,7 +7660,8 @@ OpenLayers.Map = OpenLayers.Class({
     initialize: function (div, options) {
         
         // If only one argument is provided, check if it is an object.
-        if(arguments.length === 1 && typeof div === "object") {
+        var isDOMElement = OpenLayers.Util.isElement(div);
+        if(arguments.length === 1 && typeof div === "object" && !isDOMElement) {
             options = div;
             div = options && options.div;
         }
@@ -7972,7 +8374,7 @@ OpenLayers.Map = OpenLayers.Class({
      *     the layer is moved down.  Again, note that this cannot (or at least
      *     should not) be effectively used to raise base layers above overlays.
      *
-     * Paremeters:
+     * Parameters:
      * layer - {<OpenLayers.Layer>} 
      * delta - {int} 
      */
@@ -7998,6 +8400,7 @@ OpenLayers.Map = OpenLayers.Class({
 
                 // preserve center and scale when changing base layers
                 var center = this.getCachedCenter();
+                var oldResolution = this.getResolution();
                 var newResolution = OpenLayers.Util.getResolutionFromScale(
                     this.getScale(), newBaseLayer.units
                 );
@@ -8026,7 +8429,7 @@ OpenLayers.Map = OpenLayers.Class({
                         newResolution || this.resolution, true
                     );
                     // zoom and force zoom change
-                    this.setCenter(center, newZoom, false, true);
+                    this.setCenter(center, newZoom, false, oldResolution != newResolution);
                 }
 
                 this.events.triggerEvent("changebaselayer", {
@@ -8428,7 +8831,7 @@ OpenLayers.Map = OpenLayers.Class({
    
    /** 
      * APIMethod: panTo
-     * Allows user to pan to a new lonlat
+     * Allows user to pan to a new lonlat.
      * If the new lonlat is in the current extent the map will slide smoothly
      * 
      * Parameters:
@@ -8689,7 +9092,7 @@ OpenLayers.Map = OpenLayers.Class({
 
             if (centerChanged) {
                 if (!zoomChanged && this.center) { 
-                    // if zoom hasnt changed, just slide layerContainer
+                    // if zoom hasn't changed, just slide layerContainer
                     //  (must be done before setting this.center to new value)
                     this.centerLayerContainer(lonlat);
                 }
@@ -9110,44 +9513,46 @@ OpenLayers.Map = OpenLayers.Class({
             if (map.baseLayer.wrapDateLine) {
                 zoom = map.adjustZoom(zoom);
             }
+            var center = xy ?
+                map.getZoomTargetCenter(xy, map.getResolutionForZoom(zoom)) :
+                map.getCenter();
+            if (center) {
+                map.events.triggerEvent('zoomstart', {
+                    center: center,
+                    zoom: zoom
+                });
+            }
             if (map.zoomTween) {
+                map.zoomTween.stop();
                 var currentRes = map.getResolution(),
                     targetRes = map.getResolutionForZoom(zoom),
                     start = {scale: 1},
                     end = {scale: currentRes / targetRes};
-                if (map.zoomTween.playing && map.zoomTween.duration < 3 * map.zoomDuration) {
-                    // update the end scale, and reuse the running zoomTween
-                    map.zoomTween.finish = {
-                        scale: map.zoomTween.finish.scale * end.scale
-                    };
-                } else {
-                    if (!xy) {
-                        var size = map.getSize();
-                        xy = {x: size.w / 2, y: size.h / 2};
-                    }
-                    map.zoomTween.start(start, end, map.zoomDuration, {
-                        minFrameRate: 50, // don't spend much time zooming
-                        callbacks: {
-                            eachStep: function(data) {
-                                var containerOrigin = map.layerContainerOriginPx,
-                                    scale = data.scale,
-                                    dx = ((scale - 1) * (containerOrigin.x - xy.x)) | 0,
-                                    dy = ((scale - 1) * (containerOrigin.y - xy.y)) | 0;
-                                map.applyTransform(containerOrigin.x + dx, containerOrigin.y + dy, scale);
-                            },
-                            done: function(data) {
-                                map.applyTransform();
-                                var resolution = map.getResolution() / data.scale,
-                                    zoom = map.getZoomForResolution(resolution, true)
-                                map.moveTo(map.getZoomTargetCenter(xy, resolution), zoom, true);
-                            }
+                if (!xy) {
+                    var size = map.getSize();
+                    xy = {x: size.w / 2, y: size.h / 2};
+                }
+                map.zoomTween.start(start, end, map.zoomDuration, {
+                    minFrameRate: 50, // don't spend much time zooming
+                    callbacks: {
+                        eachStep: function(data) {
+                            var containerOrigin = map.layerContainerOriginPx,
+                                scale = data.scale,
+                                dx = ((scale - 1) * (containerOrigin.x - xy.x)) | 0,
+                                dy = ((scale - 1) * (containerOrigin.y - xy.y)) | 0;
+                            map.applyTransform(containerOrigin.x + dx, containerOrigin.y + dy, scale);
+                        },
+                        done: function(data) {
+                            map.applyTransform();
+                            var resolution = map.getResolution() / data.scale,
+                                newZoom = map.getZoomForResolution(resolution, true),
+                                newCenter = data.scale === 1 ? center :
+                                        map.getZoomTargetCenter(xy, resolution);
+                            map.moveTo(newCenter, newZoom);
                         }
-                    });
-                }
+                    }
+                });
             } else {
-                var center = xy ?
-                    map.getZoomTargetCenter(xy, map.getResolutionForZoom(zoom)) :
-                    null;
                 map.setCenter(center, zoom);
             }
         }
@@ -9158,6 +9563,9 @@ OpenLayers.Map = OpenLayers.Class({
      * 
      */
     zoomIn: function() {
+        if (this.zoomTween) {
+            this.zoomTween.stop();
+        }
         this.zoomTo(this.getZoom() + 1);
     },
     
@@ -9166,6 +9574,9 @@ OpenLayers.Map = OpenLayers.Class({
      * 
      */
     zoomOut: function() {
+        if (this.zoomTween) {
+            this.zoomTween.stop();
+        }
         this.zoomTo(this.getZoom() - 1);
     },
 
@@ -9579,10 +9990,10 @@ OpenLayers.Map.TILE_WIDTH = 256;
  */
 OpenLayers.Map.TILE_HEIGHT = 256;
 /* ======================================================================
-    OpenLayers/Layer.js
+    OpenLayers/Feature.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -9590,3111 +10001,2494 @@ OpenLayers.Map.TILE_HEIGHT = 256;
 
 /**
  * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Map.js
- * @requires OpenLayers/Projection.js
+ * @requires OpenLayers/Util.js
  */
 
 /**
- * Class: OpenLayers.Layer
+ * Class: OpenLayers.Feature
+ * Features are combinations of geography and attributes. The OpenLayers.Feature
+ *     class specifically combines a marker and a lonlat.
  */
-OpenLayers.Layer = OpenLayers.Class({
-
-    /**
-     * APIProperty: id
-     * {String}
-     */
-    id: null,
+OpenLayers.Feature = OpenLayers.Class({
 
     /** 
-     * APIProperty: name
-     * {String}
+     * Property: layer 
+     * {<OpenLayers.Layer>} 
      */
-    name: null,
+    layer: null,
 
     /** 
-     * APIProperty: div
-     * {DOMElement}
+     * Property: id 
+     * {String} 
      */
-    div: null,
-
-    /**
-     * APIProperty: opacity
-     * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default
-     * is 1.
+    id: null,
+    
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} 
      */
-    opacity: 1,
+    lonlat: null,
 
-    /**
-     * APIProperty: alwaysInRange
-     * {Boolean} If a layer's display should not be scale-based, this should 
-     *     be set to true. This will cause the layer, as an overlay, to always 
-     *     be 'active', by always returning true from the calculateInRange() 
-     *     function. 
-     * 
-     *     If not explicitly specified for a layer, its value will be 
-     *     determined on startup in initResolutions() based on whether or not 
-     *     any scale-specific properties have been set as options on the 
-     *     layer. If no scale-specific options have been set on the layer, we 
-     *     assume that it should always be in range.
-     * 
-     *     See #987 for more info.
+    /** 
+     * Property: data 
+     * {Object} 
      */
-    alwaysInRange: null,   
+    data: null,
 
-    /**
-     * Constant: RESOLUTION_PROPERTIES
-     * {Array} The properties that are used for calculating resolutions
-     *     information.
+    /** 
+     * Property: marker 
+     * {<OpenLayers.Marker>} 
      */
-    RESOLUTION_PROPERTIES: [
-        'scales', 'resolutions',
-        'maxScale', 'minScale',
-        'maxResolution', 'minResolution',
-        'numZoomLevels', 'maxZoomLevel'
-    ],
+    marker: null,
 
     /**
-     * APIProperty: events
-     * {<OpenLayers.Events>}
-     *
-     * Register a listener for a particular event with the following syntax:
-     * (code)
-     * layer.events.register(type, obj, listener);
-     * (end)
-     *
-     * Listeners will be called with a reference to an event object.  The
-     *     properties of this event depends on exactly what happened.
-     *
-     * All event objects have at least the following properties:
-     * object - {Object} A reference to layer.events.object.
-     * element - {DOMElement} A reference to layer.events.element.
-     *
-     * Supported map event types:
-     * loadstart - Triggered when layer loading starts.  When using a Vector 
-     *     layer with a Fixed or BBOX strategy, the event object includes 
-     *     a *filter* property holding the OpenLayers.Filter used when 
-     *     calling read on the protocol.
-     * loadend - Triggered when layer loading ends.  When using a Vector layer
-     *     with a Fixed or BBOX strategy, the event object includes a 
-     *     *response* property holding an OpenLayers.Protocol.Response object.
-     * visibilitychanged - Triggered when the layer's visibility property is
-     *     changed, e.g. by turning the layer on or off in the layer switcher.
-     *     Note that the actual visibility of the layer can also change if it
-     *     gets out of range (see <calculateInRange>). If you also want to catch
-     *     these cases, register for the map's 'changelayer' event instead.
-     * move - Triggered when layer moves (triggered with every mousemove
-     *     during a drag).
-     * moveend - Triggered when layer is done moving, object passed as
-     *     argument has a zoomChanged boolean property which tells that the
-     *     zoom has changed.
-     * added - Triggered after the layer is added to a map.  Listeners will
-     *     receive an object with a *map* property referencing the map and a
-     *     *layer* property referencing the layer.
-     * removed - Triggered after the layer is removed from the map.  Listeners
-     *     will receive an object with a *map* property referencing the map and
-     *     a *layer* property referencing the layer.
+     * APIProperty: popupClass
+     * {<OpenLayers.Class>} The class which will be used to instantiate
+     *     a new Popup. Default is <OpenLayers.Popup.Anchored>.
      */
-    events: null,
+    popupClass: null,
 
-    /**
-     * APIProperty: map
-     * {<OpenLayers.Map>} This variable is set when the layer is added to 
-     *     the map, via the accessor function setMap().
-     */
-    map: null,
-    
-    /**
-     * APIProperty: isBaseLayer
-     * {Boolean} Whether or not the layer is a base layer. This should be set 
-     *     individually by all subclasses. Default is false
-     */
-    isBaseLayer: false,
-    /**
-     * Property: alpha
-     * {Boolean} The layer's images have an alpha channel.  Default is false.
+    /** 
+     * Property: popup 
+     * {<OpenLayers.Popup>} 
      */
-    alpha: false,
+    popup: null,
 
     /** 
-     * APIProperty: displayInLayerSwitcher
-     * {Boolean} Display the layer's name in the layer switcher.  Default is
-     *     true.
+     * Constructor: OpenLayers.Feature
+     * Constructor for features.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * lonlat - {<OpenLayers.LonLat>} 
+     * data - {Object} 
+     * 
+     * Returns:
+     * {<OpenLayers.Feature>}
      */
-    displayInLayerSwitcher: true,
+    initialize: function(layer, lonlat, data) {
+        this.layer = layer;
+        this.lonlat = lonlat;
+        this.data = (data != null) ? data : {};
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); 
+    },
 
-    /**
-     * APIProperty: visibility
-     * {Boolean} The layer should be displayed in the map.  Default is true.
+    /** 
+     * Method: destroy
+     * nullify references to prevent circular references and memory leaks
      */
-    visibility: true,
+    destroy: function() {
 
-    /**
-     * APIProperty: attribution
-     * {String} Attribution string, displayed when an 
-     *     <OpenLayers.Control.Attribution> has been added to the map.
-     */
-    attribution: null, 
+        //remove the popup from the map
+        if ((this.layer != null) && (this.layer.map != null)) {
+            if (this.popup != null) {
+                this.layer.map.removePopup(this.popup);
+            }
+        }
+        // remove the marker from the layer
+        if (this.layer != null && this.marker != null) {
+            this.layer.removeMarker(this.marker);
+        }
 
-    /** 
-     * Property: inRange
-     * {Boolean} The current map resolution is within the layer's min/max 
-     *     range. This is set in <OpenLayers.Map.setCenter> whenever the zoom 
-     *     changes.
-     */
-    inRange: false,
+        this.layer = null;
+        this.id = null;
+        this.lonlat = null;
+        this.data = null;
+        if (this.marker != null) {
+            this.destroyMarker(this.marker);
+            this.marker = null;
+        }
+        if (this.popup != null) {
+            this.destroyPopup(this.popup);
+            this.popup = null;
+        }
+    },
     
     /**
-     * Propery: imageSize
-     * {<OpenLayers.Size>} For layers with a gutter, the image is larger than 
-     *     the tile by twice the gutter in each dimension.
+     * Method: onScreen
+     * 
+     * Returns:
+     * {Boolean} Whether or not the feature is currently visible on screen
+     *           (based on its 'lonlat' property)
      */
-    imageSize: null,
+    onScreen:function() {
+        
+        var onScreen = false;
+        if ((this.layer != null) && (this.layer.map != null)) {
+            var screenBounds = this.layer.map.getExtent();
+            onScreen = screenBounds.containsLonLat(this.lonlat);
+        }    
+        return onScreen;
+    },
     
-  // OPTIONS
-
-    /** 
-     * Property: options
-     * {Object} An optional object whose properties will be set on the layer.
-     *     Any of the layer properties can be set as a property of the options
-     *     object and sent to the constructor when the layer is created.
-     */
-    options: null,
 
     /**
-     * APIProperty: eventListeners
-     * {Object} If set as an option at construction, the eventListeners
-     *     object will be registered with <OpenLayers.Events.on>.  Object
-     *     structure must be a listeners object as shown in the example for
-     *     the events.on method.
+     * Method: createMarker
+     * Based on the data associated with the Feature, create and return a marker object.
+     *
+     * Returns: 
+     * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
+     *          set in this.data. If no 'lonlat' is set, returns null. If no
+     *          'icon' is set, OpenLayers.Marker() will load the default image.
+     *          
+     *          Note - this.marker is set to return value
+     * 
      */
-    eventListeners: null,
+    createMarker: function() {
+
+        if (this.lonlat != null) {
+            this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
+        }
+        return this.marker;
+    },
 
     /**
-     * APIProperty: gutter
-     * {Integer} Determines the width (in pixels) of the gutter around image
-     *     tiles to ignore.  By setting this property to a non-zero value,
-     *     images will be requested that are wider and taller than the tile
-     *     size by a value of 2 x gutter.  This allows artifacts of rendering
-     *     at tile edges to be ignored.  Set a gutter value that is equal to
-     *     half the size of the widest symbol that needs to be displayed.
-     *     Defaults to zero.  Non-tiled layers always have zero gutter.
-     */ 
-    gutter: 0, 
+     * Method: destroyMarker
+     * Destroys marker.
+     * If user overrides the createMarker() function, s/he should be able
+     *   to also specify an alternative function for destroying it
+     */
+    destroyMarker: function() {
+        this.marker.destroy();  
+    },
 
     /**
-     * APIProperty: projection
-     * {<OpenLayers.Projection>} or {<String>} Specifies the projection of the layer.
-     *     Can be set in the layer options. If not specified in the layer options,
-     *     it is set to the default projection specified in the map,
-     *     when the layer is added to the map.
-     *     Projection along with default maxExtent and resolutions
-     *     are set automatically with commercial baselayers in EPSG:3857,
-     *     such as Google, Bing and OpenStreetMap, and do not need to be specified.
-     *     Otherwise, if specifying projection, also set maxExtent,
-     *     maxResolution or resolutions as appropriate.
-     *     When using vector layers with strategies, layer projection should be set
-     *     to the projection of the source data if that is different from the map default.
+     * Method: createPopup
+     * Creates a popup object created from the 'lonlat', 'popupSize',
+     *     and 'popupContentHTML' properties set in this.data. It uses
+     *     this.marker.icon as default anchor. 
+     *  
+     *  If no 'lonlat' is set, returns null. 
+     *  If no this.marker has been created, no anchor is sent.
+     *
+     *  Note - the returned popup object is 'owned' by the feature, so you
+     *      cannot use the popup's destroy method to discard the popup.
+     *      Instead, you must use the feature's destroyPopup
      * 
-     *     Can be either a string or an <OpenLayers.Projection> object;
-     *     if a string is passed, will be converted to an object when
-     *     the layer is added to the map.
+     *  Note - this.popup is set to return value
+     * 
+     * Parameters: 
+     * closeBox - {Boolean} create popup with closebox or not
+     * 
+     * Returns:
+     * {<OpenLayers.Popup>} Returns the created popup, which is also set
+     *     as 'popup' property of this feature. Will be of whatever type
+     *     specified by this feature's 'popupClass' property, but must be
+     *     of type <OpenLayers.Popup>.
      * 
      */
-    projection: null,    
-    
-    /**
-     * APIProperty: units
-     * {String} The layer map units.  Defaults to null.  Possible values
-     *     are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
-     *     Normally taken from the projection.
-     *     Only required if both map and layers do not define a projection,
-     *     or if they define a projection which does not define units.
-     */
-    units: null,
+    createPopup: function(closeBox) {
 
-    /**
-     * APIProperty: scales
-     * {Array}  An array of map scales in descending order.  The values in the
-     *     array correspond to the map scale denominator.  Note that these
-     *     values only make sense if the display (monitor) resolution of the
-     *     client is correctly guessed by whomever is configuring the
-     *     application.  In addition, the units property must also be set.
-     *     Use <resolutions> instead wherever possible.
-     */
-    scales: null,
+        if (this.lonlat != null) {
+            if (!this.popup) {
+                var anchor = (this.marker) ? this.marker.icon : null;
+                var popupClass = this.popupClass ? 
+                    this.popupClass : OpenLayers.Popup.Anchored;
+                this.popup = new popupClass(this.id + "_popup", 
+                                            this.lonlat,
+                                            this.data.popupSize,
+                                            this.data.popupContentHTML,
+                                            anchor, 
+                                            closeBox); 
+            }    
+            if (this.data.overflow != null) {
+                this.popup.contentDiv.style.overflow = this.data.overflow;
+            }    
+            
+            this.popup.feature = this;
+        }        
+        return this.popup;
+    },
 
-    /**
-     * APIProperty: resolutions
-     * {Array} A list of map resolutions (map units per pixel) in descending
-     *     order.  If this is not set in the layer constructor, it will be set
-     *     based on other resolution related properties (maxExtent,
-     *     maxResolution, maxScale, etc.).
-     */
-    resolutions: null,
     
     /**
-     * APIProperty: maxExtent
-     * {<OpenLayers.Bounds>|Array} If provided as an array, the array
-     *     should consist of four values (left, bottom, right, top).
-     *     The maximum extent for the layer.  Defaults to null.
-     * 
-     *     The center of these bounds will not stray outside
-     *     of the viewport extent during panning.  In addition, if
-     *     <displayOutsideMaxExtent> is set to false, data will not be
-     *     requested that falls completely outside of these bounds.
+     * Method: destroyPopup
+     * Destroys the popup created via createPopup.
+     *
+     * As with the marker, if user overrides the createPopup() function, s/he 
+     *   should also be able to override the destruction
      */
-    maxExtent: null,
-    
-    /**
-     * APIProperty: minExtent
-     * {<OpenLayers.Bounds>|Array} If provided as an array, the array
-     *     should consist of four values (left, bottom, right, top).
-     *     The minimum extent for the layer.  Defaults to null.
+    destroyPopup: function() {
+        if (this.popup) {
+            this.popup.feature = null;
+            this.popup.destroy();
+            this.popup = null;
+        }    
+    },
+
+    CLASS_NAME: "OpenLayers.Feature"
+});
+/* ======================================================================
+    OpenLayers/Feature/Vector.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+// TRASH THIS
+OpenLayers.State = {
+    /** states */
+    UNKNOWN: 'Unknown',
+    INSERT: 'Insert',
+    UPDATE: 'Update',
+    DELETE: 'Delete'
+};
+
+/**
+ * @requires OpenLayers/Feature.js
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Feature.Vector
+ * Vector features use the OpenLayers.Geometry classes as geometry description.
+ * They have an 'attributes' property, which is the data object, and a 'style'
+ * property, the default values of which are defined in the 
+ * <OpenLayers.Feature.Vector.style> objects.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Feature>
+ */
+OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
+
+    /** 
+     * Property: fid 
+     * {String} 
      */
-    minExtent: null,
+    fid: null,
     
-    /**
-     * APIProperty: maxResolution
-     * {Float} Default max is 360 deg / 256 px, which corresponds to
-     *     zoom level 0 on gmaps.  Specify a different value in the layer 
-     *     options if you are not using the default <OpenLayers.Map.tileSize>
-     *     and displaying the whole world.
+    /** 
+     * APIProperty: geometry 
+     * {<OpenLayers.Geometry>} 
      */
-    maxResolution: null,
+    geometry: null,
 
-    /**
-     * APIProperty: minResolution
-     * {Float}
+    /** 
+     * APIProperty: attributes 
+     * {Object} This object holds arbitrary, serializable properties that
+     *     describe the feature.
      */
-    minResolution: null,
+    attributes: null,
 
     /**
-     * APIProperty: numZoomLevels
-     * {Integer}
+     * Property: bounds
+     * {<OpenLayers.Bounds>} The box bounding that feature's geometry, that
+     *     property can be set by an <OpenLayers.Format> object when
+     *     deserializing the feature, so in most cases it represents an
+     *     information set by the server. 
      */
-    numZoomLevels: null,
-    
-    /**
-     * APIProperty: minScale
-     * {Float}
+    bounds: null,
+
+    /** 
+     * Property: state 
+     * {String} 
      */
-    minScale: null,
+    state: null,
     
-    /**
-     * APIProperty: maxScale
-     * {Float}
+    /** 
+     * APIProperty: style 
+     * {Object} 
      */
-    maxScale: null,
+    style: null,
 
     /**
-     * APIProperty: displayOutsideMaxExtent
-     * {Boolean} Request map tiles that are completely outside of the max 
-     *     extent for this layer. Defaults to false.
+     * APIProperty: url
+     * {String} If this property is set it will be taken into account by
+     *     {<OpenLayers.HTTP>} when updating or deleting the feature.
      */
-    displayOutsideMaxExtent: false,
-
+    url: null,
+    
     /**
-     * APIProperty: wrapDateLine
-     * {Boolean} Wraps the world at the international dateline, so the map can
-     * be panned infinitely in longitudinal direction. Only use this on the
-     * base layer, and only if the layer's maxExtent equals the world bounds.
-     * #487 for more info.   
+     * Property: renderIntent
+     * {String} rendering intent currently being used
      */
-    wrapDateLine: false,
+    renderIntent: "default",
     
     /**
-     * Property: metadata
-     * {Object} This object can be used to store additional information on a
-     *     layer object.
-     */
-    metadata: null,
-    
-    /**
-     * Constructor: OpenLayers.Layer
+     * APIProperty: modified
+     * {Object} An object with the originals of the geometry and attributes of
+     * the feature, if they were changed. Currently this property is only read
+     * by <OpenLayers.Format.WFST.v1>, and written by
+     * <OpenLayers.Control.ModifyFeature>, which sets the geometry property.
+     * Applications can set the originals of modified attributes in the
+     * attributes property. Note that applications have to check if this
+     * object and the attributes property is already created before using it.
+     * After a change made with ModifyFeature, this object could look like
      *
-     * Parameters:
-     * name - {String} The layer name
-     * options - {Object} Hashtable of extra options to tag onto the layer
+     * (code)
+     * {
+     *     geometry: >Object
+     * }
+     * (end)
+     *
+     * When an application has made changes to feature attributes, it could
+     * have set the attributes to something like this:
+     *
+     * (code)
+     * {
+     *     attributes: {
+     *         myAttribute: "original"
+     *     }
+     * }
+     * (end)
+     *
+     * Note that <OpenLayers.Format.WFST.v1> only checks for truthy values in
+     * *modified.geometry* and the attribute names in *modified.attributes*,
+     * but it is recommended to set the original values (and not just true) as
+     * attribute value, so applications could use this information to undo
+     * changes.
      */
-    initialize: function(name, options) {
-
-        this.metadata = {};
-        
-        options = OpenLayers.Util.extend({}, options);
-        // make sure we respect alwaysInRange if set on the prototype
-        if (this.alwaysInRange != null) {
-            options.alwaysInRange = this.alwaysInRange;
-        }
-        this.addOptions(options);
-
-        this.name = name;
-        
-        if (this.id == null) {
-
-            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-
-            this.div = OpenLayers.Util.createDiv(this.id);
-            this.div.style.width = "100%";
-            this.div.style.height = "100%";
-            this.div.dir = "ltr";
-
-            this.events = new OpenLayers.Events(this, this.div);
-            if(this.eventListeners instanceof Object) {
-                this.events.on(this.eventListeners);
-            }
+    modified: null,
 
-        }
-    },
-    
-    /**
-     * Method: destroy
-     * Destroy is a destructor: this is to alleviate cyclic references which
-     *     the Javascript garbage cleaner can not take care of on its own.
-     *
+    /** 
+     * Constructor: OpenLayers.Feature.Vector
+     * Create a vector feature. 
+     * 
      * Parameters:
-     * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
-     *     been destroyed.  Default is true.
+     * geometry - {<OpenLayers.Geometry>} The geometry that this feature
+     *     represents.
+     * attributes - {Object} An optional object that will be mapped to the
+     *     <attributes> property. 
+     * style - {Object} An optional style object.
      */
-    destroy: function(setNewBaseLayer) {
-        if (setNewBaseLayer == null) {
-            setNewBaseLayer = true;
-        }
-        if (this.map != null) {
-            this.map.removeLayer(this, setNewBaseLayer);
-        }
-        this.projection = null;
-        this.map = null;
-        this.name = null;
-        this.div = null;
-        this.options = null;
-
-        if (this.events) {
-            if(this.eventListeners) {
-                this.events.un(this.eventListeners);
-            }
-            this.events.destroy();
+    initialize: function(geometry, attributes, style) {
+        OpenLayers.Feature.prototype.initialize.apply(this,
+                                                      [null, null, attributes]);
+        this.lonlat = null;
+        this.geometry = geometry ? geometry : null;
+        this.state = null;
+        this.attributes = {};
+        if (attributes) {
+            this.attributes = OpenLayers.Util.extend(this.attributes,
+                                                     attributes);
         }
-        this.eventListeners = null;
-        this.events = null;
+        this.style = style ? style : null; 
     },
     
-   /**
-    * Method: clone
-    *
-    * Parameters:
-    * obj - {<OpenLayers.Layer>} The layer to be cloned
-    *
-    * Returns:
-    * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
-    */
-    clone: function (obj) {
-        
-        if (obj == null) {
-            obj = new OpenLayers.Layer(this.name, this.getOptions());
+    /** 
+     * Method: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+        if (this.layer) {
+            this.layer.removeFeatures(this);
+            this.layer = null;
         }
-        
-        // catch any randomly tagged-on properties
-        OpenLayers.Util.applyDefaults(obj, this);
-        
-        // a cloned layer should never have its map property set
-        //  because it has not been added to a map yet. 
-        obj.map = null;
-        
-        return obj;
+            
+        this.geometry = null;
+        this.modified = null;
+        OpenLayers.Feature.prototype.destroy.apply(this, arguments);
     },
     
     /**
-     * Method: getOptions
-     * Extracts an object from the layer with the properties that were set as
-     *     options, but updates them with the values currently set on the
-     *     instance.
-     * 
+     * Method: clone
+     * Create a clone of this vector feature.  Does not set any non-standard
+     *     properties.
+     *
      * Returns:
-     * {Object} the <options> of the layer, representing the current state.
+     * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
      */
-    getOptions: function() {
-        var options = {};
-        for(var o in this.options) {
-            options[o] = this[o];
-        }
-        return options;
+    clone: function () {
+        return new OpenLayers.Feature.Vector(
+            this.geometry ? this.geometry.clone() : null,
+            this.attributes,
+            this.style);
     },
-    
-    /** 
-     * APIMethod: setName
-     * Sets the new layer name for this layer.  Can trigger a changelayer event
-     *     on the map.
+
+    /**
+     * Method: onScreen
+     * Determine whether the feature is within the map viewport.  This method
+     *     tests for an intersection between the geometry and the viewport
+     *     bounds.  If a more efficient but less precise geometry bounds
+     *     intersection is desired, call the method with the boundsOnly
+     *     parameter true.
      *
      * Parameters:
-     * newName - {String} The new name.
+     * boundsOnly - {Boolean} Only test whether a feature's bounds intersects
+     *     the viewport bounds.  Default is false.  If false, the feature's
+     *     geometry must intersect the viewport for onScreen to return true.
+     * 
+     * Returns:
+     * {Boolean} The feature is currently visible on screen (optionally
+     *     based on its bounds if boundsOnly is true).
      */
-    setName: function(newName) {
-        if (newName != this.name) {
-            this.name = newName;
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer", {
-                    layer: this,
-                    property: "name"
-                });
-            }
-        }
-    },    
-    
-   /**
-    * APIMethod: addOptions
-    * 
-    * Parameters:
-    * newOptions - {Object}
-    * reinitialize - {Boolean} If set to true, and if resolution options of the
-    *     current baseLayer were changed, the map will be recentered to make
-    *     sure that it is displayed with a valid resolution, and a
-    *     changebaselayer event will be triggered.
-    */
-    addOptions: function (newOptions, reinitialize) {
-
-        if (this.options == null) {
-            this.options = {};
-        }
-        
-        if (newOptions) {
-            // make sure this.projection references a projection object
-            if(typeof newOptions.projection == "string") {
-                newOptions.projection = new OpenLayers.Projection(newOptions.projection);
-            }
-            if (newOptions.projection) {
-                // get maxResolution, units and maxExtent from projection defaults if
-                // they are not defined already
-                OpenLayers.Util.applyDefaults(newOptions,
-                    OpenLayers.Projection.defaults[newOptions.projection.getCode()]);
-            }
-            // allow array for extents
-            if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) {
-                newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent);
-            }
-            if (newOptions.minExtent && !(newOptions.minExtent instanceof OpenLayers.Bounds)) {
-                newOptions.minExtent = new OpenLayers.Bounds(newOptions.minExtent);
-            }
-        }
-
-        // update our copy for clone
-        OpenLayers.Util.extend(this.options, newOptions);
-
-        // add new options to this
-        OpenLayers.Util.extend(this, newOptions);
-        
-        // get the units from the projection, if we have a projection
-        // and it it has units
-        if(this.projection && this.projection.getUnits()) {
-            this.units = this.projection.getUnits();
-        }
-
-        // re-initialize resolutions if necessary, i.e. if any of the
-        // properties of the "properties" array defined below is set
-        // in the new options
-        if(this.map) {
-            // store current resolution so we can try to restore it later
-            var resolution = this.map.getResolution();
-            var properties = this.RESOLUTION_PROPERTIES.concat(
-                ["projection", "units", "minExtent", "maxExtent"]
-            );
-            for(var o in newOptions) {
-                if(newOptions.hasOwnProperty(o) &&
-                   OpenLayers.Util.indexOf(properties, o) >= 0) {
-
-                    this.initResolutions();
-                    if (reinitialize && this.map.baseLayer === this) {
-                        // update map position, and restore previous resolution
-                        this.map.setCenter(this.map.getCenter(),
-                            this.map.getZoomForResolution(resolution),
-                            false, true
-                        );
-                        // trigger a changebaselayer event to make sure that
-                        // all controls (especially
-                        // OpenLayers.Control.PanZoomBar) get notified of the
-                        // new options
-                        this.map.events.triggerEvent("changebaselayer", {
-                            layer: this
-                        });
-                    }
-                    break;
-                }
+    onScreen:function(boundsOnly) {
+        var onScreen = false;
+        if(this.layer && this.layer.map) {
+            var screenBounds = this.layer.map.getExtent();
+            if(boundsOnly) {
+                var featureBounds = this.geometry.getBounds();
+                onScreen = screenBounds.intersectsBounds(featureBounds);
+            } else {
+                var screenPoly = screenBounds.toGeometry();
+                onScreen = screenPoly.intersects(this.geometry);
             }
-        }
+        }    
+        return onScreen;
     },
 
     /**
-     * APIMethod: onMapResize
-     * This function can be implemented by subclasses
+     * Method: getVisibility
+     * Determine whether the feature is displayed or not. It may not displayed
+     *     because:
+     *     - its style display property is set to 'none',
+     *     - it doesn't belong to any layer,
+     *     - the styleMap creates a symbolizer with display property set to 'none'
+     *          for it,
+     *     - the layer which it belongs to is not visible.
+     * 
+     * Returns:
+     * {Boolean} The feature is currently displayed.
      */
-    onMapResize: function() {
-        //this function can be implemented by subclasses  
+    getVisibility: function() {
+        return !(this.style && this.style.display == 'none' ||
+                 !this.layer ||
+                 this.layer && this.layer.styleMap &&
+                 this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||
+                 this.layer && !this.layer.getVisibility());
     },
-
+    
     /**
-     * APIMethod: redraw
-     * Redraws the layer.  Returns true if the layer was redrawn, false if not.
-     *
+     * Method: createMarker
+     * HACK - we need to decide if all vector features should be able to
+     *     create markers
+     * 
      * Returns:
-     * {Boolean} The layer was redrawn.
+     * {<OpenLayers.Marker>} For now just returns null
      */
-    redraw: function() {
-        var redrawn = false;
-        if (this.map) {
-
-            // min/max Range may have changed
-            this.inRange = this.calculateInRange();
-
-            // map's center might not yet be set
-            var extent = this.getExtent();
-
-            if (extent && this.inRange && this.visibility) {
-                var zoomChanged = true;
-                this.moveTo(extent, zoomChanged, false);
-                this.events.triggerEvent("moveend",
-                    {"zoomChanged": zoomChanged});
-                redrawn = true;
-            }
-        }
-        return redrawn;
+    createMarker: function() {
+        return null;
     },
 
     /**
-     * Method: moveTo
+     * Method: destroyMarker
+     * HACK - we need to decide if all vector features should be able to
+     *     delete markers
      * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
-     *     do some init work in that case.
-     * dragging - {Boolean}
+     * If user overrides the createMarker() function, s/he should be able
+     *   to also specify an alternative function for destroying it
      */
-    moveTo:function(bounds, zoomChanged, dragging) {
-        var display = this.visibility;
-        if (!this.isBaseLayer) {
-            display = display && this.inRange;
-        }
-        this.display(display);
+    destroyMarker: function() {
+        // pass
     },
 
     /**
-     * Method: moveByPx
-     * Move the layer based on pixel vector. To be implemented by subclasses.
-     *
-     * Parameters:
-     * dx - {Number} The x coord of the displacement vector.
-     * dy - {Number} The y coord of the displacement vector.
+     * Method: createPopup
+     * HACK - we need to decide if all vector features should be able to
+     *     create popups
+     * 
+     * Returns:
+     * {<OpenLayers.Popup>} For now just returns null
      */
-    moveByPx: function(dx, dy) {
+    createPopup: function() {
+        return null;
     },
 
     /**
-     * Method: setMap
-     * Set the map property for the layer. This is done through an accessor
-     *     so that subclasses can override this and take special action once 
-     *     they have their map variable set. 
+     * Method: atPoint
+     * Determins whether the feature intersects with the specified location.
      * 
-     *     Here we take care to bring over any of the necessary default 
-     *     properties from the map. 
+     * Parameters: 
+     * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
+     *     object with a 'lon' and 'lat' properties.
+     * toleranceLon - {float} Optional tolerance in Geometric Coords
+     * toleranceLat - {float} Optional tolerance in Geographic Coords
      * 
-     * Parameters:
-     * map - {<OpenLayers.Map>}
+     * Returns:
+     * {Boolean} Whether or not the feature is at the specified location
      */
-    setMap: function(map) {
-        if (this.map == null) {
-        
-            this.map = map;
-            
-            // grab some essential layer data from the map if it hasn't already
-            //  been set
-            this.maxExtent = this.maxExtent || this.map.maxExtent;
-            this.minExtent = this.minExtent || this.map.minExtent;
-
-            this.projection = this.projection || this.map.projection;
-            if (typeof this.projection == "string") {
-                this.projection = new OpenLayers.Projection(this.projection);
-            }
-
-            // Check the projection to see if we can get units -- if not, refer
-            // to properties.
-            this.units = this.projection.getUnits() ||
-                         this.units || this.map.units;
-            
-            this.initResolutions();
-            
-            if (!this.isBaseLayer) {
-                this.inRange = this.calculateInRange();
-                var show = ((this.visibility) && (this.inRange));
-                this.div.style.display = show ? "" : "none";
-            }
-            
-            // deal with gutters
-            this.setTileSize();
+    atPoint: function(lonlat, toleranceLon, toleranceLat) {
+        var atPoint = false;
+        if(this.geometry) {
+            atPoint = this.geometry.atPoint(lonlat, toleranceLon, 
+                                                    toleranceLat);
         }
+        return atPoint;
     },
-    
+
     /**
-     * Method: afterAdd
-     * Called at the end of the map.addLayer sequence.  At this point, the map
-     *     will have a base layer.  To be overridden by subclasses.
+     * Method: destroyPopup
+     * HACK - we need to decide if all vector features should be able to
+     * delete popups
      */
-    afterAdd: function() {
+    destroyPopup: function() {
+        // pass
     },
-    
+
     /**
-     * APIMethod: removeMap
-     * Just as setMap() allows each layer the possibility to take a 
-     *     personalized action on being added to the map, removeMap() allows
-     *     each layer to take a personalized action on being removed from it. 
-     *     For now, this will be mostly unused, except for the EventPane layer,
-     *     which needs this hook so that it can remove the special invisible
-     *     pane. 
-     * 
+     * Method: move
+     * Moves the feature and redraws it at its new location
+     *
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * location - {<OpenLayers.LonLat> or <OpenLayers.Pixel>} the
+     *         location to which to move the feature.
      */
-    removeMap: function(map) {
-        //to be overridden by subclasses
+    move: function(location) {
+
+        if(!this.layer || !this.geometry.move){
+            //do nothing if no layer or immoveable geometry
+            return undefined;
+        }
+
+        var pixel;
+        if (location.CLASS_NAME == "OpenLayers.LonLat") {
+            pixel = this.layer.getViewPortPxFromLonLat(location);
+        } else {
+            pixel = location;
+        }
+        
+        var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());
+        var res = this.layer.map.getResolution();
+        this.geometry.move(res * (pixel.x - lastPixel.x),
+                           res * (lastPixel.y - pixel.y));
+        this.layer.drawFeature(this);
+        return lastPixel;
     },
     
     /**
-     * APIMethod: getImageSize
+     * Method: toState
+     * Sets the new state
      *
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>} optional tile bounds, can be used
-     *     by subclasses that have to deal with different tile sizes at the
-     *     layer extent edges (e.g. Zoomify)
-     * 
-     * Returns:
-     * {<OpenLayers.Size>} The size that the image should be, taking into 
-     *     account gutters.
-     */ 
-    getImageSize: function(bounds) { 
-        return (this.imageSize || this.tileSize); 
-    },    
-  
-    /**
-     * APIMethod: setTileSize
-     * Set the tile size based on the map size.  This also sets layer.imageSize
-     *     or use by Tile.Image.
-     * 
-     * Parameters:
-     * size - {<OpenLayers.Size>}
+     * state - {String} 
      */
-    setTileSize: function(size) {
-        var tileSize = (size) ? size :
-                                ((this.tileSize) ? this.tileSize :
-                                                   this.map.getTileSize());
-        this.tileSize = tileSize;
-        if(this.gutter) {
-          // layers with gutters need non-null tile sizes
-          //if(tileSize == null) {
-          //    OpenLayers.console.error("Error in layer.setMap() for " +
-          //                              this.name + ": layers with " +
-          //                              "gutters need non-null tile sizes");
-          //}
-            this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), 
-                                                 tileSize.h + (2*this.gutter)); 
+    toState: function(state) {
+        if (state == OpenLayers.State.UPDATE) {
+            switch (this.state) {
+                case OpenLayers.State.UNKNOWN:
+                case OpenLayers.State.DELETE:
+                    this.state = state;
+                    break;
+                case OpenLayers.State.UPDATE:
+                case OpenLayers.State.INSERT:
+                    break;
+            }
+        } else if (state == OpenLayers.State.INSERT) {
+            switch (this.state) {
+                case OpenLayers.State.UNKNOWN:
+                    break;
+                default:
+                    this.state = state;
+                    break;
+            }
+        } else if (state == OpenLayers.State.DELETE) {
+            switch (this.state) {
+                case OpenLayers.State.INSERT:
+                    // the feature should be destroyed
+                    break;
+                case OpenLayers.State.DELETE:
+                    break;
+                case OpenLayers.State.UNKNOWN:
+                case OpenLayers.State.UPDATE:
+                    this.state = state;
+                    break;
+            }
+        } else if (state == OpenLayers.State.UNKNOWN) {
+            this.state = state;
         }
     },
+    
+    CLASS_NAME: "OpenLayers.Feature.Vector"
+});
 
-    /**
-     * APIMethod: getVisibility
-     * 
-     * Returns:
-     * {Boolean} The layer should be displayed (if in range).
-     */
-    getVisibility: function() {
-        return this.visibility;
+
+/**
+ * Constant: OpenLayers.Feature.Vector.style
+ * OpenLayers features can have a number of style attributes. The 'default' 
+ *     style will typically be used if no other style is specified. These
+ *     styles correspond for the most part, to the styling properties defined
+ *     by the SVG standard. 
+ *     Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties
+ *     Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties
+ *
+ * Symbolizer properties:
+ * fill - {Boolean} Set to false if no fill is desired.
+ * fillColor - {String} Hex fill color.  Default is "#ee9900".
+ * fillOpacity - {Number} Fill opacity (0-1).  Default is 0.4 
+ * stroke - {Boolean} Set to false if no stroke is desired.
+ * strokeColor - {String} Hex stroke color.  Default is "#ee9900".
+ * strokeOpacity - {Number} Stroke opacity (0-1).  Default is 1.
+ * strokeWidth - {Number} Pixel stroke width.  Default is 1.
+ * strokeLinecap - {String} Stroke cap type.  Default is "round".  [butt | round | square]
+ * strokeDashstyle - {String} Stroke dash style.  Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid]
+ * graphic - {Boolean} Set to false if no graphic is desired.
+ * pointRadius - {Number} Pixel point radius.  Default is 6.
+ * pointerEvents - {String}  Default is "visiblePainted".
+ * cursor - {String} Default is "".
+ * externalGraphic - {String} Url to an external graphic that will be used for rendering points.
+ * graphicWidth - {Number} Pixel width for sizing an external graphic.
+ * graphicHeight - {Number} Pixel height for sizing an external graphic.
+ * graphicOpacity - {Number} Opacity (0-1) for an external graphic.
+ * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.
+ * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.
+ * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset).
+ * graphicZIndex - {Number} The integer z-index value to use in rendering.
+ * graphicName - {String} Named graphic to use when rendering points.  Supported values include "circle" (default),
+ *     "square", "star", "x", "cross", "triangle".
+ * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead
+ * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer.
+ * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.
+ * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.
+ * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.
+ * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.
+ * backgroundHeight - {Number} The height of the background graphic.  If not provided, the graphicHeight will be used.
+ * backgroundWidth - {Number} The width of the background width.  If not provided, the graphicWidth will be used.
+ * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either
+ *     fillText or mozDrawText to be available.
+ * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string
+ *     composed of two characters. The first character is for the horizontal alignment, the second for the vertical
+ *     alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical
+ *     alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". Default is "cm".
+ * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.
+ * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.
+ * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
+ *     Default is false.
+ * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.
+ * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the  SVG renderers.
+ * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers.
+ * fontColor - {String} The font color for the label, to be provided like CSS.
+ * fontOpacity - {Number} Opacity (0-1) for the label
+ * fontFamily - {String} The font family for the label, to be provided like in CSS.
+ * fontSize - {String} The font size for the label, to be provided like in CSS.
+ * fontStyle - {String} The font style for the label, to be provided like in CSS.
+ * fontWeight - {String} The font weight for the label, to be provided like in CSS.
+ * display - {String} Symbolizers will have no effect if display is set to "none".  All other values have no effect.
+ */ 
+OpenLayers.Feature.Vector.style = {
+    'default': {
+        fillColor: "#ee9900",
+        fillOpacity: 0.4, 
+        hoverFillColor: "white",
+        hoverFillOpacity: 0.8,
+        strokeColor: "#ee9900",
+        strokeOpacity: 1,
+        strokeWidth: 1,
+        strokeLinecap: "round",
+        strokeDashstyle: "solid",
+        hoverStrokeColor: "red",
+        hoverStrokeOpacity: 1,
+        hoverStrokeWidth: 0.2,
+        pointRadius: 6,
+        hoverPointRadius: 1,
+        hoverPointUnit: "%",
+        pointerEvents: "visiblePainted",
+        cursor: "inherit",
+        fontColor: "#000000",
+        labelAlign: "cm",
+        labelOutlineColor: "white",
+        labelOutlineWidth: 3
     },
+    'select': {
+        fillColor: "blue",
+        fillOpacity: 0.4, 
+        hoverFillColor: "white",
+        hoverFillOpacity: 0.8,
+        strokeColor: "blue",
+        strokeOpacity: 1,
+        strokeWidth: 2,
+        strokeLinecap: "round",
+        strokeDashstyle: "solid",
+        hoverStrokeColor: "red",
+        hoverStrokeOpacity: 1,
+        hoverStrokeWidth: 0.2,
+        pointRadius: 6,
+        hoverPointRadius: 1,
+        hoverPointUnit: "%",
+        pointerEvents: "visiblePainted",
+        cursor: "pointer",
+        fontColor: "#000000",
+        labelAlign: "cm",
+        labelOutlineColor: "white",
+        labelOutlineWidth: 3
+
+    },
+    'temporary': {
+        fillColor: "#66cccc",
+        fillOpacity: 0.2, 
+        hoverFillColor: "white",
+        hoverFillOpacity: 0.8,
+        strokeColor: "#66cccc",
+        strokeOpacity: 1,
+        strokeLinecap: "round",
+        strokeWidth: 2,
+        strokeDashstyle: "solid",
+        hoverStrokeColor: "red",
+        hoverStrokeOpacity: 1,
+        hoverStrokeWidth: 0.2,
+        pointRadius: 6,
+        hoverPointRadius: 1,
+        hoverPointUnit: "%",
+        pointerEvents: "visiblePainted",
+        cursor: "inherit",
+        fontColor: "#000000",
+        labelAlign: "cm",
+        labelOutlineColor: "white",
+        labelOutlineWidth: 3
 
-    /** 
-     * APIMethod: setVisibility
-     * Set the visibility flag for the layer and hide/show & redraw 
-     *     accordingly. Fire event unless otherwise specified
-     * 
-     * Note that visibility is no longer simply whether or not the layer's
-     *     style.display is set to "block". Now we store a 'visibility' state 
-     *     property on the layer class, this allows us to remember whether or 
-     *     not we *desire* for a layer to be visible. In the case where the 
-     *     map's resolution is out of the layer's range, this desire may be 
-     *     subverted.
-     * 
-     * Parameters:
-     * visibility - {Boolean} Whether or not to display the layer (if in range)
-     */
-    setVisibility: function(visibility) {
-        if (visibility != this.visibility) {
-            this.visibility = visibility;
-            this.display(visibility);
-            this.redraw();
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer", {
-                    layer: this,
-                    property: "visibility"
-                });
-            }
-            this.events.triggerEvent("visibilitychanged");
-        }
     },
+    'delete': {
+        display: "none"
+    }
+};    
+/* ======================================================================
+    OpenLayers/Style.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Style
+ * This class represents a UserStyle obtained
+ *     from a SLD, containing styling rules.
+ */
+OpenLayers.Style = OpenLayers.Class({
+
+    /**
+     * Property: id
+     * {String} A unique id for this session.
+     */
+    id: null,
+    
+    /**
+     * APIProperty: name
+     * {String}
+     */
+    name: null,
+    
+    /**
+     * Property: title
+     * {String} Title of this style (set if included in SLD)
+     */
+    title: null,
+    
+    /**
+     * Property: description
+     * {String} Description of this style (set if abstract is included in SLD)
+     */
+    description: null,
 
+    /**
+     * APIProperty: layerName
+     * {<String>} name of the layer that this style belongs to, usually
+     * according to the NamedLayer attribute of an SLD document.
+     */
+    layerName: null,
+    
+    /**
+     * APIProperty: isDefault
+     * {Boolean}
+     */
+    isDefault: false,
+     
     /** 
-     * APIMethod: display
-     * Hide or show the Layer. This is designed to be used internally, and 
-     *     is not generally the way to enable or disable the layer. For that,
-     *     use the setVisibility function instead..
-     * 
-     * Parameters:
-     * display - {Boolean}
+     * Property: rules 
+     * {Array(<OpenLayers.Rule>)}
      */
-    display: function(display) {
-        if (display != (this.div.style.display != "none")) {
-            this.div.style.display = (display && this.calculateInRange()) ? "block" : "none";
-        }
-    },
+    rules: null,
+    
+    /**
+     * APIProperty: context
+     * {Object} An optional object with properties that symbolizers' property
+     * values should be evaluated against. If no context is specified,
+     * feature.attributes will be used
+     */
+    context: null,
 
     /**
-     * APIMethod: calculateInRange
+     * Property: defaultStyle
+     * {Object} hash of style properties to use as default for merging
+     * rule-based style symbolizers onto. If no rules are defined,
+     * createSymbolizer will return this style. If <defaultsPerSymbolizer> is set to
+     * true, the defaultStyle will only be taken into account if there are
+     * rules defined.
+     */
+    defaultStyle: null,
+    
+    /**
+     * Property: defaultsPerSymbolizer
+     * {Boolean} If set to true, the <defaultStyle> will extend the symbolizer
+     * of every rule. Properties of the <defaultStyle> will also be used to set
+     * missing symbolizer properties if the symbolizer has stroke, fill or
+     * graphic set to true. Default is false.
+     */
+    defaultsPerSymbolizer: false,
+    
+    /**
+     * Property: propertyStyles
+     * {Hash of Boolean} cache of style properties that need to be parsed for
+     * propertyNames. Property names are keys, values won't be used.
+     */
+    propertyStyles: null,
+    
+
+    /** 
+     * Constructor: OpenLayers.Style
+     * Creates a UserStyle.
+     *
+     * Parameters:
+     * style        - {Object} Optional hash of style properties that will be
+     *                used as default style for this style object. This style
+     *                applies if no rules are specified. Symbolizers defined in
+     *                rules will extend this default style.
+     * options - {Object} An optional object with properties to set on the
+     *     style.
+     *
+     * Valid options:
+     * rules - {Array(<OpenLayers.Rule>)} List of rules to be added to the
+     *     style.
      * 
      * Returns:
-     * {Boolean} The layer is displayable at the current map's current
-     *     resolution. Note that if 'alwaysInRange' is true for the layer, 
-     *     this function will always return true.
+     * {<OpenLayers.Style>}
      */
-    calculateInRange: function() {
-        var inRange = false;
+    initialize: function(style, options) {
 
-        if (this.alwaysInRange) {
-            inRange = true;
-        } else {
-            if (this.map) {
-                var resolution = this.map.getResolution();
-                inRange = ( (resolution >= this.minResolution) &&
-                            (resolution <= this.maxResolution) );
-            }
+        OpenLayers.Util.extend(this, options);
+        this.rules = [];
+        if(options && options.rules) {
+            this.addRules(options.rules);
         }
-        return inRange;
+
+        // use the default style from OpenLayers.Feature.Vector if no style
+        // was given in the constructor
+        this.setDefaultStyle(style ||
+                             OpenLayers.Feature.Vector.style["default"]);
+
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
     },
 
     /** 
-     * APIMethod: setIsBaseLayer
-     * 
-     * Parameters:
-     * isBaseLayer - {Boolean}
+     * APIMethod: destroy
+     * nullify references to prevent circular references and memory leaks
      */
-    setIsBaseLayer: function(isBaseLayer) {
-        if (isBaseLayer != this.isBaseLayer) {
-            this.isBaseLayer = isBaseLayer;
-            if (this.map != null) {
-                this.map.events.triggerEvent("changebaselayer", {
-                    layer: this
-                });
-            }
+    destroy: function() {
+        for (var i=0, len=this.rules.length; i<len; i++) {
+            this.rules[i].destroy();
+            this.rules[i] = null;
         }
+        this.rules = null;
+        this.defaultStyle = null;
     },
-
-  /********************************************************/
-  /*                                                      */
-  /*                 Baselayer Functions                  */
-  /*                                                      */
-  /********************************************************/
-  
-    /** 
-     * Method: initResolutions
-     * This method's responsibility is to set up the 'resolutions' array 
-     *     for the layer -- this array is what the layer will use to interface
-     *     between the zoom levels of the map and the resolution display 
-     *     of the layer.
+    
+    /**
+     * Method: createSymbolizer
+     * creates a style by applying all feature-dependent rules to the base
+     * style.
      * 
-     * The user has several options that determine how the array is set up.
-     *  
-     * For a detailed explanation, see the following wiki from the 
-     *     openlayers.org homepage:
-     *     http://trac.openlayers.org/wiki/SettingZoomLevels
+     * Parameters:
+     * feature - {<OpenLayers.Feature>} feature to evaluate rules for
+     * 
+     * Returns:
+     * {Object} symbolizer hash
      */
-    initResolutions: function() {
-
-        // ok we want resolutions, here's our strategy:
-        //
-        // 1. if resolutions are defined in the layer config, use them
-        // 2. else, if scales are defined in the layer config then derive
-        //    resolutions from these scales
-        // 3. else, attempt to calculate resolutions from maxResolution,
-        //    minResolution, numZoomLevels, maxZoomLevel set in the
-        //    layer config
-        // 4. if we still don't have resolutions, and if resolutions
-        //    are defined in the same, use them
-        // 5. else, if scales are defined in the map then derive
-        //    resolutions from these scales
-        // 6. else, attempt to calculate resolutions from maxResolution,
-        //    minResolution, numZoomLevels, maxZoomLevel set in the
-        //    map
-        // 7. hope for the best!
-
-        var i, len, p;
-        var props = {}, alwaysInRange = true;
+    createSymbolizer: function(feature) {
+        var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(
+            OpenLayers.Util.extend({}, this.defaultStyle), feature);
+        
+        var rules = this.rules;
 
-        // get resolution data from layer config
-        // (we also set alwaysInRange in the layer as appropriate)
-        for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
-            p = this.RESOLUTION_PROPERTIES[i];
-            props[p] = this.options[p];
-            if(alwaysInRange && this.options[p]) {
-                alwaysInRange = false;
+        var rule, context;
+        var elseRules = [];
+        var appliedRules = false;
+        for(var i=0, len=rules.length; i<len; i++) {
+            rule = rules[i];
+            // does the rule apply?
+            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(this.options.alwaysInRange == null) {
-            this.alwaysInRange = alwaysInRange;
-        }
-
-        // if we don't have resolutions then attempt to derive them from scales
-        if(props.resolutions == null) {
-            props.resolutions = this.resolutionsFromScales(props.scales);
-        }
-
-        // if we still don't have resolutions then attempt to calculate them
-        if(props.resolutions == null) {
-            props.resolutions = this.calculateResolutions(props);
-        }
-
-        // if we couldn't calculate resolutions then we look at we have
-        // in the map
-        if(props.resolutions == null) {
-            for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
-                p = this.RESOLUTION_PROPERTIES[i];
-                props[p] = this.options[p] != null ?
-                    this.options[p] : this.map[p];
-            }
-            if(props.resolutions == null) {
-                props.resolutions = this.resolutionsFromScales(props.scales);
-            }
-            if(props.resolutions == null) {
-                props.resolutions = this.calculateResolutions(props);
+        
+        // if no other rules apply, apply the rules with else filters
+        if(appliedRules == false && elseRules.length > 0) {
+            appliedRules = true;
+            for(var i=0, len=elseRules.length; i<len; i++) {
+                this.applySymbolizer(elseRules[i], style, feature);
             }
         }
 
-        // ok, we new need to set properties in the instance
-
-        // get maxResolution from the config if it's defined there
-        var maxResolution;
-        if(this.options.maxResolution &&
-           this.options.maxResolution !== "auto") {
-            maxResolution = this.options.maxResolution;
+        // don't display if there were rules but none applied
+        if(rules.length > 0 && appliedRules == false) {
+            style.display = "none";
         }
-        if(this.options.minScale) {
-            maxResolution = OpenLayers.Util.getResolutionFromScale(
-                this.options.minScale, this.units);
+        
+        if (style.label != null && typeof style.label !== "string") {
+            style.label = String(style.label);
         }
-
-        // get minResolution from the config if it's defined there
-        var minResolution;
-        if(this.options.minResolution &&
-           this.options.minResolution !== "auto") {
-            minResolution = this.options.minResolution;
-        }
-        if(this.options.maxScale) {
-            minResolution = OpenLayers.Util.getResolutionFromScale(
-                this.options.maxScale, this.units);
-        }
-
-        if(props.resolutions) {
-
-            //sort resolutions array descendingly
-            props.resolutions.sort(function(a, b) {
-                return (b - a);
-            });
-
-            // if we still don't have a maxResolution get it from the
-            // resolutions array
-            if(!maxResolution) {
-                maxResolution = props.resolutions[0];
-            }
-
-            // if we still don't have a minResolution get it from the
-            // resolutions array
-            if(!minResolution) {
-                var lastIdx = props.resolutions.length - 1;
-                minResolution = props.resolutions[lastIdx];
-            }
-        }
-
-        this.resolutions = props.resolutions;
-        if(this.resolutions) {
-            len = this.resolutions.length;
-            this.scales = new Array(len);
-            for(i=0; i<len; i++) {
-                this.scales[i] = OpenLayers.Util.getScaleFromResolution(
-                    this.resolutions[i], this.units);
-            }
-            this.numZoomLevels = len;
-        }
-        this.minResolution = minResolution;
-        if(minResolution) {
-            this.maxScale = OpenLayers.Util.getScaleFromResolution(
-                minResolution, this.units);
-        }
-        this.maxResolution = maxResolution;
-        if(maxResolution) {
-            this.minScale = OpenLayers.Util.getScaleFromResolution(
-                maxResolution, this.units);
-        }
-    },
-
-    /**
-     * Method: resolutionsFromScales
-     * Derive resolutions from scales.
-     *
-     * Parameters:
-     * scales - {Array(Number)} Scales
-     *
-     * Returns
-     * {Array(Number)} Resolutions
-     */
-    resolutionsFromScales: function(scales) {
-        if(scales == null) {
-            return;
-        }
-        var resolutions, i, len;
-        len = scales.length;
-        resolutions = new Array(len);
-        for(i=0; i<len; i++) {
-            resolutions[i] = OpenLayers.Util.getResolutionFromScale(
-                scales[i], this.units);
-        }
-        return resolutions;
+        
+        return style;
     },
-
+    
     /**
-     * Method: calculateResolutions
-     * Calculate resolutions based on the provided properties.
+     * Method: applySymbolizer
      *
      * Parameters:
-     * props - {Object} Properties
+     * rule - {<OpenLayers.Rule>}
+     * style - {Object}
+     * feature - {<OpenLayer.Feature.Vector>}
      *
      * Returns:
-     * {Array({Number})} Array of resolutions.
+     * {Object} A style with new symbolizer applied.
      */
-    calculateResolutions: function(props) {
-
-        var viewSize, wRes, hRes;
-
-        // determine maxResolution
-        var maxResolution = props.maxResolution;
-        if(props.minScale != null) {
-            maxResolution =
-                OpenLayers.Util.getResolutionFromScale(props.minScale,
-                                                       this.units);
-        } else if(maxResolution == "auto" && this.maxExtent != null) {
-            viewSize = this.map.getSize();
-            wRes = this.maxExtent.getWidth() / viewSize.w;
-            hRes = this.maxExtent.getHeight() / viewSize.h;
-            maxResolution = Math.max(wRes, hRes);
-        }
-
-        // determine minResolution
-        var minResolution = props.minResolution;
-        if(props.maxScale != null) {
-            minResolution =
-                OpenLayers.Util.getResolutionFromScale(props.maxScale,
-                                                       this.units);
-        } else if(props.minResolution == "auto" && this.minExtent != null) {
-            viewSize = this.map.getSize();
-            wRes = this.minExtent.getWidth() / viewSize.w;
-            hRes = this.minExtent.getHeight()/ viewSize.h;
-            minResolution = Math.max(wRes, hRes);
-        }
-
-        if(typeof maxResolution !== "number" &&
-           typeof minResolution !== "number" &&
-           this.maxExtent != null) {
-            // maxResolution for default grid sets assumes that at zoom
-            // level zero, the whole world fits on one tile.
-            var tileSize = this.map.getTileSize();
-            maxResolution = Math.max(
-                this.maxExtent.getWidth() / tileSize.w,
-                this.maxExtent.getHeight() / tileSize.h
-            );
-        }
-
-        // determine numZoomLevels
-        var maxZoomLevel = props.maxZoomLevel;
-        var numZoomLevels = props.numZoomLevels;
-        if(typeof minResolution === "number" &&
-           typeof maxResolution === "number" && numZoomLevels === undefined) {
-            var ratio = maxResolution / minResolution;
-            numZoomLevels = Math.floor(Math.log(ratio) / Math.log(2)) + 1;
-        } else if(numZoomLevels === undefined && maxZoomLevel != null) {
-            numZoomLevels = maxZoomLevel + 1;
-        }
-
-        // are we able to calculate resolutions?
-        if(typeof numZoomLevels !== "number" || numZoomLevels <= 0 ||
-           (typeof maxResolution !== "number" &&
-                typeof minResolution !== "number")) {
-            return;
-        }
-
-        // now we have numZoomLevels and at least one of maxResolution
-        // or minResolution, we can populate the resolutions array
-
-        var resolutions = new Array(numZoomLevels);
-        var base = 2;
-        if(typeof minResolution == "number" &&
-           typeof maxResolution == "number") {
-            // if maxResolution and minResolution are set, we calculate
-            // the base for exponential scaling that starts at
-            // maxResolution and ends at minResolution in numZoomLevels
-            // steps.
-            base = Math.pow(
-                    (maxResolution / minResolution),
-                (1 / (numZoomLevels - 1))
-            );
-        }
+    applySymbolizer: function(rule, style, feature) {
+        var symbolizerPrefix = feature.geometry ?
+                this.getSymbolizerPrefix(feature.geometry) :
+                OpenLayers.Style.SYMBOLIZER_PREFIXES[0];
 
-        var i;
-        if(typeof maxResolution === "number") {
-            for(i=0; i<numZoomLevels; i++) {
-                resolutions[i] = maxResolution / Math.pow(base, i);
+        var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;
+        
+        if(this.defaultsPerSymbolizer === true) {
+            var defaults = this.defaultStyle;
+            OpenLayers.Util.applyDefaults(symbolizer, {
+                pointRadius: defaults.pointRadius
+            });
+            if(symbolizer.stroke === true || symbolizer.graphic === true) {
+                OpenLayers.Util.applyDefaults(symbolizer, {
+                    strokeWidth: defaults.strokeWidth,
+                    strokeColor: defaults.strokeColor,
+                    strokeOpacity: defaults.strokeOpacity,
+                    strokeDashstyle: defaults.strokeDashstyle,
+                    strokeLinecap: defaults.strokeLinecap
+                });
             }
-        } else {
-            for(i=0; i<numZoomLevels; i++) {
-                resolutions[numZoomLevels - 1 - i] =
-                    minResolution * Math.pow(base, i);
+            if(symbolizer.fill === true || symbolizer.graphic === true) {
+                OpenLayers.Util.applyDefaults(symbolizer, {
+                    fillColor: defaults.fillColor,
+                    fillOpacity: defaults.fillOpacity
+                });
+            }
+            if(symbolizer.graphic === true) {
+                OpenLayers.Util.applyDefaults(symbolizer, {
+                    pointRadius: this.defaultStyle.pointRadius,
+                    externalGraphic: this.defaultStyle.externalGraphic,
+                    graphicName: this.defaultStyle.graphicName,
+                    graphicOpacity: this.defaultStyle.graphicOpacity,
+                    graphicWidth: this.defaultStyle.graphicWidth,
+                    graphicHeight: this.defaultStyle.graphicHeight,
+                    graphicXOffset: this.defaultStyle.graphicXOffset,
+                    graphicYOffset: this.defaultStyle.graphicYOffset
+                });
             }
         }
 
-        return resolutions;
+        // merge the style with the current style
+        return this.createLiterals(
+                OpenLayers.Util.extend(style, symbolizer), feature);
     },
-
+    
     /**
-     * APIMethod: getResolution
+     * Method: createLiterals
+     * creates literals for all style properties that have an entry in
+     * <this.propertyStyles>.
      * 
-     * Returns:
-     * {Float} The currently selected resolution of the map, taken from the
-     *     resolutions array, indexed by current zoom level.
-     */
-    getResolution: function() {
-        var zoom = this.map.getZoom();
-        return this.getResolutionForZoom(zoom);
-    },
-
-    /** 
-     * APIMethod: getExtent
+     * Parameters:
+     * style   - {Object} style to create literals for. Will be modified
+     *           inline.
+     * feature - {Object}
      * 
      * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
-     *     bounds of the current viewPort.
+     * {Object} the modified style
      */
-    getExtent: function() {
-        // just use stock map calculateBounds function -- passing no arguments
-        //  means it will user map's current center & resolution
-        //
-        return this.map.calculateBounds();
+    createLiterals: function(style, feature) {
+        var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);
+        OpenLayers.Util.extend(context, this.context);
+        
+        for (var i in this.propertyStyles) {
+            style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);
+        }
+        return style;
     },
-
+    
     /**
-     * APIMethod: getZoomForExtent
+     * Method: findPropertyStyles
+     * Looks into all rules for this style and the defaultStyle to collect
+     * all the style hash property names containing ${...} strings that have
+     * to be replaced using the createLiteral method before returning them.
      * 
-     * Parameters:
-     * extent - {<OpenLayers.Bounds>}
-     * closest - {Boolean} Find the zoom level that most closely fits the 
-     *     specified bounds. Note that this may result in a zoom that does 
-     *     not exactly contain the entire extent.
-     *     Default is false.
-     *
      * Returns:
-     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
-     *     for the passed-in extent. We do this by calculating the ideal 
-     *     resolution for the given extent (based on the map size) and then 
-     *     calling getZoomForResolution(), passing along the 'closest'
-     *     parameter.
+     * {Object} hash of property names that need createLiteral parsing. The
+     * name of the property is the key, and the value is true;
      */
-    getZoomForExtent: function(extent, closest) {
-        var viewSize = this.map.getSize();
-        var idealResolution = Math.max( extent.getWidth()  / viewSize.w,
-                                        extent.getHeight() / viewSize.h );
+    findPropertyStyles: function() {
+        var propertyStyles = {};
 
-        return this.getZoomForResolution(idealResolution, closest);
+        // check the default style
+        var style = this.defaultStyle;
+        this.addPropertyStyles(propertyStyles, style);
+
+        // walk through all rules to check for properties in their symbolizer
+        var rules = this.rules;
+        var symbolizer, value;
+        for (var i=0, len=rules.length; i<len; i++) {
+            symbolizer = rules[i].symbolizer;
+            for (var key in symbolizer) {
+                value = symbolizer[key];
+                if (typeof value == "object") {
+                    // symbolizer key is "Point", "Line" or "Polygon"
+                    this.addPropertyStyles(propertyStyles, value);
+                } else {
+                    // symbolizer is a hash of style properties
+                    this.addPropertyStyles(propertyStyles, symbolizer);
+                    break;
+                }
+            }
+        }
+        return propertyStyles;
     },
     
-    /** 
-     * Method: getDataExtent
-     * Calculates the max extent which includes all of the data for the layer.
-     *     This function is to be implemented by subclasses.
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>}
-     */
-    getDataExtent: function () {
-        //to be implemented by subclasses
-    },
-
     /**
-     * APIMethod: getResolutionForZoom
+     * Method: addPropertyStyles
      * 
      * Parameters:
-     * zoom - {Float}
+     * propertyStyles - {Object} hash to add new property styles to. Will be
+     *                  modified inline
+     * symbolizer     - {Object} search this symbolizer for property styles
      * 
      * Returns:
-     * {Float} A suitable resolution for the specified zoom.
+     * {Object} propertyStyles hash
      */
-    getResolutionForZoom: function(zoom) {
-        zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));
-        var resolution;
-        if(this.map.fractionalZoom) {
-            var low = Math.floor(zoom);
-            var high = Math.ceil(zoom);
-            resolution = this.resolutions[low] -
-                ((zoom-low) * (this.resolutions[low]-this.resolutions[high]));
-        } else {
-            resolution = this.resolutions[Math.round(zoom)];
+    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 resolution;
+        return propertyStyles;
     },
-
+    
     /**
-     * APIMethod: getZoomForResolution
+     * APIMethod: addRules
+     * Adds rules to this style.
      * 
      * Parameters:
-     * resolution - {Float}
-     * closest - {Boolean} Find the zoom level that corresponds to the absolute 
-     *     closest resolution, which may result in a zoom whose corresponding
-     *     resolution is actually smaller than we would have desired (if this
-     *     is being called from a getZoomForExtent() call, then this means that
-     *     the returned zoom index might not actually contain the entire 
-     *     extent specified... but it'll be close).
-     *     Default is false.
-     * 
-     * Returns:
-     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
-     *     that corresponds to the best fit resolution given the passed in 
-     *     value and the 'closest' specification.
+     * rules - {Array(<OpenLayers.Rule>)}
      */
-    getZoomForResolution: function(resolution, closest) {
-        var zoom, i, len;
-        if(this.map.fractionalZoom) {
-            var lowZoom = 0;
-            var highZoom = this.resolutions.length - 1;
-            var highRes = this.resolutions[lowZoom];
-            var lowRes = this.resolutions[highZoom];
-            var res;
-            for(i=0, len=this.resolutions.length; i<len; ++i) {
-                res = this.resolutions[i];
-                if(res >= resolution) {
-                    highRes = res;
-                    lowZoom = i;
-                }
-                if(res <= resolution) {
-                    lowRes = res;
-                    highZoom = i;
-                    break;
-                }
-            }
-            var dRes = highRes - lowRes;
-            if(dRes > 0) {
-                zoom = lowZoom + ((highRes - resolution) / dRes);
-            } else {
-                zoom = lowZoom;
-            }
-        } else {
-            var diff;
-            var minDiff = Number.POSITIVE_INFINITY;
-            for(i=0, len=this.resolutions.length; i<len; i++) {            
-                if (closest) {
-                    diff = Math.abs(this.resolutions[i] - resolution);
-                    if (diff > minDiff) {
-                        break;
-                    }
-                    minDiff = diff;
-                } else {
-                    if (this.resolutions[i] < resolution) {
-                        break;
-                    }
-                }
-            }
-            zoom = Math.max(0, i-1);
-        }
-        return zoom;
+    addRules: function(rules) {
+        Array.prototype.push.apply(this.rules, rules);
+        this.propertyStyles = this.findPropertyStyles();
     },
     
     /**
-     * APIMethod: getLonLatFromViewPortPx
+     * APIMethod: setDefaultStyle
+     * Sets the default style for this style object.
      * 
      * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or
-     *                                          an object with a 'x'
-     *                                          and 'y' properties.
-     *
-     * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in 
-     *     view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
+     * style - {Object} Hash of style properties
      */
-    getLonLatFromViewPortPx: function (viewPortPx) {
-        var lonlat = null;
-        var map = this.map;
-        if (viewPortPx != null && map.minPx) {
-            var res = map.getResolution();
-            var maxExtent = map.getMaxExtent({restricted: true});
-            var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left;
-            var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top;
-            lonlat = new OpenLayers.LonLat(lon, lat);
-
-            if (this.wrapDateLine) {
-                lonlat = lonlat.wrapDateLine(this.maxExtent);
-            }
-        }
-        return lonlat;
+    setDefaultStyle: function(style) {
+        this.defaultStyle = style; 
+        this.propertyStyles = this.findPropertyStyles();
     },
-
+        
     /**
-     * APIMethod: getViewPortPxFromLonLat
-     * Returns a pixel location given a map location.  This method will return
-     *     fractional pixel values.
+     * Method: getSymbolizerPrefix
+     * Returns the correct symbolizer prefix according to the
+     * geometry type of the passed geometry
      * 
      * Parameters:
-     * lonlat - {<OpenLayers.LonLat>|Object} An OpenLayers.LonLat or
-     *                                       an object with a 'lon'
-     *                                       and 'lat' properties.
-     *
-     * Returns: 
-     * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in 
-     *     lonlat translated into view port pixels.
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {String} key of the according symbolizer
      */
-    getViewPortPxFromLonLat: function (lonlat, resolution) {
-        var px = null; 
-        if (lonlat != null) {
-            resolution = resolution || this.map.getResolution();
-            var extent = this.map.calculateBounds(null, resolution);
-            px = new OpenLayers.Pixel(
-                (1/resolution * (lonlat.lon - extent.left)),
-                (1/resolution * (extent.top - lonlat.lat))
-            );    
+    getSymbolizerPrefix: function(geometry) {
+        var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
+        for (var i=0, len=prefixes.length; i<len; i++) {
+            if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {
+                return prefixes[i];
+            }
         }
-        return px;
     },
     
     /**
-     * APIMethod: setOpacity
-     * Sets the opacity for the entire layer (all images)
+     * APIMethod: clone
+     * Clones this style.
      * 
-     * Parameters:
-     * opacity - {Float}
+     * Returns:
+     * {<OpenLayers.Style>} Clone of this style.
      */
-    setOpacity: function(opacity) {
-        if (opacity != this.opacity) {
-            this.opacity = opacity;
-            var childNodes = this.div.childNodes;
-            for(var i = 0, len = childNodes.length; i < len; ++i) {
-                var element = childNodes[i].firstChild || childNodes[i];
-                var lastChild = childNodes[i].lastChild;
-                //TODO de-uglify this
-                if (lastChild && lastChild.nodeName.toLowerCase() === "iframe") {
-                    element = lastChild.parentNode;
-                }
-                OpenLayers.Util.modifyDOMElement(element, null, null, null, 
-                                                 null, null, null, opacity);
-            }
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer", {
-                    layer: this,
-                    property: "opacity"
-                });
+    clone: function() {
+        var options = OpenLayers.Util.extend({}, this);
+        // clone rules
+        if(this.rules) {
+            options.rules = [];
+            for(var i=0, len=this.rules.length; i<len; ++i) {
+                options.rules.push(this.rules[i].clone());
             }
         }
+        // clone context
+        options.context = this.context && OpenLayers.Util.extend({}, this.context);
+        //clone default style
+        var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);
+        return new OpenLayers.Style(defaultStyle, options);
     },
+    
+    CLASS_NAME: "OpenLayers.Style"
+});
 
-    /**
-     * Method: getZIndex
-     * 
-     * Returns: 
-     * {Integer} the z-index of this layer
-     */    
-    getZIndex: function () {
-        return this.div.style.zIndex;
-    },
-
-    /**
-     * Method: setZIndex
-     * 
-     * Parameters: 
-     * zIndex - {Integer}
-     */    
-    setZIndex: function (zIndex) {
-        this.div.style.zIndex = zIndex;
-    },
-
-    /**
-     * Method: adjustBounds
-     * This function will take a bounds, and if wrapDateLine option is set
-     *     on the layer, it will return a bounds which is wrapped around the 
-     *     world. We do not wrap for bounds which *cross* the 
-     *     maxExtent.left/right, only bounds which are entirely to the left 
-     *     or entirely to the right.
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    adjustBounds: function (bounds) {
-
-        if (this.gutter) {
-            // Adjust the extent of a bounds in map units by the 
-            // layer's gutter in pixels.
-            var mapGutter = this.gutter * this.map.getResolution();
-            bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
-                                           bounds.bottom - mapGutter,
-                                           bounds.right + mapGutter,
-                                           bounds.top + mapGutter);
-        }
-
-        if (this.wrapDateLine) {
-            // wrap around the date line, within the limits of rounding error
-            var wrappingOptions = { 
-                'rightTolerance':this.getResolution(),
-                'leftTolerance':this.getResolution()
-            };    
-            bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
-                              
-        }
-        return bounds;
-    },
 
-    CLASS_NAME: "OpenLayers.Layer"
-});
+/**
+ * Function: createLiteral
+ * converts a style value holding a combination of PropertyName and Literal
+ * into a Literal, taking the property values from the passed features.
+ * 
+ * Parameters:
+ * value - {String} value to parse. If this string contains a construct like
+ *         "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
+ *         will be replaced by the value of the "bar" attribute of the passed
+ *         feature.
+ * context - {Object} context to take attribute values from
+ * feature - {<OpenLayers.Feature.Vector>} optional feature to pass to
+ *           <OpenLayers.String.format> for evaluating functions in the
+ *           context.
+ * property - {String} optional, name of the property for which the literal is
+ *            being created for evaluating functions in the context.
+ * 
+ * Returns:
+ * {String} the parsed value. In the example of the value parameter above, the
+ * result would be "foo valueOfBar", assuming that the passed feature has an
+ * attribute named "bar" with the value "valueOfBar".
+ */
+OpenLayers.Style.createLiteral = function(value, context, feature, property) {
+    if (typeof value == "string" && value.indexOf("${") != -1) {
+        value = OpenLayers.String.format(value, context, [feature, property]);
+        value = (isNaN(value) || !value) ? value : parseFloat(value);
+    }
+    return value;
+};
+    
+/**
+ * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
+ * {Array} prefixes of the sld symbolizers. These are the
+ * same as the main geometry types
+ */
+OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',
+    'Raster'];
 /* ======================================================================
-    OpenLayers/Layer/SphericalMercator.js
+    OpenLayers/Rule.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
 
+
 /**
- * @requires OpenLayers/Layer.js
- * @requires OpenLayers/Projection.js
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Style.js
  */
 
 /**
- * Class: OpenLayers.Layer.SphericalMercator
- * A mixin for layers that wraps up the pieces neccesary to have a coordinate
- *     conversion for working with commercial APIs which use a spherical
- *     mercator projection.  Using this layer as a base layer, additional
- *     layers can be used as overlays if they are in the same projection.
- *
- * A layer is given properties of this object by setting the sphericalMercator
- *     property to true.
- *
- * More projection information:
- *  - http://spatialreference.org/ref/user/google-projection/
- *
- * Proj4 Text:
- *     +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
- *     +k=1.0 +units=m +nadgrids=@null +no_defs
- *
- * WKT:
- *     900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
- *     DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]], 
- *     PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295], 
- *     AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
- *     PROJECTION["Mercator_1SP_Google"], 
- *     PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0], 
- *     PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0], 
- *     PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
- *     AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
+ * Class: OpenLayers.Rule
+ * This class represents an SLD Rule, as being used for rule-based SLD styling.
  */
-OpenLayers.Layer.SphericalMercator = {
-
+OpenLayers.Rule = OpenLayers.Class({
+    
     /**
-     * Method: getExtent
-     * Get the map's extent.
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} The map extent.
+     * Property: id
+     * {String} A unique id for this session.
      */
-    getExtent: function() {
-        var extent = null;
-        if (this.sphericalMercator) {
-            extent = this.map.calculateBounds();
-        } else {
-            extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
-        }
-        return extent;
-    },
-
+    id: null,
+    
     /**
-     * Method: getLonLatFromViewPortPx
-     * Get a map location from a pixel location
-     * 
-     * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     *  {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
-     *  port OpenLayers.Pixel, translated into lon/lat by map lib
-     *  If the map lib is not loaded or not centered, returns null
+     * APIProperty: name
+     * {String} name of this rule
      */
-    getLonLatFromViewPortPx: function (viewPortPx) {
-        return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
-    },
+    name: null,
     
     /**
-     * Method: getViewPortPxFromLonLat
-     * Get a pixel location from a map location
-     *
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
-     * OpenLayers.LonLat, translated into view port pixels by map lib
-     * If map lib is not loaded or not centered, returns null
-     */
-    getViewPortPxFromLonLat: function (lonlat) {
-        return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
-    },
-
-    /** 
-     * Method: initMercatorParameters 
-     * Set up the mercator parameters on the layer: resolutions,
-     *     projection, units.
+     * Property: title
+     * {String} Title of this rule (set if included in SLD)
      */
-    initMercatorParameters: function() {
-        // set up properties for Mercator - assume EPSG:900913
-        this.RESOLUTIONS = [];
-        var maxResolution = 156543.03390625;
-        for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
-            this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
-        }
-        this.units = "m";
-        this.projection = this.projection || "EPSG:900913";
-    },
-
+    title: null,
+    
     /**
-     * APIMethod: forwardMercator
-     * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
-     *
-     * Parameters:
-     * lon - {float} 
-     * lat - {float}
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
+     * Property: description
+     * {String} Description of this rule (set if abstract is included in SLD)
      */
-    forwardMercator: (function() {
-        var gg = new OpenLayers.Projection("EPSG:4326");
-        var sm = new OpenLayers.Projection("EPSG:900913");
-        return function(lon, lat) {
-            var point = OpenLayers.Projection.transform({x: lon, y: lat}, gg, sm);
-            return new OpenLayers.LonLat(point.x, point.y);
-        };
-    })(),
+    description: null,
 
     /**
-     * APIMethod: inverseMercator
-     * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
-     *
-     * Parameters:
-     * x - {float} A map x in Spherical Mercator.
-     * y - {float} A map y in Spherical Mercator.
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
+     * Property: context
+     * {Object} An optional object with properties that the rule should be
+     * evaluated against. If no context is specified, feature.attributes will
+     * be used.
      */
-    inverseMercator: (function() {
-        var gg = new OpenLayers.Projection("EPSG:4326");
-        var sm = new OpenLayers.Projection("EPSG:900913");
-        return function(x, y) {
-            var point = OpenLayers.Projection.transform({x: x, y: y}, sm, gg);
-            return new OpenLayers.LonLat(point.x, point.y);
-        };
-    })()
-
-};
-/* ======================================================================
-    OpenLayers/Layer/EventPane.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Layer.EventPane
- * Base class for 3rd party layers, providing a DOM element which isolates
- * the 3rd-party layer from mouse events.
- * Only used by Google layers.
- *
- * Automatically instantiated by the Google constructor, and not usually instantiated directly.
- *
- * Create a new event pane layer with the
- * <OpenLayers.Layer.EventPane> constructor.
- * 
- * Inherits from:
- *  - <OpenLayers.Layer>
- */
-OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, {
+    context: null,
     
     /**
-     * APIProperty: smoothDragPan
-     * {Boolean} smoothDragPan determines whether non-public/internal API
-     *     methods are used for better performance while dragging EventPane 
-     *     layers. When not in sphericalMercator mode, the smoother dragging 
-     *     doesn't actually move north/south directly with the number of 
-     *     pixels moved, resulting in a slight offset when you drag your mouse 
-     *     north south with this option on. If this visual disparity bothers 
-     *     you, you should turn this option off, or use spherical mercator. 
-     *     Default is on.
+     * Property: filter
+     * {<OpenLayers.Filter>} Optional filter for the rule.
      */
-    smoothDragPan: true,
+    filter: null,
 
     /**
-     * Property: isBaseLayer
-     * {Boolean} EventPaned layers are always base layers, by necessity.
-     */ 
-    isBaseLayer: true,
-
+     * Property: elseFilter
+     * {Boolean} Determines whether this rule is only to be applied only if
+     * no other rules match (ElseFilter according to the SLD specification). 
+     * Default is false.  For instances of OpenLayers.Rule, if elseFilter is
+     * false, the rule will always apply.  For subclasses, the else property is 
+     * ignored.
+     */
+    elseFilter: false,
+    
     /**
-     * APIProperty: isFixed
-     * {Boolean} EventPaned layers are fixed by default.
-     */ 
-    isFixed: true,
-
+     * Property: symbolizer
+     * {Object} Symbolizer or hash of symbolizers for this rule. If hash of
+     * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The
+     * latter if useful if it is required to style e.g. vertices of a line
+     * with a point symbolizer. Note, however, that this is not implemented
+     * yet in OpenLayers, but it is the way how symbolizers are defined in
+     * SLD.
+     */
+    symbolizer: null,
+    
     /**
-     * Property: pane
-     * {DOMElement} A reference to the element that controls the events.
+     * Property: symbolizers
+     * {Array} Collection of symbolizers associated with this rule.  If 
+     *     provided at construction, the symbolizers array has precedence
+     *     over the deprecated symbolizer property.  Note that multiple 
+     *     symbolizers are not currently supported by the vector renderers.
+     *     Rules with multiple symbolizers are currently only useful for
+     *     maintaining elements in an SLD document.
      */
-    pane: null,
-
-
+    symbolizers: null,
+    
     /**
-     * Property: mapObject
-     * {Object} This is the object which will be used to load the 3rd party library
-     * in the case of the google layer, this will be of type GMap, 
-     * in the case of the ve layer, this will be of type VEMap
-     */ 
-    mapObject: null,
-
+     * APIProperty: minScaleDenominator
+     * {Number} or {String} minimum scale at which to draw the feature.
+     * In the case of a String, this can be a combination of text and
+     * propertyNames in the form "literal ${propertyName}"
+     */
+    minScaleDenominator: null,
 
     /**
-     * Constructor: OpenLayers.Layer.EventPane
-     * Create a new event pane layer
+     * APIProperty: maxScaleDenominator
+     * {Number} or {String} maximum scale at which to draw the feature.
+     * In the case of a String, this can be a combination of text and
+     * propertyNames in the form "literal ${propertyName}"
+     */
+    maxScaleDenominator: null,
+    
+    /** 
+     * Constructor: OpenLayers.Rule
+     * Creates a Rule.
      *
      * Parameters:
-     * name - {String}
-     * options - {Object} Hashtable of extra options to tag onto the layer
+     * options - {Object} An optional object with properties to set on the
+     *           rule
+     * 
+     * Returns:
+     * {<OpenLayers.Rule>}
      */
-    initialize: function(name, options) {
-        OpenLayers.Layer.prototype.initialize.apply(this, arguments);
-        if (this.pane == null) {
-            this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane");
+    initialize: function(options) {
+        this.symbolizer = {};
+        OpenLayers.Util.extend(this, options);
+        if (this.symbolizers) {
+            delete this.symbolizer;
         }
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
     },
-    
-    /**
+
+    /** 
      * APIMethod: destroy
-     * Deconstruct this layer.
+     * nullify references to prevent circular references and memory leaks
      */
     destroy: function() {
-        this.mapObject = null;
-        this.pane = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
+        for (var i in this.symbolizer) {
+            this.symbolizer[i] = null;
+        }
+        this.symbolizer = null;
+        delete this.symbolizers;
     },
-
     
     /**
-     * Method: setMap
-     * Set the map property for the layer. This is done through an accessor
-     * so that subclasses can override this and take special action once 
-     * they have their map variable set. 
-     *
+     * APIMethod: evaluate
+     * evaluates this rule for a specific feature
+     * 
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * feature - {<OpenLayers.Feature>} feature to apply the rule to.
+     * 
+     * Returns:
+     * {Boolean} true if the rule applies, false if it does not.
+     * This rule is the default rule and always returns true.
      */
-    setMap: function(map) {
-        OpenLayers.Layer.prototype.setMap.apply(this, arguments);
+    evaluate: function(feature) {
+        var context = this.getContext(feature);
+        var applies = true;
+
+        if (this.minScaleDenominator || this.maxScaleDenominator) {
+            var scale = feature.layer.map.getScale();
+        }
         
-        this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
-        this.pane.style.display = this.div.style.display;
-        this.pane.style.width="100%";
-        this.pane.style.height="100%";
-        if (OpenLayers.BROWSER_NAME == "msie") {
-            this.pane.style.background = 
-                "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")";
+        // check if within minScale/maxScale bounds
+        if (this.minScaleDenominator) {
+            applies = scale >= OpenLayers.Style.createLiteral(
+                    this.minScaleDenominator, context);
         }
-
-        if (this.isFixed) {
-            this.map.viewPortDiv.appendChild(this.pane);
-        } else {
-            this.map.layerContainerDiv.appendChild(this.pane);
+        if (applies && this.maxScaleDenominator) {
+            applies = scale < OpenLayers.Style.createLiteral(
+                    this.maxScaleDenominator, context);
         }
-
-        // once our layer has been added to the map, we can load it
-        this.loadMapObject();
-    
-        // if map didn't load, display warning
-        if (this.mapObject == null) {
-            this.loadWarningMessage();
+        
+        // check if optional filter applies
+        if(applies && this.filter) {
+            // feature id filters get the feature, others get the context
+            if(this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") {
+                applies = this.filter.evaluate(feature);
+            } else {
+                applies = this.filter.evaluate(context);
+            }
         }
-    },
 
+        return applies;
+    },
+    
     /**
-     * APIMethod: removeMap
-     * On being removed from the map, we'll like to remove the invisible 'pane'
-     *     div that we added to it on creation. 
+     * Method: getContext
+     * Gets the context for evaluating this rule
      * 
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * feature - {<OpenLayers.Feature>} feature to take the context from if
+     *           none is specified.
      */
-    removeMap: function(map) {
-        if (this.pane && this.pane.parentNode) {
-            this.pane.parentNode.removeChild(this.pane);
+    getContext: function(feature) {
+        var context = this.context;
+        if (!context) {
+            context = feature.attributes || feature.data;
         }
-        OpenLayers.Layer.prototype.removeMap.apply(this, arguments);
+        if (typeof this.context == "function") {
+            context = this.context(feature);
+        }
+        return context;
     },
-  
+    
     /**
-     * Method: loadWarningMessage
-     * If we can't load the map lib, then display an error message to the 
-     *     user and tell them where to go for help.
-     * 
-     *     This function sets up the layout for the warning message. Each 3rd
-     *     party layer must implement its own getWarningHTML() function to 
-     *     provide the actual warning message.
-     */
-    loadWarningMessage:function() {
-
-        this.div.style.backgroundColor = "darkblue";
-
-        var viewSize = this.map.getSize();
-        
-        var msgW = Math.min(viewSize.w, 300);
-        var msgH = Math.min(viewSize.h, 200);
-        var size = new OpenLayers.Size(msgW, msgH);
-
-        var centerPx = new OpenLayers.Pixel(viewSize.w/2, viewSize.h/2);
-
-        var topLeft = centerPx.add(-size.w/2, -size.h/2);            
-
-        var div = OpenLayers.Util.createDiv(this.name + "_warning", 
-                                            topLeft, 
-                                            size,
-                                            null,
-                                            null,
-                                            null,
-                                            "auto");
-
-        div.style.padding = "7px";
-        div.style.backgroundColor = "yellow";
-
-        div.innerHTML = this.getWarningHTML();
-        this.div.appendChild(div);
-    },
-  
-    /** 
-     * Method: getWarningHTML
-     * To be implemented by subclasses.
+     * APIMethod: clone
+     * Clones this rule.
      * 
      * Returns:
-     * {String} String with information on why layer is broken, how to get
-     *          it working.
-     */
-    getWarningHTML:function() {
-        //should be implemented by subclasses
-        return "";
-    },
-  
-    /**
-     * Method: display
-     * Set the display on the pane
-     *
-     * Parameters:
-     * display - {Boolean}
-     */
-    display: function(display) {
-        OpenLayers.Layer.prototype.display.apply(this, arguments);
-        this.pane.style.display = this.div.style.display;
-    },
-  
-    /**
-     * Method: setZIndex
-     * Set the z-index order for the pane.
-     * 
-     * Parameters:
-     * zIndex - {int}
-     */
-    setZIndex: function (zIndex) {
-        OpenLayers.Layer.prototype.setZIndex.apply(this, arguments);
-        this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
-    },
-    
-    /**
-     * Method: moveByPx
-     * Move the layer based on pixel vector. To be implemented by subclasses.
-     *
-     * Parameters:
-     * dx - {Number} The x coord of the displacement vector.
-     * dy - {Number} The y coord of the displacement vector.
+     * {<OpenLayers.Rule>} Clone of this rule.
      */
-    moveByPx: function(dx, dy) {
-        OpenLayers.Layer.prototype.moveByPx.apply(this, arguments);
-        
-        if (this.dragPanMapObject) {
-            this.dragPanMapObject(dx, -dy);
+    clone: function() {
+        var options = OpenLayers.Util.extend({}, this);
+        if (this.symbolizers) {
+            // clone symbolizers
+            var len = this.symbolizers.length;
+            options.symbolizers = new Array(len);
+            for (var i=0; i<len; ++i) {
+                options.symbolizers[i] = this.symbolizers[i].clone();
+            }
         } else {
-            this.moveTo(this.map.getCachedCenter());
-        }
-    },
-
-    /**
-     * Method: moveTo
-     * Handle calls to move the layer.
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean}
-     * dragging - {Boolean}
-     */
-    moveTo:function(bounds, zoomChanged, dragging) {
-        OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
-
-        if (this.mapObject != null) {
-
-            var newCenter = this.map.getCenter();
-            var newZoom = this.map.getZoom();
-
-            if (newCenter != null) {
-
-                var moOldCenter = this.getMapObjectCenter();
-                var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter);
-
-                var moOldZoom = this.getMapObjectZoom();
-                var oldZoom= this.getOLZoomFromMapObjectZoom(moOldZoom);
-
-                if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) {
-
-                    if (!zoomChanged && oldCenter && this.dragPanMapObject && 
-                        this.smoothDragPan) {
-                        var oldPx = this.map.getViewPortPxFromLonLat(oldCenter);
-                        var newPx = this.map.getViewPortPxFromLonLat(newCenter);
-                        this.dragPanMapObject(newPx.x-oldPx.x, oldPx.y-newPx.y);
-                    } else {
-                        var center = this.getMapObjectLonLatFromOLLonLat(newCenter);
-                        var zoom = this.getMapObjectZoomFromOLZoom(newZoom);
-                        this.setMapObjectCenter(center, zoom, dragging);
-                    }
+            // clone symbolizer
+            options.symbolizer = {};
+            var value, type;
+            for(var key in this.symbolizer) {
+                value = this.symbolizer[key];
+                type = typeof value;
+                if(type === "object") {
+                    options.symbolizer[key] = OpenLayers.Util.extend({}, value);
+                } else if(type === "string") {
+                    options.symbolizer[key] = value;
                 }
             }
         }
+        // clone filter
+        options.filter = this.filter && this.filter.clone();
+        // clone context
+        options.context = this.context && OpenLayers.Util.extend({}, this.context);
+        return new OpenLayers.Rule(options);
     },
+        
+    CLASS_NAME: "OpenLayers.Rule"
+});
+/* ======================================================================
+    OpenLayers/StyleMap.js
+   ====================================================================== */
 
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
 
-  /********************************************************/
-  /*                                                      */
-  /*                 Baselayer Functions                  */
-  /*                                                      */
-  /********************************************************/
-
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Style.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+/**
+ * Class: OpenLayers.StyleMap
+ */
+OpenLayers.StyleMap = OpenLayers.Class({
+    
     /**
-     * Method: getLonLatFromViewPortPx
-     * Get a map location from a pixel location
-     * 
-     * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     *  {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
-     *  port OpenLayers.Pixel, translated into lon/lat by map lib
-     *  If the map lib is not loaded or not centered, returns null
+     * Property: styles
+     * {Object} Hash of {<OpenLayers.Style>}, keyed by names of well known
+     * rendering intents (e.g. "default", "temporary", "select", "delete").
      */
-    getLonLatFromViewPortPx: function (viewPortPx) {
-        var lonlat = null;
-        if ( (this.mapObject != null) && 
-             (this.getMapObjectCenter() != null) ) {
-            var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx);
-            var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel);
-            lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat);
-        }
-        return lonlat;
-    },
-
+    styles: null,
+    
     /**
-     * Method: getViewPortPxFromLonLat
-     * Get a pixel location from a map location
-     *
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
-     * OpenLayers.LonLat, translated into view port pixels by map lib
-     * If map lib is not loaded or not centered, returns null
+     * Property: extendDefault
+     * {Boolean} if true, every render intent will extend the symbolizers
+     * specified for the "default" intent at rendering time. Otherwise, every
+     * rendering intent will be treated as a completely independent style.
      */
-    getViewPortPxFromLonLat: function (lonlat) {
-        var viewPortPx = null;
-        if ( (this.mapObject != null) && 
-             (this.getMapObjectCenter() != null) ) {
-
-            var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat);
-            var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat);
-        
-            viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel);
-        }
-        return viewPortPx;
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*               Translation Functions                  */
-  /*                                                      */
-  /*   The following functions translate Map Object and   */
-  /*            OL formats for Pixel, LonLat              */
-  /*                                                      */
-  /********************************************************/
-
-  //
-  // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat
-  //
-
+    extendDefault: true,
+    
     /**
-     * Method: getOLLonLatFromMapObjectLonLat
-     * Get an OL style map location from a 3rd party style map location
-     *
-     * Parameters
-     * moLonLat - {Object}
+     * Constructor: OpenLayers.StyleMap
      * 
-     * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in 
-     *          MapObject LonLat
-     *          Returns null if null value is passed in
+     * Parameters:
+     * style   - {Object} Optional. Either a style hash, or a style object, or
+     *           a hash of style objects (style hashes) keyed by rendering
+     *           intent. If just one style hash or style object is passed,
+     *           this will be used for all known render intents (default,
+     *           select, temporary)
+     * options - {Object} optional hash of additional options for this
+     *           instance
      */
-    getOLLonLatFromMapObjectLonLat: function(moLonLat) {
-        var olLonLat = null;
-        if (moLonLat != null) {
-            var lon = this.getLongitudeFromMapObjectLonLat(moLonLat);
-            var lat = this.getLatitudeFromMapObjectLonLat(moLonLat);
-            olLonLat = new OpenLayers.LonLat(lon, lat);
+    initialize: function (style, options) {
+        this.styles = {
+            "default": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["default"]),
+            "select": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["select"]),
+            "temporary": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["temporary"]),
+            "delete": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["delete"])
+        };
+        
+        // take whatever the user passed as style parameter and convert it
+        // into parts of stylemap.
+        if(style instanceof OpenLayers.Style) {
+            // user passed a style object
+            this.styles["default"] = style;
+            this.styles["select"] = style;
+            this.styles["temporary"] = style;
+            this.styles["delete"] = style;
+        } else if(typeof style == "object") {
+            for(var key in style) {
+                if(style[key] instanceof OpenLayers.Style) {
+                    // user passed a hash of style objects
+                    this.styles[key] = style[key];
+                } else if(typeof style[key] == "object") {
+                    // user passsed a hash of style hashes
+                    this.styles[key] = new OpenLayers.Style(style[key]);
+                } else {
+                    // user passed a style hash (i.e. symbolizer)
+                    this.styles["default"] = new OpenLayers.Style(style);
+                    this.styles["select"] = new OpenLayers.Style(style);
+                    this.styles["temporary"] = new OpenLayers.Style(style);
+                    this.styles["delete"] = new OpenLayers.Style(style);
+                    break;
+                }
+            }
         }
-        return olLonLat;
+        OpenLayers.Util.extend(this, options);
     },
 
     /**
-     * Method: getMapObjectLonLatFromOLLonLat
-     * Get a 3rd party map location from an OL map location.
-     *
-     * Parameters:
-     * olLonLat - {<OpenLayers.LonLat>}
-     * 
-     * Returns:
-     * {Object} A MapObject LonLat, translated from the passed in 
-     *          OpenLayers.LonLat
-     *          Returns null if null value is passed in
+     * Method: destroy
      */
-    getMapObjectLonLatFromOLLonLat: function(olLonLat) {
-        var moLatLng = null;
-        if (olLonLat != null) {
-            moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon,
-                                                         olLonLat.lat);
+    destroy: function() {
+        for(var key in this.styles) {
+            this.styles[key].destroy();
         }
-        return moLatLng;
+        this.styles = null;
     },
-
-
-  //
-  // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel
-  //
-
+    
     /**
-     * Method: getOLPixelFromMapObjectPixel
-     * Get an OL pixel location from a 3rd party pixel location.
-     *
+     * Method: createSymbolizer
+     * Creates the symbolizer for a feature for a render intent.
+     * 
      * Parameters:
-     * moPixel - {Object}
+     * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
+     *           of the intended style against.
+     * intent  - {String} The intent determines the symbolizer that will be
+     *           used to draw the feature. Well known intents are "default"
+     *           (for just drawing the features), "select" (for selected
+     *           features) and "temporary" (for drawing features).
      * 
      * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in 
-     *          MapObject Pixel
-     *          Returns null if null value is passed in
+     * {Object} symbolizer hash
      */
-    getOLPixelFromMapObjectPixel: function(moPixel) {
-        var olPixel = null;
-        if (moPixel != null) {
-            var x = this.getXFromMapObjectPixel(moPixel);
-            var y = this.getYFromMapObjectPixel(moPixel);
-            olPixel = new OpenLayers.Pixel(x, y);
+    createSymbolizer: function(feature, intent) {
+        if(!feature) {
+            feature = new OpenLayers.Feature.Vector();
         }
-        return olPixel;
+        if(!this.styles[intent]) {
+            intent = "default";
+        }
+        feature.renderIntent = intent;
+        var defaultSymbolizer = {};
+        if(this.extendDefault && intent != "default") {
+            defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
+        }
+        return OpenLayers.Util.extend(defaultSymbolizer,
+            this.styles[intent].createSymbolizer(feature));
     },
-
+    
     /**
-     * Method: getMapObjectPixelFromOLPixel
-     * Get a 3rd party pixel location from an OL pixel location
-     *
-     * Parameters:
-     * olPixel - {<OpenLayers.Pixel>}
+     * Method: addUniqueValueRules
+     * Convenience method to create comparison rules for unique values of a
+     * property. The rules will be added to the style object for a specified
+     * rendering intent. This method is a shortcut for creating something like
+     * the "unique value legends" familiar from well known desktop GIS systems
      * 
-     * Returns:
-     * {Object} A MapObject Pixel, translated from the passed in 
-     *          OpenLayers.Pixel
-     *          Returns null if null value is passed in
+     * Parameters:
+     * renderIntent - {String} rendering intent to add the rules to
+     * property     - {String} values of feature attributes to create the
+     *                rules for
+     * symbolizers  - {Object} Hash of symbolizers, keyed by the desired
+     *                property values 
+     * context      - {Object} An optional object with properties that
+     *                symbolizers' property values should be evaluated
+     *                against. If no context is specified, feature.attributes
+     *                will be used
      */
-    getMapObjectPixelFromOLPixel: function(olPixel) {
-        var moPixel = null;
-        if (olPixel != null) {
-            moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y);
+    addUniqueValueRules: function(renderIntent, property, symbolizers, context) {
+        var rules = [];
+        for (var value in symbolizers) {
+            rules.push(new OpenLayers.Rule({
+                symbolizer: symbolizers[value],
+                context: context,
+                filter: new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.EQUAL_TO,
+                    property: property,
+                    value: value
+                })
+            }));
         }
-        return moPixel;
+        this.styles[renderIntent].addRules(rules);
     },
 
-    CLASS_NAME: "OpenLayers.Layer.EventPane"
+    CLASS_NAME: "OpenLayers.StyleMap"
 });
 /* ======================================================================
-    OpenLayers/Layer/FixedZoomLevels.js
+    OpenLayers/Request.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
 
 /**
- * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Request/XMLHttpRequest.js
  */
 
 /**
- * Class: OpenLayers.Layer.FixedZoomLevels
- *   Some Layers will already have established zoom levels (like google 
- *    or ve). Instead of trying to determine them and populate a resolutions[]
- *    Array with those values, we will hijack the resolution functionality
- *    here.
- * 
- *   When you subclass FixedZoomLevels: 
- * 
- *   The initResolutions() call gets nullified, meaning no resolutions[] array 
- *    is set up. Which would be a big problem getResolution() in Layer, since 
- *    it merely takes map.zoom and indexes into resolutions[]... but....
- * 
- *   The getResolution() call is also overridden. Instead of using the 
- *    resolutions[] array, we simply calculate the current resolution based
- *    on the current extent and the current map size. But how will we be able
- *    to calculate the current extent without knowing the resolution...?
- *  
- *   The getExtent() function is also overridden. Instead of calculating extent
- *    based on the center point and the current resolution, we instead 
- *    calculate the extent by getting the lonlats at the top-left and 
- *    bottom-right by using the getLonLatFromViewPortPx() translation function,
- *    taken from the pixel locations (0,0) and the size of the map. But how 
- *    will we be able to do lonlat-px translation without resolution....?
- * 
- *   The getZoomForResolution() method is overridden. Instead of indexing into
- *    the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
- *    the desired resolution. With this extent, we then call getZoomForExtent() 
- * 
- * 
- *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels, 
- *    it is your responsibility to provide the following three functions:
- * 
- *   - getLonLatFromViewPortPx
- *   - getViewPortPxFromLonLat
- *   - getZoomForExtent
- * 
- *  ...those three functions should generally be provided by any reasonable 
- *  API that you might be working from.
- *
+ * TODO: deprecate me
+ * Use OpenLayers.Request.proxy instead.
  */
-OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
-      
-  /********************************************************/
-  /*                                                      */
-  /*                 Baselayer Functions                  */
-  /*                                                      */
-  /*    The following functions must all be implemented   */
-  /*                  by all base layers                  */
-  /*                                                      */
-  /********************************************************/
+OpenLayers.ProxyHost = "";
+
+/**
+ * Namespace: OpenLayers.Request
+ * The OpenLayers.Request namespace contains convenience methods for working
+ *     with XMLHttpRequests.  These methods work with a cross-browser
+ *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
+ */
+if (!OpenLayers.Request) {
+    /**
+     * This allows for OpenLayers/Request/XMLHttpRequest.js to be included
+     * before or after this script.
+     */
+    OpenLayers.Request = {};
+}
+OpenLayers.Util.extend(OpenLayers.Request, {
     
     /**
-     * Constructor: OpenLayers.Layer.FixedZoomLevels
-     * Create a new fixed zoom levels layer.
+     * Constant: DEFAULT_CONFIG
+     * {Object} Default configuration for all requests.
      */
-    initialize: function() {
-        //this class is only just to add the following functions... 
-        // nothing to actually do here... but it is probably a good
-        // idea to have layers that use these functions call this 
-        // inititalize() anyways, in case at some point we decide we 
-        // do want to put some functionality or state in here. 
+    DEFAULT_CONFIG: {
+        method: "GET",
+        url: window.location.href,
+        async: true,
+        user: undefined,
+        password: undefined,
+        params: null,
+        proxy: OpenLayers.ProxyHost,
+        headers: {},
+        data: null,
+        callback: function() {},
+        success: null,
+        failure: null,
+        scope: null
     },
     
     /**
-     * Method: initResolutions
-     * Populate the resolutions array
+     * Constant: URL_SPLIT_REGEX
      */
-    initResolutions: function() {
-
-        var props = ['minZoomLevel', 'maxZoomLevel', 'numZoomLevels'];
-          
-        for(var i=0, len=props.length; i<len; i++) {
-            var property = props[i];
-            this[property] = (this.options[property] != null)  
-                                     ? this.options[property] 
-                                     : this.map[property];
-        }
-
-        if ( (this.minZoomLevel == null) ||
-             (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
-            this.minZoomLevel = this.MIN_ZOOM_LEVEL;
-        }        
-
-        //
-        // At this point, we know what the minimum desired zoom level is, and
-        //  we must calculate the total number of zoom levels. 
-        //  
-        //  Because we allow for the setting of either the 'numZoomLevels'
-        //   or the 'maxZoomLevel' properties... on either the layer or the  
-        //   map, we have to define some rules to see which we take into
-        //   account first in this calculation. 
-        //
-        // The following is the precedence list for these properties:
-        // 
-        // (1) numZoomLevels set on layer
-        // (2) maxZoomLevel set on layer
-        // (3) numZoomLevels set on map
-        // (4) maxZoomLevel set on map*
-        // (5) none of the above*
-        //
-        // *Note that options (4) and (5) are only possible if the user 
-        //  _explicitly_ sets the 'numZoomLevels' property on the map to 
-        //  null, since it is set by default to 16. 
-        //
+    URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,
+    
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>} An events object that handles all 
+     *     events on the {<OpenLayers.Request>} object.
+     *
+     * All event listeners will receive an event object with three properties:
+     * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
+     * config - {Object} The config object sent to the specific request method.
+     * requestUrl - {String} The request url.
+     * 
+     * Supported event types:
+     * complete - Triggered when we have a response from the request, if a
+     *     listener returns false, no further response processing will take
+     *     place.
+     * success - Triggered when the HTTP response has a success code (200-299).
+     * failure - Triggered when the HTTP response does not have a success code.
+     */
+    events: new OpenLayers.Events(this),
+    
+    /**
+     * Method: makeSameOrigin
+     * Using the specified proxy, returns a same origin url of the provided url.
+     *
+     * Parameters:
+     * url - {String} An arbitrary url
+     * proxy {String|Function} The proxy to use to make the provided url a
+     *     same origin url.
+     *
+     * Returns
+     * {String} the same origin url. If no proxy is provided, the returned url
+     *     will be the same as the provided url.
+     */
+    makeSameOrigin: function(url, proxy) {
+        var sameOrigin = url.indexOf("http") !== 0;
+        var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);
+        if (urlParts) {
+            var location = window.location;
+            sameOrigin =
+                urlParts[1] == location.protocol &&
+                urlParts[3] == location.hostname;
+            var uPort = urlParts[4], lPort = location.port;
+            if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") {
+                sameOrigin = sameOrigin && uPort == lPort;
+            }
+        }
+        if (!sameOrigin) {
+            if (proxy) {
+                if (typeof proxy == "function") {
+                    url = proxy(url);
+                } else {
+                    url = proxy + encodeURIComponent(url);
+                }
+            }
+        }
+        return url;
+    },
 
-        //
-        // Note to future: In 3.0, I think we should remove the default 
-        // value of 16 for map.numZoomLevels. Rather, I think that value 
-        // should be set as a default on the Layer.WMS class. If someone
-        // creates a 3rd party layer and does not specify any 'minZoomLevel', 
-        // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly 
-        // specified any of those on the map object either.. then I think
-        // it is fair to say that s/he wants all the zoom levels available.
-        // 
-        // By making map.numZoomLevels *null* by default, that will be the 
-        // case. As it is, I don't feel comfortable changing that right now
-        // as it would be a glaring API change and actually would probably
-        // break many peoples' codes. 
-        //
+    /**
+     * APIMethod: issue
+     * Create a new XMLHttpRequest object, open it, set any headers, bind
+     *     a callback to done state, and send any data.  It is recommended that
+     *     you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
+     *     This method is only documented to provide detail on the configuration
+     *     options available to all request methods.
+     *
+     * Parameters:
+     * config - {Object} Object containing properties for configuring the
+     *     request.  Allowed configuration properties are described below.
+     *     This object is modified and should not be reused.
+     *
+     * Allowed config properties:
+     * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
+     *     OPTIONS.  Default is GET.
+     * url - {String} URL for the request.
+     * async - {Boolean} Open an asynchronous request.  Default is true.
+     * user - {String} User for relevant authentication scheme.  Set
+     *     to null to clear current user.
+     * password - {String} Password for relevant authentication scheme.
+     *     Set to null to clear current password.
+     * proxy - {String} Optional proxy.  Defaults to
+     *     <OpenLayers.ProxyHost>.
+     * params - {Object} Any key:value pairs to be appended to the
+     *     url as a query string.  Assumes url doesn't already include a query
+     *     string or hash.  Typically, this is only appropriate for <GET>
+     *     requests where the query string will be appended to the url.
+     *     Parameter values that are arrays will be
+     *     concatenated with a comma (note that this goes against form-encoding)
+     *     as is done with <OpenLayers.Util.getParameterString>.
+     * headers - {Object} Object with header:value pairs to be set on
+     *     the request.
+     * data - {String | Document} Optional data to send with the request.
+     *     Typically, this is only used with <POST> and <PUT> requests.
+     *     Make sure to provide the appropriate "Content-Type" header for your
+     *     data.  For <POST> and <PUT> requests, the content type defaults to
+     *     "application-xml".  If your data is a different content type, or
+     *     if you are using a different HTTP method, set the "Content-Type"
+     *     header to match your data type.
+     * callback - {Function} Function to call when request is done.
+     *     To determine if the request failed, check request.status (200
+     *     indicates success).
+     * success - {Function} Optional function to call if request status is in
+     *     the 200s.  This will be called in addition to callback above and
+     *     would typically only be used as an alternative.
+     * failure - {Function} Optional function to call if request status is not
+     *     in the 200s.  This will be called in addition to callback above and
+     *     would typically only be used as an alternative.
+     * scope - {Object} If callback is a public method on some object,
+     *     set the scope to that object.
+     *
+     * Returns:
+     * {XMLHttpRequest} Request object.  To abort the request before a response
+     *     is received, call abort() on the request object.
+     */
+    issue: function(config) {        
+        // apply default config - proxy host may have changed
+        var defaultConfig = OpenLayers.Util.extend(
+            this.DEFAULT_CONFIG,
+            {proxy: OpenLayers.ProxyHost}
+        );
+        config = config || {};
+        config.headers = config.headers || {};
+        config = OpenLayers.Util.applyDefaults(config, defaultConfig);
+        config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);
+        // Always set the "X-Requested-With" header to signal that this request
+        // was issued through the XHR-object. Since header keys are case 
+        // insensitive and we want to allow overriding of the "X-Requested-With"
+        // header through the user we cannot use applyDefaults, but have to 
+        // check manually whether we were called with a "X-Requested-With"
+        // header.
+        var customRequestedWithHeader = false,
+            headerKey;
+        for(headerKey in config.headers) {
+            if (config.headers.hasOwnProperty( headerKey )) {
+                if (headerKey.toLowerCase() === 'x-requested-with') {
+                    customRequestedWithHeader = true;
+                }
+            }
+        }
+        if (customRequestedWithHeader === false) {
+            // we did not have a custom "X-Requested-With" header
+            config.headers['X-Requested-With'] = 'XMLHttpRequest';
+        }
 
-        //the number of zoom levels we'd like to have.
-        var desiredZoomLevels;
+        // create request, open, and set headers
+        var request = new OpenLayers.Request.XMLHttpRequest();
+        var url = OpenLayers.Util.urlAppend(config.url, 
+            OpenLayers.Util.getParameterString(config.params || {}));
+        url = OpenLayers.Request.makeSameOrigin(url, config.proxy);
+        request.open(
+            config.method, url, config.async, config.user, config.password
+        );
+        for(var header in config.headers) {
+            request.setRequestHeader(header, config.headers[header]);
+        }
 
-        //this is the maximum number of zoom levels the layer will allow, 
-        // given the specified starting minimum zoom level.
-        var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
+        var events = this.events;
 
-        if ( ((this.options.numZoomLevels == null) && 
-              (this.options.maxZoomLevel != null)) // (2)
-              ||
-             ((this.numZoomLevels == null) &&
-              (this.maxZoomLevel != null)) // (4)
-           ) {
-            //calculate based on specified maxZoomLevel (on layer or map)
-            desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
+        // we want to execute runCallbacks with "this" as the
+        // execution scope
+        var self = this;
+        
+        request.onreadystatechange = function() {
+            if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+                var proceed = events.triggerEvent(
+                    "complete",
+                    {request: request, config: config, requestUrl: url}
+                );
+                if(proceed !== false) {
+                    self.runCallbacks(
+                        {request: request, config: config, requestUrl: url}
+                    );
+                }
+            }
+        };
+        
+        // send request (optionally with data) and return
+        // call in a timeout for asynchronous requests so the return is
+        // available before readyState == 4 for cached docs
+        if(config.async === false) {
+            request.send(config.data);
         } else {
-            //calculate based on specified numZoomLevels (on layer or map)
-            // this covers cases (1) and (3)
-            desiredZoomLevels = this.numZoomLevels;
+            window.setTimeout(function(){
+                if (request.readyState !== 0) { // W3C: 0-UNSENT
+                    request.send(config.data);
+                }
+            }, 0);
+        }
+        return request;
+    },
+    
+    /**
+     * Method: runCallbacks
+     * Calls the complete, success and failure callbacks. Application
+     *    can listen to the "complete" event, have the listener 
+     *    display a confirm window and always return false, and
+     *    execute OpenLayers.Request.runCallbacks if the user
+     *    hits "yes" in the confirm window.
+     *
+     * Parameters:
+     * options - {Object} Hash containing request, config and requestUrl keys
+     */
+    runCallbacks: function(options) {
+        var request = options.request;
+        var config = options.config;
+        
+        // bind callbacks to readyState 4 (done)
+        var complete = (config.scope) ?
+            OpenLayers.Function.bind(config.callback, config.scope) :
+            config.callback;
+        
+        // optional success callback
+        var success;
+        if(config.success) {
+            success = (config.scope) ?
+                OpenLayers.Function.bind(config.success, config.scope) :
+                config.success;
         }
 
-        if (desiredZoomLevels != null) {
-            //Now that we know what we would *like* the number of zoom levels
-            // to be, based on layer or map options, we have to make sure that
-            // it does not conflict with the actual limit, as specified by 
-            // the constants on the layer itself (and calculated into the
-            // 'limitZoomLevels' variable). 
-            this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
-        } else {
-            // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was 
-            // set on either the layer or the map. So we just use the 
-            // maximum limit as calculated by the layer's constants.
-            this.numZoomLevels = limitZoomLevels;
+        // optional failure callback
+        var failure;
+        if(config.failure) {
+            failure = (config.scope) ?
+                OpenLayers.Function.bind(config.failure, config.scope) :
+                config.failure;
         }
 
-        //now that the 'numZoomLevels' is appropriately, safely set, 
-        // we go back and re-calculate the 'maxZoomLevel'.
-        this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
+        if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" &&
+                                                        request.responseText) {
+            request.status = 200;
+        }
+        complete(request);
 
-        if (this.RESOLUTIONS != null) {
-            var resolutionsIndex = 0;
-            this.resolutions = [];
-            for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
-                this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];            
+        if (!request.status || (request.status >= 200 && request.status < 300)) {
+            this.events.triggerEvent("success", options);
+            if(success) {
+                success(request);
             }
-            this.maxResolution = this.resolutions[0];
-            this.minResolution = this.resolutions[this.resolutions.length - 1];
-        }       
+        }
+        if(request.status && (request.status < 200 || request.status >= 300)) {                    
+            this.events.triggerEvent("failure", options);
+            if(failure) {
+                failure(request);
+            }
+        }
     },
     
     /**
-     * APIMethod: getResolution
-     * Get the current map resolution
+     * APIMethod: GET
+     * Send an HTTP GET request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to GET.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
      * 
      * Returns:
-     * {Float} Map units per Pixel
+     * {XMLHttpRequest} Request object.
      */
-    getResolution: function() {
-
-        if (this.resolutions != null) {
-            return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
-        } else {
-            var resolution = null;
-            
-            var viewSize = this.map.getSize();
-            var extent = this.getExtent();
-            
-            if ((viewSize != null) && (extent != null)) {
-                resolution = Math.max( extent.getWidth()  / viewSize.w,
-                                       extent.getHeight() / viewSize.h );
-            }
-            return resolution;
-        }
-     },
-
+    GET: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "GET"});
+        return OpenLayers.Request.issue(config);
+    },
+    
     /**
-     * APIMethod: getExtent
-     * Calculates using px-> lonlat translation functions on tl and br 
-     *     corners of viewport
+     * APIMethod: POST
+     * Send a POST request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to POST and "Content-Type" header set to "application/xml".
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.  The
+     *     default "Content-Type" header will be set to "application-xml" if
+     *     none is provided.  This object is modified and should not be reused.
      * 
      * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
-     *                       bounds of the current viewPort.
+     * {XMLHttpRequest} Request object.
      */
-    getExtent: function () {
-        var size = this.map.getSize();
-        var tl = this.getLonLatFromViewPortPx({
-            x: 0, y: 0
-        });
-        var br = this.getLonLatFromViewPortPx({
-            x: size.w, y: size.h
-        });
-        
-        if ((tl != null) && (br != null)) {
-            return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat);
-        } else {
-            return null;
+    POST: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "POST"});
+        // set content type to application/xml if it isn't already set
+        config.headers = config.headers ? config.headers : {};
+        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+            config.headers["Content-Type"] = "application/xml";
         }
+        return OpenLayers.Request.issue(config);
     },
-
+    
     /**
-     * Method: getZoomForResolution
-     * Get the zoom level for a given resolution
+     * APIMethod: PUT
+     * Send an HTTP PUT request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to PUT and "Content-Type" header set to "application/xml".
      *
      * Parameters:
-     * resolution - {Float}
-     *
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.  The
+     *     default "Content-Type" header will be set to "application-xml" if
+     *     none is provided.  This object is modified and should not be reused.
+     * 
      * Returns:
-     * {Integer} A suitable zoom level for the specified resolution.
-     *           If no baselayer is set, returns null.
+     * {XMLHttpRequest} Request object.
      */
-    getZoomForResolution: function(resolution) {
-      
-        if (this.resolutions != null) {
-            return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
-        } else {
-            var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
-            return this.getZoomForExtent(extent);
+    PUT: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "PUT"});
+        // set content type to application/xml if it isn't already set
+        config.headers = config.headers ? config.headers : {};
+        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+            config.headers["Content-Type"] = "application/xml";
         }
+        return OpenLayers.Request.issue(config);
     },
-
-
-
-    
-    /********************************************************/
-    /*                                                      */
-    /*             Translation Functions                    */
-    /*                                                      */
-    /*    The following functions translate GMaps and OL    */ 
-    /*     formats for Pixel, LonLat, Bounds, and Zoom      */
-    /*                                                      */
-    /********************************************************/
-    
     
-    //
-    // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
-    //
+    /**
+     * APIMethod: DELETE
+     * Send an HTTP DELETE request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to DELETE.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    DELETE: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "DELETE"});
+        return OpenLayers.Request.issue(config);
+    },
   
     /**
-     * Method: getOLZoomFromMapObjectZoom
-     * Get the OL zoom index from the map object zoom level
+     * APIMethod: HEAD
+     * Send an HTTP HEAD request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to HEAD.
      *
      * Parameters:
-     * moZoom - {Integer}
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
      * 
      * Returns:
-     * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
-     *           Returns null if null value is passed in
+     * {XMLHttpRequest} Request object.
      */
-    getOLZoomFromMapObjectZoom: function(moZoom) {
-        var zoom = null;
-        if (moZoom != null) {
-            zoom = moZoom - this.minZoomLevel;
-            if (this.map.baseLayer !== this) {
-                zoom = this.map.baseLayer.getZoomForResolution(
-                    this.getResolutionForZoom(zoom)
-                );
-            }
-        }
-        return zoom;
+    HEAD: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "HEAD"});
+        return OpenLayers.Request.issue(config);
     },
     
     /**
-     * Method: getMapObjectZoomFromOLZoom
-     * Get the map object zoom level from the OL zoom level
+     * APIMethod: OPTIONS
+     * Send an HTTP OPTIONS request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to OPTIONS.
      *
      * Parameters:
-     * olZoom - {Integer}
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
      * 
      * Returns:
-     * {Integer} A MapObject level, translated from the passed in olZoom
-     *           Returns null if null value is passed in
+     * {XMLHttpRequest} Request object.
      */
-    getMapObjectZoomFromOLZoom: function(olZoom) {
-        var zoom = null; 
-        if (olZoom != null) {
-            zoom = olZoom + this.minZoomLevel;
-            if (this.map.baseLayer !== this) {
-                zoom = this.getZoomForResolution(
-                    this.map.baseLayer.getResolutionForZoom(zoom)
-                );
-            }
-        }
-        return zoom;
-    },
+    OPTIONS: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
+        return OpenLayers.Request.issue(config);
+    }
 
-    CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
 });
-
 /* ======================================================================
-    OpenLayers/Layer/Google.js
+    OpenLayers/Request/XMLHttpRequest.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
+// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 /**
- * @requires OpenLayers/Layer/SphericalMercator.js
- * @requires OpenLayers/Layer/EventPane.js
- * @requires OpenLayers/Layer/FixedZoomLevels.js
- * @requires OpenLayers/Lang.js
+ * @requires OpenLayers/Request.js
  */
 
-/**
- * Class: OpenLayers.Layer.Google
- * 
- * Provides a wrapper for Google's Maps API
- * Normally the Terms of Use for this API do not allow wrapping, but Google
- * have provided written consent to OpenLayers for this - see email in 
- * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html
- * 
- * Inherits from:
- *  - <OpenLayers.Layer.SphericalMercator>
- *  - <OpenLayers.Layer.EventPane>
- *  - <OpenLayers.Layer.FixedZoomLevels>
- */
-OpenLayers.Layer.Google = OpenLayers.Class(
-    OpenLayers.Layer.EventPane, 
-    OpenLayers.Layer.FixedZoomLevels, {
-    
-    /** 
-     * Constant: MIN_ZOOM_LEVEL
-     * {Integer} 0 
-     */
-    MIN_ZOOM_LEVEL: 0,
-    
-    /** 
-     * Constant: MAX_ZOOM_LEVEL
-     * {Integer} 21
-     */
-    MAX_ZOOM_LEVEL: 21,
+(function () {
 
-    /** 
-     * Constant: RESOLUTIONS
-     * {Array(Float)} Hardcode these resolutions so that they are more closely
-     *                tied with the standard wms projection
-     */
-    RESOLUTIONS: [
-        1.40625, 
-        0.703125, 
-        0.3515625, 
-        0.17578125, 
-        0.087890625, 
-        0.0439453125,
-        0.02197265625, 
-        0.010986328125, 
-        0.0054931640625, 
-        0.00274658203125,
-        0.001373291015625, 
-        0.0006866455078125, 
-        0.00034332275390625,
-        0.000171661376953125, 
-        0.0000858306884765625, 
-        0.00004291534423828125,
-        0.00002145767211914062, 
-        0.00001072883605957031,
-        0.00000536441802978515, 
-        0.00000268220901489257,
-        0.0000013411045074462891,
-        0.00000067055225372314453
-    ],
+    // Save reference to earlier defined object implementation (if any)
+    var oXMLHttpRequest    = window.XMLHttpRequest;
 
-    /**
-     * APIProperty: type
-     * {GMapType}
-     */
-    type: null,
+    // Define on browser type
+    var bGecko    = !!window.controllers,
+        bIE        = window.document.all && !window.opera,
+        bIE7    = bIE && window.navigator.userAgent.match(/MSIE 7.0/);
 
-    /**
-     * APIProperty: wrapDateLine
-     * {Boolean} Allow user to pan forever east/west.  Default is true.  
-     *     Setting this to false only restricts panning if 
-     *     <sphericalMercator> is true. 
-     */
-    wrapDateLine: true,
+    // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()"
+    function fXMLHttpRequest() {
+        this._object    = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
+        this._listeners    = [];
+    };
 
-    /**
-     * APIProperty: sphericalMercator
-     * {Boolean} Should the map act as a mercator-projected map? This will
-     *     cause all interactions with the map to be in the actual map 
-     *     projection, which allows support for vector drawing, overlaying 
-     *     other maps, etc. 
-     */
-    sphericalMercator: false, 
-    
-    /**
-     * Property: version
-     * {Number} The version of the Google Maps API
-     */
-    version: null,
+    // Constructor
+    function cXMLHttpRequest() {
+        return new fXMLHttpRequest;
+    };
+    cXMLHttpRequest.prototype    = fXMLHttpRequest.prototype;
 
-    /** 
-     * Constructor: OpenLayers.Layer.Google
-     * 
-     * Parameters:
-     * name - {String} A name for the layer.
-     * options - {Object} An optional object whose properties will be set
-     *     on the layer.
-     */
-    initialize: function(name, options) {
-        options = options || {};
-        if(!options.version) {
-            options.version = typeof GMap2 === "function" ? "2" : "3";
-        }
-        var mixin = OpenLayers.Layer.Google["v" +
-            options.version.replace(/\./g, "_")];
-        if (mixin) {
-            OpenLayers.Util.applyDefaults(options, mixin);
-        } else {
-            throw "Unsupported Google Maps API version: " + options.version;
-        }
+    // BUGFIX: Firefox with Firebug installed would break pages if not executed
+    if (bGecko && oXMLHttpRequest.wrapped)
+        cXMLHttpRequest.wrapped    = oXMLHttpRequest.wrapped;
 
-        OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS);
-        if (options.maxExtent) {
-            options.maxExtent = options.maxExtent.clone();
-        }
+    // Constants
+    cXMLHttpRequest.UNSENT                = 0;
+    cXMLHttpRequest.OPENED                = 1;
+    cXMLHttpRequest.HEADERS_RECEIVED    = 2;
+    cXMLHttpRequest.LOADING                = 3;
+    cXMLHttpRequest.DONE                = 4;
 
-        OpenLayers.Layer.EventPane.prototype.initialize.apply(this,
-            [name, options]);
-        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
-            [name, options]);
+    // Public Properties
+    cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
+    cXMLHttpRequest.prototype.responseText    = '';
+    cXMLHttpRequest.prototype.responseXML    = null;
+    cXMLHttpRequest.prototype.status        = 0;
+    cXMLHttpRequest.prototype.statusText    = '';
 
-        if (this.sphericalMercator) {
-            OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
-            this.initMercatorParameters();
-        }    
-    },
+    // Priority proposal
+    cXMLHttpRequest.prototype.priority        = "NORMAL";
 
-    /**
-     * Method: clone
-     * Create a clone of this layer
-     *
-     * Returns:
-     * {<OpenLayers.Layer.Google>} An exact clone of this layer
-     */
-    clone: function() {
-        /**
-         * This method isn't intended to be called by a subclass and it
-         * doesn't call the same method on the superclass.  We don't call
-         * the super's clone because we don't want properties that are set
-         * on this layer after initialize (i.e. this.mapObject etc.).
-         */
-        return new OpenLayers.Layer.Google(
-            this.name, this.getOptions()
-        );
-    },
+    // Instance-level Events Handlers
+    cXMLHttpRequest.prototype.onreadystatechange    = null;
 
-    /**
-     * APIMethod: setVisibility
-     * Set the visibility flag for the layer and hide/show & redraw 
-     *     accordingly. Fire event unless otherwise specified
-     * 
-     * Note that visibility is no longer simply whether or not the layer's
-     *     style.display is set to "block". Now we store a 'visibility' state 
-     *     property on the layer class, this allows us to remember whether or 
-     *     not we *desire* for a layer to be visible. In the case where the 
-     *     map's resolution is out of the layer's range, this desire may be 
-     *     subverted.
-     * 
-     * Parameters:
-     * visible - {Boolean} Display the layer (if in range)
-     */
-    setVisibility: function(visible) {
-        // sharing a map container, opacity has to be set per layer
-        var opacity = this.opacity == null ? 1 : this.opacity;
-        OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments);
-        this.setOpacity(opacity);
-    },
-    
-    /** 
-     * APIMethod: display
-     * Hide or show the Layer
-     * 
-     * Parameters:
-     * visible - {Boolean}
-     */
-    display: function(visible) {
-        if (!this._dragging) {
-            this.setGMapVisibility(visible);
-        }
-        OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
-    },
-    
-    /**
-     * Method: moveTo
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
-     *     do some init work in that case.
-     * dragging - {Boolean}
-     */
-    moveTo: function(bounds, zoomChanged, dragging) {
-        this._dragging = dragging;
-        OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments);
-        delete this._dragging;
-    },
-    
-    /**
-     * APIMethod: setOpacity
-     * Sets the opacity for the entire layer (all images)
-     * 
-     * Parameters:
-     * opacity - {Float}
-     */
-    setOpacity: function(opacity) {
-        if (opacity !== this.opacity) {
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer", {
-                    layer: this,
-                    property: "opacity"
-                });
-            }
-            this.opacity = opacity;
-        }
-        // Though this layer's opacity may not change, we're sharing a container
-        // and need to update the opacity for the entire container.
-        if (this.getVisibility()) {
-            var container = this.getMapContainer();
-            OpenLayers.Util.modifyDOMElement(
-                container, null, null, null, null, null, null, opacity
-            );
-        }
-    },
+    // Class-level Events Handlers
+    cXMLHttpRequest.onreadystatechange    = null;
+    cXMLHttpRequest.onopen                = null;
+    cXMLHttpRequest.onsend                = null;
+    cXMLHttpRequest.onabort                = null;
 
-    /**
-     * APIMethod: destroy
-     * Clean up this layer.
-     */
-    destroy: function() {
-        /**
-         * We have to override this method because the event pane destroy
-         * deletes the mapObject reference before removing this layer from
-         * the map.
-         */
-        if (this.map) {
-            this.setGMapVisibility(false);
-            var cache = OpenLayers.Layer.Google.cache[this.map.id];
-            if (cache && cache.count <= 1) {
-                this.removeGMapElements();
-            }            
-        }
-        OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments);
-    },
-    
-    /**
-     * Method: removeGMapElements
-     * Remove all elements added to the dom.  This should only be called if
-     * this is the last of the Google layers for the given map.
-     */
-    removeGMapElements: function() {
-        var cache = OpenLayers.Layer.Google.cache[this.map.id];
-        if (cache) {
-            // remove shared elements from dom
-            var container = this.mapObject && this.getMapContainer();                
-            if (container && container.parentNode) {
-                container.parentNode.removeChild(container);
-            }
-            var termsOfUse = cache.termsOfUse;
-            if (termsOfUse && termsOfUse.parentNode) {
-                termsOfUse.parentNode.removeChild(termsOfUse);
-            }
-            var poweredBy = cache.poweredBy;
-            if (poweredBy && poweredBy.parentNode) {
-                poweredBy.parentNode.removeChild(poweredBy);
-            }
-            if (this.mapObject && window.google && google.maps &&
-                    google.maps.event && google.maps.event.clearListeners) {
-                google.maps.event.clearListeners(this.mapObject, 'tilesloaded');
-            }
-        }
-    },
+    // Public Methods
+    cXMLHttpRequest.prototype.open    = function(sMethod, sUrl, bAsync, sUser, sPassword) {
+        // Delete headers, required when object is reused
+        delete this._headers;
 
-    /**
-     * APIMethod: removeMap
-     * On being removed from the map, also remove termsOfUse and poweredBy divs
-     * 
-     * Parameters:
-     * map - {<OpenLayers.Map>}
-     */
-    removeMap: function(map) {
-        // hide layer before removing
-        if (this.visibility && this.mapObject) {
-            this.setGMapVisibility(false);
-        }
-        // check to see if last Google layer in this map
-        var cache = OpenLayers.Layer.Google.cache[map.id];
-        if (cache) {
-            if (cache.count <= 1) {
-                this.removeGMapElements();
-                delete OpenLayers.Layer.Google.cache[map.id];
-            } else {
-                // decrement the layer count
-                --cache.count;
-            }
-        }
-        // remove references to gmap elements
-        delete this.termsOfUse;
-        delete this.poweredBy;
-        delete this.mapObject;
-        delete this.dragObject;
-        OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
-    },
-    
-  //
-  // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
-  //
+        // When bAsync parameter value is omitted, use true as default
+        if (arguments.length < 3)
+            bAsync    = true;
 
-    /**
-     * APIMethod: getOLBoundsFromMapObjectBounds
-     * 
-     * Parameters:
-     * moBounds - {Object}
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the 
-     *                       passed-in MapObject Bounds.
-     *                       Returns null if null value is passed in.
-     */
-    getOLBoundsFromMapObjectBounds: function(moBounds) {
-        var olBounds = null;
-        if (moBounds != null) {
-            var sw = moBounds.getSouthWest();
-            var ne = moBounds.getNorthEast();
-            if (this.sphericalMercator) {
-                sw = this.forwardMercator(sw.lng(), sw.lat());
-                ne = this.forwardMercator(ne.lng(), ne.lat());
-            } else {
-                sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); 
-                ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); 
-            }    
-            olBounds = new OpenLayers.Bounds(sw.lon, 
-                                             sw.lat, 
-                                             ne.lon, 
-                                             ne.lat );
-        }
-        return olBounds;
-    },
+        // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
+        this._async        = bAsync;
 
-    /** 
-     * APIMethod: getWarningHTML
-     * 
-     * Returns: 
-     * {String} String with information on why layer is broken, how to get
-     *          it working.
-     */
-    getWarningHTML:function() {
-        return OpenLayers.i18n("googleWarning");
-    },
+        // Set the onreadystatechange handler
+        var oRequest    = this,
+            nState        = this.readyState,
+            fOnUnload;
 
+        // BUGFIX: IE - memory leak on page unload (inter-page leak)
+        if (bIE && bAsync) {
+            fOnUnload = function() {
+                if (nState != cXMLHttpRequest.DONE) {
+                    fCleanTransport(oRequest);
+                    // Safe to abort here since onreadystatechange handler removed
+                    oRequest.abort();
+                }
+            };
+            window.attachEvent("onunload", fOnUnload);
+        }
 
-    /************************************
-     *                                  *
-     *   MapObject Interface Controls   *
-     *                                  *
-     ************************************/
+        // Add method sniffer
+        if (cXMLHttpRequest.onopen)
+            cXMLHttpRequest.onopen.apply(this, arguments);
 
+        if (arguments.length > 4)
+            this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+        else
+        if (arguments.length > 3)
+            this._object.open(sMethod, sUrl, bAsync, sUser);
+        else
+            this._object.open(sMethod, sUrl, bAsync);
 
-  // Get&Set Center, Zoom
+        this.readyState    = cXMLHttpRequest.OPENED;
+        fReadyStateChange(this);
 
-    /**
-     * APIMethod: getMapObjectCenter
-     * 
-     * Returns: 
-     * {Object} The mapObject's current center in Map Object format
-     */
-    getMapObjectCenter: function() {
-        return this.mapObject.getCenter();
-    },
+        this._object.onreadystatechange    = function() {
+            if (bGecko && !bAsync)
+                return;
 
-    /** 
-     * APIMethod: getMapObjectZoom
-     * 
-     * Returns:
-     * {Integer} The mapObject's current zoom, in Map Object format
-     */
-    getMapObjectZoom: function() {
-        return this.mapObject.getZoom();
-    },
+            // Synchronize state
+            oRequest.readyState        = oRequest._object.readyState;
 
-  
-    /************************************
-     *                                  *
-     *       MapObject Primitives       *
-     *                                  *
-     ************************************/
+            //
+            fSynchronizeValues(oRequest);
 
+            // BUGFIX: Firefox fires unnecessary DONE when aborting
+            if (oRequest._aborted) {
+                // Reset readyState to UNSENT
+                oRequest.readyState    = cXMLHttpRequest.UNSENT;
 
-  // LonLat
-    
-    /**
-     * APIMethod: getLongitudeFromMapObjectLonLat
-     * 
-     * Parameters:
-     * moLonLat - {Object} MapObject LonLat format
-     * 
-     * Returns:
-     * {Float} Longitude of the given MapObject LonLat
-     */
-    getLongitudeFromMapObjectLonLat: function(moLonLat) {
-        return this.sphericalMercator ? 
-          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
-          moLonLat.lng();  
-    },
+                // Return now
+                return;
+            }
 
-    /**
-     * APIMethod: getLatitudeFromMapObjectLonLat
-     * 
-     * Parameters:
-     * moLonLat - {Object} MapObject LonLat format
-     * 
-     * Returns:
-     * {Float} Latitude of the given MapObject LonLat
-     */
-    getLatitudeFromMapObjectLonLat: function(moLonLat) {
-        var lat = this.sphericalMercator ? 
-          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
-          moLonLat.lat(); 
-        return lat;  
-    },
-    
-  // Pixel
-    
-    /**
-     * APIMethod: getXFromMapObjectPixel
-     * 
-     * Parameters:
-     * moPixel - {Object} MapObject Pixel format
-     * 
-     * Returns:
-     * {Integer} X value of the MapObject Pixel
-     */
-    getXFromMapObjectPixel: function(moPixel) {
-        return moPixel.x;
-    },
+            if (oRequest.readyState == cXMLHttpRequest.DONE) {
+                // Free up queue
+                delete oRequest._data;
+/*                if (bAsync)
+                    fQueue_remove(oRequest);*/
+                //
+                fCleanTransport(oRequest);
+// Uncomment this block if you need a fix for IE cache
+/*
+                // BUGFIX: IE - cache issue
+                if (!oRequest._object.getResponseHeader("Date")) {
+                    // Save object to cache
+                    oRequest._cached    = oRequest._object;
 
-    /**
-     * APIMethod: getYFromMapObjectPixel
-     * 
-     * Parameters:
-     * moPixel - {Object} MapObject Pixel format
-     * 
-     * Returns:
-     * {Integer} Y value of the MapObject Pixel
-     */
-    getYFromMapObjectPixel: function(moPixel) {
-        return moPixel.y;
-    },
-    
-    CLASS_NAME: "OpenLayers.Layer.Google"
-});
+                    // Instantiate a new transport object
+                    cXMLHttpRequest.call(oRequest);
 
-/**
- * Property: OpenLayers.Layer.Google.cache
- * {Object} Cache for elements that should only be created once per map.
- */
-OpenLayers.Layer.Google.cache = {};
+                    // Re-send request
+                    if (sUser) {
+                         if (sPassword)
+                            oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+                        else
+                            oRequest._object.open(sMethod, sUrl, bAsync, sUser);
+                    }
+                    else
+                        oRequest._object.open(sMethod, sUrl, bAsync);
+                    oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
+                    // Copy headers set
+                    if (oRequest._headers)
+                        for (var sHeader in oRequest._headers)
+                            if (typeof oRequest._headers[sHeader] == "string")    // Some frameworks prototype objects with functions
+                                oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
 
+                    oRequest._object.onreadystatechange    = function() {
+                        // Synchronize state
+                        oRequest.readyState        = oRequest._object.readyState;
 
-/**
- * Constant: OpenLayers.Layer.Google.v2
- * 
- * Mixin providing functionality specific to the Google Maps API v2.
- * 
- * This API has been deprecated by Google.
- * Developers are encouraged to migrate to v3 of the API; support for this
- * is provided by <OpenLayers.Layer.Google.v3>
- */
-OpenLayers.Layer.Google.v2 = {
-    
-    /**
-     * Property: termsOfUse
-     * {DOMElement} Div for Google's copyright and terms of use link
-     */
-    termsOfUse: null, 
+                        if (oRequest._aborted) {
+                            //
+                            oRequest.readyState    = cXMLHttpRequest.UNSENT;
 
-    /**
-     * Property: poweredBy
-     * {DOMElement} Div for Google's powered by logo and link
-     */
-    poweredBy: null, 
+                            // Return
+                            return;
+                        }
 
-    /**
-     * Property: dragObject
-     * {GDraggableObject} Since 2.93, Google has exposed the ability to get
-     *     the maps GDraggableObject. We can now use this for smooth panning
-     */
-    dragObject: null, 
-    
-    /** 
-     * Method: loadMapObject
-     * Load the GMap and register appropriate event listeners. If we can't 
-     *     load GMap2, then display a warning message.
-     */
-    loadMapObject:function() {
-        if (!this.type) {
-            this.type = G_NORMAL_MAP;
-        }
-        var mapObject, termsOfUse, poweredBy;
-        var cache = OpenLayers.Layer.Google.cache[this.map.id];
-        if (cache) {
-            // there are already Google layers added to this map
-            mapObject = cache.mapObject;
-            termsOfUse = cache.termsOfUse;
-            poweredBy = cache.poweredBy;
-            // increment the layer count
-            ++cache.count;
-        } else {
-            // this is the first Google layer for this map
+                        if (oRequest.readyState == cXMLHttpRequest.DONE) {
+                            // Clean Object
+                            fCleanTransport(oRequest);
 
-            var container = this.map.viewPortDiv;
-            var div = document.createElement("div");
-            div.id = this.map.id + "_GMap2Container";
-            div.style.position = "absolute";
-            div.style.width = "100%";
-            div.style.height = "100%";
-            container.appendChild(div);
+                            // get cached request
+                            if (oRequest.status == 304)
+                                oRequest._object    = oRequest._cached;
 
-            // create GMap and shuffle elements
-            try {
-                mapObject = new GMap2(div);
-                
-                // move the ToS and branding stuff up to the container div
-                termsOfUse = div.lastChild;
-                container.appendChild(termsOfUse);
-                termsOfUse.style.zIndex = "1100";
-                termsOfUse.style.right = "";
-                termsOfUse.style.bottom = "";
-                termsOfUse.className = "olLayerGoogleCopyright";
-
-                poweredBy = div.lastChild;
-                container.appendChild(poweredBy);
-                poweredBy.style.zIndex = "1100";
-                poweredBy.style.right = "";
-                poweredBy.style.bottom = "";
-                poweredBy.className = "olLayerGooglePoweredBy gmnoprint";
-                
-            } catch (e) {
-                throw(e);
-            }
-            // cache elements for use by any other google layers added to
-            // this same map
-            OpenLayers.Layer.Google.cache[this.map.id] = {
-                mapObject: mapObject,
-                termsOfUse: termsOfUse,
-                poweredBy: poweredBy,
-                count: 1
-            };
-        }
+                            //
+                            delete oRequest._cached;
 
-        this.mapObject = mapObject;
-        this.termsOfUse = termsOfUse;
-        this.poweredBy = poweredBy;
-        
-        // ensure this layer type is one of the mapObject types
-        if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
-                                    this.type) === -1) {
-            this.mapObject.addMapType(this.type);
-        }
+                            //
+                            fSynchronizeValues(oRequest);
 
-        //since v 2.93 getDragObject is now available.
-        if(typeof mapObject.getDragObject == "function") {
-            this.dragObject = mapObject.getDragObject();
-        } else {
-            this.dragPanMapObject = null;
-        }
-        
-        if(this.isBaseLayer === false) {
-            this.setGMapVisibility(this.div.style.display !== "none");
-        }
+                            //
+                            fReadyStateChange(oRequest);
 
-    },
+                            // BUGFIX: IE - memory leak in interrupted
+                            if (bIE && bAsync)
+                                window.detachEvent("onunload", fOnUnload);
+                        }
+                    };
+                    oRequest._object.send(null);
 
-    /**
-     * APIMethod: onMapResize
-     */
-    onMapResize: function() {
-        // workaround for resizing of invisible or not yet fully loaded layers
-        // where GMap2.checkResize() does not work. We need to load the GMap
-        // for the old div size, then checkResize(), and then call
-        // layer.moveTo() to trigger GMap.setCenter() (which will finish
-        // the GMap initialization).
-        if(this.visibility && this.mapObject.isLoaded()) {
-            this.mapObject.checkResize();
-        } else {
-            if(!this._resized) {
-                var layer = this;
-                var handle = GEvent.addListener(this.mapObject, "load", function() {
-                    GEvent.removeListener(handle);
-                    delete layer._resized;
-                    layer.mapObject.checkResize();
-                    layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
-                });
+                    // Return now - wait until re-sent request is finished
+                    return;
+                };
+*/
+                // BUGFIX: IE - memory leak in interrupted
+                if (bIE && bAsync)
+                    window.detachEvent("onunload", fOnUnload);
             }
-            this._resized = true;
+
+            // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
+            if (nState != oRequest.readyState)
+                fReadyStateChange(oRequest);
+
+            nState    = oRequest.readyState;
         }
-    },
+    };
+    function fXMLHttpRequest_send(oRequest) {
+        oRequest._object.send(oRequest._data);
 
-    /**
-     * Method: setGMapVisibility
-     * Display the GMap container and associated elements.
-     * 
-     * Parameters:
-     * visible - {Boolean} Display the GMap elements.
-     */
-    setGMapVisibility: function(visible) {
-        var cache = OpenLayers.Layer.Google.cache[this.map.id];
-        if (cache) {
-            var container = this.mapObject.getContainer();
-            if (visible === true) {
-                this.mapObject.setMapType(this.type);
-                container.style.display = "";
-                this.termsOfUse.style.left = "";
-                this.termsOfUse.style.display = "";
-                this.poweredBy.style.display = "";            
-                cache.displayed = this.id;
-            } else {
-                if (cache.displayed === this.id) {
-                    delete cache.displayed;
-                }
-                if (!cache.displayed) {
-                    container.style.display = "none";
-                    this.termsOfUse.style.display = "none";
-                    // move ToU far to the left in addition to setting display
-                    // to "none", because at the end of the GMap2 load
-                    // sequence, display: none will be unset and ToU would be
-                    // visible after loading a map with a google layer that is
-                    // initially hidden. 
-                    this.termsOfUse.style.left = "-9999px";
-                    this.poweredBy.style.display = "none";
-                }
+        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+        if (bGecko && !oRequest._async) {
+            oRequest.readyState    = cXMLHttpRequest.OPENED;
+
+            // Synchronize state
+            fSynchronizeValues(oRequest);
+
+            // Simulate missing states
+            while (oRequest.readyState < cXMLHttpRequest.DONE) {
+                oRequest.readyState++;
+                fReadyStateChange(oRequest);
+                // Check if we are aborted
+                if (oRequest._aborted)
+                    return;
             }
         }
-    },
-    
-    /**
-     * Method: getMapContainer
-     * 
-     * Returns:
-     * {DOMElement} the GMap container's div
-     */
-    getMapContainer: function() {
-        return this.mapObject.getContainer();
-    },
+    };
+    cXMLHttpRequest.prototype.send    = function(vData) {
+        // Add method sniffer
+        if (cXMLHttpRequest.onsend)
+            cXMLHttpRequest.onsend.apply(this, arguments);
 
-  //
-  // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
-  //
+        if (!arguments.length)
+            vData    = null;
 
-    /**
-     * APIMethod: getMapObjectBoundsFromOLBounds
-     * 
-     * Parameters:
-     * olBounds - {<OpenLayers.Bounds>}
-     * 
-     * Returns:
-     * {Object} A MapObject Bounds, translated from olBounds
-     *          Returns null if null value is passed in
-     */
-    getMapObjectBoundsFromOLBounds: function(olBounds) {
-        var moBounds = null;
-        if (olBounds != null) {
-            var sw = this.sphericalMercator ? 
-              this.inverseMercator(olBounds.bottom, olBounds.left) : 
-              new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
-            var ne = this.sphericalMercator ? 
-              this.inverseMercator(olBounds.top, olBounds.right) : 
-              new OpenLayers.LonLat(olBounds.top, olBounds.right);
-            moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon),
-                                         new GLatLng(ne.lat, ne.lon));
+        // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
+        // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
+        // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
+        if (vData && vData.nodeType) {
+            vData    = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
+            if (!this._headers["Content-Type"])
+                this._object.setRequestHeader("Content-Type", "application/xml");
         }
-        return moBounds;
-    },
 
+        this._data    = vData;
+/*
+        // Add to queue
+        if (this._async)
+            fQueue_add(this);
+        else*/
+            fXMLHttpRequest_send(this);
+    };
+    cXMLHttpRequest.prototype.abort    = function() {
+        // Add method sniffer
+        if (cXMLHttpRequest.onabort)
+            cXMLHttpRequest.onabort.apply(this, arguments);
 
-    /************************************
-     *                                  *
-     *   MapObject Interface Controls   *
-     *                                  *
-     ************************************/
+        // BUGFIX: Gecko - unnecessary DONE when aborting
+        if (this.readyState > cXMLHttpRequest.UNSENT)
+            this._aborted    = true;
 
+        this._object.abort();
 
-  // Get&Set Center, Zoom
+        // BUGFIX: IE - memory leak
+        fCleanTransport(this);
 
-    /** 
-     * APIMethod: setMapObjectCenter
-     * Set the mapObject to the specified center and zoom
-     * 
-     * Parameters:
-     * center - {Object} MapObject LonLat format
-     * zoom - {int} MapObject zoom format
-     */
-    setMapObjectCenter: function(center, zoom) {
-        this.mapObject.setCenter(center, zoom); 
-    },
-   
-    /**
-     * APIMethod: dragPanMapObject
-     * 
-     * Parameters:
-     * dX - {Integer}
-     * dY - {Integer}
-     */
-    dragPanMapObject: function(dX, dY) {
-        this.dragObject.moveBy(new GSize(-dX, dY));
-    },
+        this.readyState    = cXMLHttpRequest.UNSENT;
 
+        delete this._data;
+/*        if (this._async)
+            fQueue_remove(this);*/
+    };
+    cXMLHttpRequest.prototype.getAllResponseHeaders    = function() {
+        return this._object.getAllResponseHeaders();
+    };
+    cXMLHttpRequest.prototype.getResponseHeader    = function(sName) {
+        return this._object.getResponseHeader(sName);
+    };
+    cXMLHttpRequest.prototype.setRequestHeader    = function(sName, sValue) {
+        // BUGFIX: IE - cache issue
+        if (!this._headers)
+            this._headers    = {};
+        this._headers[sName]    = sValue;
 
-  // LonLat - Pixel Translation
-  
-    /**
-     * APIMethod: getMapObjectLonLatFromMapObjectPixel
-     * 
-     * Parameters:
-     * moPixel - {Object} MapObject Pixel format
-     * 
-     * Returns:
-     * {Object} MapObject LonLat translated from MapObject Pixel
-     */
-    getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
-        return this.mapObject.fromContainerPixelToLatLng(moPixel);
-    },
+        return this._object.setRequestHeader(sName, sValue);
+    };
 
-    /**
-     * APIMethod: getMapObjectPixelFromMapObjectLonLat
-     * 
-     * Parameters:
-     * moLonLat - {Object} MapObject LonLat format
-     * 
-     * Returns:
-     * {Object} MapObject Pixel transtlated from MapObject LonLat
-     */
-    getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
-        return this.mapObject.fromLatLngToContainerPixel(moLonLat);
-    },
+    // EventTarget interface implementation
+    cXMLHttpRequest.prototype.addEventListener    = function(sName, fHandler, bUseCapture) {
+        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
+                return;
+        // Add listener
+        this._listeners.push([sName, fHandler, bUseCapture]);
+    };
 
-  
-  // Bounds
-  
-    /** 
-     * APIMethod: getMapObjectZoomFromMapObjectBounds
-     * 
-     * Parameters:
-     * moBounds - {Object} MapObject Bounds format
-     * 
-     * Returns:
-     * {Object} MapObject Zoom for specified MapObject Bounds
-     */
-    getMapObjectZoomFromMapObjectBounds: function(moBounds) {
-        return this.mapObject.getBoundsZoomLevel(moBounds);
-    },
+    cXMLHttpRequest.prototype.removeEventListener    = function(sName, fHandler, bUseCapture) {
+        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
+                break;
+        // Remove listener
+        if (oListener)
+            this._listeners.splice(nIndex, 1);
+    };
 
-    /************************************
-     *                                  *
-     *       MapObject Primitives       *
-     *                                  *
-     ************************************/
+    cXMLHttpRequest.prototype.dispatchEvent    = function(oEvent) {
+        var oEventPseudo    = {
+            'type':            oEvent.type,
+            'target':        this,
+            'currentTarget':this,
+            'eventPhase':    2,
+            'bubbles':        oEvent.bubbles,
+            'cancelable':    oEvent.cancelable,
+            'timeStamp':    oEvent.timeStamp,
+            'stopPropagation':    function() {},    // There is no flow
+            'preventDefault':    function() {},    // There is no default action
+            'initEvent':        function() {}    // Original event object should be initialized
+        };
 
+        // Execute onreadystatechange
+        if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)
+            (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
 
-  // LonLat
-    
-    /**
-     * APIMethod: getMapObjectLonLatFromLonLat
-     * 
-     * Parameters:
-     * lon - {Float}
-     * lat - {Float}
-     * 
-     * Returns:
-     * {Object} MapObject LonLat built from lon and lat params
-     */
-    getMapObjectLonLatFromLonLat: function(lon, lat) {
-        var gLatLng;
-        if(this.sphericalMercator) {
-            var lonlat = this.inverseMercator(lon, lat);
-            gLatLng = new GLatLng(lonlat.lat, lonlat.lon);
-        } else {
-            gLatLng = new GLatLng(lat, lon);
+        // Execute listeners
+        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+            if (oListener[0] == oEventPseudo.type && !oListener[2])
+                (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
+    };
+
+    //
+    cXMLHttpRequest.prototype.toString    = function() {
+        return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
+    };
+
+    cXMLHttpRequest.toString    = function() {
+        return '[' + "XMLHttpRequest" + ']';
+    };
+
+    // Helper function
+    function fReadyStateChange(oRequest) {
+        // Sniffing code
+        if (cXMLHttpRequest.onreadystatechange)
+            cXMLHttpRequest.onreadystatechange.apply(oRequest);
+
+        // Fake event
+        oRequest.dispatchEvent({
+            'type':            "readystatechange",
+            'bubbles':        false,
+            'cancelable':    false,
+            'timeStamp':    new Date + 0
+        });
+    };
+
+    function fGetDocument(oRequest) {
+        var oDocument    = oRequest.responseXML,
+            sResponse    = oRequest.responseText;
+        // Try parsing responseText
+        if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
+            oDocument    = new window.ActiveXObject("Microsoft.XMLDOM");
+            oDocument.async                = false;
+            oDocument.validateOnParse    = false;
+            oDocument.loadXML(sResponse);
         }
-        return gLatLng;
-    },
+        // Check if there is no error in document
+        if (oDocument)
+            if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
+                return null;
+        return oDocument;
+    };
 
-  // Pixel
-    
+    function fSynchronizeValues(oRequest) {
+        try {    oRequest.responseText    = oRequest._object.responseText;    } catch (e) {}
+        try {    oRequest.responseXML    = fGetDocument(oRequest._object);    } catch (e) {}
+        try {    oRequest.status            = oRequest._object.status;            } catch (e) {}
+        try {    oRequest.statusText        = oRequest._object.statusText;        } catch (e) {}
+    };
+
+    function fCleanTransport(oRequest) {
+        // BUGFIX: IE - memory leak (on-page leak)
+        oRequest._object.onreadystatechange    = new window.Function;
+    };
+/*
+    // Queue manager
+    var oQueuePending    = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]},
+        aQueueRunning    = [];
+    function fQueue_add(oRequest) {
+        oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest);
+        //
+        setTimeout(fQueue_process);
+    };
+
+    function fQueue_remove(oRequest) {
+        for (var nIndex = 0, bFound    = false; nIndex < aQueueRunning.length; nIndex++)
+            if (bFound)
+                aQueueRunning[nIndex - 1]    = aQueueRunning[nIndex];
+            else
+            if (aQueueRunning[nIndex] == oRequest)
+                bFound    = true;
+        if (bFound)
+            aQueueRunning.length--;
+        //
+        setTimeout(fQueue_process);
+    };
+
+    function fQueue_process() {
+        if (aQueueRunning.length < 6) {
+            for (var sPriority in oQueuePending) {
+                if (oQueuePending[sPriority].length) {
+                    var oRequest    = oQueuePending[sPriority][0];
+                    oQueuePending[sPriority]    = oQueuePending[sPriority].slice(1);
+                    //
+                    aQueueRunning.push(oRequest);
+                    // Send request
+                    fXMLHttpRequest_send(oRequest);
+                    break;
+                }
+            }
+        }
+    };
+*/
+    // Internet Explorer 5.0 (missing apply)
+    if (!window.Function.prototype.apply) {
+        window.Function.prototype.apply    = function(oRequest, oArguments) {
+            if (!oArguments)
+                oArguments    = [];
+            oRequest.__func    = this;
+            oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
+            delete oRequest.__func;
+        };
+    };
+
+    // Register new object with window
     /**
-     * APIMethod: getMapObjectPixelFromXY
-     * 
-     * Parameters:
-     * x - {Integer}
-     * y - {Integer}
-     * 
-     * Returns:
-     * {Object} MapObject Pixel from x and y parameters
+     * Class: OpenLayers.Request.XMLHttpRequest
+     * Standard-compliant (W3C) cross-browser implementation of the
+     *     XMLHttpRequest object.  From
+     *     http://code.google.com/p/xmlhttprequest/.
      */
-    getMapObjectPixelFromXY: function(x, y) {
-        return new GPoint(x, y);
+    if (!OpenLayers.Request) {
+        /**
+         * This allows for OpenLayers/Request.js to be included
+         * before or after this script.
+         */
+        OpenLayers.Request = {};
     }
-    
-};
+    OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
+})();
 /* ======================================================================
-    OpenLayers/Control.js
+    OpenLayers/Protocol.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
@@ -12704,424 +12498,263 @@ OpenLayers.Layer.Google.v2 = {
  */
 
 /**
- * Class: OpenLayers.Control
- * Controls affect the display or behavior of the map. They allow everything
- * from panning and zooming to displaying a scale indicator. Controls by 
- * default are added to the map they are contained within however it is
- * possible to add a control to an external div by passing the div in the
- * options parameter.
- * 
- * Example:
- * The following example shows how to add many of the common controls
- * to a map.
- * 
- * > var map = new OpenLayers.Map('map', { controls: [] });
- * >
- * > map.addControl(new OpenLayers.Control.PanZoomBar());
- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- * > map.addControl(new OpenLayers.Control.Permalink());
- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
- * > map.addControl(new OpenLayers.Control.MousePosition());
- * > map.addControl(new OpenLayers.Control.OverviewMap());
- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
- *
- * The next code fragment is a quick example of how to intercept 
- * shift-mouse click to display the extent of the bounding box
- * dragged out by the user.  Usually controls are not created
- * in exactly this manner.  See the source for a more complete 
- * example:
- *
- * > var control = new OpenLayers.Control();
- * > OpenLayers.Util.extend(control, {
- * >     draw: function () {
- * >         // this Handler.Box will intercept the shift-mousedown
- * >         // before Control.MouseDefault gets to see it
- * >         this.box = new OpenLayers.Handler.Box( control, 
- * >             {"done": this.notice},
- * >             {keyMask: OpenLayers.Handler.MOD_SHIFT});
- * >         this.box.activate();
- * >     },
- * >
- * >     notice: function (bounds) {
- * >         OpenLayers.Console.userError(bounds);
- * >     }
- * > }); 
- * > map.addControl(control);
- * 
+ * Class: OpenLayers.Protocol
+ * Abstract vector layer protocol class.  Not to be instantiated directly.  Use
+ *     one of the protocol subclasses instead.
  */
-OpenLayers.Control = OpenLayers.Class({
-
-    /** 
-     * Property: id 
-     * {String} 
-     */
-    id: null,
+OpenLayers.Protocol = OpenLayers.Class({
     
-    /** 
-     * Property: map 
-     * {<OpenLayers.Map>} this gets set in the addControl() function in
-     * OpenLayers.Map 
+    /**
+     * Property: format
+     * {<OpenLayers.Format>} The format used by this protocol.
      */
-    map: null,
-
-    /** 
-     * APIProperty: div 
-     * {DOMElement} The element that contains the control, if not present the 
-     *     control is placed inside the map.
-     */
-    div: null,
-
-    /** 
-     * APIProperty: type 
-     * {Number} Controls can have a 'type'. The type determines the type of
-     * interactions which are possible with them when they are placed in an
-     * <OpenLayers.Control.Panel>. 
-     */
-    type: null, 
-
-    /** 
-     * Property: allowSelection
-     * {Boolean} By default, controls do not allow selection, because
-     * it may interfere with map dragging. If this is true, OpenLayers
-     * will not prevent selection of the control.
-     * Default is false.
-     */
-    allowSelection: false,  
-
-    /** 
-     * Property: displayClass 
-     * {string}  This property is used for CSS related to the drawing of the
-     * Control. 
-     */
-    displayClass: "",
+    format: null,
     
     /**
-    * APIProperty: title  
-    * {string}  This property is used for showing a tooltip over the  
-    * Control.  
-    */ 
-    title: "",
-
-    /**
-     * APIProperty: autoActivate
-     * {Boolean} Activate the control when it is added to a map.  Default is
-     *     false.
-     */
-    autoActivate: false,
-
-    /** 
-     * APIProperty: active 
-     * {Boolean} The control is active (read-only).  Use <activate> and 
-     *     <deactivate> to change control state.
+     * Property: options
+     * {Object} Any options sent to the constructor.
      */
-    active: null,
+    options: null,
 
     /**
-     * Property: handlerOptions
-     * {Object} Used to set non-default properties on the control's handler
-     */
-    handlerOptions: null,
-
-    /** 
-     * Property: handler 
-     * {<OpenLayers.Handler>} null
+     * Property: autoDestroy
+     * {Boolean} The creator of the protocol can set autoDestroy to false
+     *      to fully control when the protocol is destroyed. Defaults to
+     *      true.
      */
-    handler: null,
-
+    autoDestroy: true,
+   
     /**
-     * APIProperty: eventListeners
-     * {Object} If set as an option at construction, the eventListeners
-     *     object will be registered with <OpenLayers.Events.on>.  Object
-     *     structure must be a listeners object as shown in the example for
-     *     the events.on method.
+     * Property: defaultFilter
+     * {<OpenLayers.Filter>} Optional default filter to read requests
      */
-    eventListeners: null,
-
-    /** 
-     * APIProperty: events
-     * {<OpenLayers.Events>} Events instance for listeners and triggering
-     *     control specific events.
-     *
-     * Register a listener for a particular event with the following syntax:
-     * (code)
-     * control.events.register(type, obj, listener);
-     * (end)
-     *
-     * Listeners will be called with a reference to an event object.  The
-     *     properties of this event depends on exactly what happened.
-     *
-     * All event objects have at least the following properties:
-     * object - {Object} A reference to control.events.object (a reference
-     *      to the control).
-     * element - {DOMElement} A reference to control.events.element (which
-     *      will be null unless documented otherwise).
+    defaultFilter: null,
+    
+    /**
+     * Constructor: OpenLayers.Protocol
+     * Abstract class for vector protocols.  Create instances of a subclass.
      *
-     * Supported map event types:
-     * activate - Triggered when activated.
-     * deactivate - Triggered when deactivated.
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
      */
-    events: null,
+    initialize: function(options) {
+        options = options || {};
+        OpenLayers.Util.extend(this, options);
+        this.options = options;
+    },
 
     /**
-     * Constructor: OpenLayers.Control
-     * Create an OpenLayers Control.  The options passed as a parameter
-     * directly extend the control.  For example passing the following:
-     * 
-     * > var control = new OpenLayers.Control({div: myDiv});
+     * Method: mergeWithDefaultFilter
+     * Merge filter passed to the read method with the default one
      *
-     * Overrides the default div attribute value of null.
-     * 
      * Parameters:
-     * options - {Object} 
+     * filter - {<OpenLayers.Filter>}
      */
-    initialize: function (options) {
-        // We do this before the extend so that instances can override
-        // className in options.
-        this.displayClass = 
-            this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
-        
-        OpenLayers.Util.extend(this, options);
-        
-        this.events = new OpenLayers.Events(this);
-        if(this.eventListeners instanceof Object) {
-            this.events.on(this.eventListeners);
-        }
-        if (this.id == null) {
-            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+    mergeWithDefaultFilter: function(filter) {
+        var merged;
+        if (filter && this.defaultFilter) {
+            merged = new OpenLayers.Filter.Logical({
+                type: OpenLayers.Filter.Logical.AND,
+                filters: [this.defaultFilter, filter]
+            });
+        } else {
+            merged = filter || this.defaultFilter || undefined;
         }
+        return merged;
     },
 
     /**
-     * Method: destroy
-     * The destroy method is used to perform any clean up before the control
-     * is dereferenced.  Typically this is where event listeners are removed
-     * to prevent memory leaks.
+     * APIMethod: destroy
+     * Clean up the protocol.
      */
-    destroy: function () {
-        if(this.events) {
-            if(this.eventListeners) {
-                this.events.un(this.eventListeners);
-            }
-            this.events.destroy();
-            this.events = null;
-        }
-        this.eventListeners = null;
-
-        // eliminate circular references
-        if (this.handler) {
-            this.handler.destroy();
-            this.handler = null;
-        }
-        if(this.handlers) {
-            for(var key in this.handlers) {
-                if(this.handlers.hasOwnProperty(key) &&
-                   typeof this.handlers[key].destroy == "function") {
-                    this.handlers[key].destroy();
-                }
-            }
-            this.handlers = null;
-        }
-        if (this.map) {
-            this.map.removeControl(this);
-            this.map = null;
-        }
-        this.div = null;
+    destroy: function() {
+        this.options = null;
+        this.format = null;
     },
-
-    /** 
-     * Method: setMap
-     * Set the map property for the control. This is done through an accessor
-     * so that subclasses can override this and take special action once 
-     * they have their map variable set. 
+    
+    /**
+     * APIMethod: read
+     * Construct a request for reading new features.
      *
      * Parameters:
-     * map - {<OpenLayers.Map>} 
+     * options - {Object} Optional object for configuring the request.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     * object, the same object will be passed to the callback function passed
+     * if one exists in the options object.
      */
-    setMap: function(map) {
-        this.map = map;
-        if (this.handler) {
-            this.handler.setMap(map);
-        }
+    read: function(options) {
+        options = options || {};
+        options.filter = this.mergeWithDefaultFilter(options.filter);
     },
-  
+    
+    
     /**
-     * Method: draw
-     * The draw method is called when the control is ready to be displayed
-     * on the page.  If a div has not been created one is created.  Controls
-     * with a visual component will almost always want to override this method 
-     * to customize the look of control. 
+     * APIMethod: create
+     * Construct a request for writing newly created features.
      *
      * Parameters:
-     * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
-     *      or null.
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *            {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
      *
      * Returns:
-     * {DOMElement} A reference to the DIV DOMElement containing the control
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     * object, the same object will be passed to the callback function passed
+     * if one exists in the options object.
      */
-    draw: function (px) {
-        if (this.div == null) {
-            this.div = OpenLayers.Util.createDiv(this.id);
-            this.div.className = this.displayClass;
-            if (!this.allowSelection) {
-                this.div.className += " olControlNoSelect";
-                this.div.setAttribute("unselectable", "on", 0);
-                this.div.onselectstart = OpenLayers.Function.False; 
-            }    
-            if (this.title != "") {
-                this.div.title = this.title;
-            }
-        }
-        if (px != null) {
-            this.position = px.clone();
-        }
-        this.moveTo(this.position);
-        return this.div;
+    create: function() {
     },
-
+    
     /**
-     * Method: moveTo
-     * Sets the left and top style attributes to the passed in pixel 
-     * coordinates.
+     * APIMethod: update
+     * Construct a request updating modified features.
      *
      * Parameters:
-     * px - {<OpenLayers.Pixel>}
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *            {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     * object, the same object will be passed to the callback function passed
+     * if one exists in the options object.
      */
-    moveTo: function (px) {
-        if ((px != null) && (this.div != null)) {
-            this.div.style.left = px.x + "px";
-            this.div.style.top = px.y + "px";
-        }
+    update: function() {
     },
-
+    
     /**
-     * APIMethod: activate
-     * Explicitly activates a control and it's associated
-     * handler if one has been set.  Controls can be
-     * deactivated by calling the deactivate() method.
-     * 
+     * APIMethod: delete
+     * Construct a request deleting a removed feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *
      * Returns:
-     * {Boolean}  True if the control was successfully activated or
-     *            false if the control was already active.
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     * object, the same object will be passed to the callback function passed
+     * if one exists in the options object.
      */
-    activate: function () {
-        if (this.active) {
-            return false;
-        }
-        if (this.handler) {
-            this.handler.activate();
-        }
-        this.active = true;
-        if(this.map) {
-            OpenLayers.Element.addClass(
-                this.map.viewPortDiv,
-                this.displayClass.replace(/ /g, "") + "Active"
-            );
-        }
-        this.events.triggerEvent("activate");
-        return true;
+    "delete": function() {
     },
-    
+
     /**
-     * APIMethod: deactivate
-     * Deactivates a control and it's associated handler if any.  The exact
-     * effect of this depends on the control itself.
-     * 
+     * APIMethod: commit
+     * Go over the features and for each take action
+     * based on the feature state. Possible actions are create,
+     * update and delete.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})}
+     * options - {Object} Object whose possible keys are "create", "update",
+     *      "delete", "callback" and "scope", the values referenced by the
+     *      first three are objects as passed to the "create", "update", and
+     *      "delete" methods, the value referenced by the "callback" key is
+     *      a function which is called when the commit operation is complete
+     *      using the scope referenced by the "scope" key.
+     *
      * Returns:
-     * {Boolean} True if the control was effectively deactivated or false
-     *           if the control was already inactive.
+     * {Array({<OpenLayers.Protocol.Response>})} An array of
+     * <OpenLayers.Protocol.Response> objects.
      */
-    deactivate: function () {
-        if (this.active) {
-            if (this.handler) {
-                this.handler.deactivate();
-            }
-            this.active = false;
-            if(this.map) {
-                OpenLayers.Element.removeClass(
-                    this.map.viewPortDiv,
-                    this.displayClass.replace(/ /g, "") + "Active"
-                );
-            }
-            this.events.triggerEvent("deactivate");
-            return true;
-        }
-        return false;
+    commit: function() {
     },
 
-    CLASS_NAME: "OpenLayers.Control"
+    /**
+     * Method: abort
+     * Abort an ongoing request.
+     *
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>}
+     */
+    abort: function(response) {
+    },
+   
+    /**
+     * Method: createCallback
+     * Returns a function that applies the given public method with resp and
+     *     options arguments.
+     *
+     * Parameters:
+     * method - {Function} The method to be applied by the callback.
+     * response - {<OpenLayers.Protocol.Response>} The protocol response object.
+     * options - {Object} Options sent to the protocol method
+     */
+    createCallback: function(method, response, options) {
+        return OpenLayers.Function.bind(function() {
+            method.apply(this, [response, options]);
+        }, this);
+    },
+   
+    CLASS_NAME: "OpenLayers.Protocol" 
 });
 
 /**
- * Constant: OpenLayers.Control.TYPE_BUTTON
- */
-OpenLayers.Control.TYPE_BUTTON = 1;
-
-/**
- * Constant: OpenLayers.Control.TYPE_TOGGLE
- */
-OpenLayers.Control.TYPE_TOGGLE = 2;
-
-/**
- * Constant: OpenLayers.Control.TYPE_TOOL
+ * Class: OpenLayers.Protocol.Response
+ * Protocols return Response objects to their users.
  */
-OpenLayers.Control.TYPE_TOOL   = 3;
-/* ======================================================================
-    OpenLayers/Strategy.js
-   ====================================================================== */
+OpenLayers.Protocol.Response = OpenLayers.Class({
+    /**
+     * Property: code
+     * {Number} - OpenLayers.Protocol.Response.SUCCESS or
+     *            OpenLayers.Protocol.Response.FAILURE
+     */
+    code: null,
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
+    /**
+     * Property: requestType
+     * {String} The type of request this response corresponds to. Either
+     *      "create", "read", "update" or "delete".
+     */
+    requestType: null,
 
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- */
+    /**
+     * Property: last
+     * {Boolean} - true if this is the last response expected in a commit,
+     * false otherwise, defaults to true.
+     */
+    last: true,
 
-/**
- * Class: OpenLayers.Strategy
- * Abstract vector layer strategy class.  Not to be instantiated directly.  Use
- *     one of the strategy subclasses instead.
- */
-OpenLayers.Strategy = OpenLayers.Class({
-    
     /**
-     * Property: layer
-     * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
+     * Property: features
+     * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
+     * The features returned in the response by the server. Depending on the 
+     * protocol's read payload, either features or data will be populated.
      */
-    layer: null,
-    
+    features: null,
+
     /**
-     * Property: options
-     * {Object} Any options sent to the constructor.
+     * Property: data
+     * {Object}
+     * The data returned in the response by the server. Depending on the 
+     * protocol's read payload, either features or data will be populated.
      */
-    options: null,
+    data: null,
 
-    /** 
-     * Property: active 
-     * {Boolean} The control is active.
+    /**
+     * Property: reqFeatures
+     * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
+     * The features provided by the user and placed in the request by the
+     *      protocol.
      */
-    active: null,
+    reqFeatures: null,
 
     /**
-     * Property: autoActivate
-     * {Boolean} The creator of the strategy can set autoActivate to false
-     *      to fully control when the protocol is activated and deactivated.
-     *      Defaults to true.
+     * Property: priv
      */
-    autoActivate: true,
+    priv: null,
 
     /**
-     * Property: autoDestroy
-     * {Boolean} The creator of the strategy can set autoDestroy to false
-     *      to fully control when the strategy is destroyed. Defaults to
-     *      true.
+     * Property: error
+     * {Object} The error object in case a service exception was encountered.
      */
-    autoDestroy: true,
+    error: null,
 
     /**
-     * Constructor: OpenLayers.Strategy
-     * Abstract class for vector strategies.  Create instances of a subclass.
+     * Constructor: OpenLayers.Protocol.Response
      *
      * Parameters:
      * options - {Object} Optional object whose properties will be set on the
@@ -13129,1521 +12762,1672 @@ OpenLayers.Strategy = OpenLayers.Class({
      */
     initialize: function(options) {
         OpenLayers.Util.extend(this, options);
-        this.options = options;
-        // set the active property here, so that user cannot override it
-        this.active = false;
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Clean up the strategy.
-     */
-    destroy: function() {
-        this.deactivate();
-        this.layer = null;
-        this.options = null;
     },
 
     /**
-     * Method: setLayer
-     * Called to set the <layer> property.
-     *
-     * Parameters:
-     * layer - {<OpenLayers.Layer.Vector>}
-     */
-    setLayer: function(layer) {
-        this.layer = layer;
-    },
-    
-    /**
-     * Method: activate
-     * Activate the strategy.  Register any listeners, do appropriate setup.
+     * Method: success
      *
      * Returns:
-     * {Boolean} True if the strategy was successfully activated or false if
-     *      the strategy was already active.
+     * {Boolean} - true on success, false otherwise
      */
-    activate: function() {
-        if (!this.active) {
-            this.active = true;
-            return true;
-        }
-        return false;
+    success: function() {
+        return this.code > 0;
     },
-    
-    /**
-     * Method: deactivate
-     * Deactivate the strategy.  Unregister any listeners, do appropriate
-     *     tear-down.
-     *
-     * Returns:
-     * {Boolean} True if the strategy was successfully deactivated or false if
-     *      the strategy was already inactive.
-     */
-    deactivate: function() {
-        if (this.active) {
-            this.active = false;
-            return true;
-        }
-        return false;
-    },
-   
-    CLASS_NAME: "OpenLayers.Strategy" 
+
+    CLASS_NAME: "OpenLayers.Protocol.Response"
 });
+
+OpenLayers.Protocol.Response.SUCCESS = 1;
+OpenLayers.Protocol.Response.FAILURE = 0;
 /* ======================================================================
-    OpenLayers/Feature.js
+    OpenLayers/Protocol/WFS.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the 2-clause BSD license.
  * See license.txt in the OpenLayers distribution or repository for the
  * full text of the license. */
 
+/**
+ * @requires OpenLayers/Protocol.js
+ */
 
 /**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Util.js
+ * Class: OpenLayers.Protocol.WFS
+ * Used to create a versioned WFS protocol.  Default version is 1.0.0.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol>} A WFS protocol of the given version.
+ *
+ * Example:
+ * (code)
+ *     var protocol = new OpenLayers.Protocol.WFS({
+ *         version: "1.1.0",
+ *         url:  "http://demo.opengeo.org/geoserver/wfs",
+ *         featureType: "tasmania_roads",
+ *         featureNS: "http://www.openplans.org/topp",
+ *         geometryName: "the_geom"
+ *     });
+ * (end)
+ *
+ * See the protocols for specific WFS versions for more detail.
  */
+OpenLayers.Protocol.WFS = function(options) {
+    options = OpenLayers.Util.applyDefaults(
+        options, OpenLayers.Protocol.WFS.DEFAULTS
+    );
+    var cls = OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g, "_")];
+    if(!cls) {
+        throw "Unsupported WFS version: " + options.version;
+    }
+    return new cls(options);
+};
 
 /**
- * Class: OpenLayers.Feature
- * Features are combinations of geography and attributes. The OpenLayers.Feature
- *     class specifically combines a marker and a lonlat.
+ * Function: fromWMSLayer
+ * Convenience function to create a WFS protocol from a WMS layer.  This makes
+ *     the assumption that a WFS requests can be issued at the same URL as
+ *     WMS requests and that a WFS featureType exists with the same name as the
+ *     WMS layer.
+ *     
+ * This function is designed to auto-configure <url>, <featureType>,
+ *     <featurePrefix> and <srsName> for WFS <version> 1.1.0. Note that
+ *     srsName matching with the WMS layer will not work with WFS 1.0.0.
+ * 
+ * Parameters:
+ * layer - {<OpenLayers.Layer.WMS>} WMS layer that has a matching WFS
+ *     FeatureType at the same server url with the same typename.
+ * options - {Object} Default properties to be set on the protocol.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.WFS>}
  */
-OpenLayers.Feature = OpenLayers.Class({
+OpenLayers.Protocol.WFS.fromWMSLayer = function(layer, options) {
+    var typeName, featurePrefix;
+    var param = layer.params["LAYERS"];
+    var parts = (OpenLayers.Util.isArray(param) ? param[0] : param).split(":");
+    if(parts.length > 1) {
+        featurePrefix = parts[0];
+    }
+    typeName = parts.pop();
+    var protocolOptions = {
+        url: layer.url,
+        featureType: typeName,
+        featurePrefix: featurePrefix,
+        srsName: layer.projection && layer.projection.getCode() ||
+                 layer.map && layer.map.getProjectionObject().getCode(),
+        version: "1.1.0"
+    };
+    return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(
+        options, protocolOptions
+    ));
+};
 
-    /** 
-     * Property: layer 
-     * {<OpenLayers.Layer>} 
-     */
-    layer: null,
+/**
+ * Constant: OpenLayers.Protocol.WFS.DEFAULTS
+ */
+OpenLayers.Protocol.WFS.DEFAULTS = {
+    "version": "1.0.0"
+};
+/* ======================================================================
+    OpenLayers/Protocol/WFS/v1.js
+   ====================================================================== */
 
-    /** 
-     * Property: id 
-     * {String} 
+/* Copyright (c) 2006-2015 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol/WFS.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.WFS.v1
+ * Abstract class for for v1.0.0 and v1.1.0 protocol.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, {
+    
+    /**
+     * Property: version
+     * {String} WFS version number.
      */
-    id: null,
+    version: null,
     
-    /** 
-     * Property: lonlat 
-     * {<OpenLayers.LonLat>} 
+    /**
+     * Property: srsName
+     * {String} Name of spatial reference system.  Default is "EPSG:4326".
      */
-    lonlat: null,
-
-    /** 
-     * Property: data 
-     * {Object} 
+    srsName: "EPSG:4326",
+    
+    /**
+     * Property: featureType
+     * {String} Local feature typeName.
      */
-    data: null,
-
-    /** 
-     * Property: marker 
-     * {<OpenLayers.Marker>} 
+    featureType: null,
+    
+    /**
+     * Property: featureNS
+     * {String} Feature namespace.
      */
-    marker: null,
+    featureNS: null,
+    
+    /**
+     * Property: geometryName
+     * {String} Name of the geometry attribute for features.  Default is
+     *     "the_geom" for WFS <version> 1.0, and null for higher versions.
+     */
+    geometryName: "the_geom",
 
     /**
-     * APIProperty: popupClass
-     * {<OpenLayers.Class>} The class which will be used to instantiate
-     *     a new Popup. Default is <OpenLayers.Popup.Anchored>.
+     * Property: maxFeatures
+     * {Integer} Optional maximum number of features to retrieve.
      */
-    popupClass: null,
+    
+    /**
+     * Property: schema
+     * {String} Optional schema location that will be included in the
+     *     schemaLocation attribute value.  Note that the feature type schema
+     *     is required for a strict XML validator (on transactions with an
+     *     insert for example), but is *not* required by the WFS specification
+     *     (since the server is supposed to know about feature type schemas).
+     */
+    schema: null,
 
-    /** 
-     * Property: popup 
-     * {<OpenLayers.Popup>} 
+    /**
+     * Property: featurePrefix
+     * {String} Namespace alias for feature type.  Default is "feature".
      */
-    popup: null,
+    featurePrefix: "feature",
+    
+    /**
+     * Property: formatOptions
+     * {Object} Optional options for the format.  If a format is not provided,
+     *     this property can be used to extend the default format options.
+     */
+    formatOptions: null,
 
     /** 
-     * Constructor: OpenLayers.Feature
-     * Constructor for features.
+     * Property: readFormat 
+     * {<OpenLayers.Format>} For WFS requests it is possible to get a  
+     *     different output format than GML. In that case, we cannot parse  
+     *     the response with the default format (WFST) and we need a different 
+     *     format for reading. 
+     */ 
+    readFormat: null,
+    
+    /**
+     * Property: readOptions
+     * {Object} Optional object to pass to format's read.
+     */
+    readOptions: null,
+    
+    /**
+     * Constructor: OpenLayers.Protocol.WFS
+     * A class for giving layers WFS protocol.
      *
      * Parameters:
-     * layer - {<OpenLayers.Layer>} 
-     * lonlat - {<OpenLayers.LonLat>} 
-     * data - {Object} 
-     * 
-     * Returns:
-     * {<OpenLayers.Feature>}
-     */
-    initialize: function(layer, lonlat, data) {
-        this.layer = layer;
-        this.lonlat = lonlat;
-        this.data = (data != null) ? data : {};
-        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); 
-    },
-
-    /** 
-     * Method: destroy
-     * nullify references to prevent circular references and memory leaks
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options properties:
+     * url - {String} URL to send requests to (required).
+     * featureType - {String} Local (without prefix) feature typeName (required).
+     * featureNS - {String} Feature namespace (required, but can be autodetected
+     *     during the first query if GML is used as readFormat and
+     *     featurePrefix is provided and matches the prefix used by the server
+     *     for this featureType).
+     * featurePrefix - {String} Feature namespace alias (optional - only used
+     *     for writing if featureNS is provided).  Default is 'feature'.
+     * geometryName - {String} Name of geometry attribute.  The default is
+     *     'the_geom' for WFS <version> 1.0, and null for higher versions. If
+     *     null, it will be set to the name of the first geometry found in the
+     *     first read operation.
+     * multi - {Boolean} If set to true, geometries will be casted to Multi
+     *     geometries before they are written in a transaction. No casting will
+     *     be done when reading features.
      */
-    destroy: function() {
-
-        //remove the popup from the map
-        if ((this.layer != null) && (this.layer.map != null)) {
-            if (this.popup != null) {
-                this.layer.map.removePopup(this.popup);
-            }
-        }
-        // remove the marker from the layer
-        if (this.layer != null && this.marker != null) {
-            this.layer.removeMarker(this.marker);
-        }
-
-        this.layer = null;
-        this.id = null;
-        this.lonlat = null;
-        this.data = null;
-        if (this.marker != null) {
-            this.destroyMarker(this.marker);
-            this.marker = null;
+    initialize: function(options) {
+        OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
+        if(!options.format) {
+            this.format = OpenLayers.Format.WFST(OpenLayers.Util.extend({
+                version: this.version,
+                featureType: this.featureType,
+                featureNS: this.featureNS,
+                featurePrefix: this.featurePrefix,
+                geometryName: this.geometryName,
+                srsName: this.srsName,
+                schema: this.schema
+            }, this.formatOptions));
         }
-        if (this.popup != null) {
-            this.destroyPopup(this.popup);
-            this.popup = null;
+        if (!options.geometryName && parseFloat(this.format.version) > 1.0) {
+            this.setGeometryName(null);
         }
     },
     
     /**
-     * Method: onScreen
-     * 
-     * Returns:
-     * {Boolean} Whether or not the feature is currently visible on screen
-     *           (based on its 'lonlat' property)
+     * APIMethod: destroy
+     * Clean up the protocol.
      */
-    onScreen:function() {
-        
-        var onScreen = false;
-        if ((this.layer != null) && (this.layer.map != null)) {
-            var screenBounds = this.layer.map.getExtent();
-            onScreen = screenBounds.containsLonLat(this.lonlat);
-        }    
-        return onScreen;
+    destroy: function() {
+        if(this.options && !this.options.format) {
+            this.format.destroy();
+        }
+        this.format = null;
+        OpenLayers.Protocol.prototype.destroy.apply(this);
     },
-    
 
     /**
-     * Method: createMarker
-     * Based on the data associated with the Feature, create and return a marker object.
+     * APIMethod: read
+     * Construct a request for reading new features.  Since WFS splits the
+     *     basic CRUD operations into GetFeature requests (for read) and
+     *     Transactions (for all others), this method does not make use of the
+     *     format's read method (that is only about reading transaction
+     *     responses).
      *
-     * Returns: 
-     * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
-     *          set in this.data. If no 'lonlat' is set, returns null. If no
-     *          'icon' is set, OpenLayers.Marker() will load the default image.
-     *          
-     *          Note - this.marker is set to return value
-     * 
+     * Parameters:
+     * options - {Object} Options for the read operation, in addition to the
+     *     options set on the instance (options set here will take precedence).
+     *
+     * To use a configured protocol to get e.g. a WFS hit count, applications
+     * could do the following:
+     *
+     * (code)
+     * protocol.read({
+     *     readOptions: {output: "object"},
+     *     resultType: "hits",
+     *     maxFeatures: null,
+     *     callback: function(resp) {
+     *         // process resp.numberOfFeatures here
+     *     }
+     * });
+     * (end)
+     *
+     * To use a configured protocol to use WFS paging (if supported by the
+     * server), applications could do the following:
+     *
+     * (code)
+     * protocol.read({
+     *     startIndex: 0,
+     *     count: 50
+     * });
+     * (end)
+     *
+     * To limit the attributes returned by the GetFeature request, applications
+     * can use the propertyNames option to specify the properties to include in
+     * the response:
+     *
+     * (code)
+     * protocol.read({
+     *     propertyNames: ["DURATION", "INTENSITY"]
+     * });
+     * (end)
      */
-    createMarker: function() {
+    read: function(options) {
+        OpenLayers.Protocol.prototype.read.apply(this, arguments);
+        options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options || {});
+        var response = new OpenLayers.Protocol.Response({requestType: "read"});
+        
+        var data = OpenLayers.Format.XML.prototype.write.apply(
+            this.format, [this.format.writeNode("wfs:GetFeature", options)]
+        );
 
-        if (this.lonlat != null) {
-            this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
-        }
-        return this.marker;
+        response.priv = OpenLayers.Request.POST({
+            url: options.url,
+            callback: this.createCallback(this.handleRead, response, options),
+            params: options.params,
+            headers: options.headers,
+            data: data
+        });
+
+        return response;
     },
 
     /**
-     * Method: destroyMarker
-     * Destroys marker.
-     * If user overrides the createMarker() function, s/he should be able
-     *   to also specify an alternative function for destroying it
+     * APIMethod: setFeatureType
+     * Change the feature type on the fly.
+     *
+     * Parameters:
+     * featureType - {String} Local (without prefix) feature typeName.
      */
-    destroyMarker: function() {
-        this.marker.destroy();  
+    setFeatureType: function(featureType) {
+        this.featureType = featureType;
+        this.format.featureType = featureType;
     },
-
     /**
-     * Method: createPopup
-     * Creates a popup object created from the 'lonlat', 'popupSize',
-     *     and 'popupContentHTML' properties set in this.data. It uses
-     *     this.marker.icon as default anchor. 
-     *  
-     *  If no 'lonlat' is set, returns null. 
-     *  If no this.marker has been created, no anchor is sent.
+     * APIMethod: setGeometryName
+     * Sets the geometryName option after instantiation.
      *
-     *  Note - the returned popup object is 'owned' by the feature, so you
-     *      cannot use the popup's destroy method to discard the popup.
-     *      Instead, you must use the feature's destroyPopup
-     * 
-     *  Note - this.popup is set to return value
-     * 
-     * Parameters: 
-     * closeBox - {Boolean} create popup with closebox or not
-     * 
-     * Returns:
-     * {<OpenLayers.Popup>} Returns the created popup, which is also set
-     *     as 'popup' property of this feature. Will be of whatever type
-     *     specified by this feature's 'popupClass' property, but must be
-     *     of type <OpenLayers.Popup>.
-     * 
+     * Parameters:
+     * geometryName - {String} Name of geometry attribute.
      */
-    createPopup: function(closeBox) {
-
-        if (this.lonlat != null) {
-            if (!this.popup) {
-                var anchor = (this.marker) ? this.marker.icon : null;
-                var popupClass = this.popupClass ? 
-                    this.popupClass : OpenLayers.Popup.Anchored;
-                this.popup = new popupClass(this.id + "_popup", 
-                                            this.lonlat,
-                                            this.data.popupSize,
-                                            this.data.popupContentHTML,
-                                            anchor, 
-                                            closeBox); 
-            }    
-            if (this.data.overflow != null) {
-                this.popup.contentDiv.style.overflow = this.data.overflow;
-            }    
-            
-            this.popup.feature = this;
-        }        
-        return this.popup;
+    setGeometryName: function(geometryName) {
+        this.geometryName = geometryName;
+        this.format.geometryName = geometryName;
     },
-
     
     /**
-     * Method: destroyPopup
-     * Destroys the popup created via createPopup.
+     * Method: handleRead
+     * Deal with response from the read request.
      *
-     * As with the marker, if user overrides the createPopup() function, s/he 
-     *   should also be able to override the destruction
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>} The response object to pass
+     *     to the user callback.
+     * options - {Object} The user options passed to the read call.
      */
-    destroyPopup: function() {
-        if (this.popup) {
-            this.popup.feature = null;
-            this.popup.destroy();
-            this.popup = null;
-        }    
-    },
-
-    CLASS_NAME: "OpenLayers.Feature"
-});
-/* ======================================================================
-    OpenLayers/Feature/Vector.js
-   ====================================================================== */
+    handleRead: function(response, options) {
+        options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options);
 
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-// TRASH THIS
-OpenLayers.State = {
-    /** states */
-    UNKNOWN: 'Unknown',
-    INSERT: 'Insert',
-    UPDATE: 'Update',
-    DELETE: 'Delete'
-};
-
-/**
- * @requires OpenLayers/Feature.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Feature.Vector
- * Vector features use the OpenLayers.Geometry classes as geometry description.
- * They have an 'attributes' property, which is the data object, and a 'style'
- * property, the default values of which are defined in the 
- * <OpenLayers.Feature.Vector.style> objects.
- * 
- * Inherits from:
- *  - <OpenLayers.Feature>
- */
-OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
-
-    /** 
-     * Property: fid 
-     * {String} 
-     */
-    fid: null,
-    
-    /** 
-     * APIProperty: geometry 
-     * {<OpenLayers.Geometry>} 
-     */
-    geometry: null,
-
-    /** 
-     * APIProperty: attributes 
-     * {Object} This object holds arbitrary, serializable properties that
-     *     describe the feature.
-     */
-    attributes: null,
+        if(options.callback) {
+            var request = response.priv;
+            if(request.status >= 200 && request.status < 300) {
+                // success
+                var result = this.parseResponse(request, options.readOptions);
+                if (result && result.success !== false) { 
+                    if (options.readOptions && options.readOptions.output == "object") {
+                        OpenLayers.Util.extend(response, result);
+                    } else {
+                        response.features = result;
+                    }
+                    response.code = OpenLayers.Protocol.Response.SUCCESS;
+                } else {
+                    // failure (service exception)
+                    response.code = OpenLayers.Protocol.Response.FAILURE;
+                    response.error = result;
+                }
+            } else {
+                // failure
+                response.code = OpenLayers.Protocol.Response.FAILURE;
+            }
+            options.callback.call(options.scope, response);
+        }
+    },
 
     /**
-     * Property: bounds
-     * {<OpenLayers.Bounds>} The box bounding that feature's geometry, that
-     *     property can be set by an <OpenLayers.Format> object when
-     *     deserializing the feature, so in most cases it represents an
-     *     information set by the server. 
-     */
-    bounds: null,
-
-    /** 
-     * Property: state 
-     * {String} 
-     */
-    state: null,
-    
-    /** 
-     * APIProperty: style 
-     * {Object} 
+     * Method: parseResponse
+     * Read HTTP response body and return features
+     *
+     * Parameters:
+     * request - {XMLHttpRequest} The request object
+     * options - {Object} Optional object to pass to format's read
+     *
+     * Returns:
+     * {Object} or {Array({<OpenLayers.Feature.Vector>})} or
+     *     {<OpenLayers.Feature.Vector>} 
+     * An object with a features property, an array of features or a single 
+     * feature.
      */
-    style: null,
+    parseResponse: function(request, options) {
+        var doc = request.responseXML;
+        if(!doc || !doc.documentElement) {
+            doc = request.responseText;
+        }
+        if(!doc || doc.length <= 0) {
+            return null;
+        }
+        var result = (this.readFormat !== null) ? this.readFormat.read(doc) : 
+            this.format.read(doc, options);
+        if (!this.featureNS) {
+            var format = this.readFormat || this.format;
+            this.featureNS = format.featureNS;
+            // no need to auto-configure again on subsequent reads
+            format.autoConfig = false;
+            if (!this.geometryName) {
+                this.setGeometryName(format.geometryName);
+            }
+        }
+        return result;
+    },
 
     /**
-     * APIProperty: url
-     * {String} If this property is set it will be taken into account by
-     *     {<OpenLayers.HTTP>} when upadting or deleting the feature.
-     */
-    url: null,
-    
-    /**
-     * Property: renderIntent
-     * {String} rendering intent currently being used
-     */
-    renderIntent: "default",
-    
-    /**
-     * APIProperty: modified
-     * {Object} An object with the originals of the geometry and attributes of
-     * the feature, if they were changed. Currently this property is only read
-     * by <OpenLayers.Format.WFST.v1>, and written by
-     * <OpenLayers.Control.ModifyFeature>, which sets the geometry property.
-     * Applications can set the originals of modified attributes in the
-     * attributes property. Note that applications have to check if this
-     * object and the attributes property is already created before using it.
-     * After a change made with ModifyFeature, this object could look like
-     *
-     * (code)
-     * {
-     *     geometry: >Object
-     * }
-     * (end)
+     * Method: commit
+     * Given a list of feature, assemble a batch request for update, create,
+     *     and delete transactions.  A commit call on the prototype amounts
+     *     to writing a WFS transaction - so the write method on the format
+     *     is used.
      *
-     * When an application has made changes to feature attributes, it could
-     * have set the attributes to something like this:
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)}
+     * options - {Object}
      *
-     * (code)
-     * {
-     *     attributes: {
-     *         myAttribute: "original"
-     *     }
-     * }
-     * (end)
+     * Valid options properties:
+     * nativeElements - {Array({Object})} Array of objects with information for writing
+     * out <Native> elements, these objects have vendorId, safeToIgnore and
+     * value properties. The <Native> element is intended to allow access to 
+     * vendor specific capabilities of any particular web feature server or 
+     * datastore.
      *
-     * Note that <OpenLayers.Format.WFST.v1> only checks for truthy values in
-     * *modified.geometry* and the attribute names in *modified.attributes*,
-     * but it is recommended to set the original values (and not just true) as
-     * attribute value, so applications could use this information to undo
-     * changes.
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} A response object with a features
+     *     property containing any insertIds and a priv property referencing
+     *     the XMLHttpRequest object.
      */