3ab927311766054abc660c675401221f40cd2301
[philipp/winterrodeln/mediawiki_extensions/wrmap.git] / openlayers / OpenLayers.js
1 /*
2
3   OpenLayers.js -- OpenLayers Map Viewer Library
4
5   Copyright (c) 2006-2013 by OpenLayers Contributors
6   Published under the 2-clause BSD license.
7   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.
8
9   Includes compressed code under the following licenses:
10
11   (For uncompressed versions of the code used, please see the
12   OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
13
14 */
15
16 /**
17  * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
18  * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
19  *
20  * Licensed under the Apache License, Version 2.0 (the "License");
21  * you may not use this file except in compliance with the License.
22  * You may obtain a copy of the License at
23  * http://www.apache.org/licenses/LICENSE-2.0
24  */
25
26 /**
27  * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
28  * Copyright (c) 2006, Yahoo! Inc.
29  * All rights reserved.
30  * 
31  * Redistribution and use of this software in source and binary forms, with or
32  * without modification, are permitted provided that the following conditions
33  * are met:
34  * 
35  * * Redistributions of source code must retain the above copyright notice,
36  *   this list of conditions and the following disclaimer.
37  * 
38  * * Redistributions in binary form must reproduce the above copyright notice,
39  *   this list of conditions and the following disclaimer in the documentation
40  *   and/or other materials provided with the distribution.
41  * 
42  * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
43  *   used to endorse or promote products derived from this software without
44  *   specific prior written permission of Yahoo! Inc.
45  * 
46  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
47  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
50  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
56  * POSSIBILITY OF SUCH DAMAGE.
57  */
58 /* ======================================================================
59     OpenLayers/SingleFile.js
60    ====================================================================== */
61
62 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
63  * full list of contributors). Published under the 2-clause BSD license.
64  * See license.txt in the OpenLayers distribution or repository for the
65  * full text of the license. */
66
67 var OpenLayers = {
68     /**
69      * Constant: VERSION_NUMBER
70      */
71     VERSION_NUMBER: "Release 2.13.1",
72
73     /**
74      * Constant: singleFile
75      * TODO: remove this in 3.0 when we stop supporting build profiles that
76      * include OpenLayers.js
77      */
78     singleFile: true,
79
80     /**
81      * Method: _getScriptLocation
82      * Return the path to this script. This is also implemented in
83      * OpenLayers.js
84      *
85      * Returns:
86      * {String} Path to this script
87      */
88     _getScriptLocation: (function() {
89         var r = new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),
90             s = document.getElementsByTagName('script'),
91             src, m, l = "";
92         for(var i=0, len=s.length; i<len; i++) {
93             src = s[i].getAttribute('src');
94             if(src) {
95                 m = src.match(r);
96                 if(m) {
97                     l = m[1];
98                     break;
99                 }
100             }
101         }
102         return (function() { return l; });
103     })(),
104     
105     /**
106      * Property: ImgPath
107      * {String} Set this to the path where control images are stored, a path  
108      * given here must end with a slash. If set to '' (which is the default) 
109      * OpenLayers will use its script location + "img/".
110      * 
111      * You will need to set this property when you have a singlefile build of 
112      * OpenLayers that either is not named "OpenLayers.js" or if you move
113      * the file in a way such that the image directory cannot be derived from 
114      * the script location.
115      * 
116      * If your custom OpenLayers build is named "my-custom-ol.js" and the images
117      * of OpenLayers are in a folder "/resources/external/images/ol" a correct
118      * way of including OpenLayers in your HTML would be:
119      * 
120      * (code)
121      *   <script src="/path/to/my-custom-ol.js" type="text/javascript"></script>
122      *   <script type="text/javascript">
123      *      // tell OpenLayers where the control images are
124      *      // remember the trailing slash
125      *      OpenLayers.ImgPath = "/resources/external/images/ol/";
126      *   </script>
127      * (end code)
128      * 
129      * Please remember that when your OpenLayers script is not named 
130      * "OpenLayers.js" you will have to make sure that the default theme is 
131      * loaded into the page by including an appropriate <link>-tag, 
132      * e.g.:
133      * 
134      * (code)
135      *   <link rel="stylesheet" href="/path/to/default/style.css"  type="text/css">
136      * (end code)
137      */
138     ImgPath : ''
139 };
140 /* ======================================================================
141     OpenLayers/BaseTypes.js
142    ====================================================================== */
143
144 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
145  * full list of contributors). Published under the 2-clause BSD license.
146  * See license.txt in the OpenLayers distribution or repository for the
147  * full text of the license. */
148
149 /**
150  * @requires OpenLayers/SingleFile.js
151  */
152
153 /** 
154  * Header: OpenLayers Base Types
155  * OpenLayers custom string, number and function functions are described here.
156  */
157
158 /**
159  * Namespace: OpenLayers.String
160  * Contains convenience functions for string manipulation.
161  */
162 OpenLayers.String = {
163
164     /**
165      * APIFunction: startsWith
166      * Test whether a string starts with another string. 
167      * 
168      * Parameters:
169      * str - {String} The string to test.
170      * sub - {String} The substring to look for.
171      *  
172      * Returns:
173      * {Boolean} The first string starts with the second.
174      */
175     startsWith: function(str, sub) {
176         return (str.indexOf(sub) == 0);
177     },
178
179     /**
180      * APIFunction: contains
181      * Test whether a string contains another string.
182      * 
183      * Parameters:
184      * str - {String} The string to test.
185      * sub - {String} The substring to look for.
186      * 
187      * Returns:
188      * {Boolean} The first string contains the second.
189      */
190     contains: function(str, sub) {
191         return (str.indexOf(sub) != -1);
192     },
193     
194     /**
195      * APIFunction: trim
196      * Removes leading and trailing whitespace characters from a string.
197      * 
198      * Parameters:
199      * str - {String} The (potentially) space padded string.  This string is not
200      *     modified.
201      * 
202      * Returns:
203      * {String} A trimmed version of the string with all leading and 
204      *     trailing spaces removed.
205      */
206     trim: function(str) {
207         return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
208     },
209     
210     /**
211      * APIFunction: camelize
212      * Camel-case a hyphenated string. 
213      *     Ex. "chicken-head" becomes "chickenHead", and
214      *     "-chicken-head" becomes "ChickenHead".
215      *
216      * Parameters:
217      * str - {String} The string to be camelized.  The original is not modified.
218      * 
219      * Returns:
220      * {String} The string, camelized
221      */
222     camelize: function(str) {
223         var oStringList = str.split('-');
224         var camelizedString = oStringList[0];
225         for (var i=1, len=oStringList.length; i<len; i++) {
226             var s = oStringList[i];
227             camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
228         }
229         return camelizedString;
230     },
231     
232     /**
233      * APIFunction: format
234      * Given a string with tokens in the form ${token}, return a string
235      *     with tokens replaced with properties from the given context
236      *     object.  Represent a literal "${" by doubling it, e.g. "${${".
237      *
238      * Parameters:
239      * template - {String} A string with tokens to be replaced.  A template
240      *     has the form "literal ${token}" where the token will be replaced
241      *     by the value of context["token"].
242      * context - {Object} An optional object with properties corresponding
243      *     to the tokens in the format string.  If no context is sent, the
244      *     window object will be used.
245      * args - {Array} Optional arguments to pass to any functions found in
246      *     the context.  If a context property is a function, the token
247      *     will be replaced by the return from the function called with
248      *     these arguments.
249      *
250      * Returns:
251      * {String} A string with tokens replaced from the context object.
252      */
253     format: function(template, context, args) {
254         if(!context) {
255             context = window;
256         }
257
258         // Example matching: 
259         // str   = ${foo.bar}
260         // match = foo.bar
261         var replacer = function(str, match) {
262             var replacement;
263
264             // Loop through all subs. Example: ${a.b.c}
265             // 0 -> replacement = context[a];
266             // 1 -> replacement = context[a][b];
267             // 2 -> replacement = context[a][b][c];
268             var subs = match.split(/\.+/);
269             for (var i=0; i< subs.length; i++) {
270                 if (i == 0) {
271                     replacement = context;
272                 }
273                 if (replacement === undefined) {
274                     break;
275                 }
276                 replacement = replacement[subs[i]];
277             }
278
279             if(typeof replacement == "function") {
280                 replacement = args ?
281                     replacement.apply(null, args) :
282                     replacement();
283             }
284
285             // If replacement is undefined, return the string 'undefined'.
286             // This is a workaround for a bugs in browsers not properly 
287             // dealing with non-participating groups in regular expressions:
288             // http://blog.stevenlevithan.com/archives/npcg-javascript
289             if (typeof replacement == 'undefined') {
290                 return 'undefined';
291             } else {
292                 return replacement; 
293             }
294         };
295
296         return template.replace(OpenLayers.String.tokenRegEx, replacer);
297     },
298
299     /**
300      * Property: tokenRegEx
301      * Used to find tokens in a string.
302      * Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
303      */
304     tokenRegEx:  /\$\{([\w.]+?)\}/g,
305     
306     /**
307      * Property: numberRegEx
308      * Used to test strings as numbers.
309      */
310     numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
311     
312     /**
313      * APIFunction: isNumeric
314      * Determine whether a string contains only a numeric value.
315      *
316      * Examples:
317      * (code)
318      * OpenLayers.String.isNumeric("6.02e23") // true
319      * OpenLayers.String.isNumeric("12 dozen") // false
320      * OpenLayers.String.isNumeric("4") // true
321      * OpenLayers.String.isNumeric(" 4 ") // false
322      * (end)
323      *
324      * Returns:
325      * {Boolean} String contains only a number.
326      */
327     isNumeric: function(value) {
328         return OpenLayers.String.numberRegEx.test(value);
329     },
330     
331     /**
332      * APIFunction: numericIf
333      * Converts a string that appears to be a numeric value into a number.
334      * 
335      * Parameters:
336      * value - {String}
337      * trimWhitespace - {Boolean}
338      *
339      * Returns:
340      * {Number|String} a Number if the passed value is a number, a String
341      *     otherwise. 
342      */
343     numericIf: function(value, trimWhitespace) {
344         var originalValue = value;
345         if (trimWhitespace === true && value != null && value.replace) {
346             value = value.replace(/^\s*|\s*$/g, "");
347         }
348         return OpenLayers.String.isNumeric(value) ? parseFloat(value) : originalValue;
349     }
350
351 };
352
353 /**
354  * Namespace: OpenLayers.Number
355  * Contains convenience functions for manipulating numbers.
356  */
357 OpenLayers.Number = {
358
359     /**
360      * Property: decimalSeparator
361      * Decimal separator to use when formatting numbers.
362      */
363     decimalSeparator: ".",
364     
365     /**
366      * Property: thousandsSeparator
367      * Thousands separator to use when formatting numbers.
368      */
369     thousandsSeparator: ",",
370     
371     /**
372      * APIFunction: limitSigDigs
373      * Limit the number of significant digits on a float.
374      * 
375      * Parameters:
376      * num - {Float}
377      * sig - {Integer}
378      * 
379      * Returns:
380      * {Float} The number, rounded to the specified number of significant
381      *     digits.
382      */
383     limitSigDigs: function(num, sig) {
384         var fig = 0;
385         if (sig > 0) {
386             fig = parseFloat(num.toPrecision(sig));
387         }
388         return fig;
389     },
390     
391     /**
392      * APIFunction: format
393      * Formats a number for output.
394      * 
395      * Parameters:
396      * num  - {Float}
397      * dec  - {Integer} Number of decimal places to round to.
398      *        Defaults to 0. Set to null to leave decimal places unchanged.
399      * tsep - {String} Thousands separator.
400      *        Default is ",".
401      * dsep - {String} Decimal separator.
402      *        Default is ".".
403      *
404      * Returns:
405      * {String} A string representing the formatted number.
406      */
407     format: function(num, dec, tsep, dsep) {
408         dec = (typeof dec != "undefined") ? dec : 0; 
409         tsep = (typeof tsep != "undefined") ? tsep :
410             OpenLayers.Number.thousandsSeparator; 
411         dsep = (typeof dsep != "undefined") ? dsep :
412             OpenLayers.Number.decimalSeparator;
413
414         if (dec != null) {
415             num = parseFloat(num.toFixed(dec));
416         }
417
418         var parts = num.toString().split(".");
419         if (parts.length == 1 && dec == null) {
420             // integer where we do not want to touch the decimals
421             dec = 0;
422         }
423         
424         var integer = parts[0];
425         if (tsep) {
426             var thousands = /(-?[0-9]+)([0-9]{3})/; 
427             while(thousands.test(integer)) { 
428                 integer = integer.replace(thousands, "$1" + tsep + "$2"); 
429             }
430         }
431         
432         var str;
433         if (dec == 0) {
434             str = integer;
435         } else {
436             var rem = parts.length > 1 ? parts[1] : "0";
437             if (dec != null) {
438                 rem = rem + new Array(dec - rem.length + 1).join("0");
439             }
440             str = integer + dsep + rem;
441         }
442         return str;
443     },
444
445     /**
446      * Method: zeroPad
447      * Create a zero padded string optionally with a radix for casting numbers.
448      *
449      * Parameters:
450      * num - {Number} The number to be zero padded.
451      * len - {Number} The length of the string to be returned.
452      * radix - {Number} An integer between 2 and 36 specifying the base to use
453      *     for representing numeric values.
454      */
455     zeroPad: function(num, len, radix) {
456         var str = num.toString(radix || 10);
457         while (str.length < len) {
458             str = "0" + str;
459         }
460         return str;
461     }    
462 };
463
464 /**
465  * Namespace: OpenLayers.Function
466  * Contains convenience functions for function manipulation.
467  */
468 OpenLayers.Function = {
469     /**
470      * APIFunction: bind
471      * Bind a function to an object.  Method to easily create closures with
472      *     'this' altered.
473      * 
474      * Parameters:
475      * func - {Function} Input function.
476      * object - {Object} The object to bind to the input function (as this).
477      * 
478      * Returns:
479      * {Function} A closure with 'this' set to the passed in object.
480      */
481     bind: function(func, object) {
482         // create a reference to all arguments past the second one
483         var args = Array.prototype.slice.apply(arguments, [2]);
484         return function() {
485             // Push on any additional arguments from the actual function call.
486             // These will come after those sent to the bind call.
487             var newArgs = args.concat(
488                 Array.prototype.slice.apply(arguments, [0])
489             );
490             return func.apply(object, newArgs);
491         };
492     },
493     
494     /**
495      * APIFunction: bindAsEventListener
496      * Bind a function to an object, and configure it to receive the event
497      *     object as first parameter when called. 
498      * 
499      * Parameters:
500      * func - {Function} Input function to serve as an event listener.
501      * object - {Object} A reference to this.
502      * 
503      * Returns:
504      * {Function}
505      */
506     bindAsEventListener: function(func, object) {
507         return function(event) {
508             return func.call(object, event || window.event);
509         };
510     },
511     
512     /**
513      * APIFunction: False
514      * A simple function to that just does "return false". We use this to 
515      * avoid attaching anonymous functions to DOM event handlers, which 
516      * causes "issues" on IE<8.
517      * 
518      * Usage:
519      * document.onclick = OpenLayers.Function.False;
520      * 
521      * Returns:
522      * {Boolean}
523      */
524     False : function() {
525         return false;
526     },
527
528     /**
529      * APIFunction: True
530      * A simple function to that just does "return true". We use this to 
531      * avoid attaching anonymous functions to DOM event handlers, which 
532      * causes "issues" on IE<8.
533      * 
534      * Usage:
535      * document.onclick = OpenLayers.Function.True;
536      * 
537      * Returns:
538      * {Boolean}
539      */
540     True : function() {
541         return true;
542     },
543     
544     /**
545      * APIFunction: Void
546      * A reusable function that returns ``undefined``.
547      *
548      * Returns:
549      * {undefined}
550      */
551     Void: function() {}
552
553 };
554
555 /**
556  * Namespace: OpenLayers.Array
557  * Contains convenience functions for array manipulation.
558  */
559 OpenLayers.Array = {
560
561     /**
562      * APIMethod: filter
563      * Filter an array.  Provides the functionality of the
564      *     Array.prototype.filter extension to the ECMA-262 standard.  Where
565      *     available, Array.prototype.filter will be used.
566      *
567      * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter
568      *
569      * Parameters:
570      * array - {Array} The array to be filtered.  This array is not mutated.
571      *     Elements added to this array by the callback will not be visited.
572      * callback - {Function} A function that is called for each element in
573      *     the array.  If this function returns true, the element will be
574      *     included in the return.  The function will be called with three
575      *     arguments: the element in the array, the index of that element, and
576      *     the array itself.  If the optional caller parameter is specified
577      *     the callback will be called with this set to caller.
578      * caller - {Object} Optional object to be set as this when the callback
579      *     is called.
580      *
581      * Returns:
582      * {Array} An array of elements from the passed in array for which the
583      *     callback returns true.
584      */
585     filter: function(array, callback, caller) {
586         var selected = [];
587         if (Array.prototype.filter) {
588             selected = array.filter(callback, caller);
589         } else {
590             var len = array.length;
591             if (typeof callback != "function") {
592                 throw new TypeError();
593             }
594             for(var i=0; i<len; i++) {
595                 if (i in array) {
596                     var val = array[i];
597                     if (callback.call(caller, val, i, array)) {
598                         selected.push(val);
599                     }
600                 }
601             }        
602         }
603         return selected;
604     }
605     
606 };
607 /* ======================================================================
608     OpenLayers/BaseTypes/Class.js
609    ====================================================================== */
610
611 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
612  * full list of contributors). Published under the 2-clause BSD license.
613  * See license.txt in the OpenLayers distribution or repository for the
614  * full text of the license. */
615
616 /**
617  * @requires OpenLayers/SingleFile.js
618  */
619
620 /**
621  * Constructor: OpenLayers.Class
622  * Base class used to construct all other classes. Includes support for 
623  *     multiple inheritance. 
624  *     
625  * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
626  *     syntax for creating classes and dealing with inheritance 
627  *     will be removed.
628  * 
629  * To create a new OpenLayers-style class, use the following syntax:
630  * (code)
631  *     var MyClass = OpenLayers.Class(prototype);
632  * (end)
633  *
634  * To create a new OpenLayers-style class with multiple inheritance, use the
635  *     following syntax:
636  * (code)
637  *     var MyClass = OpenLayers.Class(Class1, Class2, prototype);
638  * (end)
639  * 
640  * Note that instanceof reflection will only reveal Class1 as superclass.
641  *
642  */
643 OpenLayers.Class = function() {
644     var len = arguments.length;
645     var P = arguments[0];
646     var F = arguments[len-1];
647
648     var C = typeof F.initialize == "function" ?
649         F.initialize :
650         function(){ P.prototype.initialize.apply(this, arguments); };
651
652     if (len > 1) {
653         var newArgs = [C, P].concat(
654                 Array.prototype.slice.call(arguments).slice(1, len-1), F);
655         OpenLayers.inherit.apply(null, newArgs);
656     } else {
657         C.prototype = F;
658     }
659     return C;
660 };
661
662 /**
663  * Function: OpenLayers.inherit
664  *
665  * Parameters:
666  * C - {Object} the class that inherits
667  * P - {Object} the superclass to inherit from
668  *
669  * In addition to the mandatory C and P parameters, an arbitrary number of
670  * objects can be passed, which will extend C.
671  */
672 OpenLayers.inherit = function(C, P) {
673    var F = function() {};
674    F.prototype = P.prototype;
675    C.prototype = new F;
676    var i, l, o;
677    for(i=2, l=arguments.length; i<l; i++) {
678        o = arguments[i];
679        if(typeof o === "function") {
680            o = o.prototype;
681        }
682        OpenLayers.Util.extend(C.prototype, o);
683    }
684 };
685
686 /**
687  * APIFunction: extend
688  * Copy all properties of a source object to a destination object.  Modifies
689  *     the passed in destination object.  Any properties on the source object
690  *     that are set to undefined will not be (re)set on the destination object.
691  *
692  * Parameters:
693  * destination - {Object} The object that will be modified
694  * source - {Object} The object with properties to be set on the destination
695  *
696  * Returns:
697  * {Object} The destination object.
698  */
699 OpenLayers.Util = OpenLayers.Util || {};
700 OpenLayers.Util.extend = function(destination, source) {
701     destination = destination || {};
702     if (source) {
703         for (var property in source) {
704             var value = source[property];
705             if (value !== undefined) {
706                 destination[property] = value;
707             }
708         }
709
710         /**
711          * IE doesn't include the toString property when iterating over an object's
712          * properties with the for(property in object) syntax.  Explicitly check if
713          * the source has its own toString property.
714          */
715
716         /*
717          * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
718          * prototype object" when calling hawOwnProperty if the source object
719          * is an instance of window.Event.
720          */
721
722         var sourceIsEvt = typeof window.Event == "function"
723                           && source instanceof window.Event;
724
725         if (!sourceIsEvt
726            && source.hasOwnProperty && source.hasOwnProperty("toString")) {
727             destination.toString = source.toString;
728         }
729     }
730     return destination;
731 };
732 /* ======================================================================
733     OpenLayers/BaseTypes/Bounds.js
734    ====================================================================== */
735
736 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
737  * full list of contributors). Published under the 2-clause BSD license.
738  * See license.txt in the OpenLayers distribution or repository for the
739  * full text of the license. */
740
741 /**
742  * @requires OpenLayers/BaseTypes/Class.js
743  */
744
745 /**
746  * Class: OpenLayers.Bounds
747  * Instances of this class represent bounding boxes.  Data stored as left,
748  * bottom, right, top floats. All values are initialized to null, however,
749  * you should make sure you set them before using the bounds for anything.
750  * 
751  * Possible use case:
752  * (code)
753  *     bounds = new OpenLayers.Bounds();
754  *     bounds.extend(new OpenLayers.LonLat(4,5));
755  *     bounds.extend(new OpenLayers.LonLat(5,6));
756  *     bounds.toBBOX(); // returns 4,5,5,6
757  * (end)
758  */
759 OpenLayers.Bounds = OpenLayers.Class({
760
761     /**
762      * Property: left
763      * {Number} Minimum horizontal coordinate.
764      */
765     left: null,
766
767     /**
768      * Property: bottom
769      * {Number} Minimum vertical coordinate.
770      */
771     bottom: null,
772
773     /**
774      * Property: right
775      * {Number} Maximum horizontal coordinate.
776      */
777     right: null,
778
779     /**
780      * Property: top
781      * {Number} Maximum vertical coordinate.
782      */
783     top: null,
784     
785     /**
786      * Property: centerLonLat
787      * {<OpenLayers.LonLat>} A cached center location.  This should not be
788      *     accessed directly.  Use <getCenterLonLat> instead.
789      */
790     centerLonLat: null,
791
792     /**
793      * Constructor: OpenLayers.Bounds
794      * Construct a new bounds object. Coordinates can either be passed as four
795      * arguments, or as a single argument.
796      *
797      * Parameters (four arguments):
798      * left - {Number} The left bounds of the box.  Note that for width
799      *        calculations, this is assumed to be less than the right value.
800      * bottom - {Number} The bottom bounds of the box.  Note that for height
801      *          calculations, this is assumed to be less than the top value.
802      * right - {Number} The right bounds.
803      * top - {Number} The top bounds.
804      *
805      * Parameters (single argument):
806      * bounds - {Array(Number)} [left, bottom, right, top]
807      */
808     initialize: function(left, bottom, right, top) {
809         if (OpenLayers.Util.isArray(left)) {
810             top = left[3];
811             right = left[2];
812             bottom = left[1];
813             left = left[0];
814         }
815         if (left != null) {
816             this.left = OpenLayers.Util.toFloat(left);
817         }
818         if (bottom != null) {
819             this.bottom = OpenLayers.Util.toFloat(bottom);
820         }
821         if (right != null) {
822             this.right = OpenLayers.Util.toFloat(right);
823         }
824         if (top != null) {
825             this.top = OpenLayers.Util.toFloat(top);
826         }
827     },
828
829     /**
830      * Method: clone
831      * Create a cloned instance of this bounds.
832      *
833      * Returns:
834      * {<OpenLayers.Bounds>} A fresh copy of the bounds
835      */
836     clone:function() {
837         return new OpenLayers.Bounds(this.left, this.bottom, 
838                                      this.right, this.top);
839     },
840
841     /**
842      * Method: equals
843      * Test a two bounds for equivalence.
844      *
845      * Parameters:
846      * bounds - {<OpenLayers.Bounds>}
847      *
848      * Returns:
849      * {Boolean} The passed-in bounds object has the same left,
850      *           right, top, bottom components as this.  Note that if bounds 
851      *           passed in is null, returns false.
852      */
853     equals:function(bounds) {
854         var equals = false;
855         if (bounds != null) {
856             equals = ((this.left == bounds.left) && 
857                       (this.right == bounds.right) &&
858                       (this.top == bounds.top) && 
859                       (this.bottom == bounds.bottom));
860         }
861         return equals;
862     },
863
864     /** 
865      * APIMethod: toString
866      * Returns a string representation of the bounds object.
867      * 
868      * Returns:
869      * {String} String representation of bounds object. 
870      */
871     toString:function() {
872         return [this.left, this.bottom, this.right, this.top].join(",");
873     },
874
875     /**
876      * APIMethod: toArray
877      * Returns an array representation of the bounds object.
878      *
879      * Returns an array of left, bottom, right, top properties, or -- when the
880      *     optional parameter is true -- an array of the  bottom, left, top,
881      *     right properties.
882      *
883      * Parameters:
884      * reverseAxisOrder - {Boolean} Should we reverse the axis order?
885      *
886      * Returns:
887      * {Array} array of left, bottom, right, top
888      */
889     toArray: function(reverseAxisOrder) {
890         if (reverseAxisOrder === true) {
891             return [this.bottom, this.left, this.top, this.right];
892         } else {
893             return [this.left, this.bottom, this.right, this.top];
894         }
895     },    
896
897     /** 
898      * APIMethod: toBBOX
899      * Returns a boundingbox-string representation of the bounds object.
900      * 
901      * Parameters:
902      * decimal - {Integer} How many significant digits in the bbox coords?
903      *                     Default is 6
904      * reverseAxisOrder - {Boolean} Should we reverse the axis order?
905      * 
906      * Returns:
907      * {String} Simple String representation of bounds object.
908      *          (e.g. "5,42,10,45")
909      */
910     toBBOX:function(decimal, reverseAxisOrder) {
911         if (decimal== null) {
912             decimal = 6; 
913         }
914         var mult = Math.pow(10, decimal);
915         var xmin = Math.round(this.left * mult) / mult;
916         var ymin = Math.round(this.bottom * mult) / mult;
917         var xmax = Math.round(this.right * mult) / mult;
918         var ymax = Math.round(this.top * mult) / mult;
919         if (reverseAxisOrder === true) {
920             return ymin + "," + xmin + "," + ymax + "," + xmax;
921         } else {
922             return xmin + "," + ymin + "," + xmax + "," + ymax;
923         }
924     },
925  
926     /**
927      * APIMethod: toGeometry
928      * Create a new polygon geometry based on this bounds.
929      *
930      * Returns:
931      * {<OpenLayers.Geometry.Polygon>} A new polygon with the coordinates
932      *     of this bounds.
933      */
934     toGeometry: function() {
935         return new OpenLayers.Geometry.Polygon([
936             new OpenLayers.Geometry.LinearRing([
937                 new OpenLayers.Geometry.Point(this.left, this.bottom),
938                 new OpenLayers.Geometry.Point(this.right, this.bottom),
939                 new OpenLayers.Geometry.Point(this.right, this.top),
940                 new OpenLayers.Geometry.Point(this.left, this.top)
941             ])
942         ]);
943     },
944     
945     /**
946      * APIMethod: getWidth
947      * Returns the width of the bounds.
948      * 
949      * Returns:
950      * {Float} The width of the bounds (right minus left).
951      */
952     getWidth:function() {
953         return (this.right - this.left);
954     },
955
956     /**
957      * APIMethod: getHeight
958      * Returns the height of the bounds.
959      * 
960      * Returns:
961      * {Float} The height of the bounds (top minus bottom).
962      */
963     getHeight:function() {
964         return (this.top - this.bottom);
965     },
966
967     /**
968      * APIMethod: getSize
969      * Returns an <OpenLayers.Size> object of the bounds.
970      * 
971      * Returns:
972      * {<OpenLayers.Size>} The size of the bounds.
973      */
974     getSize:function() {
975         return new OpenLayers.Size(this.getWidth(), this.getHeight());
976     },
977
978     /**
979      * APIMethod: getCenterPixel
980      * Returns the <OpenLayers.Pixel> object which represents the center of the
981      *     bounds.
982      * 
983      * Returns:
984      * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
985      */
986     getCenterPixel:function() {
987         return new OpenLayers.Pixel( (this.left + this.right) / 2,
988                                      (this.bottom + this.top) / 2);
989     },
990
991     /**
992      * APIMethod: getCenterLonLat
993      * Returns the <OpenLayers.LonLat> object which represents the center of the
994      *     bounds.
995      *
996      * Returns:
997      * {<OpenLayers.LonLat>} The center of the bounds in map space.
998      */
999     getCenterLonLat:function() {
1000         if(!this.centerLonLat) {
1001             this.centerLonLat = new OpenLayers.LonLat(
1002                 (this.left + this.right) / 2, (this.bottom + this.top) / 2
1003             );
1004         }
1005         return this.centerLonLat;
1006     },
1007
1008     /**
1009      * APIMethod: scale
1010      * Scales the bounds around a pixel or lonlat. Note that the new 
1011      *     bounds may return non-integer properties, even if a pixel
1012      *     is passed. 
1013      * 
1014      * Parameters:
1015      * ratio - {Float} 
1016      * origin - {<OpenLayers.Pixel> or <OpenLayers.LonLat>}
1017      *          Default is center.
1018      *
1019      * Returns:
1020      * {<OpenLayers.Bounds>} A new bounds that is scaled by ratio
1021      *                      from origin.
1022      */
1023     scale: function(ratio, origin){
1024         if(origin == null){
1025             origin = this.getCenterLonLat();
1026         }
1027         
1028         var origx,origy;
1029
1030         // get origin coordinates
1031         if(origin.CLASS_NAME == "OpenLayers.LonLat"){
1032             origx = origin.lon;
1033             origy = origin.lat;
1034         } else {
1035             origx = origin.x;
1036             origy = origin.y;
1037         }
1038
1039         var left = (this.left - origx) * ratio + origx;
1040         var bottom = (this.bottom - origy) * ratio + origy;
1041         var right = (this.right - origx) * ratio + origx;
1042         var top = (this.top - origy) * ratio + origy;
1043         
1044         return new OpenLayers.Bounds(left, bottom, right, top);
1045     },
1046
1047     /**
1048      * APIMethod: add
1049      * Shifts the coordinates of the bound by the given horizontal and vertical
1050      *     deltas.
1051      *
1052      * (start code)
1053      * var bounds = new OpenLayers.Bounds(0, 0, 10, 10);
1054      * bounds.toString();
1055      * // => "0,0,10,10"
1056      *
1057      * bounds.add(-1.5, 4).toString();
1058      * // => "-1.5,4,8.5,14"
1059      * (end)
1060      *
1061      * This method will throw a TypeError if it is passed null as an argument.
1062      *
1063      * Parameters:
1064      * x - {Float} horizontal delta
1065      * y - {Float} vertical delta
1066      *
1067      * Returns:
1068      * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
1069      *     this, but shifted by the passed-in x and y values.
1070      */
1071     add:function(x, y) {
1072         if ( (x == null) || (y == null) ) {
1073             throw new TypeError('Bounds.add cannot receive null values');
1074         }
1075         return new OpenLayers.Bounds(this.left + x, this.bottom + y,
1076                                      this.right + x, this.top + y);
1077     },
1078     
1079     /**
1080      * APIMethod: extend
1081      * Extend the bounds to include the <OpenLayers.LonLat>,
1082      *     <OpenLayers.Geometry.Point> or <OpenLayers.Bounds> specified.
1083      *
1084      * Please note that this function assumes that left < right and
1085      *     bottom < top.
1086      *
1087      * Parameters:
1088      * object - {<OpenLayers.LonLat>, <OpenLayers.Geometry.Point> or
1089      *     <OpenLayers.Bounds>} The object to be included in the new bounds
1090      *     object.
1091      */
1092     extend:function(object) {
1093         if (object) {
1094             switch(object.CLASS_NAME) {
1095                 case "OpenLayers.LonLat":
1096                     this.extendXY(object.lon, object.lat);
1097                     break;
1098                 case "OpenLayers.Geometry.Point":
1099                     this.extendXY(object.x, object.y);
1100                     break;
1101
1102                 case "OpenLayers.Bounds":
1103                     // clear cached center location
1104                     this.centerLonLat = null;
1105
1106                     if ( (this.left == null) || (object.left < this.left)) {
1107                         this.left = object.left;
1108                     }
1109                     if ( (this.bottom == null) || (object.bottom < this.bottom) ) {
1110                         this.bottom = object.bottom;
1111                     }
1112                     if ( (this.right == null) || (object.right > this.right) ) {
1113                         this.right = object.right;
1114                     }
1115                     if ( (this.top == null) || (object.top > this.top) ) {
1116                         this.top = object.top;
1117                     }
1118                     break;
1119             }
1120         }
1121     },
1122
1123     /**
1124      * APIMethod: extendXY
1125      * Extend the bounds to include the XY coordinate specified.
1126      *
1127      * Parameters:
1128      * x - {number} The X part of the the coordinate.
1129      * y - {number} The Y part of the the coordinate.
1130      */
1131     extendXY:function(x, y) {
1132         // clear cached center location
1133         this.centerLonLat = null;
1134
1135         if ((this.left == null) || (x < this.left)) {
1136             this.left = x;
1137         }
1138         if ((this.bottom == null) || (y < this.bottom)) {
1139             this.bottom = y;
1140         }
1141         if ((this.right == null) || (x > this.right)) {
1142             this.right = x;
1143         }
1144         if ((this.top == null) || (y > this.top)) {
1145             this.top = y;
1146         }
1147     },
1148
1149     /**
1150      * APIMethod: containsLonLat
1151      * Returns whether the bounds object contains the given <OpenLayers.LonLat>.
1152      * 
1153      * Parameters:
1154      * ll - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
1155      *     object with a 'lon' and 'lat' properties.
1156      * options - {Object} Optional parameters
1157      *
1158      * Acceptable options:
1159      * inclusive - {Boolean} Whether or not to include the border.
1160      *     Default is true.
1161      * worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, the
1162      *     ll will be considered as contained if it exceeds the world bounds,
1163      *     but can be wrapped around the dateline so it is contained by this
1164      *     bounds.
1165      *
1166      * Returns:
1167      * {Boolean} The passed-in lonlat is within this bounds.
1168      */
1169     containsLonLat: function(ll, options) {
1170         if (typeof options === "boolean") {
1171             options =  {inclusive: options};
1172         }
1173         options = options || {};
1174         var contains = this.contains(ll.lon, ll.lat, options.inclusive),
1175             worldBounds = options.worldBounds;
1176         if (worldBounds && !contains) {
1177             var worldWidth = worldBounds.getWidth();
1178             var worldCenterX = (worldBounds.left + worldBounds.right) / 2;
1179             var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth);
1180             contains = this.containsLonLat({
1181                 lon: ll.lon - worldsAway * worldWidth,
1182                 lat: ll.lat
1183             }, {inclusive: options.inclusive});
1184         }
1185         return contains;
1186     },
1187
1188     /**
1189      * APIMethod: containsPixel
1190      * Returns whether the bounds object contains the given <OpenLayers.Pixel>.
1191      * 
1192      * Parameters:
1193      * px - {<OpenLayers.Pixel>}
1194      * inclusive - {Boolean} Whether or not to include the border. Default is
1195      *     true.
1196      *
1197      * Returns:
1198      * {Boolean} The passed-in pixel is within this bounds.
1199      */
1200     containsPixel:function(px, inclusive) {
1201         return this.contains(px.x, px.y, inclusive);
1202     },
1203     
1204     /**
1205      * APIMethod: contains
1206      * Returns whether the bounds object contains the given x and y.
1207      * 
1208      * Parameters:
1209      * x - {Float}
1210      * y - {Float}
1211      * inclusive - {Boolean} Whether or not to include the border. Default is
1212      *     true.
1213      *
1214      * Returns:
1215      * {Boolean} Whether or not the passed-in coordinates are within this
1216      *     bounds.
1217      */
1218     contains:function(x, y, inclusive) {
1219         //set default
1220         if (inclusive == null) {
1221             inclusive = true;
1222         }
1223
1224         if (x == null || y == null) {
1225             return false;
1226         }
1227
1228         x = OpenLayers.Util.toFloat(x);
1229         y = OpenLayers.Util.toFloat(y);
1230
1231         var contains = false;
1232         if (inclusive) {
1233             contains = ((x >= this.left) && (x <= this.right) && 
1234                         (y >= this.bottom) && (y <= this.top));
1235         } else {
1236             contains = ((x > this.left) && (x < this.right) && 
1237                         (y > this.bottom) && (y < this.top));
1238         }              
1239         return contains;
1240     },
1241
1242     /**
1243      * APIMethod: intersectsBounds
1244      * Determine whether the target bounds intersects this bounds.  Bounds are
1245      *     considered intersecting if any of their edges intersect or if one
1246      *     bounds contains the other.
1247      * 
1248      * Parameters:
1249      * bounds - {<OpenLayers.Bounds>} The target bounds.
1250      * options - {Object} Optional parameters.
1251      * 
1252      * Acceptable options:
1253      * inclusive - {Boolean} Treat coincident borders as intersecting.  Default
1254      *     is true.  If false, bounds that do not overlap but only touch at the
1255      *     border will not be considered as intersecting.
1256      * worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, two
1257      *     bounds will be considered as intersecting if they intersect when 
1258      *     shifted to within the world bounds.  This applies only to bounds that
1259      *     cross or are completely outside the world bounds.
1260      *
1261      * Returns:
1262      * {Boolean} The passed-in bounds object intersects this bounds.
1263      */
1264     intersectsBounds:function(bounds, options) {
1265         if (typeof options === "boolean") {
1266             options =  {inclusive: options};
1267         }
1268         options = options || {};
1269         if (options.worldBounds) {
1270             var self = this.wrapDateLine(options.worldBounds);
1271             bounds = bounds.wrapDateLine(options.worldBounds);
1272         } else {
1273             self = this;
1274         }
1275         if (options.inclusive == null) {
1276             options.inclusive = true;
1277         }
1278         var intersects = false;
1279         var mightTouch = (
1280             self.left == bounds.right ||
1281             self.right == bounds.left ||
1282             self.top == bounds.bottom ||
1283             self.bottom == bounds.top
1284         );
1285         
1286         // if the two bounds only touch at an edge, and inclusive is false,
1287         // then the bounds don't *really* intersect.
1288         if (options.inclusive || !mightTouch) {
1289             // otherwise, if one of the boundaries even partially contains another,
1290             // inclusive of the edges, then they do intersect.
1291             var inBottom = (
1292                 ((bounds.bottom >= self.bottom) && (bounds.bottom <= self.top)) ||
1293                 ((self.bottom >= bounds.bottom) && (self.bottom <= bounds.top))
1294             );
1295             var inTop = (
1296                 ((bounds.top >= self.bottom) && (bounds.top <= self.top)) ||
1297                 ((self.top > bounds.bottom) && (self.top < bounds.top))
1298             );
1299             var inLeft = (
1300                 ((bounds.left >= self.left) && (bounds.left <= self.right)) ||
1301                 ((self.left >= bounds.left) && (self.left <= bounds.right))
1302             );
1303             var inRight = (
1304                 ((bounds.right >= self.left) && (bounds.right <= self.right)) ||
1305                 ((self.right >= bounds.left) && (self.right <= bounds.right))
1306             );
1307             intersects = ((inBottom || inTop) && (inLeft || inRight));
1308         }
1309         // document me
1310         if (options.worldBounds && !intersects) {
1311             var world = options.worldBounds;
1312             var width = world.getWidth();
1313             var selfCrosses = !world.containsBounds(self);
1314             var boundsCrosses = !world.containsBounds(bounds);
1315             if (selfCrosses && !boundsCrosses) {
1316                 bounds = bounds.add(-width, 0);
1317                 intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive});
1318             } else if (boundsCrosses && !selfCrosses) {
1319                 self = self.add(-width, 0);
1320                 intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive});                
1321             }
1322         }
1323         return intersects;
1324     },
1325     
1326     /**
1327      * APIMethod: containsBounds
1328      * Returns whether the bounds object contains the given <OpenLayers.Bounds>.
1329      * 
1330      * bounds - {<OpenLayers.Bounds>} The target bounds.
1331      * partial - {Boolean} If any of the target corners is within this bounds
1332      *     consider the bounds contained.  Default is false.  If false, the
1333      *     entire target bounds must be contained within this bounds.
1334      * inclusive - {Boolean} Treat shared edges as contained.  Default is
1335      *     true.
1336      *
1337      * Returns:
1338      * {Boolean} The passed-in bounds object is contained within this bounds. 
1339      */
1340     containsBounds:function(bounds, partial, inclusive) {
1341         if (partial == null) {
1342             partial = false;
1343         }
1344         if (inclusive == null) {
1345             inclusive = true;
1346         }
1347         var bottomLeft  = this.contains(bounds.left, bounds.bottom, inclusive);
1348         var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
1349         var topLeft  = this.contains(bounds.left, bounds.top, inclusive);
1350         var topRight = this.contains(bounds.right, bounds.top, inclusive);
1351         
1352         return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
1353                          : (bottomLeft && bottomRight && topLeft && topRight);
1354     },
1355
1356     /** 
1357      * APIMethod: determineQuadrant
1358      * Returns the the quadrant ("br", "tr", "tl", "bl") in which the given
1359      *     <OpenLayers.LonLat> lies.
1360      *
1361      * Parameters:
1362      * lonlat - {<OpenLayers.LonLat>}
1363      *
1364      * Returns:
1365      * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
1366      *     coordinate lies.
1367      */
1368     determineQuadrant: function(lonlat) {
1369     
1370         var quadrant = "";
1371         var center = this.getCenterLonLat();
1372         
1373         quadrant += (lonlat.lat < center.lat) ? "b" : "t";
1374         quadrant += (lonlat.lon < center.lon) ? "l" : "r";
1375     
1376         return quadrant; 
1377     },
1378     
1379     /**
1380      * APIMethod: transform
1381      * Transform the Bounds object from source to dest. 
1382      *
1383      * Parameters: 
1384      * source - {<OpenLayers.Projection>} Source projection. 
1385      * dest   - {<OpenLayers.Projection>} Destination projection. 
1386      *
1387      * Returns:
1388      * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
1389      */
1390     transform: function(source, dest) {
1391         // clear cached center location
1392         this.centerLonLat = null;
1393         var ll = OpenLayers.Projection.transform(
1394             {'x': this.left, 'y': this.bottom}, source, dest);
1395         var lr = OpenLayers.Projection.transform(
1396             {'x': this.right, 'y': this.bottom}, source, dest);
1397         var ul = OpenLayers.Projection.transform(
1398             {'x': this.left, 'y': this.top}, source, dest);
1399         var ur = OpenLayers.Projection.transform(
1400             {'x': this.right, 'y': this.top}, source, dest);
1401         this.left   = Math.min(ll.x, ul.x);
1402         this.bottom = Math.min(ll.y, lr.y);
1403         this.right  = Math.max(lr.x, ur.x);
1404         this.top    = Math.max(ul.y, ur.y);
1405         return this;
1406     },
1407
1408     /**
1409      * APIMethod: wrapDateLine
1410      * Wraps the bounds object around the dateline.
1411      *  
1412      * Parameters:
1413      * maxExtent - {<OpenLayers.Bounds>}
1414      * options - {Object} Some possible options are:
1415      *
1416      * Allowed Options:
1417      *                    leftTolerance - {float} Allow for a margin of error 
1418      *                                            with the 'left' value of this 
1419      *                                            bound.
1420      *                                            Default is 0.
1421      *                    rightTolerance - {float} Allow for a margin of error 
1422      *                                             with the 'right' value of 
1423      *                                             this bound.
1424      *                                             Default is 0.
1425      * 
1426      * Returns:
1427      * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the 
1428      *                       "dateline" (as specified by the borders of 
1429      *                       maxExtent). Note that this function only returns 
1430      *                       a different bounds value if this bounds is 
1431      *                       *entirely* outside of the maxExtent. If this 
1432      *                       bounds straddles the dateline (is part in/part 
1433      *                       out of maxExtent), the returned bounds will always 
1434      *                       cross the left edge of the given maxExtent.
1435      *.
1436      */
1437     wrapDateLine: function(maxExtent, options) {    
1438         options = options || {};
1439         
1440         var leftTolerance = options.leftTolerance || 0;
1441         var rightTolerance = options.rightTolerance || 0;
1442
1443         var newBounds = this.clone();
1444     
1445         if (maxExtent) {
1446             var width = maxExtent.getWidth();
1447
1448             //shift right?
1449             while (newBounds.left < maxExtent.left && 
1450                    newBounds.right - rightTolerance <= maxExtent.left ) { 
1451                 newBounds = newBounds.add(width, 0);
1452             }
1453
1454             //shift left?
1455             while (newBounds.left + leftTolerance >= maxExtent.right && 
1456                    newBounds.right > maxExtent.right ) { 
1457                 newBounds = newBounds.add(-width, 0);
1458             }
1459            
1460             // crosses right only? force left
1461             var newLeft = newBounds.left + leftTolerance;
1462             if (newLeft < maxExtent.right && newLeft > maxExtent.left && 
1463                    newBounds.right - rightTolerance > maxExtent.right) {
1464                 newBounds = newBounds.add(-width, 0);
1465             }
1466         }
1467                 
1468         return newBounds;
1469     },
1470
1471     CLASS_NAME: "OpenLayers.Bounds"
1472 });
1473
1474 /** 
1475  * APIFunction: fromString
1476  * Alternative constructor that builds a new OpenLayers.Bounds from a 
1477  *     parameter string.
1478  *
1479  * (begin code)
1480  * OpenLayers.Bounds.fromString("5,42,10,45");
1481  * // => equivalent to ...
1482  * new OpenLayers.Bounds(5, 42, 10, 45);
1483  * (end)
1484  *
1485  * Parameters: 
1486  * str - {String} Comma-separated bounds string. (e.g. "5,42,10,45")
1487  * reverseAxisOrder - {Boolean} Does the string use reverse axis order?
1488  *
1489  * Returns:
1490  * {<OpenLayers.Bounds>} New bounds object built from the 
1491  *                       passed-in String.
1492  */
1493 OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
1494     var bounds = str.split(",");
1495     return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
1496 };
1497
1498 /** 
1499  * APIFunction: fromArray
1500  * Alternative constructor that builds a new OpenLayers.Bounds from an array.
1501  *
1502  * (begin code)
1503  * OpenLayers.Bounds.fromArray( [5, 42, 10, 45] );
1504  * // => equivalent to ...
1505  * new OpenLayers.Bounds(5, 42, 10, 45);
1506  * (end)
1507  *
1508  * Parameters:
1509  * bbox - {Array(Float)} Array of bounds values (e.g. [5,42,10,45])
1510  * reverseAxisOrder - {Boolean} Does the array use reverse axis order?
1511  *
1512  * Returns:
1513  * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
1514  */
1515 OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
1516     return reverseAxisOrder === true ?
1517            new OpenLayers.Bounds(bbox[1], bbox[0], bbox[3], bbox[2]) :
1518            new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]);
1519 };
1520
1521 /** 
1522  * APIFunction: fromSize
1523  * Alternative constructor that builds a new OpenLayers.Bounds from a size.
1524  *
1525  * (begin code)
1526  * OpenLayers.Bounds.fromSize( new OpenLayers.Size(10, 20) );
1527  * // => equivalent to ...
1528  * new OpenLayers.Bounds(0, 20, 10, 0);
1529  * (end)
1530  *
1531  * Parameters:
1532  * size - {<OpenLayers.Size> or Object} <OpenLayers.Size> or an object with
1533  *     both 'w' and 'h' properties.
1534  *
1535  * Returns:
1536  * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
1537  */
1538 OpenLayers.Bounds.fromSize = function(size) {
1539     return new OpenLayers.Bounds(0,
1540                                  size.h,
1541                                  size.w,
1542                                  0);
1543 };
1544
1545 /**
1546  * Function: oppositeQuadrant
1547  * Get the opposite quadrant for a given quadrant string.
1548  *
1549  * (begin code)
1550  * OpenLayers.Bounds.oppositeQuadrant( "tl" );
1551  * // => "br"
1552  *
1553  * OpenLayers.Bounds.oppositeQuadrant( "tr" );
1554  * // => "bl"
1555  * (end)
1556  *
1557  * Parameters:
1558  * quadrant - {String} two character quadrant shortstring
1559  *
1560  * Returns:
1561  * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if 
1562  *          you pass in "bl" it returns "tr", if you pass in "br" it 
1563  *          returns "tl", etc.
1564  */
1565 OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
1566     var opp = "";
1567     
1568     opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
1569     opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
1570     
1571     return opp;
1572 };
1573 /* ======================================================================
1574     OpenLayers/BaseTypes/Element.js
1575    ====================================================================== */
1576
1577 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
1578  * full list of contributors). Published under the 2-clause BSD license.
1579  * See license.txt in the OpenLayers distribution or repository for the
1580  * full text of the license. */
1581
1582 /**
1583  * @requires OpenLayers/Util.js
1584  * @requires OpenLayers/BaseTypes.js
1585  */
1586
1587 /**
1588  * Namespace: OpenLayers.Element
1589  */
1590 OpenLayers.Element = {
1591
1592     /**
1593      * APIFunction: visible
1594      * 
1595      * Parameters: 
1596      * element - {DOMElement}
1597      * 
1598      * Returns:
1599      * {Boolean} Is the element visible?
1600      */
1601     visible: function(element) {
1602         return OpenLayers.Util.getElement(element).style.display != 'none';
1603     },
1604
1605     /**
1606      * APIFunction: toggle
1607      * Toggle the visibility of element(s) passed in
1608      * 
1609      * Parameters:
1610      * element - {DOMElement} Actually user can pass any number of elements
1611      */
1612     toggle: function() {
1613         for (var i=0, len=arguments.length; i<len; i++) {
1614             var element = OpenLayers.Util.getElement(arguments[i]);
1615             var display = OpenLayers.Element.visible(element) ? 'none' 
1616                                                               : '';
1617             element.style.display = display;
1618         }
1619     },
1620
1621     /**
1622      * APIFunction: remove
1623      * Remove the specified element from the DOM.
1624      * 
1625      * Parameters:
1626      * element - {DOMElement}
1627      */
1628     remove: function(element) {
1629         element = OpenLayers.Util.getElement(element);
1630         element.parentNode.removeChild(element);
1631     },
1632
1633     /**
1634      * APIFunction: getHeight
1635      *  
1636      * Parameters:
1637      * element - {DOMElement}
1638      * 
1639      * Returns:
1640      * {Integer} The offset height of the element passed in
1641      */
1642     getHeight: function(element) {
1643         element = OpenLayers.Util.getElement(element);
1644         return element.offsetHeight;
1645     },
1646
1647     /**
1648      * Function: hasClass
1649      * Tests if an element has the given CSS class name.
1650      *
1651      * Parameters:
1652      * element - {DOMElement} A DOM element node.
1653      * name - {String} The CSS class name to search for.
1654      *
1655      * Returns:
1656      * {Boolean} The element has the given class name.
1657      */
1658     hasClass: function(element, name) {
1659         var names = element.className;
1660         return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names));
1661     },
1662     
1663     /**
1664      * Function: addClass
1665      * Add a CSS class name to an element.  Safe where element already has
1666      *     the class name.
1667      *
1668      * Parameters:
1669      * element - {DOMElement} A DOM element node.
1670      * name - {String} The CSS class name to add.
1671      *
1672      * Returns:
1673      * {DOMElement} The element.
1674      */
1675     addClass: function(element, name) {
1676         if(!OpenLayers.Element.hasClass(element, name)) {
1677             element.className += (element.className ? " " : "") + name;
1678         }
1679         return element;
1680     },
1681
1682     /**
1683      * Function: removeClass
1684      * Remove a CSS class name from an element.  Safe where element does not
1685      *     have the class name.
1686      *
1687      * Parameters:
1688      * element - {DOMElement} A DOM element node.
1689      * name - {String} The CSS class name to remove.
1690      *
1691      * Returns:
1692      * {DOMElement} The element.
1693      */
1694     removeClass: function(element, name) {
1695         var names = element.className;
1696         if(names) {
1697             element.className = OpenLayers.String.trim(
1698                 names.replace(
1699                     new RegExp("(^|\\s+)" + name + "(\\s+|$)"), " "
1700                 )
1701             );
1702         }
1703         return element;
1704     },
1705
1706     /**
1707      * Function: toggleClass
1708      * Remove a CSS class name from an element if it exists.  Add the class name
1709      *     if it doesn't exist.
1710      *
1711      * Parameters:
1712      * element - {DOMElement} A DOM element node.
1713      * name - {String} The CSS class name to toggle.
1714      *
1715      * Returns:
1716      * {DOMElement} The element.
1717      */
1718     toggleClass: function(element, name) {
1719         if(OpenLayers.Element.hasClass(element, name)) {
1720             OpenLayers.Element.removeClass(element, name);
1721         } else {
1722             OpenLayers.Element.addClass(element, name);
1723         }
1724         return element;
1725     },
1726
1727     /**
1728      * APIFunction: getStyle
1729      * 
1730      * Parameters:
1731      * element - {DOMElement}
1732      * style - {?}
1733      * 
1734      * Returns:
1735      * {?}
1736      */
1737     getStyle: function(element, style) {
1738         element = OpenLayers.Util.getElement(element);
1739
1740         var value = null;
1741         if (element && element.style) {
1742             value = element.style[OpenLayers.String.camelize(style)];
1743             if (!value) {
1744                 if (document.defaultView && 
1745                     document.defaultView.getComputedStyle) {
1746                     
1747                     var css = document.defaultView.getComputedStyle(element, null);
1748                     value = css ? css.getPropertyValue(style) : null;
1749                 } else if (element.currentStyle) {
1750                     value = element.currentStyle[OpenLayers.String.camelize(style)];
1751                 }
1752             }
1753         
1754             var positions = ['left', 'top', 'right', 'bottom'];
1755             if (window.opera &&
1756                 (OpenLayers.Util.indexOf(positions,style) != -1) &&
1757                 (OpenLayers.Element.getStyle(element, 'position') == 'static')) { 
1758                 value = 'auto';
1759             }
1760         }
1761     
1762         return value == 'auto' ? null : value;
1763     }
1764
1765 };
1766 /* ======================================================================
1767     OpenLayers/BaseTypes/LonLat.js
1768    ====================================================================== */
1769
1770 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
1771  * full list of contributors). Published under the 2-clause BSD license.
1772  * See license.txt in the OpenLayers distribution or repository for the
1773  * full text of the license. */
1774
1775 /**
1776  * @requires OpenLayers/BaseTypes/Class.js
1777  */
1778
1779 /**
1780  * Class: OpenLayers.LonLat
1781  * This class represents a longitude and latitude pair
1782  */
1783 OpenLayers.LonLat = OpenLayers.Class({
1784
1785     /** 
1786      * APIProperty: lon
1787      * {Float} The x-axis coodinate in map units
1788      */
1789     lon: 0.0,
1790     
1791     /** 
1792      * APIProperty: lat
1793      * {Float} The y-axis coordinate in map units
1794      */
1795     lat: 0.0,
1796
1797     /**
1798      * Constructor: OpenLayers.LonLat
1799      * Create a new map location. Coordinates can be passed either as two
1800      * arguments, or as a single argument.
1801      *
1802      * Parameters (two arguments):
1803      * lon - {Number} The x-axis coordinate in map units.  If your map is in
1804      *     a geographic projection, this will be the Longitude.  Otherwise,
1805      *     it will be the x coordinate of the map location in your map units.
1806      * lat - {Number} The y-axis coordinate in map units.  If your map is in
1807      *     a geographic projection, this will be the Latitude.  Otherwise,
1808      *     it will be the y coordinate of the map location in your map units.
1809      *
1810      * Parameters (single argument):
1811      * location - {Array(Float)} [lon, lat]
1812      */
1813     initialize: function(lon, lat) {
1814         if (OpenLayers.Util.isArray(lon)) {
1815             lat = lon[1];
1816             lon = lon[0];
1817         }
1818         this.lon = OpenLayers.Util.toFloat(lon);
1819         this.lat = OpenLayers.Util.toFloat(lat);
1820     },
1821     
1822     /**
1823      * Method: toString
1824      * Return a readable string version of the lonlat
1825      *
1826      * Returns:
1827      * {String} String representation of OpenLayers.LonLat object. 
1828      *           (e.g. <i>"lon=5,lat=42"</i>)
1829      */
1830     toString:function() {
1831         return ("lon=" + this.lon + ",lat=" + this.lat);
1832     },
1833
1834     /** 
1835      * APIMethod: toShortString
1836      * 
1837      * Returns:
1838      * {String} Shortened String representation of OpenLayers.LonLat object. 
1839      *         (e.g. <i>"5, 42"</i>)
1840      */
1841     toShortString:function() {
1842         return (this.lon + ", " + this.lat);
1843     },
1844
1845     /** 
1846      * APIMethod: clone
1847      * 
1848      * Returns:
1849      * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon 
1850      *                       and lat values
1851      */
1852     clone:function() {
1853         return new OpenLayers.LonLat(this.lon, this.lat);
1854     },
1855
1856     /** 
1857      * APIMethod: add
1858      * 
1859      * Parameters:
1860      * lon - {Float}
1861      * lat - {Float}
1862      * 
1863      * Returns:
1864      * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and 
1865      *                       lat passed-in added to this's. 
1866      */
1867     add:function(lon, lat) {
1868         if ( (lon == null) || (lat == null) ) {
1869             throw new TypeError('LonLat.add cannot receive null values');
1870         }
1871         return new OpenLayers.LonLat(this.lon + OpenLayers.Util.toFloat(lon), 
1872                                      this.lat + OpenLayers.Util.toFloat(lat));
1873     },
1874
1875     /** 
1876      * APIMethod: equals
1877      * 
1878      * Parameters:
1879      * ll - {<OpenLayers.LonLat>}
1880      * 
1881      * Returns:
1882      * {Boolean} Boolean value indicating whether the passed-in 
1883      *           <OpenLayers.LonLat> object has the same lon and lat 
1884      *           components as this.
1885      *           Note: if ll passed in is null, returns false
1886      */
1887     equals:function(ll) {
1888         var equals = false;
1889         if (ll != null) {
1890             equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
1891                       (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
1892         }
1893         return equals;
1894     },
1895
1896     /**
1897      * APIMethod: transform
1898      * Transform the LonLat object from source to dest. This transformation is
1899      *    *in place*: if you want a *new* lonlat, use .clone() first.
1900      *
1901      * Parameters: 
1902      * source - {<OpenLayers.Projection>} Source projection. 
1903      * dest   - {<OpenLayers.Projection>} Destination projection. 
1904      *
1905      * Returns:
1906      * {<OpenLayers.LonLat>} Itself, for use in chaining operations.
1907      */
1908     transform: function(source, dest) {
1909         var point = OpenLayers.Projection.transform(
1910             {'x': this.lon, 'y': this.lat}, source, dest);
1911         this.lon = point.x;
1912         this.lat = point.y;
1913         return this;
1914     },
1915     
1916     /**
1917      * APIMethod: wrapDateLine
1918      * 
1919      * Parameters:
1920      * maxExtent - {<OpenLayers.Bounds>}
1921      * 
1922      * Returns:
1923      * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the 
1924      *                       "dateline" (as specified by the borders of 
1925      *                       maxExtent)
1926      */
1927     wrapDateLine: function(maxExtent) {    
1928
1929         var newLonLat = this.clone();
1930     
1931         if (maxExtent) {
1932             //shift right?
1933             while (newLonLat.lon < maxExtent.left) {
1934                 newLonLat.lon +=  maxExtent.getWidth();
1935             }    
1936            
1937             //shift left?
1938             while (newLonLat.lon > maxExtent.right) {
1939                 newLonLat.lon -= maxExtent.getWidth();
1940             }    
1941         }
1942                 
1943         return newLonLat;
1944     },
1945
1946     CLASS_NAME: "OpenLayers.LonLat"
1947 });
1948
1949 /** 
1950  * Function: fromString
1951  * Alternative constructor that builds a new <OpenLayers.LonLat> from a 
1952  *     parameter string
1953  * 
1954  * Parameters:
1955  * str - {String} Comma-separated Lon,Lat coordinate string. 
1956  *                 (e.g. <i>"5,40"</i>)
1957  * 
1958  * Returns:
1959  * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
1960  *                       passed-in String.
1961  */
1962 OpenLayers.LonLat.fromString = function(str) {
1963     var pair = str.split(",");
1964     return new OpenLayers.LonLat(pair[0], pair[1]);
1965 };
1966
1967 /** 
1968  * Function: fromArray
1969  * Alternative constructor that builds a new <OpenLayers.LonLat> from an 
1970  *     array of two numbers that represent lon- and lat-values.
1971  * 
1972  * Parameters:
1973  * arr - {Array(Float)} Array of lon/lat values (e.g. [5,-42])
1974  * 
1975  * Returns:
1976  * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
1977  *                       passed-in array.
1978  */
1979 OpenLayers.LonLat.fromArray = function(arr) {
1980     var gotArr = OpenLayers.Util.isArray(arr),
1981         lon = gotArr && arr[0],
1982         lat = gotArr && arr[1];
1983     return new OpenLayers.LonLat(lon, lat);
1984 };
1985 /* ======================================================================
1986     OpenLayers/BaseTypes/Pixel.js
1987    ====================================================================== */
1988
1989 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
1990  * full list of contributors). Published under the 2-clause BSD license.
1991  * See license.txt in the OpenLayers distribution or repository for the
1992  * full text of the license. */
1993
1994 /**
1995  * @requires OpenLayers/BaseTypes/Class.js
1996  */
1997
1998 /**
1999  * Class: OpenLayers.Pixel
2000  * This class represents a screen coordinate, in x and y coordinates
2001  */
2002 OpenLayers.Pixel = OpenLayers.Class({
2003     
2004     /**
2005      * APIProperty: x
2006      * {Number} The x coordinate
2007      */
2008     x: 0.0,
2009
2010     /**
2011      * APIProperty: y
2012      * {Number} The y coordinate
2013      */
2014     y: 0.0,
2015     
2016     /**
2017      * Constructor: OpenLayers.Pixel
2018      * Create a new OpenLayers.Pixel instance
2019      *
2020      * Parameters:
2021      * x - {Number} The x coordinate
2022      * y - {Number} The y coordinate
2023      *
2024      * Returns:
2025      * An instance of OpenLayers.Pixel
2026      */
2027     initialize: function(x, y) {
2028         this.x = parseFloat(x);
2029         this.y = parseFloat(y);
2030     },
2031     
2032     /**
2033      * Method: toString
2034      * Cast this object into a string
2035      *
2036      * Returns:
2037      * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
2038      */
2039     toString:function() {
2040         return ("x=" + this.x + ",y=" + this.y);
2041     },
2042
2043     /**
2044      * APIMethod: clone
2045      * Return a clone of this pixel object
2046      *
2047      * Returns:
2048      * {<OpenLayers.Pixel>} A clone pixel
2049      */
2050     clone:function() {
2051         return new OpenLayers.Pixel(this.x, this.y); 
2052     },
2053     
2054     /**
2055      * APIMethod: equals
2056      * Determine whether one pixel is equivalent to another
2057      *
2058      * Parameters:
2059      * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
2060      *                                  a 'x' and 'y' properties.
2061      *
2062      * Returns:
2063      * {Boolean} The point passed in as parameter is equal to this. Note that
2064      * if px passed in is null, returns false.
2065      */
2066     equals:function(px) {
2067         var equals = false;
2068         if (px != null) {
2069             equals = ((this.x == px.x && this.y == px.y) ||
2070                       (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
2071         }
2072         return equals;
2073     },
2074
2075     /**
2076      * APIMethod: distanceTo
2077      * Returns the distance to the pixel point passed in as a parameter.
2078      *
2079      * Parameters:
2080      * px - {<OpenLayers.Pixel>}
2081      *
2082      * Returns:
2083      * {Float} The pixel point passed in as parameter to calculate the
2084      *     distance to.
2085      */
2086     distanceTo:function(px) {
2087         return Math.sqrt(
2088             Math.pow(this.x - px.x, 2) +
2089             Math.pow(this.y - px.y, 2)
2090         );
2091     },
2092
2093     /**
2094      * APIMethod: add
2095      *
2096      * Parameters:
2097      * x - {Integer}
2098      * y - {Integer}
2099      *
2100      * Returns:
2101      * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
2102      * values passed in.
2103      */
2104     add:function(x, y) {
2105         if ( (x == null) || (y == null) ) {
2106             throw new TypeError('Pixel.add cannot receive null values');
2107         }
2108         return new OpenLayers.Pixel(this.x + x, this.y + y);
2109     },
2110
2111     /**
2112     * APIMethod: offset
2113     * 
2114     * Parameters
2115     * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
2116     *                                  a 'x' and 'y' properties.
2117     * 
2118     * Returns:
2119     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
2120     *                      x&y values of the pixel passed in.
2121     */
2122     offset:function(px) {
2123         var newPx = this.clone();
2124         if (px) {
2125             newPx = this.add(px.x, px.y);
2126         }
2127         return newPx;
2128     },
2129
2130     CLASS_NAME: "OpenLayers.Pixel"
2131 });
2132 /* ======================================================================
2133     OpenLayers/BaseTypes/Size.js
2134    ====================================================================== */
2135
2136 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2137  * full list of contributors). Published under the 2-clause BSD license.
2138  * See license.txt in the OpenLayers distribution or repository for the
2139  * full text of the license. */
2140
2141 /**
2142  * @requires OpenLayers/BaseTypes/Class.js
2143  */
2144
2145 /**
2146  * Class: OpenLayers.Size
2147  * Instances of this class represent a width/height pair
2148  */
2149 OpenLayers.Size = OpenLayers.Class({
2150
2151     /**
2152      * APIProperty: w
2153      * {Number} width
2154      */
2155     w: 0.0,
2156     
2157     /**
2158      * APIProperty: h
2159      * {Number} height
2160      */
2161     h: 0.0,
2162
2163
2164     /**
2165      * Constructor: OpenLayers.Size
2166      * Create an instance of OpenLayers.Size
2167      *
2168      * Parameters:
2169      * w - {Number} width
2170      * h - {Number} height
2171      */
2172     initialize: function(w, h) {
2173         this.w = parseFloat(w);
2174         this.h = parseFloat(h);
2175     },
2176
2177     /**
2178      * Method: toString
2179      * Return the string representation of a size object
2180      *
2181      * Returns:
2182      * {String} The string representation of OpenLayers.Size object. 
2183      * (e.g. <i>"w=55,h=66"</i>)
2184      */
2185     toString:function() {
2186         return ("w=" + this.w + ",h=" + this.h);
2187     },
2188
2189     /**
2190      * APIMethod: clone
2191      * Create a clone of this size object
2192      *
2193      * Returns:
2194      * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
2195      * values
2196      */
2197     clone:function() {
2198         return new OpenLayers.Size(this.w, this.h);
2199     },
2200
2201     /**
2202      *
2203      * APIMethod: equals
2204      * Determine where this size is equal to another
2205      *
2206      * Parameters:
2207      * sz - {<OpenLayers.Size>|Object} An OpenLayers.Size or an object with
2208      *                                  a 'w' and 'h' properties.
2209      *
2210      * Returns: 
2211      * {Boolean} The passed in size has the same h and w properties as this one.
2212      * Note that if sz passed in is null, returns false.
2213      */
2214     equals:function(sz) {
2215         var equals = false;
2216         if (sz != null) {
2217             equals = ((this.w == sz.w && this.h == sz.h) ||
2218                       (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
2219         }
2220         return equals;
2221     },
2222
2223     CLASS_NAME: "OpenLayers.Size"
2224 });
2225 /* ======================================================================
2226     OpenLayers/Console.js
2227    ====================================================================== */
2228
2229 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2230  * full list of contributors). Published under the 2-clause BSD license.
2231  * See license.txt in the OpenLayers distribution or repository for the
2232  * full text of the license. */
2233
2234 /**
2235  * @requires OpenLayers/BaseTypes/Class.js
2236  */
2237
2238 /**
2239  * Namespace: OpenLayers.Console
2240  * The OpenLayers.Console namespace is used for debugging and error logging.
2241  * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
2242  * calls to OpenLayers.Console methods will get redirected to window.console.
2243  * This makes use of the Firebug extension where available and allows for
2244  * cross-browser debugging Firebug style.
2245  *
2246  * Note:
2247  * Note that behavior will differ with the Firebug extention and Firebug Lite.
2248  * Most notably, the Firebug Lite console does not currently allow for
2249  * hyperlinks to code or for clicking on object to explore their properties.
2250  * 
2251  */
2252 OpenLayers.Console = {
2253     /**
2254      * Create empty functions for all console methods.  The real value of these
2255      * properties will be set if Firebug Lite (../Firebug/firebug.js script) is
2256      * included.  We explicitly require the Firebug Lite script to trigger
2257      * functionality of the OpenLayers.Console methods.
2258      */
2259     
2260     /**
2261      * APIFunction: log
2262      * Log an object in the console.  The Firebug Lite console logs string
2263      * representation of objects.  Given multiple arguments, they will
2264      * be cast to strings and logged with a space delimiter.  If the first
2265      * argument is a string with printf-like formatting, subsequent arguments
2266      * will be used in string substitution.  Any additional arguments (beyond
2267      * the number substituted in a format string) will be appended in a space-
2268      * delimited line.
2269      * 
2270      * Parameters:
2271      * object - {Object}
2272      */
2273     log: function() {},
2274
2275     /**
2276      * APIFunction: debug
2277      * Writes a message to the console, including a hyperlink to the line
2278      * where it was called.
2279      *
2280      * May be called with multiple arguments as with OpenLayers.Console.log().
2281      * 
2282      * Parameters:
2283      * object - {Object}
2284      */
2285     debug: function() {},
2286
2287     /**
2288      * APIFunction: info
2289      * Writes a message to the console with the visual "info" icon and color
2290      * coding and a hyperlink to the line where it was called.
2291      *
2292      * May be called with multiple arguments as with OpenLayers.Console.log().
2293      * 
2294      * Parameters:
2295      * object - {Object}
2296      */
2297     info: function() {},
2298
2299     /**
2300      * APIFunction: warn
2301      * Writes a message to the console with the visual "warning" icon and
2302      * color coding and a hyperlink to the line where it was called.
2303      *
2304      * May be called with multiple arguments as with OpenLayers.Console.log().
2305      * 
2306      * Parameters:
2307      * object - {Object}
2308      */
2309     warn: function() {},
2310
2311     /**
2312      * APIFunction: error
2313      * Writes a message to the console with the visual "error" icon and color
2314      * coding and a hyperlink to the line where it was called.
2315      *
2316      * May be called with multiple arguments as with OpenLayers.Console.log().
2317      * 
2318      * Parameters:
2319      * object - {Object}
2320      */
2321     error: function() {},
2322     
2323     /**
2324      * APIFunction: userError
2325      * A single interface for showing error messages to the user. The default
2326      * behavior is a Javascript alert, though this can be overridden by
2327      * reassigning OpenLayers.Console.userError to a different function.
2328      *
2329      * Expects a single error message
2330      * 
2331      * Parameters:
2332      * error - {Object}
2333      */
2334     userError: function(error) {
2335         alert(error);
2336     },
2337
2338     /**
2339      * APIFunction: assert
2340      * Tests that an expression is true. If not, it will write a message to
2341      * the console and throw an exception.
2342      *
2343      * May be called with multiple arguments as with OpenLayers.Console.log().
2344      * 
2345      * Parameters:
2346      * object - {Object}
2347      */
2348     assert: function() {},
2349
2350     /**
2351      * APIFunction: dir
2352      * Prints an interactive listing of all properties of the object. This
2353      * looks identical to the view that you would see in the DOM tab.
2354      * 
2355      * Parameters:
2356      * object - {Object}
2357      */
2358     dir: function() {},
2359
2360     /**
2361      * APIFunction: dirxml
2362      * Prints the XML source tree of an HTML or XML element. This looks
2363      * identical to the view that you would see in the HTML tab. You can click
2364      * on any node to inspect it in the HTML tab.
2365      * 
2366      * Parameters:
2367      * object - {Object}
2368      */
2369     dirxml: function() {},
2370
2371     /**
2372      * APIFunction: trace
2373      * Prints an interactive stack trace of JavaScript execution at the point
2374      * where it is called.  The stack trace details the functions on the stack,
2375      * as well as the values that were passed as arguments to each function.
2376      * You can click each function to take you to its source in the Script tab,
2377      * and click each argument value to inspect it in the DOM or HTML tabs.
2378      * 
2379      */
2380     trace: function() {},
2381
2382     /**
2383      * APIFunction: group
2384      * Writes a message to the console and opens a nested block to indent all
2385      * future messages sent to the console. Call OpenLayers.Console.groupEnd()
2386      * to close the block.
2387      *
2388      * May be called with multiple arguments as with OpenLayers.Console.log().
2389      * 
2390      * Parameters:
2391      * object - {Object}
2392      */
2393     group: function() {},
2394
2395     /**
2396      * APIFunction: groupEnd
2397      * Closes the most recently opened block created by a call to
2398      * OpenLayers.Console.group
2399      */
2400     groupEnd: function() {},
2401     
2402     /**
2403      * APIFunction: time
2404      * Creates a new timer under the given name. Call
2405      * OpenLayers.Console.timeEnd(name)
2406      * with the same name to stop the timer and print the time elapsed.
2407      *
2408      * Parameters:
2409      * name - {String}
2410      */
2411     time: function() {},
2412
2413     /**
2414      * APIFunction: timeEnd
2415      * Stops a timer created by a call to OpenLayers.Console.time(name) and
2416      * writes the time elapsed.
2417      *
2418      * Parameters:
2419      * name - {String}
2420      */
2421     timeEnd: function() {},
2422
2423     /**
2424      * APIFunction: profile
2425      * Turns on the JavaScript profiler. The optional argument title would
2426      * contain the text to be printed in the header of the profile report.
2427      *
2428      * This function is not currently implemented in Firebug Lite.
2429      * 
2430      * Parameters:
2431      * title - {String} Optional title for the profiler
2432      */
2433     profile: function() {},
2434
2435     /**
2436      * APIFunction: profileEnd
2437      * Turns off the JavaScript profiler and prints its report.
2438      * 
2439      * This function is not currently implemented in Firebug Lite.
2440      */
2441     profileEnd: function() {},
2442
2443     /**
2444      * APIFunction: count
2445      * Writes the number of times that the line of code where count was called
2446      * was executed. The optional argument title will print a message in
2447      * addition to the number of the count.
2448      *
2449      * This function is not currently implemented in Firebug Lite.
2450      *
2451      * Parameters:
2452      * title - {String} Optional title to be printed with count
2453      */
2454     count: function() {},
2455
2456     CLASS_NAME: "OpenLayers.Console"
2457 };
2458
2459 /**
2460  * Execute an anonymous function to extend the OpenLayers.Console namespace
2461  * if the firebug.js script is included.  This closure is used so that the
2462  * "scripts" and "i" variables don't pollute the global namespace.
2463  */
2464 (function() {
2465     /**
2466      * If Firebug Lite is included (before this script), re-route all
2467      * OpenLayers.Console calls to the console object.
2468      */
2469     var scripts = document.getElementsByTagName("script");
2470     for(var i=0, len=scripts.length; i<len; ++i) {
2471         if(scripts[i].src.indexOf("firebug.js") != -1) {
2472             if(console) {
2473                 OpenLayers.Util.extend(OpenLayers.Console, console);
2474                 break;
2475             }
2476         }
2477     }
2478 })();
2479 /* ======================================================================
2480     OpenLayers/Lang.js
2481    ====================================================================== */
2482
2483 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2484  * full list of contributors). Published under the 2-clause BSD license.
2485  * See license.txt in the OpenLayers distribution or repository for the
2486  * full text of the license. */
2487
2488 /**
2489  * @requires OpenLayers/BaseTypes.js
2490  * @requires OpenLayers/Console.js
2491  */
2492
2493 /**
2494  * Namespace: OpenLayers.Lang
2495  * Internationalization namespace.  Contains dictionaries in various languages
2496  *     and methods to set and get the current language.
2497  */
2498 OpenLayers.Lang = {
2499     
2500     /** 
2501      * Property: code
2502      * {String}  Current language code to use in OpenLayers.  Use the
2503      *     <setCode> method to set this value and the <getCode> method to
2504      *     retrieve it.
2505      */
2506     code: null,
2507
2508     /** 
2509      * APIProperty: defaultCode
2510      * {String} Default language to use when a specific language can't be
2511      *     found.  Default is "en".
2512      */
2513     defaultCode: "en",
2514         
2515     /**
2516      * APIFunction: getCode
2517      * Get the current language code.
2518      *
2519      * Returns:
2520      * {String} The current language code.
2521      */
2522     getCode: function() {
2523         if(!OpenLayers.Lang.code) {
2524             OpenLayers.Lang.setCode();
2525         }
2526         return OpenLayers.Lang.code;
2527     },
2528     
2529     /**
2530      * APIFunction: setCode
2531      * Set the language code for string translation.  This code is used by
2532      *     the <OpenLayers.Lang.translate> method.
2533      *
2534      * Parameters:
2535      * code - {String} These codes follow the IETF recommendations at
2536      *     http://www.ietf.org/rfc/rfc3066.txt.  If no value is set, the
2537      *     browser's language setting will be tested.  If no <OpenLayers.Lang>
2538      *     dictionary exists for the code, the <OpenLayers.String.defaultLang>
2539      *     will be used.
2540      */
2541     setCode: function(code) {
2542         var lang;
2543         if(!code) {
2544             code = (OpenLayers.BROWSER_NAME == "msie") ?
2545                 navigator.userLanguage : navigator.language;
2546         }
2547         var parts = code.split('-');
2548         parts[0] = parts[0].toLowerCase();
2549         if(typeof OpenLayers.Lang[parts[0]] == "object") {
2550             lang = parts[0];
2551         }
2552
2553         // check for regional extensions
2554         if(parts[1]) {
2555             var testLang = parts[0] + '-' + parts[1].toUpperCase();
2556             if(typeof OpenLayers.Lang[testLang] == "object") {
2557                 lang = testLang;
2558             }
2559         }
2560         if(!lang) {
2561             OpenLayers.Console.warn(
2562                 'Failed to find OpenLayers.Lang.' + parts.join("-") +
2563                 ' dictionary, falling back to default language'
2564             );
2565             lang = OpenLayers.Lang.defaultCode;
2566         }
2567         
2568         OpenLayers.Lang.code = lang;
2569     },
2570
2571     /**
2572      * APIMethod: translate
2573      * Looks up a key from a dictionary based on the current language string.
2574      *     The value of <getCode> will be used to determine the appropriate
2575      *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
2576      *
2577      * Parameters:
2578      * key - {String} The key for an i18n string value in the dictionary.
2579      * context - {Object} Optional context to be used with
2580      *     <OpenLayers.String.format>.
2581      * 
2582      * Returns:
2583      * {String} A internationalized string.
2584      */
2585     translate: function(key, context) {
2586         var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
2587         var message = dictionary && dictionary[key];
2588         if(!message) {
2589             // Message not found, fall back to message key
2590             message = key;
2591         }
2592         if(context) {
2593             message = OpenLayers.String.format(message, context);
2594         }
2595         return message;
2596     }
2597     
2598 };
2599
2600
2601 /**
2602  * APIMethod: OpenLayers.i18n
2603  * Alias for <OpenLayers.Lang.translate>.  Looks up a key from a dictionary
2604  *     based on the current language string. The value of
2605  *     <OpenLayers.Lang.getCode> will be used to determine the appropriate
2606  *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
2607  *
2608  * Parameters:
2609  * key - {String} The key for an i18n string value in the dictionary.
2610  * context - {Object} Optional context to be used with
2611  *     <OpenLayers.String.format>.
2612  * 
2613  * Returns:
2614  * {String} A internationalized string.
2615  */
2616 OpenLayers.i18n = OpenLayers.Lang.translate;
2617 /* ======================================================================
2618     OpenLayers/Util.js
2619    ====================================================================== */
2620
2621 /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2622  * full list of contributors). Published under the 2-clause BSD license.
2623  * See license.txt in the OpenLayers distribution or repository for the
2624  * full text of the license. */
2625
2626 /**
2627  * @requires OpenLayers/BaseTypes.js
2628  * @requires OpenLayers/BaseTypes/Bounds.js
2629  * @requires OpenLayers/BaseTypes/Element.js
2630  * @requires OpenLayers/BaseTypes/LonLat.js
2631  * @requires OpenLayers/BaseTypes/Pixel.js
2632  * @requires OpenLayers/BaseTypes/Size.js
2633  * @requires OpenLayers/Lang.js
2634  */
2635
2636 /**
2637  * Namespace: Util
2638  */
2639 OpenLayers.Util = OpenLayers.Util || {};
2640
2641 /** 
2642  * Function: getElement
2643  * This is the old $() from prototype
2644  *
2645  * Parameters:
2646  * e - {String or DOMElement or Window}
2647  *
2648  * Returns:
2649  * {Array(DOMElement) or DOMElement}
2650  */
2651 OpenLayers.Util.getElement = function() {
2652     var elements = [];
2653
2654     for (var i=0, len=arguments.length; i<len; i++) {
2655         var element = arguments[i];
2656         if (typeof element == 'string') {
2657             element = document.getElementById(element);
2658         }
2659         if (arguments.length == 1) {
2660             return element;
2661         }
2662         elements.push(element);
2663     }
2664     return elements;
2665 };
2666
2667 /**
2668  * Function: isElement
2669  * A cross-browser implementation of "e instanceof Element".
2670  *
2671  * Parameters:
2672  * o - {Object} The object to test.
2673  *
2674  * Returns:
2675  * {Boolean}
2676  */
2677 OpenLayers.Util.isElement = function(o) {
2678     return !!(o && o.nodeType === 1);
2679 };
2680
2681 /**
2682  * Function: isArray
2683  * Tests that the provided object is an array.
2684  * This test handles the cross-IFRAME case not caught
2685  * by "a instanceof Array" and should be used instead.
2686  * 
2687  * Parameters:
2688  * a - {Object} the object test.
2689  * 
2690  * Returns:
2691  * {Boolean} true if the object is an array.
2692  */
2693 OpenLayers.Util.isArray = function(a) {
2694     return (Object.prototype.toString.call(a) === '[object Array]');
2695 };
2696
2697 /** 
2698  * Function: removeItem
2699  * Remove an object from an array. Iterates through the array
2700  *     to find the item, then removes it.
2701  *
2702  * Parameters:
2703  * array - {Array}
2704  * item - {Object}
2705  * 
2706  * Returns:
2707  * {Array} A reference to the array
2708  */
2709 OpenLayers.Util.removeItem = function(array, item) {
2710     for(var i = array.length - 1; i >= 0; i--) {
2711         if(array[i] == item) {
2712             array.splice(i,1);
2713             //break;more than once??
2714         }
2715     }
2716     return array;
2717 };
2718
2719 /** 
2720  * Function: indexOf
2721  * Seems to exist already in FF, but not in MOZ.
2722  * 
2723  * Parameters:
2724  * array - {Array}
2725  * obj - {*}
2726  * 
2727  * Returns:
2728  * {Integer} The index at which the first object was found in the array.
2729  *           If not found, returns -1.
2730  */
2731 OpenLayers.Util.indexOf = function(array, obj) {
2732     // use the build-in function if available.
2733     if (typeof array.indexOf == "function") {
2734         return array.indexOf(obj);
2735     } else {
2736         for (var i = 0, len = array.length; i < len; i++) {
2737             if (array[i] == obj) {
2738                 return i;
2739             }
2740         }
2741         return -1;   
2742     }
2743 };
2744
2745
2746 /**
2747  * Property: dotless
2748  * {RegExp}
2749  * Compiled regular expression to match dots (".").  This is used for replacing
2750  *     dots in identifiers.  Because object identifiers are frequently used for
2751  *     DOM element identifiers by the library, we avoid using dots to make for
2752  *     more sensible CSS selectors.
2753  *
2754  * TODO: Use a module pattern to avoid bloating the API with stuff like this.
2755  */
2756 OpenLayers.Util.dotless = /\./g;
2757
2758 /**
2759  * Function: modifyDOMElement
2760  * 
2761  * Modifies many properties of a DOM element all at once.  Passing in 
2762  * null to an individual parameter will avoid setting the attribute.
2763  *
2764  * Parameters:
2765  * element - {DOMElement} DOM element to modify.
2766  * id - {String} The element id attribute to set.  Note that dots (".") will be
2767  *     replaced with underscore ("_") in setting the element id.
2768  * px - {<OpenLayers.Pixel>|Object} The element left and top position,
2769  *                                  OpenLayers.Pixel or an object with
2770  *                                  a 'x' and 'y' properties.
2771  * sz - {<OpenLayers.Size>|Object} The element width and height,
2772  *                                 OpenLayers.Size or an object with a
2773  *                                 'w' and 'h' properties.
2774  * position - {String}       The position attribute.  eg: absolute, 
2775  *                           relative, etc.
2776  * border - {String}         The style.border attribute.  eg:
2777  *                           solid black 2px
2778  * overflow - {String}       The style.overview attribute.  
2779  * opacity - {Float}         Fractional value (0.0 - 1.0)
2780  */
2781 OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
2782                                             border, overflow, opacity) {
2783
2784     if (id) {
2785         element.id = id.replace(OpenLayers.Util.dotless, "_");
2786     }
2787     if (px) {
2788         element.style.left = px.x + "px";
2789         element.style.top = px.y + "px";
2790     }
2791     if (sz) {
2792         element.style.width = sz.w + "px";
2793         element.style.height = sz.h + "px";
2794     }
2795     if (position) {
2796         element.style.position = position;
2797     }
2798     if (border) {
2799         element.style.border = border;
2800     }
2801     if (overflow) {
2802         element.style.overflow = overflow;
2803     }
2804     if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
2805         element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
2806         element.style.opacity = opacity;
2807     } else if (parseFloat(opacity) == 1.0) {
2808         element.style.filter = '';
2809         element.style.opacity = '';
2810     }
2811 };
2812
2813 /** 
2814  * Function: createDiv
2815  * Creates a new div and optionally set some standard attributes.
2816  * Null may be passed to each parameter if you do not wish to
2817  * set a particular attribute.
2818  * Note - zIndex is NOT set on the resulting div.
2819  * 
2820  * Parameters:
2821  * id - {String} An identifier for this element.  If no id is
2822  *               passed an identifier will be created 
2823  *               automatically.  Note that dots (".") will be replaced with
2824  *               underscore ("_") when generating ids.
2825  * px - {<OpenLayers.Pixel>|Object} The element left and top position,
2826  *                                  OpenLayers.Pixel or an object with
2827  *                                  a 'x' and 'y' properties.
2828  * sz - {<OpenLayers.Size>|Object} The element width and height,
2829  *                                 OpenLayers.Size or an object with a
2830  *                                 'w' and 'h' properties.
2831  * imgURL - {String} A url pointing to an image to use as a 
2832  *                   background image.
2833  * position - {String} The style.position value. eg: absolute,
2834  *                     relative etc.
2835  * border - {String} The the style.border value. 
2836  *                   eg: 2px solid black
2837  * overflow - {String} The style.overflow value. Eg. hidden
2838  * opacity - {Float} Fractional value (0.0 - 1.0)
2839  * 
2840  * Returns: 
2841  * {DOMElement} A DOM Div created with the specified attributes.
2842  */
2843 OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
2844                                      border, overflow, opacity) {
2845
2846     var dom = document.createElement('div');
2847
2848     if (imgURL) {
2849         dom.style.backgroundImage = 'url(' + imgURL + ')';
2850     }
2851
2852     //set generic properties
2853     if (!id) {
2854         id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
2855     }
2856     if (!position) {
2857         position = "absolute";
2858     }
2859     OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
2860                                      border, overflow, opacity);
2861
2862     return dom;
2863 };
2864
2865 /**
2866  * Function: createImage
2867  * Creates an img element with specific attribute values.
2868  *  
2869  * Parameters:
2870  * id - {String} The id field for the img.  If none assigned one will be
2871  *               automatically generated.
2872  * px - {<OpenLayers.Pixel>|Object} The element left and top position,
2873  *                                  OpenLayers.Pixel or an object with
2874  *                                  a 'x' and 'y' properties.
2875  * sz - {<OpenLayers.Size>|Object} The element width and height,
2876  *                                 OpenLayers.Size or an object with a
2877  *                                 'w' and 'h' properties.
2878  * imgURL - {String} The url to use as the image source.
2879  * position - {String} The style.position value.
2880  * border - {String} The border to place around the image.
2881  * opacity - {Float} Fractional value (0.0 - 1.0)
2882  * delayDisplay - {Boolean} If true waits until the image has been
2883  *                          loaded.
2884  * 
2885  * Returns:
2886  * {DOMElement} A DOM Image created with the specified attributes.
2887  */
2888 OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
2889                                        opacity, delayDisplay) {
2890
2891     var image = document.createElement("img");
2892
2893     //set generic properties
2894     if (!id) {
2895         id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
2896     }
2897     if (!position) {
2898         position = "relative";
2899     }
2900     OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
2901                                      border, null, opacity);
2902
2903     if (delayDisplay) {
2904         image.style.display = "none";
2905         function display() {
2906             image.style.display = "";
2907             OpenLayers.Event.stopObservingElement(image);
2908         }
2909         OpenLayers.Event.observe(image, "load", display);
2910         OpenLayers.Event.observe(image, "error", display);
2911     }
2912     
2913     //set special properties
2914     image.style.alt = id;
2915     image.galleryImg = "no";
2916     if (imgURL) {
2917         image.src = imgURL;
2918     }
2919         
2920     return image;
2921 };
2922
2923 /**
2924  * Property: IMAGE_RELOAD_ATTEMPTS
2925  * {Integer} How many times should we try to reload an image before giving up?
2926  *           Default is 0
2927  */
2928 OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
2929
2930 /**
2931  * Property: alphaHackNeeded
2932  * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
2933  */
2934 OpenLayers.Util.alphaHackNeeded = null;
2935
2936 /**
2937  * Function: alphaHack
2938  * Checks whether it's necessary (and possible) to use the png alpha
2939  * hack which allows alpha transparency for png images under Internet
2940  * Explorer.
2941  * 
2942  * Returns:
2943  * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
2944  */
2945 OpenLayers.Util.alphaHack = function() {
2946     if (OpenLayers.Util.alphaHackNeeded == null) {
2947         var arVersion = navigator.appVersion.split("MSIE");
2948         var version = parseFloat(arVersion[1]);
2949         var filter = false;
2950     
2951         // IEs4Lin dies when trying to access document.body.filters, because 
2952         // the property is there, but requires a DLL that can't be provided. This
2953         // means that we need to wrap this in a try/catch so that this can
2954         // continue.
2955     
2956         try { 
2957             filter = !!(document.body.filters);
2958         } catch (e) {}    
2959     
2960         OpenLayers.Util.alphaHackNeeded = (filter && 
2961                                            (version >= 5.5) && (version < 7));
2962     }
2963     return OpenLayers.Util.alphaHackNeeded;
2964 };
2965
2966 /** 
2967  * Function: modifyAlphaImageDiv
2968  * 
2969  * Parameters:
2970  * div - {DOMElement} Div containing Alpha-adjusted Image
2971  * id - {String}
2972  * px - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or an object with
2973  *                                  a 'x' and 'y' properties.
2974  * sz - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
2975  *                                 a 'w' and 'h' properties.
2976  * imgURL - {String}
2977  * position - {String}
2978  * border - {String}
2979  * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
2980  * opacity - {Float} Fractional value (0.0 - 1.0)
2981  */ 
2982 OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, 
2983                                                position, border, sizing, 
2984                                                opacity) {
2985
2986     OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
2987                                      null, null, opacity);
2988
2989     var img = div.childNodes[0];
2990
2991     if (imgURL) {
2992         img.src = imgURL;
2993     }
2994     OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, 
2995                                      "relative", border);
2996     
2997     if (OpenLayers.Util.alphaHack()) {
2998         if(div.style.display != "none") {
2999             div.style.display = "inline-block";
3000         }
3001         if (sizing == null) {
3002             sizing = "scale";
3003         }
3004         
3005         div.style.filter = "progid:DXImageTransform.Microsoft" +
3006                            ".AlphaImageLoader(src='" + img.src + "', " +
3007                            "sizingMethod='" + sizing + "')";
3008         if (parseFloat(div.style.opacity) >= 0.0 && 
3009             parseFloat(div.style.opacity) < 1.0) {
3010             div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
3011         }
3012
3013         img.style.filter = "alpha(opacity=0)";
3014     }
3015 };
3016
3017 /** 
3018  * Function: createAlphaImageDiv
3019  * 
3020  * Parameters:
3021  * id - {String}
3022  * px - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or an object with
3023  *                                  a 'x' and 'y' properties.
3024  * sz - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
3025  *                                 a 'w' and 'h' properties.
3026  * imgURL - {String}
3027  * position - {String}
3028  * border - {String}
3029  * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
3030  * opacity - {Float} Fractional value (0.0 - 1.0)
3031  * delayDisplay - {Boolean} If true waits until the image has been
3032  *                          loaded.
3033  * 
3034  * Returns:
3035  * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is 
3036  *              needed for transparency in IE, it is added.
3037  */ 
3038 OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, 
3039                                                position, border, sizing, 
3040                                                opacity, delayDisplay) {
3041     
3042     var div = OpenLayers.Util.createDiv();
3043     var img = OpenLayers.Util.createImage(null, null, null, null, null, null, 
3044                                           null, delayDisplay);
3045     img.className = "olAlphaImg";
3046     div.appendChild(img);
3047
3048     OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, 
3049                                         border, sizing, opacity);
3050     
3051     return div;
3052 };
3053
3054
3055 /** 
3056  * Function: upperCaseObject
3057  * Creates a new hashtable and copies over all the keys from the 
3058  *     passed-in object, but storing them under an uppercased
3059  *     version of the key at which they were stored.
3060  * 
3061  * Parameters: 
3062  * object - {Object}
3063  * 
3064  * Returns: 
3065  * {Object} A new Object with all the same keys but uppercased
3066  */
3067 OpenLayers.Util.upperCaseObject = function (object) {
3068     var uObject = {};
3069     for (var key in object) {
3070         uObject[key.toUpperCase()] = object[key];
3071     }
3072     return uObject;
3073 };
3074
3075 /** 
3076  * Function: applyDefaults
3077  * Takes an object and copies any properties that don't exist from
3078  *     another properties, by analogy with OpenLayers.Util.extend() from
3079  *     Prototype.js.
3080  * 
3081  * Parameters:
3082  * to - {Object} The destination object.
3083  * from - {Object} The source object.  Any properties of this object that
3084  *     are undefined in the to object will be set on the to object.
3085  *
3086  * Returns:
3087  * {Object} A reference to the to object.  Note that the to argument is modified
3088  *     in place and returned by this function.
3089  */
3090 OpenLayers.Util.applyDefaults = function (to, from) {
3091     to = to || {};
3092     /*
3093      * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
3094      * prototype object" when calling hawOwnProperty if the source object is an
3095      * instance of window.Event.
3096      */
3097     var fromIsEvt = typeof window.Event == "function"
3098                     && from instanceof window.Event;
3099
3100     for (var key in from) {
3101         if (to[key] === undefined ||
3102             (!fromIsEvt && from.hasOwnProperty
3103              && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
3104             to[key] = from[key];
3105         }
3106     }
3107     /**
3108      * IE doesn't include the toString property when iterating over an object's
3109      * properties with the for(property in object) syntax.  Explicitly check if
3110      * the source has its own toString property.
3111      */
3112     if(!fromIsEvt && from && from.hasOwnProperty
3113        && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
3114         to.toString = from.toString;
3115     }
3116     
3117     return to;
3118 };
3119
3120 /**
3121  * Function: getParameterString
3122  * 
3123  * Parameters:
3124  * params - {Object}
3125  * 
3126  * Returns:
3127  * {String} A concatenation of the properties of an object in 
3128  *          http parameter notation. 
3129  *          (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
3130  *          If a parameter is actually a list, that parameter will then
3131  *          be set to a comma-seperated list of values (foo,bar) instead
3132  *          of being URL escaped (foo%3Abar). 
3133  */
3134 OpenLayers.Util.getParameterString = function(params) {
3135     var paramsArray = [];
3136     
3137     for (var key in params) {
3138       var value = params[key];
3139       if ((value != null) && (typeof value != 'function')) {
3140         var encodedValue;
3141         if (typeof value == 'object' && value.constructor == Array) {
3142           /* value is an array; encode items and separate with "," */
3143           var encodedItemArray = [];
3144           var item;
3145           for (var itemIndex=0, len=value.length; itemIndex<len; itemIndex++) {
3146             item = value[itemIndex];
3147             encodedItemArray.push(encodeURIComponent(
3148                 (item === null || item === undefined) ? "" : item)
3149             );
3150           }
3151           encodedValue = encodedItemArray.join(",");
3152         }
3153         else {
3154           /* value is a string; simply encode */
3155           encodedValue = encodeURIComponent(value);
3156         }
3157         paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
3158       }
3159     }
3160     
3161     return paramsArray.join("&");
3162 };
3163
3164 /**
3165  * Function: urlAppend
3166  * Appends a parameter string to a url. This function includes the logic for
3167  * using the appropriate character (none, & or ?) to append to the url before
3168  * appending the param string.
3169  * 
3170  * Parameters:
3171  * url - {String} The url to append to
3172  * paramStr - {String} The param string to append
3173  * 
3174  * Returns:
3175  * {String} The new url
3176  */
3177 OpenLayers.Util.urlAppend = function(url, paramStr) {
3178     var newUrl = url;
3179     if(paramStr) {
3180         var parts = (url + " ").split(/[?&]/);
3181         newUrl += (parts.pop() === " " ?
3182             paramStr :
3183             parts.length ? "&" + paramStr : "?" + paramStr);
3184     }
3185     return newUrl;
3186 };
3187
3188 /** 
3189  * Function: getImagesLocation
3190  * 
3191  * Returns:
3192  * {String} The fully formatted image location string
3193  */
3194 OpenLayers.Util.getImagesLocation = function() {
3195     return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
3196 };
3197
3198 /** 
3199  * Function: getImageLocation
3200  * 
3201  * Returns:
3202  * {String} The fully formatted location string for a specified image
3203  */
3204 OpenLayers.Util.getImageLocation = function(image) {
3205     return OpenLayers.Util.getImagesLocation() + image;
3206 };
3207
3208
3209 /** 
3210  * Function: Try
3211  * Execute functions until one of them doesn't throw an error. 
3212  *     Capitalized because "try" is a reserved word in JavaScript.
3213  *     Taken directly from OpenLayers.Util.Try()
3214  * 
3215  * Parameters:
3216  * [*] - {Function} Any number of parameters may be passed to Try()
3217  *    It will attempt to execute each of them until one of them 
3218  *    successfully executes. 
3219  *    If none executes successfully, returns null.
3220  * 
3221  * Returns:
3222  * {*} The value returned by the first successfully executed function.
3223  */
3224 OpenLayers.Util.Try = function() {
3225     var returnValue = null;
3226
3227     for (var i=0, len=arguments.length; i<len; i++) {
3228       var lambda = arguments[i];
3229       try {
3230         returnValue = lambda();
3231         break;
3232       } catch (e) {}
3233     }
3234
3235     return returnValue;
3236 };
3237
3238 /**
3239  * Function: getXmlNodeValue
3240  * 
3241  * Parameters:
3242  * node - {XMLNode}
3243  * 
3244  * Returns:
3245  * {String} The text value of the given node, without breaking in firefox or IE
3246  */
3247 OpenLayers.Util.getXmlNodeValue = function(node) {
3248     var val = null;
3249     OpenLayers.Util.Try( 
3250         function() {
3251             val = node.text;
3252             if (!val) {
3253                 val = node.textContent;
3254             }
3255             if (!val) {
3256                 val = node.firstChild.nodeValue;
3257             }
3258         }, 
3259         function() {
3260             val = node.textContent;
3261         }); 
3262     return val;
3263 };
3264
3265 /** 
3266  * Function: mouseLeft
3267  * 
3268  * Parameters:
3269  * evt - {Event}
3270  * div - {HTMLDivElement}
3271  * 
3272  * Returns:
3273  * {Boolean}
3274  */
3275 OpenLayers.Util.mouseLeft = function (evt, div) {
3276     // start with the element to which the mouse has moved
3277     var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
3278     // walk up the DOM tree.
3279     while (target != div && target != null) {
3280         target = target.parentNode;
3281     }
3282     // if the target we stop at isn't the div, then we've left the div.
3283     return (target != div);
3284 };
3285
3286 /**
3287  * Property: precision
3288  * {Number} The number of significant digits to retain to avoid
3289  * floating point precision errors.
3290  *
3291  * We use 14 as a "safe" default because, although IEEE 754 double floats
3292  * (standard on most modern operating systems) support up to about 16
3293  * significant digits, 14 significant digits are sufficient to represent
3294  * sub-millimeter accuracy in any coordinate system that anyone is likely to
3295  * use with OpenLayers.
3296  *
3297  * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
3298  * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
3299  * with certain projections, e.g. spherical Mercator.
3300  *
3301  */
3302 OpenLayers.Util.DEFAULT_PRECISION = 14;
3303
3304 /**
3305  * Function: toFloat
3306  * Convenience method to cast an object to a Number, rounded to the
3307  * desired floating point precision.
3308  *
3309  * Parameters:
3310  * number    - {Number} The number to cast and round.
3311  * precision - {Number} An integer suitable for use with
3312  *      Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
3313  *      If set to 0, no rounding is performed.
3314  *
3315  * Returns:
3316  * {Number} The cast, rounded number.
3317  */
3318 OpenLayers.Util.toFloat = function (number, precision) {
3319     if (precision == null) {
3320         precision = OpenLayers.Util.DEFAULT_PRECISION;
3321     }
3322     if (typeof number !== "number") {
3323         number = parseFloat(number);
3324     }
3325     return precision === 0 ? number :
3326                              parseFloat(number.toPrecision(precision));
3327 };
3328
3329 /**
3330  * Function: rad
3331  * 
3332  * Parameters:
3333  * x - {Float}
3334  * 
3335  * Returns:
3336  * {Float}
3337  */
3338 OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
3339
3340 /**
3341  * Function: deg
3342  *
3343  * Parameters:
3344  * x - {Float}
3345  *
3346  * Returns:
3347  * {Float}
3348  */
3349 OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
3350
3351 /**
3352  * Property: VincentyConstants
3353  * {Object} Constants for Vincenty functions.
3354  */
3355 OpenLayers.Util.VincentyConstants = {
3356     a: 6378137,
3357     b: 6356752.3142,
3358     f: 1/298.257223563
3359 };
3360
3361 /**
3362  * APIFunction: distVincenty
3363  * Given two objects representing points with geographic coordinates, this
3364  *     calculates the distance between those points on the surface of an
3365  *     ellipsoid.
3366  *
3367  * Parameters:
3368  * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
3369  * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
3370  *
3371  * Returns:
3372  * {Float} The distance (in km) between the two input points as measured on an
3373  *     ellipsoid.  Note that the input point objects must be in geographic
3374  *     coordinates (decimal degrees) and the return distance is in kilometers.
3375  */
3376 OpenLayers.Util.distVincenty = function(p1, p2) {
3377     var ct = OpenLayers.Util.VincentyConstants;
3378     var a = ct.a, b = ct.b, f = ct.f;
3379
3380     var L = OpenLayers.Util.rad(p2.lon - p1.lon);
3381     var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
3382     var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
3383     var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
3384     var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
3385     var lambda = L, lambdaP = 2*Math.PI;
3386     var iterLimit = 20;
3387     while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
3388         var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
3389         var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
3390         (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
3391         if (sinSigma==0) {
3392             return 0;  // co-incident points
3393         }
3394         var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
3395         var sigma = Math.atan2(sinSigma, cosSigma);
3396         var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
3397         var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
3398         var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
3399         var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
3400         lambdaP = lambda;
3401         lambda = L + (1-C) * f * Math.sin(alpha) *
3402         (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
3403     }
3404     if (iterLimit==0) {
3405         return NaN;  // formula failed to converge
3406     }
3407     var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
3408     var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
3409     var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
3410     var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
3411         B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
3412     var s = b*A*(sigma-deltaSigma);
3413     var d = s.toFixed(3)/1000; // round to 1mm precision
3414     return d;
3415 };
3416
3417 /**
3418  * APIFunction: destinationVincenty
3419  * Calculate destination point given start point lat/long (numeric degrees),
3420  * bearing (numeric degrees) & distance (in m).
3421  * Adapted from Chris Veness work, see
3422  * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
3423  *
3424  * Parameters:
3425  * lonlat  - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
3426  *     properties) The start point.
3427  * brng     - {Float} The bearing (degrees).
3428  * dist     - {Float} The ground distance (meters).
3429  *
3430  * Returns:
3431  * {<OpenLayers.LonLat>} The destination point.
3432  */
3433 OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) {
3434     var u = OpenLayers.Util;
3435     var ct = u.VincentyConstants;
3436     var a = ct.a, b = ct.b, f = ct.f;
3437
3438     var lon1 = lonlat.lon;
3439     var lat1 = lonlat.lat;
3440
3441     var s = dist;
3442     var alpha1 = u.rad(brng);
3443     var sinAlpha1 = Math.sin(alpha1);
3444     var cosAlpha1 = Math.cos(alpha1);
3445
3446     var tanU1 = (1-f) * Math.tan(u.rad(lat1));
3447     var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1;
3448     var sigma1 = Math.atan2(tanU1, cosAlpha1);
3449     var sinAlpha = cosU1 * sinAlpha1;
3450     var cosSqAlpha = 1 - sinAlpha*sinAlpha;
3451     var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
3452     var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
3453     var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
3454
3455     var sigma = s / (b*A), sigmaP = 2*Math.PI;
3456     while (Math.abs(sigma-sigmaP) > 1e-12) {
3457         var cos2SigmaM = Math.cos(2*sigma1 + sigma);
3458         var sinSigma = Math.sin(sigma);
3459         var cosSigma = Math.cos(sigma);
3460         var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
3461             B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
3462         sigmaP = sigma;
3463         sigma = s / (b*A) + deltaSigma;
3464     }
3465
3466     var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1;
3467     var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1,
3468         (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp));
3469     var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1);
3470     var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
3471     var L = lambda - (1-C) * f * sinAlpha *
3472         (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
3473
3474     var revAz = Math.atan2(sinAlpha, -tmp);  // final bearing
3475
3476     return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2));
3477 };
3478
3479 /**
3480  * Function: getParameters
3481  * Parse the parameters from a URL or from the current page itself into a 
3482  *     JavaScript Object. Note that parameter values with commas are separated
3483  *     out into an Array.
3484  * 
3485  * Parameters:
3486  * url - {String} Optional url used to extract the query string.
3487  *                If url is null or is not supplied, query string is taken 
3488  *                from the page location.
3489  * options - {Object} Additional options. Optional.
3490  *
3491  * Valid options:
3492  *   splitArgs - {Boolean} Split comma delimited params into arrays? Default is
3493  *       true.
3494  * 
3495  * Returns:
3496  * {Object} An object of key/value pairs from the query string.
3497  */
3498 OpenLayers.Util.getParameters = function(url, options) {
3499     options = options || {};
3500     // if no url specified, take it from the location bar
3501     url = (url === null || url === undefined) ? window.location.href : url;
3502
3503     //parse out parameters portion of url string
3504     var paramsString = "";
3505     if (OpenLayers.String.contains(url, '?')) {
3506         var start = url.indexOf('?') + 1;
3507         var end = OpenLayers.String.contains(url, "#") ?
3508                     url.indexOf('#') : url.length;
3509         paramsString = url.substring(start, end);
3510     }
3511
3512     var parameters = {};
3513     var pairs = paramsString.split(/[&;]/);
3514     for(var i=0, len=pairs.length; i<len; ++i) {
3515         var keyValue = pairs[i].split('=');
3516         if (keyValue[0]) {
3517
3518             var key = keyValue[0];
3519             try {
3520                 key = decodeURIComponent(key);
3521             } catch (err) {
3522                 key = unescape(key);
3523             }
3524             
3525             // being liberal by replacing "+" with " "
3526             var value = (keyValue[1] || '').replace(/\+/g, " ");
3527
3528             try {
3529                 value = decodeURIComponent(value);
3530             } catch (err) {
3531                 value = unescape(value);
3532             }
3533             
3534             // follow OGC convention of comma delimited values
3535             if (options.splitArgs !== false) {
3536                 value = value.split(",");
3537             }
3538
3539             //if there's only one value, do not return as array                    
3540             if (value.length == 1) {
3541                 value = value[0];
3542             }                
3543             
3544             parameters[key] = value;
3545          }
3546      }
3547     return parameters;
3548 };
3549
3550 /**
3551  * Property: lastSeqID
3552  * {Integer} The ever-incrementing count variable.
3553  *           Used for generating unique ids.
3554  */
3555 OpenLayers.Util.lastSeqID = 0;
3556
3557 /**
3558  * Function: createUniqueID
3559  * Create a unique identifier for this session.  Each time this function
3560  *     is called, a counter is incremented.  The return will be the optional
3561  *     prefix (defaults to "id_") appended with the counter value.
3562  * 
3563  * Parameters:
3564  * prefix - {String} Optional string to prefix unique id. Default is "id_".
3565  *     Note that dots (".") in the prefix will be replaced with underscore ("_").
3566  * 
3567  * Returns:
3568  * {String} A unique id string, built on the passed in prefix.
3569  */
3570 OpenLayers.Util.createUniqueID = function(prefix) {
3571     if (prefix == null) {
3572         prefix = "id_";
3573     } else {
3574         prefix = prefix.replace(OpenLayers.Util.dotless, "_");
3575     }
3576     OpenLayers.Util.lastSeqID += 1; 
3577     return prefix + OpenLayers.Util.lastSeqID;        
3578 };
3579
3580 /**
3581  * Constant: INCHES_PER_UNIT
3582  * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
3583  * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
3584  * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
3585  * and PROJ.4 (http://trac.osgeo.org/proj/)
3586  * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
3587  * The hardcoded table of PROJ.4 units are in pj_units.c.
3588  */
3589 OpenLayers.INCHES_PER_UNIT = { 
3590     'inches': 1.0,
3591     'ft': 12.0,
3592     'mi': 63360.0,
3593     'm': 39.37,
3594     'km': 39370,
3595     'dd': 4374754,
3596     'yd': 36
3597 };
3598 OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
3599 OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
3600 OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
3601
3602 // Units from CS-Map
3603 OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
3604 OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
3605     "Inch": OpenLayers.INCHES_PER_UNIT.inches,
3606     "Meter": 1.0 / OpenLayers.METERS_PER_INCH,   //EPSG:9001
3607     "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH,   //EPSG:9003
3608     "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9002
3609     "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH,   //EPSG:9005
3610     "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH,   //EPSG:9041
3611     "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH,   //EPSG:9094
3612     "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
3613     "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
3614     "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
3615     "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
3616     "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9036
3617     "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
3618     "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH,   //EPSG:9040
3619     "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH,   //EPSG:9084
3620     "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH,   //EPSG:9085
3621     "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH,   //EPSG:9086
3622     "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH,   //EPSG:9087
3623     "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH,   //EPSG:9080
3624     "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH,   //EPSG:9081
3625     "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH,   //EPSG:9082
3626     "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH,   //EPSG:9083
3627     "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
3628     "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9096
3629     "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9093
3630     "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9030
3631     "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
3632     "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
3633     "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
3634     "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
3635     "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
3636     "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
3637     "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
3638     "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH,   //EPSG:9031
3639     "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
3640     "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9038
3641     "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9033
3642     "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9062
3643     "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9042
3644     "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9039
3645     "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9034
3646     "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9063
3647     "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9043
3648     "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
3649     "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH,   //EPSG:9097
3650     "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH,   //EPSG:9098
3651     "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
3652     "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
3653     "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
3654     "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
3655     "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
3656     "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
3657     "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
3658     "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
3659     "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
3660     "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
3661     "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
3662 });
3663
3664 //unit abbreviations supported by PROJ.4
3665 OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
3666     "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
3667     "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
3668     "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
3669     "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
3670     "kmi": OpenLayers.INCHES_PER_UNIT["nmi"],    //International Nautical Mile
3671     "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
3672     "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"],  //International Chain
3673     "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
3674     "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
3675     "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"], //U.S. Surveyor's Foot
3676     "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"], //U.S. Surveyor's Yard
3677     "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
3678     "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"],   //U.S. Surveyor's Statute Mile
3679     "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"],  //Indian Yard
3680     "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"],  //Indian Foot
3681     "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH  //Indian Chain
3682 });
3683
3684 /** 
3685  * Constant: DOTS_PER_INCH
3686  * {Integer} 72 (A sensible default)
3687  */
3688 OpenLayers.DOTS_PER_INCH = 72;
3689
3690 /**
3691  * Function: normalizeScale
3692  * 
3693  * Parameters:
3694  * scale - {float}
3695  * 
3696  * Returns:
3697  * {Float} A normalized scale value, in 1 / X format. 
3698  *         This means that if a value less than one ( already 1/x) is passed
3699  *         in, it just returns scale directly. Otherwise, it returns 
3700  *         1 / scale
3701  */
3702 OpenLayers.Util.normalizeScale = function (scale) {
3703     var normScale = (scale > 1.0) ? (1.0 / scale) 
3704                                   : scale;
3705     return normScale;
3706 };
3707
3708 /**
3709  * Function: getResolutionFromScale
3710  * 
3711  * Parameters:
3712  * scale - {Float}
3713  * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
3714  *                  Default is degrees
3715  * 
3716  * Returns:
3717  * {Float} The corresponding resolution given passed-in scale and unit 
3718  *     parameters.  If the given scale is falsey, the returned resolution will
3719  *     be undefined.
3720  */
3721 OpenLayers.Util.getResolutionFromScale = function (scale, units) {
3722     var resolution;
3723     if (scale) {
3724         if (units == null) {
3725             units = "degrees";
3726         }
3727         var normScale = OpenLayers.Util.normalizeScale(scale);
3728         resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
3729                                         * OpenLayers.DOTS_PER_INCH);        
3730     }
3731     return resolution;
3732 };
3733
3734 /**
3735  * Function: getScaleFromResolution
3736  * 
3737  * Parameters:
3738  * resolution - {Float}
3739  * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
3740  *                  Default is degrees
3741  * 
3742  * Returns:
3743  * {Float} The corresponding scale given passed-in resolution and unit 
3744  *         parameters.
3745  */
3746 OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
3747
3748     if (units == null) {
3749         units = "degrees";
3750     }
3751
3752     var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
3753                     OpenLayers.DOTS_PER_INCH;
3754     return scale;
3755 };
3756
3757 /**
3758  * Function: pagePosition
3759  * Calculates the position of an element on the page (see
3760  * http://code.google.com/p/doctype/wiki/ArticlePageOffset)
3761  *
3762  * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
3763  * Copyright (c) 2006, Yahoo! Inc.
3764  * All rights reserved.
3765  * 
3766  * Redistribution and use of this software in source and binary forms, with or
3767  * without modification, are permitted provided that the following conditions
3768  * are met:
3769  * 
3770  * * Redistributions of source code must retain the above copyright notice,
3771  *   this list of conditions and the following disclaimer.