/**
 * @package SaskTourism Google Maps Implementation
 * @version 1.3
 * @author zu.com communications <contactus@zu.com>
 * @description A self contained javascript file that will dynamically display content on http://www.sasktourism.com/
 * @copyright Copyright (c) 2007 zu.com communications
 */

SaskTourismMapsMgr = function() {

	return {

		/**
		 * The GoogleMaps object.
		 * @property _map
		 * @type GMap2
		 * @private
		 */
		_map: {},

		/**
		 * An array of all the markers on the map.
		 * @property _gMarkers
		 * @type {index: GMarker}
		 * @private
		 */
		_gMarkers: new Array(),

		/**
		 * The LocationManager will contain the information for that drop down.
		 * @property _locationManager
		 * @type {}
		 * @private
		 */
		_locationManager: new Array(),

		/**
		 * The absoulte minimum value for zooming.
		 * @property _minZoom
		 * @type int
		 * @private
		 * @static
		 */
		_minZoom: 4,

		/**
		 * The absoulte maximum value for zooming.
		 * @property _maxZoom
		 * @type int
		 * @private
		 * @static
		 */
		_maxZoom: 15,

		/**
		 * The initial value for zoom when the map loads.
		 * @property _defaultZoom
		 * @type int
		 * @private
		 * @static
		 */
		_defaultZoom: 6,

		/**
		 * The minimum zoom value before the results display.
		 * @property _resultsZoom
		 * @type int
		 * @private
		 * @static
		 */
		_resultsZoom: 10,

		/**
		 * The default zoom level for displaying product details.
		 * @property _detailsZoom
		 * @type int
		 * @private
		 * @static
		 */
		//_detailsZoom: 13,

		/**
		 * An array of different markers that are currently used.
		 * @property _chMarkers
		 * @type GMarkerManager
		 * @private
		 */
		_chMarkers: {},

		/**
		 * The default Latitude coordinate for map startup.
		 * @property _defaultLat
		 * @type float
		 * @private
		 * @static
		 */
		_defaultLat: 52.562995039558004,

		/**
		 * The default Longitude coordinate for map startup.
		 * @property _defaultLng
		 * @type float
		 * @private
		 * @static
		 */
		_defaultLng: -105.64453125,

		/**
		 * The primary div id name which will contains all map features.
		 * @property _mainDiv
		 * @type string
		 * @private
		 * @static
		 */
		_mainDiv: "skMap",

		/**
		 * The base url definition for all ajax calls.
		 * @property _baseUrl
		 * @type string
		 * @private
		 * @static
		 */
		_baseUrl: "/../../",

		/**
		 * The image root will be the root of all images used within this file.
		 * @property _imageRoot
		 * @type string
		 * @private
		 * @static
		 */
		_imageRoot: "/../../images/",

		/**
		 * The method name to be used for ajax calls.
		 * @property _ajaxMethod
		 * @type string
		 * @private
		 */
		_ajaxMethod: "",

		/**
		 * The type of map to be displayed.
		 * @property _mapType
		 * @type string
		 * @private
		 */
		_mapType: "",

		/**
		 * Saved Products (Products)
		 * @property _ajaxProducts
		 * @type mixed array
		 * @private
		 */
		_ajaxProducts: new Array(),

		/**
		 * Things to do (Products)
		 * @property _thingsToDo
		 * @type mixed array
		 * @private
		 */
		_thingsToDo: "",

		/**
		 * Where to stay (Products)
		 * @property _whereToStay
		 * @type mixed array
		 * @private
		 */
		_whereToStay: "",

		/**
		 * The will track if the results pane is displayed or not.
		 * @property _showingResults
		 * @type boolean
		 * @private
		 */
		_showingResults: false,

		/**
		 * The will lock the update event.
		 * @property _lockEvent
		 * @type boolean
		 * @private
		 */
		_lockEvent: false,

		/**
		 * The product ids to be called.
		 * @property _ptid
		 * @type string
		 * @private
		 */
		_ptid: "",

		/**
		 * Determines if error messages should be displayed or not.
		 * @property _debug
		 * @type boolean
		 * @private
		 */
		_debug: false,

		/**
		 * Saves debug messages.
		 * @property _tracker
		 * @type string
		 * @private
		 */
		_tracker: "",

		/**
		 * Sets the debug option.
		 * @method setDebug
		 * @param {boolean} debug
		 */
		setDebug: function(debug) {
			this._debug = debug;
		},

		/**
		 * Set the value of the Product Id.
		 * @method setProducts
		 * @param {string} pid The new value to be assigned
		 */
		setProducts: function(things, where) {
			this._thingsToDo = things;
			this._whereToStay = where;
		},

		/**
		 * @method getThingsToDo
		 * @return value of _thingsToDo (ProductID)
		 */
		getThingsToDo: function() {
			return this._thingsToDo;
		},

		/**
		 * @method getWhereToStay
		 * @return value of _whereToStay (ProductID)
		 */
		getWhereToStay: function() {
			return this._whereToStay;
		},

		/**
		 * Set the value of the ajax method to be used.
		 * @method setAjaxMethod
		 * @param {string} aMethod The new value to be assigned
		 */
		setAjaxMethod: function(aMethod) {
			this._ajaxMethod = aMethod;
		},

		/**
		 * Return the current ajax method to be used.
		 * @method getAjaxMethod
		 * @return {string} The ajax method.
		 */
		getAjaxMethod: function() {
			return this._ajaxMethod;
		},

		/**
		 * Set the value of the ajax method for this page.
		 * @method setMapType
		 * @param {string} mapType The new value to be assigned
		 */
		setMapType: function(mapType) {
			this._mapType = mapType;
		},

		/**
		 * Return the the defined ajax method.
		 * @method getMapType
		 * @return {string} The ajax method.
		 */
		getMapType: function() {
			return this._mapType;
		},

		/**
		 * This function checks a variable to see if its set or not.
		 * @method isset.
		 * @parm {string} variable The method to be used.
		 * @return {boolean} Tt will either be true or false!
		 */
		isset: function(variable) {
			if ( variable != "" && variable != undefined  && variable != null ) {
				return true;
			}
			else {
				return false;
			}
		},

		/**
		 * This function deals with error messages.
		 * @method sendToDebug.
		 * @parm {string} message
		 */
		sendToDebug: function(message) {
			if ( this._debug ) {
				var currentTime = new Date();
				var hours = currentTime.getHours();
				if(hours > 11){	post = "pm";} else {post = "am";}
				if(hours > 12) {hours = hours - 12;}
				var minutes = currentTime.getMinutes();
				if (minutes < 10) {minutes = "0" + minutes;}
				var seconds = currentTime.getSeconds();
				if (seconds < 10) {seconds = "0" + seconds;}

				this._tracker += "<li style=\"padding-bottom: 5px;\">" + message + " {"+hours+":"+minutes+":"+seconds+post+"}</li>";

				var objDiv = document.getElementById("skMap_Debugger");
				objDiv.innerHTML = "<ol style=\"padding: 0px 0px 0px 25px;\">" + this._tracker + "</ol>";
				objDiv.scrollTop = objDiv.scrollHeight;
			}
			else {
				return null;
			}
		},

		/**
		 * This function initializes the entire map functionallity.
		 * @method init
		 */
		init: function() {
			//load the div panes and return the div id for the map.
			var mapDiv = this.loadDisplay();


			//globalObj will be used as the global map for the eventListener functions.
			globalObj = this;

			//create and initialize the map by declaring new GMap2.
			this._map = new GMap2(document.getElementById(mapDiv));
			this._map.setCenter(new GLatLng(this._defaultLat, this._defaultLng), this._defaultZoom);
			this.addRoundedCorners();

			G_NORMAL_MAP.getMaximumResolution = function() {return globalObj._maxZoom;}
			G_NORMAL_MAP.getMinimumResolution = function() {return globalObj._minZoom;}

			this.sendToDebug("{init} The map is currently <b>unlocked</b>.");
			//adding this control will hiding the pan buttons and move the controls more to the left than the original position.
			this._map.addControl(new GLargeMapControl(),new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(-14,-58)));
            this._map.addControl(new GScaleControl());
            this._map.addControl(new GMapTypeControl());
			//Note: that "moveend" includes zooming in and out aswell as moving the map manually.
			GEvent.addListener(this._map, "moveend", this.upDateResultsPane);

			this.loadOptions();

			if ( this._map.getZoom() < this._resultsZoom ) {
				this.sendToDebug("{init} Disaply info window disabled (zoom not enough).");
			}

			this._chMarkers = new MarkerManager(this._map, {borderPadding: 0, maxZoom: this._maxZoom, trackMarkers: false});
		},

		/**
		 * This function will add the rounded corners at the bottom of the map.
		 * @method addRoundedCorners
		 */
		addRoundedCorners: function() {
			function bottomLeft() {}
			//function bottomRight() {}

			bottomLeft.prototype = new GControl();
			//bottomRight.prototype = new GControl();

			bottomLeft.prototype.initialize = function(map) {
				var bottomLeft = document.createElement("div");
				bottomLeft.style.background = " url("+globalObj._imageRoot+"bottomLeft.png) no-repeat";
				bottomLeft.style.padding = "0px";
				bottomLeft.style.margin = "0px";
				bottomLeft.style.width = "6px";
				bottomLeft.style.height = "6px";
				map.getContainer().appendChild(bottomLeft);
				return bottomLeft;
			}

			bottomLeft.prototype.getDefaultPosition = function() {
				return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0,0));
			}

			//add the corners to the map
			this._map.addControl(new bottomLeft());
		},

		/**
		 * This function will create the required html elements and append them to the main div.
		 * @method loadDisplay
		 * @return {string} The id for the map div.
		 */
		loadDisplay: function() {
			//create a hidden input element to store the xml data in.
			var newTempXml = document.createElement("input");
			newTempXml.setAttribute("id", "skMap_xml");
			newTempXml.setAttribute("type", "hidden");
			newTempXml.setAttribute("value", "");

			document.getElementById(this._mainDiv).appendChild(newTempXml);

			if ( this._debug ) {
				var newDebugger = document.createElement("div");
				newDebugger.setAttribute("id", "skMap_Debugger");
				newDebugger.style.height = "200px";
				newDebugger.style.color = "#FEAC24";
				newDebugger.style.background = "#666";
				newDebugger.style.fontSize = "0.7em";
				newDebugger.style.marginTop = "10px";
				newDebugger.style.marginBottom = "10px";
				newDebugger.style.border = "2px solid #999";
				newDebugger.style.overflow = "auto";
				document.getElementById(this._mainDiv).appendChild(newDebugger);
				document.getElementById(this._mainDiv).style.height = "800px";
			}

			//return the div id for the actual map.
			return "skMap_loadGMap";
		},

		/**
		 * This function will create the checkboxes
		 * @method loadOptions
		 */
		loadOptions: function() {
			var thingsDiv = document.getElementById("thingsOptions");
			var whereDiv = document.getElementById("whereOptions");

			for(i=0; i<this._thingsToDo.length; i++) {
				thingsDiv.innerHTML = thingsDiv.innerHTML + "<div class=\"skMap_cOption\"><input type=\"checkbox\" name=\"skMapThingsToDo\" value=\""+i+"\" /> "+this._thingsToDo[i].title+"</div>\n";
				this._thingsToDo[i].manager = new MarkerManager(this._map, {borderPadding: 0, maxZoom: this._maxZoom, trackMarkers: false});
			}
			this.sendToDebug("{loadDisplay} Things to do checkboxes added, total of: '" + i +"'");

			for(i=0; i<this._whereToStay.length; i++) {
				whereDiv.innerHTML = whereDiv.innerHTML + "<div class=\"skMap_cOption\"><input type=\"checkbox\" name=\"skMapWhereToStay\" value=\""+i+"\" /> "+this._whereToStay[i].title+"</div>\n";
				this._whereToStay[i].manager = new MarkerManager(this._map, {borderPadding: 0, maxZoom: this._maxZoom, trackMarkers: false});
			}
			this.sendToDebug("{loadDisplay} Where to stay checkboxes added, total of: '" + i +"'");
		},

		/**
		 * This function will determine which products should be displayed
		 * @method applyOptions
		 */
		applyOptions: function() {
			if(YAHOO.util.Dom.getStyle('skMap_Options', 'display') == "none") {
				YAHOO.util.Dom.setStyle('skMap_Results', 'display', 'none');
				YAHOO.util.Dom.setStyle('skMap_Options', 'display', 'block');
				document.getElementById('switchButton_link').innerHTML = "<a class=\"apply_button\" href=\"#\" onclick=\"globalObj.applyOptions(); return false;\">apply choices</a>";
				YAHOO.util.Dom.setStyle('skMap_switchButton', 'width', '125px');
				return true;
			}

			var thingsToDoOptions = document.skMapProducts.skMapThingsToDo;
			var whereToStayOptions = document.skMapProducts.skMapWhereToStay;
			this._counter = 0;

			var ptid = new Array();
			var locationsPtid = new Array();

			for(i=0; i<thingsToDoOptions.length; i++) {
				this._thingsToDo[thingsToDoOptions[i].value].manager.hideMarkers();
				this._thingsToDo[thingsToDoOptions[i].value].show = false;
				if(thingsToDoOptions[i].checked == true && this._thingsToDo[thingsToDoOptions[i].value].loaded == true) {
					this._thingsToDo[thingsToDoOptions[i].value].manager.showMarkers();
					this._thingsToDo[thingsToDoOptions[i].value].show = true;
					this._counter++;
					locationsPtid = locationsPtid.concat(this._thingsToDo[thingsToDoOptions[i].value].ids);
				}
				else if(thingsToDoOptions[i].checked == true) {
					this._thingsToDo[thingsToDoOptions[i].value].manager.showMarkers();
					this._thingsToDo[thingsToDoOptions[i].value].show = true;
					ptid = ptid.concat(this._thingsToDo[thingsToDoOptions[i].value].ids);
					locationsPtid = locationsPtid.concat(this._thingsToDo[thingsToDoOptions[i].value].ids);
					this._counter++;
				}
			}

			for(i=0; i<whereToStayOptions.length; i++) {
				this._whereToStay[whereToStayOptions[i].value].manager.hideMarkers();
				this._whereToStay[whereToStayOptions[i].value].show = false;
				if(whereToStayOptions[i].checked == true && this._whereToStay[whereToStayOptions[i].value].loaded == true) {
					this._whereToStay[whereToStayOptions[i].value].manager.showMarkers();
					this._whereToStay[whereToStayOptions[i].value].show = true;
					locationsPtid = locationsPtid.concat(this._whereToStay[whereToStayOptions[i].value].ids);
					this._counter++;
				}
				else if(whereToStayOptions[i].checked == true) {
					this._whereToStay[whereToStayOptions[i].value].manager.showMarkers();
					this._whereToStay[whereToStayOptions[i].value].show = true;
					ptid = ptid.concat(this._whereToStay[whereToStayOptions[i].value].ids);
					locationsPtid = locationsPtid.concat(this._whereToStay[whereToStayOptions[i].value].ids);
					this._counter++;
				}
			}

			if (this._counter > 4 ) {
				alert("Please select a maxium of four options.");
				return false;
			}

			this._map.setZoom(this._map.getZoom());

			this._ptid = "";
			this._ptid = ptid;


			var loaded = false;

			if(this.isset(locationsPtid)) {
				YAHOO.util.Dom.setStyle('skMap_Options', 'display', 'none');
				YAHOO.util.Dom.setStyle('skMap_Loading', 'display', 'block');
				YAHOO.util.Dom.setStyle('skMap_switchButton', 'width', '151px');
				document.getElementById('switchButton_link').innerHTML = "<a class=\"apply_button\" href=\"#\" onclick=\"globalObj.applyOptions(); return false;\">advanced options</a>";
				loaded = true;
				this.loadXmlDropDown(locationsPtid);
			}

			if( this.isset(this._ptid)) {
				if (loaded == false) {
					YAHOO.util.Dom.setStyle('skMap_Options', 'display', 'none');
					YAHOO.util.Dom.setStyle('skMap_Loading', 'display', 'block');
					YAHOO.util.Dom.setStyle('skMap_switchButton', 'width', '151px');
					document.getElementById('switchButton_link').innerHTML = "<a class=\"apply_button\" href=\"#\" onclick=\"globalObj.applyOptions(); return false;\">advanced options</a>";
				}
				this.loadXml();
			}
			else {
				YAHOO.util.Dom.setStyle('skMap_Loading', 'display', 'none');
				YAHOO.util.Dom.setStyle('skMap_Results', 'display', 'block');
				YAHOO.util.Dom.setStyle('skMap_Options', 'display', 'none');
			}
		},

		/**
		 * This function will hide and show the advanced options pane
		 * @method hideShowPanes
		 * @parm {string} hide/show switch
		 */
		hideShowPanes: function(xv) {
			if (xv == "show") {
				var a = new YAHOO.util.Anim('skMap_Options', { opacity: { to: 1 } }, .7, YAHOO.util.Easing.easeNone);
				YAHOO.util.Dom.setStyle('skMap_Results', 'display', 'none');
				YAHOO.util.Dom.setStyle('skMap_Options', 'display', 'block');
				a.onComplete.subscribe(function(){
					document.getElementById('switchButton_link').innerHTML = "<a class=\"apply_button\" href=\"#\" onclick=\"globalObj.applyOptions(); return false;\">apply choices</a>";
					YAHOO.util.Dom.setStyle('skMap_switchButton', 'width', '125px');
				});
			}
			else {
				var a = new YAHOO.util.Anim('skMap_Options', { opacity: { to: 0 } }, .7, YAHOO.util.Easing.easeNone);
				a.onComplete.subscribe(function(){
					YAHOO.util.Dom.setStyle('skMap_Options', 'display', 'none');
					YAHOO.util.Dom.setStyle('skMap_Loading', 'display', 'block');
					YAHOO.util.Dom.setStyle('skMap_switchButton', 'width', '151px');
					document.getElementById('switchButton_link').innerHTML = "<a class=\"apply_button\" href=\"#\" onclick=\"globalObj.applyOptions(); return false;\">advanced options</a>";
					this.loadxml();
				});
			}
			a.animate();
		},

		/**
		 * This function will call up the xml file and save it for further use.
		 * @method loadXml
		 */
		loadXmlDropDown: function(ptid) {
			//launch GDownload to grab the xml doc
			GDownloadUrl(this.buildUrlRequest("dropdown", ptid), function(data, responseCode) {
				if (responseCode == 200) {
					var hiddenInput = document.getElementById("skMap_xml");
					//save the xml string into the value of a hidden input element for future use.
					hiddenInput.value = "";
					hiddenInput.value = data;
					globalObj.parseXml("dropdown");
				}
				else if(responseCode == -1) {
					//if there was no response then...
					this.sendToDebug("{loadXml} Data request timed out. Please try later.");
				}
				else {
					//if something goes wrong then...
					this.sendToDebug("{loadXml} Request resulted in error. Check XML file is retrievable.");
				}
			});
		},

		/**
		 * This function will call up the xml file and save it for further use.
		 * @method loadXml
		 */
		loadXml: function() {
			//launch GDownload to grab the xml doc
			GDownloadUrl(this.buildUrlRequest("large", null), function(data, responseCode) {
				if (responseCode == 200) {
					var hiddenInput = document.getElementById("skMap_xml");
					//save the xml string into the value of a hidden input element for future use.
					hiddenInput.value = "";
					hiddenInput.value = data;
					globalObj.parseXml("large");
				}
				else if(responseCode == -1) {
					//if there was no response then...
					this.sendToDebug("{loadXml} Data request timed out. Please try later.");
				}
				else {
					//if something goes wrong then...
				    this.sendToDebug("{loadXml} Request resulted in error. Check XML file is retrievable.");
				}
			});
		},

		/**
		 * This function will compile the needed parameters for the ajax request.
		 * @method buildUrlRequest.
		 * @parm {string} type The method to be used.
		 * @return {string} The url for the ajax call.
		 */
		buildUrlRequest: function(type, ptid) {
			var url = this._baseUrl;

			if ( type == "dropdown" ) {
				url += "productlocations.asp?method=locations";
			}
			else {
				url += "productdata2.asp?method="+this.getAjaxMethod();
			}

			if ( this.isset(ptid) ) {
				url += "&ptid="+ptid;
			}
			else if ( this.isset(this._ptid) ) {
				url += "&ptid="+this._ptid;
			}

			this.sendToDebug("{buildUrlRequest} " + url);
			return url;
		},

		/**
		 * This function will loap and set the points and add them to the GMarkerManager.
		 * @method parseXml
		 * @param {string} type The type of xml to be parsed
		 */
		parseXml: function(type) {
			if( type == "large" ) {
				var thingsToDoOptions = document.skMapProducts.skMapThingsToDo;
				var whereToStayOptions = document.skMapProducts.skMapWhereToStay;
				var data = document.getElementById("skMap_xml").value;
				document.getElementById("skMap_xml").value = "";

				var thingsIcon = new GIcon();
				thingsIcon.image = this._imageRoot + "map__icon_do_zoomedout.png";
				thingsIcon.iconSize = new GSize(8,8);
				thingsIcon.iconAnchor = new GPoint(3,13);

				var whereIcon = new GIcon();
				whereIcon.image = this._imageRoot + "map__icon_stay_zoomedout.png";
				whereIcon.iconSize = new GSize(8,8);
				whereIcon.iconAnchor = new GPoint(3,13);

				if ( this.isset(data) ) {
					var xmlDoc = GXml.parse(data);
					var markers = xmlDoc.documentElement.getElementsByTagName("OrgProduct");

					//go through each option
					for(i=0; i<thingsToDoOptions.length; i++) {
						//if the option is selected and has not been loaded before:
						if(thingsToDoOptions[i].checked == true && this._thingsToDo[thingsToDoOptions[i].value].loaded == false) {
							//go through each id of the selected option
							for(j=0; j<this._thingsToDo[thingsToDoOptions[i].value].ids.length; j++) {
								this._counter = 0;
								//go through each market that was returned
								for (var k = 0; k < markers.length; k++) {
									//check to see if the marker ptid matches
									if( this._thingsToDo[thingsToDoOptions[i].value].ids[j] == markers[k].getAttribute("OPTID")) {
										this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter] = function(){}
										this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter].pid = markers[k].getAttribute("OrgProductID");
										this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter].title = markers[k].getAttribute("OPName");
										this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter].cat = this._thingsToDo[thingsToDoOptions[i].value].title;
										this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter].text = markers[k].getAttribute("OPDescription");
										this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter].marker = this.createMarker(markers[k].getAttribute("OrgProductID"), new GLatLng(parseFloat(markers[k].getAttribute("OPLat")),parseFloat(markers[k].getAttribute("OPLong"))), markers[k].getAttribute("OPDescription"), markers[k].getAttribute("OPName"), thingsIcon, markers[k].getAttribute("OrgProductID"));
										this._thingsToDo[thingsToDoOptions[i].value].manager.addMarker(this._thingsToDo[thingsToDoOptions[i].value].markers[this._counter].marker, this._minZoom, (this._resultsZoom - 1));
										this._counter++;
									}
								}
							}
							//refresh the manager so the markers display
							this._thingsToDo[thingsToDoOptions[i].value].manager.refresh();
							this._thingsToDo[thingsToDoOptions[i].value].loaded = true;
						}
					}

					//go through each option
					for(i=0; i<whereToStayOptions.length; i++) {
						//if the option is selected and has not been loaded before:
						if(whereToStayOptions[i].checked == true && this._whereToStay[whereToStayOptions[i].value].loaded == false) {
							//go through each id of the selected option
							for(j=0; j<this._whereToStay[whereToStayOptions[i].value].ids.length; j++) {
								this._counter = 0;
								//go through each market that was returned
								for (var k = 0; k < markers.length; k++) {
									//check to see if the marker ptid matches
									if( this._whereToStay[whereToStayOptions[i].value].ids[j] == markers[k].getAttribute("OPTID")) {
										this._whereToStay[whereToStayOptions[i].value].markers[this._counter] = function(){}
										this._whereToStay[whereToStayOptions[i].value].markers[this._counter].pid = markers[k].getAttribute("OrgProductID");
										this._whereToStay[whereToStayOptions[i].value].markers[this._counter].title = markers[k].getAttribute("OPName");
										this._whereToStay[whereToStayOptions[i].value].markers[this._counter].cat = this._whereToStay[whereToStayOptions[i].value].title;
										this._whereToStay[whereToStayOptions[i].value].markers[this._counter].text = markers[k].getAttribute("OPDescription");
										this._whereToStay[whereToStayOptions[i].value].markers[this._counter].marker = this.createMarker(markers[k].getAttribute("OrgProductID"), new GLatLng(parseFloat(markers[k].getAttribute("OPLat")),parseFloat(markers[k].getAttribute("OPLong"))), markers[k].getAttribute("OPDescription"), markers[k].getAttribute("OPName"), whereIcon, markers[k].getAttribute("OrgProductID"));
										this._whereToStay[whereToStayOptions[i].value].manager.addMarker(this._whereToStay[whereToStayOptions[i].value].markers[this._counter].marker, this._minZoom, (this._resultsZoom - 1));
										//this._whereToStay[whereToStayOptions[i].value].manager.addMarker(this.createMarker(markers[k].getAttribute("OrgProductID"), new GLatLng(parseFloat(markers[k].getAttribute("OPLat")),parseFloat(markers[k].getAttribute("OPLong"))), markers[k].getAttribute("OPDescription"), markers[k].getAttribute("OPName"), G_DEFAULT_ICON), (this._resultsZoom+1), this._maxZoom);
									this._counter++;
									}
								}
							}
							//refresh the manager so the markers display
							this._whereToStay[whereToStayOptions[i].value].manager.refresh();
							this._whereToStay[whereToStayOptions[i].value].loaded = true;
						}
					}
				}


				YAHOO.util.Dom.setStyle('skMap_Loading', 'display', 'none');
				YAHOO.util.Dom.setStyle('skMap_Results', 'display', 'block');
			}
			else if ( type == "dropdown" ) {
				var data = document.getElementById("skMap_xml").value;
				var dropDown = document.getElementById("skMap_whereDD");
				for(i=0;i<dropDown.options.length;i++) {
					dropDown.remove(i);
				}
				var counter = 2;
				var xmlDoc = GXml.parse(data);
				var locations = xmlDoc.documentElement.getElementsByTagName("OPLocation");
				dropDown.options[0] = new Option("Already know where you're going?", "");
				dropDown.options[1] = new Option("", "0");

				for (var i = 0; i < locations.length; i++) {
					var details = [];
					details["latitude"] = parseFloat(locations[i].getAttribute("Lat"));
					details["longitude"] = parseFloat(locations[i].getAttribute("Long"));
					details["zoom"] = parseInt(locations[i].getAttribute("ZoomLevel"));
					dropDown.options[counter] = new Option(locations[i].getAttribute("LocationName"), locations[i].getAttribute("LocationID"));
					this._locationManager[locations[i].getAttribute("LocationID")] = details;
					counter++;
				}
			}

			this.upDateResultsPane();
		},

		/**
		 * This function will loap and set the points with the MarkerManager.
		 * @method createMarker
		 * @param {int} The product index number
		 * @param {GPoint} point The lat and lng for this marker
		 * @param {string} text The text for the bubble
		 * @param {string} title The text for the tooltip
		 * @param {GIcon} aIcon The the icon object to be used
		 * @param {string} imagePath the path of the icon to be used
		 * @return {GMarker} The marker that was created
		 */
		createMarker: function(index, point, text, name, aIcon, pid) {
			var m = new GMarker(point, {draggable:false, icon:aIcon, title:name});
            var t = m.getTitle();
            
			GEvent.addListener(m, "click", function() {
				globalObj._lockEvent = true;
				globalObj.clickZoomCenter("marker", point);
				globalObj._lockEvent = true;
				globalObj._map.openInfoWindowHtml(m.getPoint(), "<div style=\"height:180px;border:solid 0px #444444;\"><p style=\"text-align: left; font-weight: bold;\">"+m.getTitle()+"</p><p style=\"text-align: left;\">"+text+"</p><div class=\"details_link\"><a href=\"/travel-information/product-detail&opid="+pid+"\" target=\"Product Detail\" onclick=\"javascript:dcsMultiTrack(\'DCS.dcssip\',\'www.sasktourism.com\',\'DCS.dcsuri\',\'LMapDetail\',\'WT.ti\',\'"+t.replace(/'/g,"\\'")+"\',\'WT.cg_n\',\'\',\'WT.cg_s\',\'\',\'WT.ad\',\'" +t.replace(/'/g,"\\'")+ "\',\'WT.ac\',\'\',\'DCSext.LMapDetail\',\'1\',\'DCSext.SearchDetail\',\'1\');\">Complete details</a></div></div>", {maxWidth:250});
			});

			return m;
		},

		/**
		 * This function will create the lettered markers.
		 * @method buildLetteredMaker
		 * @param {GMarker} The current marker at that point
		 * @param {int} The product id
		 * @param {string} The product description
		 * @param {string} The product name
		 * @param {char} The letter to be used
		 * @return {GMarker} The lettered marker that was created
		 */
		buildLetteredMaker: function(cM, pid, text, name, letter, imagePath) {
			var li = new GIcon(G_DEFAULT_ICON);
			li.image = imagePath + letter.toLowerCase() + ".png";
			li.iconSize = new GSize(21,35);
			li.iconAnchor = new GPoint(9, 35);
			li.shadow = globalObj._imageRoot + "map__icon_shadow.png";
			li.shadowSize = new GSize(42, 35);

			ct = cM.getTitle();
			var t = ct

			var marker = new GMarker(cM.getPoint(), {draggable:false, icon:li, title:ct});

			GEvent.addListener(marker, "click", function() {
				globalObj._lockEvent = true;
				globalObj._map.setCenter(cM.getPoint());
				globalObj._lockEvent = true;
				globalObj._map.openInfoWindowHtml(cM.getPoint(), "<div style=\"height:180px;border:solid 0px #444444;\"><p style=\"text-align: left; font-weight: bold;\">"+cM.getTitle()+"</p><p style=\"text-align: left;\">"+text+"</p><div class=\"details_link\"><a href=\"/travel-information/product-detail&opid="+pid+"\" target=\"Product Detail\" onclick=\"javascript:dcsMultiTrack(\'DCS.dcssip\',\'www.sasktourism.com\',\'DCS.dcsuri\',\'LMapDetail\',\'WT.ti\',\'"+t.replace(/'/g,"\\'")+"\',\'WT.cg_n\',\'\',\'WT.cg_s\',\'\',\'WT.ad\',\'" +t.replace(/'/g,"\\'")+ "\',\'WT.ac\',\'\',\'DCSext.LMapDetail\',\'1\',\'DCSext.SearchDetail\',\'1\');\">Complete details</a></div></div>", {maxWidth:250});
			});

			return marker;
		},

		/**
		 * This function will set the location from the dropdown menu.
		 * @method changeSelectedDD
		 * @param {int} type The index of the array that contains the details.
		 */
		changeSelectedDD: function(index) {
			if ( index == "" || index == "0" ) {
				this.sendToDebug("{changeSelectedDD} Index was zero or null.");
				return null;
			}
			this.sendToDebug("{changeSelectedDD} Index "+index+" was selected.");
			var details = this._locationManager[index];
			this._map.setCenter(new GLatLng(details["latitude"], details["longitude"]));
			this._map.setZoom(this._resultsZoom);
		},

		/**
		 * This function will update the results pane after the map zooms or moves.
		 * @method upDateResultsPane
		 */
		upDateResultsPane: function() {
			if ( globalObj._lockEvent == true ) {
				globalObj._lockEvent = false;
				return null;
			}

			var thingsResults = document.getElementById("thingsResults");
			var whereResults = document.getElementById("whereResults");

			globalObj.sendToDebug("{upDateResultsPane} Zoom:" + globalObj._map.getZoom()+".");

			//if the minimum zoom has not been met, then terminate this function.
			if ( globalObj._map.getZoom() < globalObj._resultsZoom ) {
				thingsResults.innerHTML = "";
				whereResults.innerHTML = "";
				//globalObj._map.disableInfoWindow();
				globalObj._chMarkers.clearMarkers();
				globalObj._chMarkers.refresh();
				return null;
			}
			else {
				//globalObj._map.enableInfoWindow();
			}

			//clear the current lettered markers
			globalObj._chMarkers.clearMarkers();
			globalObj._chMarkers.refresh();


			var bounds = globalObj._map.getBounds();
			var southWest = bounds.getSouthWest();
			var northEast = bounds.getNorthEast();

			var thingsBatch = "";
			var whereBatch = "";
			var jj = 0;
			var imagePath = globalObj._imageRoot + "map__icon_do_";
			for(i=0; i<globalObj._thingsToDo.length; i++) {
				if(globalObj._thingsToDo[i].show == true && globalObj._thingsToDo[i].loaded == true) {
					for(j=0; j<globalObj._thingsToDo[i].markers.length; j++) {
						var point = globalObj._thingsToDo[i].markers[j].marker.getPoint();
						if ( point.lng() > southWest.lng() && point.lng() < northEast.lng() && point.lat() > southWest.lat() && point.lat() < northEast.lat() ) {
							var letter = String.fromCharCode("A".charCodeAt(0) + jj);
							if(jj > 25){letter = "blank";}
							globalObj._gMarkers[globalObj._thingsToDo[i].markers[j].pid] = globalObj.buildLetteredMaker(globalObj._thingsToDo[i].markers[j].marker, globalObj._thingsToDo[i].markers[j].pid, globalObj._thingsToDo[i].markers[j].text, globalObj._thingsToDo[i].markers[j].title, letter, imagePath);
							thingsBatch += "<table id=\"skMapAnchor_"+letter.toLowerCase()+"\" class=\"resultsTable\"><tr><td class=\"icon\"><a href=\"#\" onclick=\"GEvent.trigger(globalObj._gMarkers[globalObj._thingsToDo["+i+"].markers["+j+"].pid], 'click'); return false;\"><img src=\"" + globalObj._imageRoot + "map__key_do_" + letter.toLowerCase()+".gif\" /></a></td><td class=\"link\"><a href=\"#\" onclick=\"GEvent.trigger(globalObj._gMarkers[globalObj._thingsToDo["+i+"].markers["+j+"].pid], 'click'); return false;\">" + globalObj._thingsToDo[i].markers[j].title + " <span class=\"marker_category\">["+globalObj._thingsToDo[i].markers[j].cat+"]</span></a><div id=\"skMapDescrip_"+letter.toLowerCase()+"\" class=\"description\" style=\"display: none;\">TESTING<br /><div class=\"details_link\"><a href=\"/page.asp?pageid=179&opid=\">Complete details</a></div></div></td></tr></table>\n";
							globalObj._chMarkers.addMarker(globalObj._gMarkers[globalObj._thingsToDo[i].markers[j].pid], globalObj._resultsZoom, globalObj._maxZoom);
							jj++;
						}
					}
				}
			}

			var jj = 0;
			var imagePath = globalObj._imageRoot + "map__icon_stay_";
			for(i=0; i<globalObj._whereToStay.length; i++) {
				if(globalObj._whereToStay[i].show == true && globalObj._whereToStay[i].loaded == true) {
					for(j=0; j<globalObj._whereToStay[i].markers.length; j++) {
						var point = globalObj._whereToStay[i].markers[j].marker.getPoint();
						if ( point.lng() > southWest.lng() && point.lng() < northEast.lng() && point.lat() > southWest.lat() && point.lat() < northEast.lat() ) {
							var letter = String.fromCharCode("A".charCodeAt(0) + jj);
							if(jj > 25){letter = "blank";}
							globalObj._gMarkers[globalObj._whereToStay[i].markers[j].pid] = globalObj.buildLetteredMaker(globalObj._whereToStay[i].markers[j].marker, globalObj._whereToStay[i].markers[j].pid, globalObj._whereToStay[i].markers[j].text, globalObj._whereToStay[i].markers[j].title, letter, imagePath);
							whereBatch += "<table id=\"skMapAnchor_"+letter.toLowerCase()+"\" class=\"resultsTable\"><tr><td class=\"icon\"><a href=\"#\" onclick=\"GEvent.trigger(globalObj._gMarkers[globalObj._whereToStay["+i+"].markers["+j+"].pid], 'click'); return false;\"><img src=\"" + globalObj._imageRoot + "map__key_stay_" + letter.toLowerCase()+".gif\" /></a></td><td class=\"link\"><a href=\"#\" onclick=\"GEvent.trigger(globalObj._gMarkers[globalObj._whereToStay["+i+"].markers["+j+"].pid], 'click'); return false;\">" + globalObj._whereToStay[i].markers[j].title + " <span class=\"marker_category\">["+globalObj._whereToStay[i].markers[j].cat+"]</span></a></td></tr></table>\n";
							globalObj._chMarkers.addMarker(globalObj._gMarkers[globalObj._whereToStay[i].markers[j].pid], globalObj._resultsZoom, globalObj._maxZoom);
							jj++;
						}
					}
				}
			}

			globalObj._chMarkers.refresh();
			thingsResults.innerHTML  = thingsBatch
			whereResults.innerHTML  = whereBatch
		},

		/**
		 * This function will center and zoom to the point that was clicked.
		 * @method clickZoomCenter
		 * @param {GMap2} The map that was clicked
		 * @param {GPoint} The click coords
		 */
		clickZoomCenter: function(map, point) {
			if ( globalObj._map.getZoom() < globalObj._resultsZoom ) {
				globalObj._map.setCenter(point);
				globalObj._map.setZoom(globalObj._resultsZoom);
			}
		}
	}
}



/**
 * This will be the only function explicity called
 * @method loadSkMapObj
 */
function loadSkMapObj() {
	stMaps = new SaskTourismMapsMgr();
	stMaps.setMapType(this.preSkMap_mapType);
	stMaps.setAjaxMethod(this.preSkMap_ajaxMethod);
	stMaps.setProducts(preSkMap_thingsToDo, preSkMap_whereToStay);

	if ( this.preSkMap_debug == true || this.preSkMap_debug == false ) {
		stMaps.setDebug(this.preSkMap_debug);
	}

	if ( this.preSkMap_lock ) {
		stMaps.lock();
	}

	//start everything!
	stMaps.init();

	//this will attach a listener for when the page is left or closed, elimiating (for the most part) javascript leaks.
	if (window.attachEvent) {
		window.attachEvent("onunload", GUnload);
	}
	else {
		window.addEventListener("unload", GUnload, false);
	}
}



/**
 * Creates a new MarkerManager that will show/hide markers on a map.
 *
 * @constructor
 * @param {Map} map The map to manage.
 * @param {Object} opt_opts A container for optional arguments:
 * 		{Number} maxZoom The maximum zoom level for which to create tiles.
 * 		{Number} borderPadding The width in pixels beyond the map border, where markers should be display.
 * 		{Boolean} trackMarkers Whether or not this manager should track marker movements.
 */
function MarkerManager(map, opt_opts) {
  var me = this;
  me.map_ = map;
  me.mapZoom_ = map.getZoom();
  me.projection_ = map.getCurrentMapType().getProjection();

  opt_opts = opt_opts || {};
  me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;

  var maxZoom = MarkerManager.DEFAULT_MAX_ZOOM_;
  if(opt_opts.maxZoom != undefined) {
    maxZoom = opt_opts.maxZoom;
  }
  me.maxZoom_ = maxZoom;

  me.trackMarkers_ = opt_opts.trackMarkers;

  var padding;
  if (typeof opt_opts.borderPadding == "number") {
    padding = opt_opts.borderPadding;
  } else {
    padding = MarkerManager.DEFAULT_BORDER_PADDING_;
  }
  // The padding in pixels beyond the viewport, where we will pre-load markers.
  me.swPadding_ = new GSize(-padding, padding);
  me.nePadding_ = new GSize(padding, -padding);
  me.borderPadding_ = padding;

  me.gridWidth_ = [];

  me.grid_ = [];
  me.grid_[maxZoom] = [];
  me.numMarkers_ = [];
  me.numMarkers_[maxZoom] = 0;

  GEvent.bind(map, "moveend", me, me.onMapMoveEnd_);

  // NOTE: These two closures provide easy access to the map.
  // They are used as callbacks, not as methods.
  me.removeOverlay_ = function(marker) {
    if (!marker.isInfoWindowOpened) {
      map.removeOverlay(marker);
      me.shownMarkers_--;
    }
  };
  me.addOverlay_ = function(marker) {
    if (!marker.isInfoWindowOpened) {
      marker.isInfoWindowOpened = false;
      map.addOverlay(marker);
      me.shownMarkers_++;
    }
  };

  me.resetManager_();
  me.shownMarkers_ = 0;

  me.shownBounds_ = me.getMapGridBounds_();
};

// Static constants:
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
MarkerManager.DEFAULT_MAX_ZOOM_ = this._maxZoom;
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;


/**
 * Initializes MarkerManager arrays for all zoom levels
 * Called by constructor and by clearAllMarkers
 */
MarkerManager.prototype.resetManager_ = function() {
  var me = this;
  var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
  for (var zoom = 0; zoom <= me.maxZoom_; ++zoom) {
    me.grid_[zoom] = [];
    me.numMarkers_[zoom] = 0;
    me.gridWidth_[zoom] = Math.ceil(mapWidth/me.tileSize_);
    mapWidth <<= 1;
  }
};

/**
 * Removes all currently displayed markers
 * and calls resetManager to clear arrays
 */
MarkerManager.prototype.clearMarkers = function() {
  var me = this;
  me.processAll_(me.shownBounds_, me.removeOverlay_);
  me.resetManager_();
};





MarkerManager.prototype.hideMarkers = function() {
  var me = this;
  me.maxZoom_ = 0;
};

MarkerManager.prototype.showMarkers = function() {
  var me = this;
  me.maxZoom_ = 17;
};


/**
 * Gets the tile coordinate for a given latlng point.
 *
 * @param {LatLng} latlng The geographical point.
 * @param {Number} zoom The zoom level.
 * @param {GSize} padding The padding used to shift the pixel coordinate.
 *               Used for expanding a bounds to include an extra padding
 *               of pixels surrounding the bounds.
 * @return {GPoint} The point in tile coordinates.
 *
 */
MarkerManager.prototype.getTilePoint_ = function(latlng, zoom, padding) {
  var pixelPoint = this.projection_.fromLatLngToPixel(latlng, zoom);
  return new GPoint(
      Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
      Math.floor((pixelPoint.y + padding.height) / this.tileSize_));
};


/**
 * Finds the appropriate place to add the marker to the grid.
 * Optimized for speed; does not actually add the marker to the map.
 * Designed for batch-processing thousands of markers.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom for displaying the marker.
 * @param {Number} maxZoom The maximum zoom for displaying the marker.
 */
MarkerManager.prototype.addMarkerBatch_ = function(marker, minZoom, maxZoom) {
  var mPoint = marker.getPoint();
  // Tracking markers is expensive, so we do this only if the
  // user explicitly requested it when creating marker manager.
  if (this.trackMarkers_) {
    GEvent.bind(marker, "changed", this, this.onMarkerMoved_);
  }

  GEvent.addListener(marker, "infowindowopen", function() {
    marker.isInfoWindowOpened = true;
  });

  GEvent.addListener(marker, "infowindowclose", function() {
    marker.isInfoWindowOpened = false;
  });

  var gridPoint = this.getTilePoint_(mPoint, maxZoom, GSize.ZERO);

  for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
    var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
    cell.push(marker);

    gridPoint.x = gridPoint.x >> 1;
    gridPoint.y = gridPoint.y >> 1;
  }
};


/**
 * Returns whether or not the given point is visible in the shown bounds. This
 * is a helper method that takes care of the corner case, when shownBounds have
 * negative minX value.
 *
 * @param {Point} point a point on a grid.
 * @return {Boolean} Whether or not the given point is visible in the currently
 * shown bounds.
 */
MarkerManager.prototype.isGridPointVisible_ = function(point) {
  var me = this;
  var vertical = me.shownBounds_.minY <= point.y &&
      point.y <= me.shownBounds_.maxY;
  var minX = me.shownBounds_.minX;
  var horizontal = minX <= point.x && point.x <= me.shownBounds_.maxX;
  if (!horizontal && minX < 0) {
    // Shifts the negative part of the rectangle. As point.x is always less
    // than grid width, only test shifted minX .. 0 part of the shown bounds.
    var width = me.gridWidth_[me.shownBounds_.z];
    horizontal = minX + width <= point.x && point.x <= width - 1;
  }
  return vertical && horizontal;
}


/**
 * Reacts to a notification from a marker that it has moved to a new location.
 * It scans the grid all all zoom levels and moves the marker from the old grid
 * location to a new grid location.
 *
 * @param {Marker} marker The marker that moved.
 * @param {LatLng} oldPoint The old position of the marker.
 * @param {LatLng} newPoint The new position of the marker.
 */
MarkerManager.prototype.onMarkerMoved_ = function(marker, oldPoint, newPoint) {
  // NOTE: We do not know the minimum or maximum zoom the marker was
  // added at, so we start at the absolute maximum. Whenever we successfully
  // remove a marker at a given zoom, we add it at the new grid coordinates.
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var oldGrid = me.getTilePoint_(oldPoint, zoom, GSize.ZERO);
  var newGrid = me.getTilePoint_(newPoint, zoom, GSize.ZERO);
  while (zoom >= 0 && (oldGrid.x != newGrid.x || oldGrid.y != newGrid.y)) {
    var cell = me.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
    if (cell) {
      if (me.removeFromArray(cell, marker)) {
        me.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
      }
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. Markers that moved into
    // the shown bounds are added to the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(oldGrid)) {
        if (!me.isGridPointVisible_(newGrid)) {
          me.removeOverlay_(marker);
          changed = true;
        }
      } else {
        if (me.isGridPointVisible_(newGrid)) {
          me.addOverlay_(marker);
          changed = true;
        }
      }
    }
    oldGrid.x = oldGrid.x >> 1;
    oldGrid.y = oldGrid.y >> 1;
    newGrid.x = newGrid.x >> 1;
    newGrid.y = newGrid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Searches at every zoom level to find grid cell
 * that marker would be in, removes from that array if found.
 * Also removes marker with removeOverlay if visible.
 * @param {GMarker} marker The marker to delete.
 */
MarkerManager.prototype.removeMarker = function(marker) {
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var point = marker.getPoint();
  var grid = me.getTilePoint_(point, zoom, GSize.ZERO);
  while (zoom >= 0) {
    var cell = me.getGridCellNoCreate_(grid.x, grid.y, zoom);

    if (cell) {
      me.removeFromArray(cell, marker);
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(grid)) {
          me.removeOverlay_(marker);
          changed = true;
      }
    }
    grid.x = grid.x >> 1;
    grid.y = grid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Add many markers at once.
 * Does not actually update the map, just the internal grid.
 *
 * @param {Array of Marker} markers The markers to add.
 * @param {Number} minZoom The minimum zoom level to display the markers.
 * @param {Number} opt_maxZoom The maximum zoom level to display the markers.
 */
MarkerManager.prototype.addMarkers = function(markers, minZoom, opt_maxZoom) {
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  for (var i = markers.length - 1; i >= 0; i--) {
    this.addMarkerBatch_(markers[i], minZoom, maxZoom);
  }

  this.numMarkers_[minZoom] += markers.length;
  this.refresh();
};


/**
 * Returns the value of the optional maximum zoom. This method is defined so
 * that we have just one place where optional maximum zoom is calculated.
 *
 * @param {Number} opt_maxZoom The optinal maximum zoom.
 * @return The maximum zoom.
 */
MarkerManager.prototype.getOptMaxZoom_ = function(opt_maxZoom) {
  return opt_maxZoom != undefined ? opt_maxZoom : this.maxZoom_;
}


/**
 * Calculates the total number of markers potentially visible at a given
 * zoom level.
 *
 * @param {Number} zoom The zoom level to check.
 */
MarkerManager.prototype.getMarkerCount = function(zoom) {
  var total = 0;
  for (var z = 0; z <= zoom; z++) {
    total += this.numMarkers_[z];
  }
  return total;
};


/**
 * Add a single marker to the map.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom level to display the marker.
 * @param {Number} opt_maxZoom The maximum zoom level to display the marker.
 */
MarkerManager.prototype.addMarker = function(marker, minZoom, opt_maxZoom) {
  var me = this;
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  me.addMarkerBatch_(marker, minZoom, maxZoom);
  var gridPoint = me.getTilePoint_(marker.getPoint(), me.mapZoom_, GSize.ZERO);
  if(me.isGridPointVisible_(gridPoint) &&
     minZoom <= me.shownBounds_.z &&
     me.shownBounds_.z <= maxZoom ) {
    me.addOverlay_(marker);
    me.notifyListeners_();
  }
  this.numMarkers_[minZoom]++;
};

/**
 * Returns true if this bounds (inclusively) contains the given point.
 * @param {Point} point  The point to test.
 * @return {Boolean} This Bounds contains the given Point.
 */
GBounds.prototype.containsPoint = function(point) {
  var outer = this;
  return (outer.minX <= point.x &&
          outer.maxX >= point.x &&
          outer.minY <= point.y &&
          outer.maxY >= point.y);
}

/**
 * Get a cell in the grid, creating it first if necessary.
 *
 * Optimization candidate
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  if (!gridCol) {
    gridCol = grid[x] = [];
    return gridCol[y] = [];
  }
  var gridCell = gridCol[y];
  if (!gridCell) {
    return gridCol[y] = [];
  }
  return gridCell;
};


/**
 * Get a cell in the grid, returning undefined if it does not exist.
 *
 * NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellNoCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  return gridCol ? gridCol[y] : undefined;
};


/**
 * Turns at geographical bounds into a grid-space bounds.
 *
 * @param {LatLngBounds} bounds The geographical bounds.
 * @param {Number} zoom The zoom level of the bounds.
 * @param {GSize} swPadding The padding in pixels to extend beyond the
 * given bounds.
 * @param {GSize} nePadding The padding in pixels to extend beyond the
 * given bounds.
 * @return {GBounds} The bounds in grid space.
 */
MarkerManager.prototype.getGridBounds_ = function(bounds, zoom, swPadding,
                                                  nePadding) {
  zoom = Math.min(zoom, this.maxZoom_);

  var bl = bounds.getSouthWest();
  var tr = bounds.getNorthEast();
  var sw = this.getTilePoint_(bl, zoom, swPadding);
  var ne = this.getTilePoint_(tr, zoom, nePadding);
  var gw = this.gridWidth_[zoom];

  // Crossing the prime meridian requires correction of bounds.
  if (tr.lng() < bl.lng() || ne.x < sw.x) {
    sw.x -= gw;
  }
  if (ne.x - sw.x  + 1 >= gw) {
    // Computed grid bounds are larger than the world; truncate.
    sw.x = 0;
    ne.x = gw - 1;
  }
  var gridBounds = new GBounds([sw, ne]);
  gridBounds.z = zoom;
  return gridBounds;
};


/**
 * Gets the grid-space bounds for the current map viewport.
 *
 * @return {Bounds} The bounds in grid space.
 */
MarkerManager.prototype.getMapGridBounds_ = function() {
  var me = this;
  return me.getGridBounds_(me.map_.getBounds(), me.mapZoom_,
                           me.swPadding_, me.nePadding_);
};


/**
 * Event listener for map:movend.
 * NOTE: Use a timeout so that the user is not blocked
 * from moving the map.
 *
 */
MarkerManager.prototype.onMapMoveEnd_ = function() {
  var me = this;
  me.objectSetTimeout_(this, this.updateMarkers_, 0);
};


/**
 * Call a function or evaluate an expression after a specified number of
 * milliseconds.
 *
 * Equivalent to the standard window.setTimeout function, but the given
 * function executes as a method of this instance. So the function passed to
 * objectSetTimeout can contain references to this.
 *    objectSetTimeout(this, function() { alert(this.x) }, 1000);
 *
 * @param {Object} object  The target object.
 * @param {Function} command  The command to run.
 * @param {Number} milliseconds  The delay.
 * @return {Boolean}  Success.
 */
MarkerManager.prototype.objectSetTimeout_ = function(object, command, milliseconds) {
  return window.setTimeout(function() {
    command.call(object);
  }, milliseconds);
};


/**
 * Refresh forces the marker-manager into a good state.
 * <ol>
 *   <li>If never before initialized, shows all the markers.</li>
 *   <li>If previously initialized, removes and re-adds all markers.</li>
 * </ol>
 */
MarkerManager.prototype.refresh = function() {
  var me = this;
  if (me.shownMarkers_ > 0) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
  }
  me.processAll_(me.shownBounds_, me.addOverlay_);
  me.notifyListeners_();
};


/**
 * After the viewport may have changed, add or remove markers as needed.
 */
MarkerManager.prototype.updateMarkers_ = function() {
  var me = this;
  me.mapZoom_ = this.map_.getZoom();
  var newBounds = me.getMapGridBounds_();

  // If the move does not include new grid sections,
  // we have no work to do:
  if (newBounds.equals(me.shownBounds_) && newBounds.z == me.shownBounds_.z) {
    return;
  }

  if (newBounds.z != me.shownBounds_.z) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
    me.processAll_(newBounds, me.addOverlay_);
  } else {
    // Remove markers:
    me.rectangleDiff_(me.shownBounds_, newBounds, me.removeCellMarkers_);

    // Add markers:
    me.rectangleDiff_(newBounds, me.shownBounds_, me.addCellMarkers_);
  }
  me.shownBounds_ = newBounds;

  me.notifyListeners_();
};


/**
 * Notify listeners when the state of what is displayed changes.
 */
MarkerManager.prototype.notifyListeners_ = function() {
  GEvent.trigger(this, "changed", this.shownBounds_, this.shownMarkers_);
};


/**
 * Process all markers in the bounds provided, using a callback.
 *
 * @param {Bounds} bounds The bounds in grid space.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processAll_ = function(bounds, callback) {
  for (var x = bounds.minX; x <= bounds.maxX; x++) {
    for (var y = bounds.minY; y <= bounds.maxY; y++) {
      this.processCellMarkers_(x, y,  bounds.z, callback);
    }
  }
};


/**
 * Process all markers in the grid cell, using a callback.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processCellMarkers_ = function(x, y, z, callback) {
  var cell = this.getGridCellNoCreate_(x, y, z);
  if (cell) {
    for (var i = cell.length - 1; i >= 0; i--) {
      callback(cell[i]);
    }
  }
};


/**
 * Remove all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.removeCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.removeOverlay_);
};


/**
 * Add all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.addCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.addOverlay_);
};


/**
 * Use the rectangleDiffCoords function to process all grid cells
 * that are in bounds1 but not bounds2, using a callback, and using
 * the current MarkerManager object as the instance.
 *
 * Pass the z parameter to the callback in addition to x and y.
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate (x, y, z).
 */
MarkerManager.prototype.rectangleDiff_ = function(bounds1, bounds2, callback) {
  var me = this;
  me.rectangleDiffCoords(bounds1, bounds2, function(x, y) {
    callback.apply(me, [x, y, bounds1.z]);
  });
};


/**
 * Calls the function for all points in bounds1, not in bounds2
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate.
 */
MarkerManager.prototype.rectangleDiffCoords = function(bounds1, bounds2, callback) {
  var minX1 = bounds1.minX;
  var minY1 = bounds1.minY;
  var maxX1 = bounds1.maxX;
  var maxY1 = bounds1.maxY;
  var minX2 = bounds2.minX;
  var minY2 = bounds2.minY;
  var maxX2 = bounds2.maxX;
  var maxY2 = bounds2.maxY;

  for (var x = minX1; x <= maxX1; x++) {  // All x in R1
    // All above:
    for (var y = minY1; y <= maxY1 && y < minY2; y++) {  // y in R1 above R2
      callback(x, y);
    }
    // All below:
    for (var y = Math.max(maxY2 + 1, minY1);  // y in R1 below R2
         y <= maxY1; y++) {
      callback(x, y);
    }
  }

  for (var y = Math.max(minY1, minY2);
       y <= Math.min(maxY1, maxY2); y++) {  // All y in R2 and in R1
    // Strictly left:
    for (var x = Math.min(maxX1 + 1, minX2) - 1;
         x >= minX1; x--) {  // x in R1 left of R2
      callback(x, y);
    }
    // Strictly right:
    for (var x = Math.max(minX1, maxX2 + 1);  // x in R1 right of R2
         x <= maxX1; x++) {
      callback(x, y);
    }
  }
};


/**
 * Removes value from array. O(N).
 *
 * @param {Array} array  The array to modify.
 * @param {any} value  The value to remove.
 * @param {Boolean} opt_notype  Flag to disable type checking in equality.
 * @return {Number}  The number of instances of value that were removed.
 */
MarkerManager.prototype.removeFromArray = function(array, value, opt_notype) {
  var shift = 0;
  for (var i = 0; i < array.length; ++i) {
    if (array[i] === value || (opt_notype && array[i] == value)) {
      array.splice(i--, 1);
      shift++;
    }
  }
  return shift;
};


/* Copyright (c) 2007, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.4.1 */
/* Global Event DOM */
	if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C<A.length;C=C+1){D=A[C].split(".");E=YAHOO;for(B=(D[0]=="YAHOO")?1:0;B<D.length;B=B+1){E[D[B]]=E[D[B]]||{};E=E[D[B]];}}return E;};YAHOO.log=function(D,A,C){var B=YAHOO.widget.Logger;if(B&&B.log){return B.log(D,A,C);}else{return false;}};YAHOO.register=function(A,E,D){var I=YAHOO.env.modules;if(!I[A]){I[A]={versions:[],builds:[]};}var B=I[A],H=D.version,G=D.build,F=YAHOO.env.listeners;B.name=A;B.version=H;B.build=G;B.versions.push(H);B.builds.push(G);B.mainClass=E;for(var C=0;C<F.length;C=C+1){F[C](B);}if(E){E.VERSION=H;E.BUILD=G;}else{YAHOO.log("mainClass is undefined for module "+A,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(A){return YAHOO.env.modules[A]||null;};YAHOO.env.ua=function(){var C={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0};var B=navigator.userAgent,A;if((/KHTML/).test(B)){C.webkit=1;}A=B.match(/AppleWebKit\/([^\s]*)/);if(A&&A[1]){C.webkit=parseFloat(A[1]);if(/ Mobile\//.test(B)){C.mobile="Apple";}else{A=B.match(/NokiaN[^\/]*/);if(A){C.mobile=A[0];}}A=B.match(/AdobeAIR\/([^\s]*)/);if(A){C.air=A[0];}}if(!C.webkit){A=B.match(/Opera[\s\/]([^\s]*)/);if(A&&A[1]){C.opera=parseFloat(A[1]);A=B.match(/Opera Mini[^;]*/);if(A){C.mobile=A[0];}}else{A=B.match(/MSIE\s([^;]*)/);if(A&&A[1]){C.ie=parseFloat(A[1]);}else{A=B.match(/Gecko\/([^\s]*)/);if(A){C.gecko=1;A=B.match(/rv:([^\s\)]*)/);if(A&&A[1]){C.gecko=parseFloat(A[1]);}}}}}return C;}();(function(){YAHOO.namespace("util","widget","example");if("undefined"!==typeof YAHOO_config){var B=YAHOO_config.listener,A=YAHOO.env.listeners,D=true,C;if(B){for(C=0;C<A.length;C=C+1){if(A[C]==B){D=false;break;}}if(D){A.push(B);}}}})();YAHOO.lang=YAHOO.lang||{isArray:function(B){if(B){var A=YAHOO.lang;return A.isNumber(B.length)&&A.isFunction(B.splice);}return false;},isBoolean:function(A){return typeof A==="boolean";},isFunction:function(A){return typeof A==="function";},isNull:function(A){return A===null;},isNumber:function(A){return typeof A==="number"&&isFinite(A);},isObject:function(A){return(A&&(typeof A==="object"||YAHOO.lang.isFunction(A)))||false;},isString:function(A){return typeof A==="string";},isUndefined:function(A){return typeof A==="undefined";},hasOwnProperty:function(A,B){if(Object.prototype.hasOwnProperty){return A.hasOwnProperty(B);}return !YAHOO.lang.isUndefined(A[B])&&A.constructor.prototype[B]!==A[B];},_IEEnumFix:function(C,B){if(YAHOO.env.ua.ie){var E=["toString","valueOf"],A;for(A=0;A<E.length;A=A+1){var F=E[A],D=B[F];if(YAHOO.lang.isFunction(D)&&D!=Object.prototype[F]){C[F]=D;}}}},extend:function(D,E,C){if(!E||!D){throw new Error("YAHOO.lang.extend failed, please check that "+"all dependencies are included.");}var B=function(){};B.prototype=E.prototype;D.prototype=new B();D.prototype.constructor=D;D.superclass=E.prototype;if(E.prototype.constructor==Object.prototype.constructor){E.prototype.constructor=E;}if(C){for(var A in C){D.prototype[A]=C[A];}YAHOO.lang._IEEnumFix(D.prototype,C);}},augmentObject:function(E,D){if(!D||!E){throw new Error("Absorb failed, verify dependencies.");}var A=arguments,C,F,B=A[2];if(B&&B!==true){for(C=2;C<A.length;C=C+1){E[A[C]]=D[A[C]];}}else{for(F in D){if(B||!E[F]){E[F]=D[F];}}YAHOO.lang._IEEnumFix(E,D);}},augmentProto:function(D,C){if(!C||!D){throw new Error("Augment failed, verify dependencies.");}var A=[D.prototype,C.prototype];for(var B=2;B<arguments.length;B=B+1){A.push(arguments[B]);}YAHOO.lang.augmentObject.apply(this,A);},dump:function(A,G){var C=YAHOO.lang,D,F,I=[],J="{...}",B="f(){...}",H=", ",E=" => ";if(!C.isObject(A)){return A+"";}else{if(A instanceof Date||("nodeType" in A&&"tagName" in A)){return A;}else{if(C.isFunction(A)){return B;}}}G=(C.isNumber(G))?G:3;if(C.isArray(A)){I.push("[");for(D=0,F=A.length;D<F;D=D+1){if(C.isObject(A[D])){I.push((G>0)?C.dump(A[D],G-1):J);}else{I.push(A[D]);}I.push(H);}if(I.length>1){I.pop();}I.push("]");}else{I.push("{");for(D in A){if(C.hasOwnProperty(A,D)){I.push(D+E);if(C.isObject(A[D])){I.push((G>0)?C.dump(A[D],G-1):J);}else{I.push(A[D]);}I.push(H);}}if(I.length>1){I.pop();}I.push("}");}return I.join("");},substitute:function(Q,B,J){var G,F,E,M,N,P,D=YAHOO.lang,L=[],C,H="dump",K=" ",A="{",O="}";for(;;){G=Q.lastIndexOf(A);if(G<0){break;}F=Q.indexOf(O,G);if(G+1>=F){break;}C=Q.substring(G+1,F);M=C;P=null;E=M.indexOf(K);if(E>-1){P=M.substring(E+1);M=M.substring(0,E);}N=B[M];if(J){N=J(M,N,P);}if(D.isObject(N)){if(D.isArray(N)){N=D.dump(N,parseInt(P,10));}else{P=P||"";var I=P.indexOf(H);if(I>-1){P=P.substring(4);}if(N.toString===Object.prototype.toString||I>-1){N=D.dump(N,parseInt(P,10));}else{N=N.toString();}}}else{if(!D.isString(N)&&!D.isNumber(N)){N="~-"+L.length+"-~";L[L.length]=C;}}Q=Q.substring(0,G)+N+Q.substring(F+1);}for(G=L.length-1;G>=0;G=G-1){Q=Q.replace(new RegExp("~-"+G+"-~"),"{"+L[G]+"}","g");}return Q;},trim:function(A){try{return A.replace(/^\s+|\s+$/g,"");}catch(B){return A;}},merge:function(){var D={},B=arguments;for(var C=0,A=B.length;C<A;C=C+1){YAHOO.lang.augmentObject(D,B[C],true);}return D;},later:function(H,B,I,D,E){H=H||0;B=B||{};var C=I,G=D,F,A;if(YAHOO.lang.isString(I)){C=B[I];}if(!C){throw new TypeError("method undefined");}if(!YAHOO.lang.isArray(G)){G=[D];}F=function(){C.apply(B,G);};A=(E)?setInterval(F,H):setTimeout(F,H);return{interval:E,cancel:function(){if(this.interval){clearInterval(A);}else{clearTimeout(A);}}};},isValue:function(B){var A=YAHOO.lang;return(A.isObject(B)||A.isString(B)||A.isNumber(B)||A.isBoolean(B));}};YAHOO.util.Lang=YAHOO.lang;YAHOO.lang.augment=YAHOO.lang.augmentProto;YAHOO.augment=YAHOO.lang.augmentProto;YAHOO.extend=YAHOO.lang.extend;YAHOO.register("yahoo",YAHOO,{version:"2.5.1",build:"984"});(function(){var B=YAHOO.util,K,I,J={},F={},M=window.document;YAHOO.env._id_counter=YAHOO.env._id_counter||0;var C=YAHOO.env.ua.opera,L=YAHOO.env.ua.webkit,A=YAHOO.env.ua.gecko,G=YAHOO.env.ua.ie;var E={HYPHEN:/(-[a-z])/i,ROOT_TAG:/^body|html$/i,OP_SCROLL:/^(?:inline|table-row)$/i};var N=function(P){if(!E.HYPHEN.test(P)){return P;}if(J[P]){return J[P];}var Q=P;while(E.HYPHEN.exec(Q)){Q=Q.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());}J[P]=Q;return Q;};var O=function(Q){var P=F[Q];if(!P){P=new RegExp("(?:^|\\s+)"+Q+"(?:\\s+|$)");F[Q]=P;}return P;};if(M.defaultView&&M.defaultView.getComputedStyle){K=function(P,S){var R=null;if(S=="float"){S="cssFloat";}var Q=P.ownerDocument.defaultView.getComputedStyle(P,"");if(Q){R=Q[N(S)];}return P.style[S]||R;};}else{if(M.documentElement.currentStyle&&G){K=function(P,R){switch(N(R)){case"opacity":var T=100;try{T=P.filters["DXImageTransform.Microsoft.Alpha"].opacity;}catch(S){try{T=P.filters("alpha").opacity;}catch(S){}}return T/100;case"float":R="styleFloat";default:var Q=P.currentStyle?P.currentStyle[R]:null;return(P.style[R]||Q);}};}else{K=function(P,Q){return P.style[Q];};}}if(G){I=function(P,Q,R){switch(Q){case"opacity":if(YAHOO.lang.isString(P.style.filter)){P.style.filter="alpha(opacity="+R*100+")";if(!P.currentStyle||!P.currentStyle.hasLayout){P.style.zoom=1;}}break;case"float":Q="styleFloat";default:P.style[Q]=R;}};}else{I=function(P,Q,R){if(Q=="float"){Q="cssFloat";}P.style[Q]=R;};}var D=function(P,Q){return P&&P.nodeType==1&&(!Q||Q(P));};YAHOO.util.Dom={get:function(R){if(R&&(R.nodeType||R.item)){return R;}if(YAHOO.lang.isString(R)||!R){return M.getElementById(R);}if(R.length!==undefined){var S=[];for(var Q=0,P=R.length;Q<P;++Q){S[S.length]=B.Dom.get(R[Q]);}return S;}return R;},getStyle:function(P,R){R=N(R);var Q=function(S){return K(S,R);};return B.Dom.batch(P,Q,B.Dom,true);},setStyle:function(P,R,S){R=N(R);var Q=function(T){I(T,R,S);};B.Dom.batch(P,Q,B.Dom,true);},getXY:function(P){var Q=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,"display")=="none")&&R!=R.ownerDocument.body){return false;}return H(R);};return B.Dom.batch(P,Q,B.Dom,true);},getX:function(P){var Q=function(R){return B.Dom.getXY(R)[0];};return B.Dom.batch(P,Q,B.Dom,true);},getY:function(P){var Q=function(R){return B.Dom.getXY(R)[1];};return B.Dom.batch(P,Q,B.Dom,true);},setXY:function(P,S,R){var Q=function(V){var U=this.getStyle(V,"position");if(U=="static"){this.setStyle(V,"position","relative");U="relative";}var X=this.getXY(V);if(X===false){return false;}var W=[parseInt(this.getStyle(V,"left"),10),parseInt(this.getStyle(V,"top"),10)];if(isNaN(W[0])){W[0]=(U=="relative")?0:V.offsetLeft;}if(isNaN(W[1])){W[1]=(U=="relative")?0:V.offsetTop;}if(S[0]!==null){V.style.left=S[0]-X[0]+W[0]+"px";}if(S[1]!==null){V.style.top=S[1]-X[1]+W[1]+"px";}if(!R){var T=this.getXY(V);if((S[0]!==null&&T[0]!=S[0])||(S[1]!==null&&T[1]!=S[1])){this.setXY(V,S,true);}}};B.Dom.batch(P,Q,B.Dom,true);},setX:function(Q,P){B.Dom.setXY(Q,[P,null]);},setY:function(P,Q){B.Dom.setXY(P,[null,Q]);},getRegion:function(P){var Q=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,"display")=="none")&&R!=R.ownerDocument.body){return false;}var S=B.Region.getRegion(R);return S;};return B.Dom.batch(P,Q,B.Dom,true);},getClientWidth:function(){return B.Dom.getViewportWidth();},getClientHeight:function(){return B.Dom.getViewportHeight();},getElementsByClassName:function(T,X,U,V){X=X||"*";U=(U)?B.Dom.get(U):null||M;if(!U){return[];}var Q=[],P=U.getElementsByTagName(X),W=O(T);for(var R=0,S=P.length;R<S;++R){if(W.test(P[R].className)){Q[Q.length]=P[R];if(V){V.call(P[R],P[R]);}}}return Q;},hasClass:function(R,Q){var P=O(Q);var S=function(T){return P.test(T.className);};return B.Dom.batch(R,S,B.Dom,true);},addClass:function(Q,P){var R=function(S){if(this.hasClass(S,P)){return false;}S.className=YAHOO.lang.trim([S.className,P].join(" "));return true;};return B.Dom.batch(Q,R,B.Dom,true);},removeClass:function(R,Q){var P=O(Q);var S=function(T){if(!Q||!this.hasClass(T,Q)){return false;}var U=T.className;T.className=U.replace(P," ");if(this.hasClass(T,Q)){this.removeClass(T,Q);}T.className=YAHOO.lang.trim(T.className);return true;};return B.Dom.batch(R,S,B.Dom,true);},replaceClass:function(S,Q,P){if(!P||Q===P){return false;}var R=O(Q);var T=function(U){if(!this.hasClass(U,Q)){this.addClass(U,P);return true;}U.className=U.className.replace(R," "+P+" ");if(this.hasClass(U,Q)){this.replaceClass(U,Q,P);}U.className=YAHOO.lang.trim(U.className);return true;};return B.Dom.batch(S,T,B.Dom,true);},generateId:function(P,R){R=R||"yui-gen";var Q=function(S){if(S&&S.id){return S.id;}var T=R+YAHOO.env._id_counter++;if(S){S.id=T;}return T;};return B.Dom.batch(P,Q,B.Dom,true)||Q.apply(B.Dom,arguments);},isAncestor:function(P,Q){P=B.Dom.get(P);Q=B.Dom.get(Q);if(!P||!Q){return false;}if(P.contains&&Q.nodeType&&!L){return P.contains(Q);}else{if(P.compareDocumentPosition&&Q.nodeType){return !!(P.compareDocumentPosition(Q)&16);}else{if(Q.nodeType){return !!this.getAncestorBy(Q,function(R){return R==P;});}}}return false;},inDocument:function(P){return this.isAncestor(M.documentElement,P);},getElementsBy:function(W,Q,R,T){Q=Q||"*";R=(R)?B.Dom.get(R):null||M;if(!R){return[];}var S=[],V=R.getElementsByTagName(Q);for(var U=0,P=V.length;U<P;++U){if(W(V[U])){S[S.length]=V[U];if(T){T(V[U]);}}}return S;},batch:function(T,W,V,R){T=(T&&(T.tagName||T.item))?T:B.Dom.get(T);if(!T||!W){return false;}var S=(R)?V:window;if(T.tagName||T.length===undefined){return W.call(S,T,V);}var U=[];for(var Q=0,P=T.length;Q<P;++Q){U[U.length]=W.call(S,T[Q],V);}return U;},getDocumentHeight:function(){var Q=(M.compatMode!="CSS1Compat")?M.body.scrollHeight:M.documentElement.scrollHeight;var P=Math.max(Q,B.Dom.getViewportHeight());return P;},getDocumentWidth:function(){var Q=(M.compatMode!="CSS1Compat")?M.body.scrollWidth:M.documentElement.scrollWidth;var P=Math.max(Q,B.Dom.getViewportWidth());return P;},getViewportHeight:function(){var P=self.innerHeight;
	var Q=M.compatMode;if((Q||G)&&!C){P=(Q=="CSS1Compat")?M.documentElement.clientHeight:M.body.clientHeight;}return P;},getViewportWidth:function(){var P=self.innerWidth;var Q=M.compatMode;if(Q||G){P=(Q=="CSS1Compat")?M.documentElement.clientWidth:M.body.clientWidth;}return P;},getAncestorBy:function(P,Q){while(P=P.parentNode){if(D(P,Q)){return P;}}return null;},getAncestorByClassName:function(Q,P){Q=B.Dom.get(Q);if(!Q){return null;}var R=function(S){return B.Dom.hasClass(S,P);};return B.Dom.getAncestorBy(Q,R);},getAncestorByTagName:function(Q,P){Q=B.Dom.get(Q);if(!Q){return null;}var R=function(S){return S.tagName&&S.tagName.toUpperCase()==P.toUpperCase();};return B.Dom.getAncestorBy(Q,R);},getPreviousSiblingBy:function(P,Q){while(P){P=P.previousSibling;if(D(P,Q)){return P;}}return null;},getPreviousSibling:function(P){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getPreviousSiblingBy(P);},getNextSiblingBy:function(P,Q){while(P){P=P.nextSibling;if(D(P,Q)){return P;}}return null;},getNextSibling:function(P){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getNextSiblingBy(P);},getFirstChildBy:function(P,R){var Q=(D(P.firstChild,R))?P.firstChild:null;return Q||B.Dom.getNextSiblingBy(P.firstChild,R);},getFirstChild:function(P,Q){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getFirstChildBy(P);},getLastChildBy:function(P,R){if(!P){return null;}var Q=(D(P.lastChild,R))?P.lastChild:null;return Q||B.Dom.getPreviousSiblingBy(P.lastChild,R);},getLastChild:function(P){P=B.Dom.get(P);return B.Dom.getLastChildBy(P);},getChildrenBy:function(Q,S){var R=B.Dom.getFirstChildBy(Q,S);var P=R?[R]:[];B.Dom.getNextSiblingBy(R,function(T){if(!S||S(T)){P[P.length]=T;}return false;});return P;},getChildren:function(P){P=B.Dom.get(P);if(!P){}return B.Dom.getChildrenBy(P);},getDocumentScrollLeft:function(P){P=P||M;return Math.max(P.documentElement.scrollLeft,P.body.scrollLeft);},getDocumentScrollTop:function(P){P=P||M;return Math.max(P.documentElement.scrollTop,P.body.scrollTop);},insertBefore:function(Q,P){Q=B.Dom.get(Q);P=B.Dom.get(P);if(!Q||!P||!P.parentNode){return null;}return P.parentNode.insertBefore(Q,P);},insertAfter:function(Q,P){Q=B.Dom.get(Q);P=B.Dom.get(P);if(!Q||!P||!P.parentNode){return null;}if(P.nextSibling){return P.parentNode.insertBefore(Q,P.nextSibling);}else{return P.parentNode.appendChild(Q);}},getClientRegion:function(){var R=B.Dom.getDocumentScrollTop(),Q=B.Dom.getDocumentScrollLeft(),S=B.Dom.getViewportWidth()+Q,P=B.Dom.getViewportHeight()+R;return new B.Region(R,S,P,Q);}};var H=function(){if(M.documentElement.getBoundingClientRect){return function(Q){var R=Q.getBoundingClientRect();var P=Q.ownerDocument;return[R.left+B.Dom.getDocumentScrollLeft(P),R.top+B.Dom.getDocumentScrollTop(P)];};}else{return function(R){var S=[R.offsetLeft,R.offsetTop];var Q=R.offsetParent;var P=(L&&B.Dom.getStyle(R,"position")=="absolute"&&R.offsetParent==R.ownerDocument.body);if(Q!=R){while(Q){S[0]+=Q.offsetLeft;S[1]+=Q.offsetTop;if(!P&&L&&B.Dom.getStyle(Q,"position")=="absolute"){P=true;}Q=Q.offsetParent;}}if(P){S[0]-=R.ownerDocument.body.offsetLeft;S[1]-=R.ownerDocument.body.offsetTop;}Q=R.parentNode;while(Q.tagName&&!E.ROOT_TAG.test(Q.tagName)){if(Q.scrollTop||Q.scrollLeft){if(!E.OP_SCROLL.test(B.Dom.getStyle(Q,"display"))){if(!C||B.Dom.getStyle(Q,"overflow")!=="visible"){S[0]-=Q.scrollLeft;S[1]-=Q.scrollTop;}}}Q=Q.parentNode;}return S;};}}();})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this[0]=B;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top);var D=Math.min(this.right,E.right);var A=Math.min(this.bottom,E.bottom);var B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top);var D=Math.max(this.right,E.right);var A=Math.max(this.bottom,E.bottom);var B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D);var C=F[1];var E=F[0]+D.offsetWidth;var A=F[1]+D.offsetHeight;var B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}this.x=this.right=this.left=this[0]=A;this.y=this.top=this.bottom=this[1]=B;};YAHOO.util.Point.prototype=new YAHOO.util.Region();YAHOO.register("dom",YAHOO.util.Dom,{version:"2.5.1",build:"984"});YAHOO.util.CustomEvent=function(D,B,C,A){this.type=D;this.scope=B||window;this.silent=C;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var E="_YUICEOnSubscribe";if(D!==E){this.subscribeEvent=new YAHOO.util.CustomEvent(E,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,A){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,A);}this.subscribers.push(new YAHOO.util.Subscriber(B,C,A));},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B<A;++B){var C=this.subscribers[B];if(C&&C.contains(D,F)){this._delete(B);E=true;}}return E;},fire:function(){var D=this.subscribers.length;if(!D&&this.silent){return true;}var H=[].slice.call(arguments,0),F=true,C,I=false;if(!this.silent){}var B=this.subscribers.slice();for(C=0;C<D;++C){var K=B[C];if(!K){I=true;}else{if(!this.silent){}var J=K.getScope(this.scope);if(this.signature==YAHOO.util.CustomEvent.FLAT){var A=null;if(H.length>0){A=H[0];}try{F=K.fn.call(J,A,K.obj);}catch(E){this.lastError=E;}}else{try{F=K.fn.call(J,this.type,H,K.obj);}catch(G){this.lastError=G;}}if(false===F){if(!this.silent){}return false;}}}return true;},unsubscribeAll:function(){for(var A=this.subscribers.length-1;A>-1;A--){this._delete(A);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(B,C,A){this.fn=B;this.obj=YAHOO.lang.isUndefined(C)?null:C;this.override=A;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.override){if(this.override===true){return this.obj;}else{return this.override;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var H=false;var I=[];var J=[];var G=[];var E=[];var C=0;var F=[];var B=[];var A=0;var D={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9};return{POLL_RETRYS:2000,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,_dri:null,DOMReady:false,startInterval:function(){if(!this._interval){var K=this;var L=function(){K._tryPreloadAttach();};this._interval=setInterval(L,this.POLL_INTERVAL);}},onAvailable:function(P,M,Q,O,N){var K=(YAHOO.lang.isString(P))?[P]:P;for(var L=0;L<K.length;L=L+1){F.push({id:K[L],fn:M,obj:Q,override:O,checkReady:N});}C=this.POLL_RETRYS;this.startInterval();},onContentReady:function(M,K,N,L){this.onAvailable(M,K,N,L,true);},onDOMReady:function(K,M,L){if(this.DOMReady){setTimeout(function(){var N=window;if(L){if(L===true){N=M;}else{N=L;}}K.call(N,"DOMReady",[],M);},0);}else{this.DOMReadyEvent.subscribe(K,M,L);}},addListener:function(M,K,V,Q,L){if(!V||!V.call){return false;}if(this._isValidCollection(M)){var W=true;for(var R=0,T=M.length;R<T;++R){W=this.on(M[R],K,V,Q,L)&&W;}return W;}else{if(YAHOO.lang.isString(M)){var P=this.getEl(M);if(P){M=P;}else{this.onAvailable(M,function(){YAHOO.util.Event.on(M,K,V,Q,L);});return true;}}}if(!M){return false;}if("unload"==K&&Q!==this){J[J.length]=[M,K,V,Q,L];return true;}var Y=M;if(L){if(L===true){Y=Q;}else{Y=L;}}var N=function(Z){return V.call(Y,YAHOO.util.Event.getEvent(Z,M),Q);};var X=[M,K,V,N,Y,Q,L];var S=I.length;I[S]=X;if(this.useLegacyEvent(M,K)){var O=this.getLegacyIndex(M,K);if(O==-1||M!=G[O][0]){O=G.length;B[M.id+K]=O;G[O]=[M,K,M["on"+K]];E[O]=[];M["on"+K]=function(Z){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(Z),O);};}E[O].push(X);}else{try{this._simpleAdd(M,K,N,false);}catch(U){this.lastError=U;this.removeListener(M,K,V);return false;}}return true;},fireLegacyEvent:function(O,M){var Q=true,K,S,R,T,P;S=E[M].slice();for(var L=0,N=S.length;L<N;++L){R=S[L];if(R&&R[this.WFN]){T=R[this.ADJ_SCOPE];P=R[this.WFN].call(T,O);Q=(Q&&P);}}K=G[M];if(K&&K[2]){K[2](O);}return Q;},getLegacyIndex:function(L,M){var K=this.generateId(L)+M;if(typeof B[K]=="undefined"){return -1;}else{return B[K];}},useLegacyEvent:function(L,M){if(this.webkit&&("click"==M||"dblclick"==M)){var K=parseInt(this.webkit,10);if(!isNaN(K)&&K<418){return true;}}return false;},removeListener:function(L,K,T){var O,R,V;if(typeof L=="string"){L=this.getEl(L);}else{if(this._isValidCollection(L)){var U=true;for(O=L.length-1;O>-1;O--){U=(this.removeListener(L[O],K,T)&&U);}return U;}}if(!T||!T.call){return this.purgeElement(L,false,K);}if("unload"==K){for(O=J.length-1;O>-1;O--){V=J[O];if(V&&V[0]==L&&V[1]==K&&V[2]==T){J.splice(O,1);return true;}}return false;}var P=null;var Q=arguments[3];if("undefined"===typeof Q){Q=this._getCacheIndex(L,K,T);}if(Q>=0){P=I[Q];}if(!L||!P){return false;}if(this.useLegacyEvent(L,K)){var N=this.getLegacyIndex(L,K);var M=E[N];if(M){for(O=0,R=M.length;O<R;++O){V=M[O];if(V&&V[this.EL]==L&&V[this.TYPE]==K&&V[this.FN]==T){M.splice(O,1);break;}}}}else{try{this._simpleRemove(L,K,P[this.WFN],false);}catch(S){this.lastError=S;return false;}}delete I[Q][this.WFN];delete I[Q][this.FN];I.splice(Q,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;
	if(!K){if(L.type=="mouseout"){K=L.toElement;}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in D)){K=D[K];}return K;},_getCacheIndex:function(O,P,N){for(var M=0,L=I.length;M<L;M=M+1){var K=I[M];if(K&&K[this.FN]==N&&K[this.EL]==O&&K[this.TYPE]==P){return M;}}return -1;},generateId:function(K){var L=K.id;if(!L){L="yuievtautoid-"+A;++A;K.id=L;}return L;},_isValidCollection:function(L){try{return(L&&typeof L!=="string"&&L.length&&!L.tagName&&!L.alert&&typeof L[0]!=="undefined");}catch(K){return false;}},elCache:{},getEl:function(K){return(typeof K==="string")?document.getElementById(K):K;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",this),_load:function(L){if(!H){H=true;var K=YAHOO.util.Event;K._ready();K._tryPreloadAttach();}},_ready:function(L){var K=YAHOO.util.Event;if(!K.DOMReady){K.DOMReady=true;K.DOMReadyEvent.fire();K._simpleRemove(document,"DOMContentLoaded",K._ready);}},_tryPreloadAttach:function(){if(F.length===0){C=0;clearInterval(this._interval);this._interval=null;return ;}if(this.locked){return ;}if(this.isIE){if(!this.DOMReady){this.startInterval();return ;}}this.locked=true;var Q=!H;if(!Q){Q=(C>0&&F.length>0);}var P=[];var R=function(T,U){var S=T;if(U.override){if(U.override===true){S=U.obj;}else{S=U.override;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=F.length;L<K;L=L+1){O=F[L];if(O){N=this.getEl(O.id);if(N){if(O.checkReady){if(H||N.nextSibling||!Q){M.push(O);F[L]=null;}}else{R(N,O);F[L]=null;}}else{P.push(O);}}}for(L=0,K=M.length;L<K;L=L+1){O=M[L];R(this.getEl(O.id),O);}C--;if(Q){for(L=F.length-1;L>-1;L--){O=F[L];if(!O||!O.id){F.splice(L,1);}}this.startInterval();}else{clearInterval(this._interval);this._interval=null;}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N<K;++N){this.purgeElement(M.childNodes[N],P,R);}}},getListeners:function(M,K){var P=[],L;if(!K){L=[I,J];}else{if(K==="unload"){L=[J];}else{L=[I];}}var R=(YAHOO.lang.isString(M))?this.getEl(M):M;for(var O=0;O<L.length;O=O+1){var T=L[O];if(T){for(var Q=0,S=T.length;Q<S;++Q){var N=T[Q];if(N&&N[this.EL]===R&&(!K||K===N[this.TYPE])){P.push({type:N[this.TYPE],fn:N[this.FN],obj:N[this.OBJ],adjust:N[this.OVERRIDE],scope:N[this.ADJ_SCOPE],index:Q});}}}}return(P.length)?P:null;},_unload:function(Q){var K=YAHOO.util.Event,N,M,L,P,O,R=J.slice();for(N=0,P=J.length;N<P;++N){L=R[N];if(L){var S=window;if(L[K.ADJ_SCOPE]){if(L[K.ADJ_SCOPE]===true){S=L[K.UNLOAD_OBJ];}else{S=L[K.ADJ_SCOPE];}}L[K.FN].call(S,K.getEvent(Q,L[K.EL]),L[K.UNLOAD_OBJ]);R[N]=null;L=null;S=null;}}J=null;if(I){for(M=I.length-1;M>-1;M--){L=I[M];if(L){K.removeListener(L[K.EL],L[K.TYPE],L[K.FN],M);}}L=null;}G=null;K._simpleRemove(window,"unload",K._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;
	/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller */
	if(EU.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,override:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);},createEvent:function(G,D){this.__yui_events=this.__yui_events||{};var A=D||{};var I=this.__yui_events;if(I[G]){}else{var H=A.scope||this;var E=(A.silent);var B=new YAHOO.util.CustomEvent(G,H,E,YAHOO.util.CustomEvent.FLAT);
	I[G]=B;if(A.onSubscribeCallback){B.subscribeEvent.subscribe(A.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var F=this.__yui_subscribers[G];if(F){for(var C=0;C<F.length;++C){B.subscribe(F[C].fn,F[C].obj,F[C].override);}}}return I[G];},fireEvent:function(E,D,A,C){this.__yui_events=this.__yui_events||{};var G=this.__yui_events[E];if(!G){return null;}var B=[];for(var F=1;F<arguments.length;++F){B.push(arguments[F]);}return G.fire.apply(G,B);},hasEvent:function(A){if(this.__yui_events){if(this.__yui_events[A]){return true;}}return false;}};YAHOO.util.KeyListener=function(A,F,B,C){if(!A){}else{if(!F){}else{if(!B){}}}if(!C){C=YAHOO.util.KeyListener.KEYDOWN;}var D=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(typeof A=="string"){A=document.getElementById(A);}if(typeof B=="function"){D.subscribe(B);}else{D.subscribe(B.fn,B.scope,B.correctScope);}function E(J,I){if(!F.shift){F.shift=false;}if(!F.alt){F.alt=false;}if(!F.ctrl){F.ctrl=false;}if(J.shiftKey==F.shift&&J.altKey==F.alt&&J.ctrlKey==F.ctrl){var G;if(F.keys instanceof Array){for(var H=0;H<F.keys.length;H++){G=F.keys[H];if(G==J.charCode){D.fire(J.charCode,J);break;}else{if(G==J.keyCode){D.fire(J.keyCode,J);break;}}}}else{G=F.keys;if(G==J.charCode){D.fire(J.charCode,J);}else{if(G==J.keyCode){D.fire(J.keyCode,J);}}}}}this.enable=function(){if(!this.enabled){YAHOO.util.Event.addListener(A,C,E);this.enabledEvent.fire(F);}this.enabled=true;};this.disable=function(){if(this.enabled){YAHOO.util.Event.removeListener(A,C,E);this.disabledEvent.fire(F);}this.enabled=false;};this.toString=function(){return"KeyListener ["+F.keys+"] "+A.tagName+(A.id?"["+A.id+"]":"");};};YAHOO.util.KeyListener.KEYDOWN="keydown";YAHOO.util.KeyListener.KEYUP="keyup";YAHOO.util.KeyListener.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};YAHOO.register("event",YAHOO.util.Event,{version:"2.5.1",build:"984"});YAHOO.register("yahoo-dom-event", YAHOO, {version: "2.5.1", build: "984"});
/* Animation */
	(function(){var B=YAHOO.util;var A=function(D,C,E,F){if(!D){}this.init(D,C,E,F);};A.NAME="Anim";A.prototype={toString:function(){var C=this.getEl()||{};var D=C.id||C.tagName;return(this.constructor.NAME+": "+D);},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(C,E,D){return this.method(this.currentFrame,E,D-E,this.totalFrames);},setAttribute:function(C,E,D){if(this.patterns.noNegatives.test(C)){E=(E>0)?E:0;}B.Dom.setStyle(this.getEl(),C,E+D);},getAttribute:function(C){var E=this.getEl();var G=B.Dom.getStyle(E,C);if(G!=="auto"&&!this.patterns.offsetUnit.test(G)){return parseFloat(G);}var D=this.patterns.offsetAttribute.exec(C)||[];var H=!!(D[3]);var F=!!(D[2]);if(F||(B.Dom.getStyle(E,"position")=="absolute"&&H)){G=E["offset"+D[0].charAt(0).toUpperCase()+D[0].substr(1)];}else{G=0;}return G;},getDefaultUnit:function(C){if(this.patterns.defaultUnit.test(C)){return"px";}return"";},setRuntimeAttribute:function(D){var I;var E;var F=this.attributes;this.runtimeAttributes[D]={};var H=function(J){return(typeof J!=="undefined");};if(!H(F[D]["to"])&&!H(F[D]["by"])){return false;}I=(H(F[D]["from"]))?F[D]["from"]:this.getAttribute(D);if(H(F[D]["to"])){E=F[D]["to"];}else{if(H(F[D]["by"])){if(I.constructor==Array){E=[];for(var G=0,C=I.length;G<C;++G){E[G]=I[G]+F[D]["by"][G]*1;}}else{E=I+F[D]["by"]*1;}}}this.runtimeAttributes[D].start=I;this.runtimeAttributes[D].end=E;this.runtimeAttributes[D].unit=(H(F[D].unit))?F[D]["unit"]:this.getDefaultUnit(D);return true;},init:function(E,J,I,C){var D=false;var F=null;var H=0;E=B.Dom.get(E);this.attributes=J||{};this.duration=!YAHOO.lang.isUndefined(I)?I:1;this.method=C||B.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=B.AnimMgr.fps;this.setEl=function(M){E=B.Dom.get(M);};this.getEl=function(){return E;};this.isAnimated=function(){return D;};this.getStartTime=function(){return F;};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false;}this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(B.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&&this.useSeconds){this.totalFrames=1;}B.AnimMgr.registerElement(this);return true;};this.stop=function(M){if(!this.isAnimated()){return false;}if(M){this.currentFrame=this.totalFrames;this._onTween.fire();}B.AnimMgr.stop(this);};var L=function(){this.onStart.fire();this.runtimeAttributes={};for(var M in this.attributes){this.setRuntimeAttribute(M);}D=true;H=0;F=new Date();};var K=function(){var O={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};O.toString=function(){return("duration: "+O.duration+", currentFrame: "+O.currentFrame);};this.onTween.fire(O);var N=this.runtimeAttributes;for(var M in N){this.setAttribute(M,this.doMethod(M,N[M].start,N[M].end),N[M].unit);}H+=1;};var G=function(){var M=(new Date()-F)/1000;var N={duration:M,frames:H,fps:H/M};N.toString=function(){return("duration: "+N.duration+", frames: "+N.frames+", fps: "+N.fps);};D=false;H=0;this.onComplete.fire(N);};this._onStart=new B.CustomEvent("_start",this,true);this.onStart=new B.CustomEvent("start",this);this.onTween=new B.CustomEvent("tween",this);this._onTween=new B.CustomEvent("_tween",this,true);this.onComplete=new B.CustomEvent("complete",this);this._onComplete=new B.CustomEvent("_complete",this,true);this._onStart.subscribe(L);this._onTween.subscribe(K);this._onComplete.subscribe(G);}};B.Anim=A;})();YAHOO.util.AnimMgr=new function(){var C=null;var B=[];var A=0;this.fps=1000;this.delay=1;this.registerElement=function(F){B[B.length]=F;A+=1;F._onStart.fire();this.start();};this.unRegister=function(G,F){F=F||E(G);if(!G.isAnimated()||F==-1){return false;}G._onComplete.fire();B.splice(F,1);A-=1;if(A<=0){this.stop();}return true;};this.start=function(){if(C===null){C=setInterval(this.run,this.delay);}};this.stop=function(H){if(!H){clearInterval(C);for(var G=0,F=B.length;G<F;++G){this.unRegister(B[0],0);}B=[];C=null;A=0;}else{this.unRegister(H);}};this.run=function(){for(var H=0,F=B.length;H<F;++H){var G=B[H];if(!G||!G.isAnimated()){continue;}if(G.currentFrame<G.totalFrames||G.totalFrames===null){G.currentFrame+=1;if(G.useSeconds){D(G);}G._onTween.fire();}else{YAHOO.util.AnimMgr.stop(G,H);}}};var E=function(H){for(var G=0,F=B.length;G<F;++G){if(B[G]==H){return G;}}return -1;};var D=function(G){var J=G.totalFrames;var I=G.currentFrame;var H=(G.currentFrame*G.duration*1000/G.totalFrames);var F=(new Date()-G.getStartTime());var K=0;if(F<G.duration*1000){K=Math.round((F/H-1)*G.currentFrame);}else{K=J-(I+1);}if(K>0&&isFinite(K)){if(G.currentFrame+K>=J){K=J-(I+1);}G.currentFrame+=K;}};};YAHOO.util.Bezier=new function(){this.getPosition=function(E,D){var F=E.length;var C=[];for(var B=0;B<F;++B){C[B]=[E[B][0],E[B][1]];}for(var A=1;A<F;++A){for(B=0;B<F-A;++B){C[B][0]=(1-D)*C[B][0]+D*C[parseInt(B+1,10)][0];C[B][1]=(1-D)*C[B][1]+D*C[parseInt(B+1,10)][1];}}return[C[0][0],C[0][1]];};};(function(){var A=function(F,E,G,H){A.superclass.constructor.call(this,F,E,G,H);};A.NAME="ColorAnim";var C=YAHOO.util;YAHOO.extend(A,C.Anim);var D=A.superclass;var B=A.prototype;B.patterns.color=/color$/i;B.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;B.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;B.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;B.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;B.parseColor=function(E){if(E.length==3){return E;}var F=this.patterns.hex.exec(E);if(F&&F.length==4){return[parseInt(F[1],16),parseInt(F[2],16),parseInt(F[3],16)];}F=this.patterns.rgb.exec(E);if(F&&F.length==4){return[parseInt(F[1],10),parseInt(F[2],10),parseInt(F[3],10)];}F=this.patterns.hex3.exec(E);if(F&&F.length==4){return[parseInt(F[1]+F[1],16),parseInt(F[2]+F[2],16),parseInt(F[3]+F[3],16)];}return null;};B.getAttribute=function(E){var G=this.getEl();if(this.patterns.color.test(E)){var H=YAHOO.util.Dom.getStyle(G,E);
	if(this.patterns.transparent.test(H)){var F=G.parentNode;H=C.Dom.getStyle(F,E);while(F&&this.patterns.transparent.test(H)){F=F.parentNode;H=C.Dom.getStyle(F,E);if(F.tagName.toUpperCase()=="HTML"){H="#fff";}}}}else{H=D.getAttribute.call(this,E);}return H;};B.doMethod=function(F,J,G){var I;if(this.patterns.color.test(F)){I=[];for(var H=0,E=J.length;H<E;++H){I[H]=D.doMethod.call(this,F,J[H],G[H]);}I="rgb("+Math.floor(I[0])+","+Math.floor(I[1])+","+Math.floor(I[2])+")";}else{I=D.doMethod.call(this,F,J,G);}return I;};B.setRuntimeAttribute=function(F){D.setRuntimeAttribute.call(this,F);if(this.patterns.color.test(F)){var H=this.attributes;var J=this.parseColor(this.runtimeAttributes[F].start);var G=this.parseColor(this.runtimeAttributes[F].end);if(typeof H[F]["to"]==="undefined"&&typeof H[F]["by"]!=="undefined"){G=this.parseColor(H[F].by);for(var I=0,E=J.length;I<E;++I){G[I]=J[I]+G[I];}}this.runtimeAttributes[F].start=J;this.runtimeAttributes[F].end=G;}};C.ColorAnim=A;})();
	YAHOO.util.Easing={easeNone:function(B,A,D,C){return D*B/C+A;},easeIn:function(B,A,D,C){return D*(B/=C)*B+A;},easeOut:function(B,A,D,C){return -D*(B/=C)*(B-2)+A;},easeBoth:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B+A;}return -D/2*((--B)*(B-2)-1)+A;},easeInStrong:function(B,A,D,C){return D*(B/=C)*B*B*B+A;},easeOutStrong:function(B,A,D,C){return -D*((B=B/C-1)*B*B*B-1)+A;},easeBothStrong:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B*B+A;}return -D/2*((B-=2)*B*B*B-2)+A;},elasticIn:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return -(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;},elasticOut:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return B*Math.pow(2,-10*C)*Math.sin((C*F-D)*(2*Math.PI)/E)+G+A;},elasticBoth:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F/2)==2){return A+G;}if(!E){E=F*(0.3*1.5);}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}if(C<1){return -0.5*(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;}return B*Math.pow(2,-10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E)*0.5+G+A;},backIn:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*(B/=D)*B*((C+1)*B-C)+A;},backOut:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*((B=B/D-1)*B*((C+1)*B+C)+1)+A;},backBoth:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}if((B/=D/2)<1){return E/2*(B*B*(((C*=(1.525))+1)*B-C))+A;}return E/2*((B-=2)*B*(((C*=(1.525))+1)*B+C)+2)+A;},bounceIn:function(B,A,D,C){return D-YAHOO.util.Easing.bounceOut(C-B,0,D,C)+A;},bounceOut:function(B,A,D,C){if((B/=C)<(1/2.75)){return D*(7.5625*B*B)+A;}else{if(B<(2/2.75)){return D*(7.5625*(B-=(1.5/2.75))*B+0.75)+A;}else{if(B<(2.5/2.75)){return D*(7.5625*(B-=(2.25/2.75))*B+0.9375)+A;}}}return D*(7.5625*(B-=(2.625/2.75))*B+0.984375)+A;},bounceBoth:function(B,A,D,C){if(B<C/2){return YAHOO.util.Easing.bounceIn(B*2,0,D,C)*0.5+A;}return YAHOO.util.Easing.bounceOut(B*2-C,0,D,C)*0.5+D*0.5+A;}};(function(){var A=function(H,G,I,J){if(H){A.superclass.constructor.call(this,H,G,I,J);}};A.NAME="Motion";var E=YAHOO.util;YAHOO.extend(A,E.ColorAnim);var F=A.superclass;var C=A.prototype;C.patterns.points=/^points$/i;C.setAttribute=function(G,I,H){if(this.patterns.points.test(G)){H=H||"px";F.setAttribute.call(this,"left",I[0],H);F.setAttribute.call(this,"top",I[1],H);}else{F.setAttribute.call(this,G,I,H);}};C.getAttribute=function(G){if(this.patterns.points.test(G)){var H=[F.getAttribute.call(this,"left"),F.getAttribute.call(this,"top")];}else{H=F.getAttribute.call(this,G);}return H;};C.doMethod=function(G,K,H){var J=null;if(this.patterns.points.test(G)){var I=this.method(this.currentFrame,0,100,this.totalFrames)/100;J=E.Bezier.getPosition(this.runtimeAttributes[G],I);}else{J=F.doMethod.call(this,G,K,H);}return J;};C.setRuntimeAttribute=function(P){if(this.patterns.points.test(P)){var H=this.getEl();var J=this.attributes;var G;var L=J["points"]["control"]||[];var I;var M,O;if(L.length>0&&!(L[0] instanceof Array)){L=[L];}else{var K=[];for(M=0,O=L.length;M<O;++M){K[M]=L[M];}L=K;}if(E.Dom.getStyle(H,"position")=="static"){E.Dom.setStyle(H,"position","relative");}if(D(J["points"]["from"])){E.Dom.setXY(H,J["points"]["from"]);}else{E.Dom.setXY(H,E.Dom.getXY(H));}G=this.getAttribute("points");if(D(J["points"]["to"])){I=B.call(this,J["points"]["to"],G);
		var N=E.Dom.getXY(this.getEl());for(M=0,O=L.length;M<O;++M){L[M]=B.call(this,L[M],G);}}else{if(D(J["points"]["by"])){I=[G[0]+J["points"]["by"][0],G[1]+J["points"]["by"][1]];for(M=0,O=L.length;M<O;++M){L[M]=[G[0]+L[M][0],G[1]+L[M][1]];}}}this.runtimeAttributes[P]=[G];if(L.length>0){this.runtimeAttributes[P]=this.runtimeAttributes[P].concat(L);}this.runtimeAttributes[P][this.runtimeAttributes[P].length]=I;}else{F.setRuntimeAttribute.call(this,P);}};var B=function(G,I){var H=E.Dom.getXY(this.getEl());G=[G[0]-H[0]+I[0],G[1]-H[1]+I[1]];return G;};var D=function(G){return(typeof G!=="undefined");};E.Motion=A;})();(function(){var D=function(F,E,G,H){if(F){D.superclass.constructor.call(this,F,E,G,H);}};D.NAME="Scroll";var B=YAHOO.util;YAHOO.extend(D,B.ColorAnim);var C=D.superclass;var A=D.prototype;A.doMethod=function(E,H,F){var G=null;if(E=="scroll"){G=[this.method(this.currentFrame,H[0],F[0]-H[0],this.totalFrames),this.method(this.currentFrame,H[1],F[1]-H[1],this.totalFrames)];}else{G=C.doMethod.call(this,E,H,F);}return G;};A.getAttribute=function(E){var G=null;var F=this.getEl();if(E=="scroll"){G=[F.scrollLeft,F.scrollTop];}else{G=C.getAttribute.call(this,E);}return G;};A.setAttribute=function(E,H,G){var F=this.getEl();if(E=="scroll"){F.scrollLeft=H[0];F.scrollTop=H[1];}else{C.setAttribute.call(this,E,H,G);}};B.Scroll=D;})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.5.1",build:"984"});