/*extern booking, GEvent, GOverlay, G_MAP_FLOAT_PANE, GBounds, GPoint, GLargeMapControl, GScaleControl, GHierarchicalMapTypeControl, GDownloadUrl, GMarker, GLatLng, GSize, GIcon, G_SATELLITE_MAP, GLatLngBounds, GMap2, GMarkerManager, GUnload, G_PHYSICAL_MAP, Drag, document, gClientIsIE55, gClientIsIElte6, navigator */

// The booking namespace global is defined in /static/defaults/js/base.js.
booking.buildMapNamespace = function ()
{
	booking.map =
	{
		description       : 'Object-literal namespace for sitewide Google Maps.',
		version           : '1.4.8',
		controls          : [],
		markers           : [],
		// Constants
		ZOOM_TARGET_HOTEL_PREVIEW : 13,
		ZOOM_TARGET_HOTEL_NORMAL  : 14,
		CLASS_PREVIEW     : 'preview',
		CLASS_NORMAL      : 'normal',
		MARGIN_TOP        : 30,
		MARGIN_RIGHT      : 0,
		MARGIN_BOTTOM     : 30,
		MARGIN_LEFT       : 72,
		CSS_POSITION_TOP  : 40,
		MAP_PREVIEW_THUMBNAIL_IS_REAL_MAP : false,
		LOAD_MAP_ON_WINDOW_LOAD : false,
		LOAD_MAP_HIDDEN : false,
		REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP : false,
		SHOW_INFOWINDOW_ON_SHOWMAP_LINK_MOUSEOVER : true,
		DEFAULT_DISPLAY_MODE : 6,
		JS_VOID_URL : '#',
		PLACEMARKS_LIMIT : 50,
		MARKER_MOUSEOVER_Z_INDEX_OFFSET : 100000,
		MARKER_PATH_PREFIX : '/static/affiliate_base/img',
		SHOW_LEGEND : booking.env.setvar_affiliate_is_bookings2 ? true : false
	};
	/*
		This switch controls the following constants:
			LOAD_MAP_ON_WINDOW_LOAD
			LOAD_MAP_HIDDEN
			MAP_PREVIEW_THUMBNAIL_IS_REAL_MAP
			REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP
	*/
	if (booking.env.s_raw_param_map_mode)
	{
		booking.map.display_mode = booking.env.s_raw_param_map_mode;
	}
	else
	{
		booking.map.display_mode = booking.map.DEFAULT_DISPLAY_MODE;
	}
	switch (booking.map.display_mode)
	{
		// Map mode 1 specifies that we display a real map thumbnail then maximize the same map to full size on click.
		case 1 :
			booking.map.MAP_PREVIEW_THUMBNAIL_IS_REAL_MAP = true;
			booking.map.REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP = true;
			break;
		// Map mode 2 specifies that we display a real map thumbnail then generate and display a new full-size map on thumbnail click.
		case 2 :
			booking.map.MAP_PREVIEW_THUMBNAIL_IS_REAL_MAP = true;
			break;
		// Map mode 3 specifies the preview thumbnail is a real map then generate a real full-size map on window load for display on thumbnail click
		case 3 :
			booking.map.MAP_PREVIEW_THUMBNAIL_IS_REAL_MAP = true;
			booking.map.LOAD_MAP_ON_WINDOW_LOAD = true;
			booking.map.LOAD_MAP_HIDDEN = true;
			break;
		// Map mode 4 specifies that we display a static map thumbnail then generate a real full-size map on thumbnail click.
		case 4 :
			break;
		// Map mode 5 specifies that we display a static map thumbnail then generate a real full-size map on window load for display on thumbnail click.
		case 5 :
			booking.map.LOAD_MAP_ON_WINDOW_LOAD = true;
			booking.map.LOAD_MAP_HIDDEN = true;
			break;
		// Map mode 6 specifies that we display a static Google map thumbnail then generate and display a real full-size map on thumbnail click.
		case 6 :
			break;
	}
	// Class to build infowindow on a marker
	booking.map.BuildInfoWindow = function (item)
	{
		this.item_ = item;
	};
	booking.map.BuildInfoWindow.prototype.it = function ()
	{
		GEvent.removeListener(this.item_.marker.handleBuildInfoWindow);
		this.item_.marker.infoWindow = new booking.map.InfoWindow2(this.item_, booking.env);
		booking.map.obj.addOverlay(this.item_.marker.infoWindow);
		this.item_.mouseoverHandle = GEvent.addDomListener(
			this.item_.marker,
			'mouseover',
			function ()
			{
				this.infoWindow.show();
			});
		this.item_.mouseoutHandle = GEvent.addDomListener(
			this.item_.marker,
			'mouseout',
			function ()
			{
				this.infoWindow.hide();
			});
		GEvent.trigger(this.item_.marker, 'mouseover');
	};
	booking.Go = function (url)
	{
		this.url_ = url;
	};
	booking.Go.prototype.to = function ()
	{
		document.location = this.url_;
	};
	booking.map.InfoWindow2 = function (record, env)
	{
		this._record = record;
		this.div = {
			"@class" : "BInfoWindow below",
			"h3" : {},
			"p" : {}
		};
		if (record)
		{
			this.div["@id"] = record.id;
			this.div["@class"] += (' ' + record.icon_type);
			if (record.b_class)
			{
				this.div.h3.img = {
					"@src" : '/static/img/icons/stars/' + record.b_class + 'sterren-small.png',
					"@alt" : record.b_class + ' ' + (record.b_class == 1 ? env.star : env.stars)
				};
			}
			if (record.b_image_url)
			{
				this.div.p.img = {
					"@src" : record.b_image_url,
					"@alt" : "thumbnail photograph"
				};
			}
			if (record.b_type == 'hotel')
			{
				this.div.h3["#text"] = record.title;
				this.div.p["#text"] = record.b_description;
			}
			else
			{
				this.div.h3["#text"] = record.title;
				this.div.h3.span = {
					"@class" : "subhead",
					"br" : {},
					"#text" : record.subhead
				};
				if (record.b_hotelcount)
				{
					//record.b_hotelcount = 0;
					this.div.p["#text"] = record.b_hotelcount + ' ' + (record.b_hotelcount == 1 ? env.map_hotel : env.map_hotels);
				}
				else
				{
					delete this.div.p;
				}
			}
		}
	};
	booking.map.InfoWindow2.prototype = new GOverlay();
	// Class to display an infowindow
	booking.map.InfoWindow2.prototype.initialize = function (map)
	{ // Called by the map after the overlay is added to the map using GMap2.addOverlay(). The overlay object can draw itself into the different panes of the map that can be obtained using GMap2.getPane().
		this._map = map;
		booking.utils.buildHtmlNode(this, map.getPane(G_MAP_FLOAT_PANE));
	};
	booking.map.InfoWindow2.prototype.remove = function ()
	{ // Called by the map after the overlay is removed from the map using GMap2.removeOverlay() or GMap2.clearOverlays(). The overlay must remove itself from the map panes here.
		this.div._node.parentNode.removeChild(this.div._node);
	};
	booking.map.InfoWindow2.prototype.copy = function ()
	{ // Returns an uninitialized copy of itself that can be added to the map.
		return new booking.InfoWindow(this._record);
	};
	booking.map.InfoWindow2.prototype.redraw = function (force)
	{ // Called by the map when the map display has changed. The argument force will be true if the zoom level or the pixel offset of the map view has changed, so that the pixel coordinates need to be recomputed.
		if (!force)
		{
			return;
		}
	};
	// Event handler to show the infowindow.
	booking.map.InfoWindow2.prototype.show = function ()
	{
		if (booking.map.display.subject && (this._record !== booking.map.display.subject))
		{
			booking.map.display.clear();
		}
		booking.utils.removeClass(this.div._node, 'disabled');
		this.position();
		this._record.marker.increaseZIndex(booking.map.MARKER_MOUSEOVER_Z_INDEX_OFFSET);
	};
	// Position the infowindow immediately below the marker and ensure it fits within the map window and doesn’t overlay the map controls.
	booking.map.InfoWindow2.prototype.position = function ()
	{
		var
			markerAnchor = this._map.fromLatLngToDivPixel(this._record.latLng),
			left = 'auto',
			// We use the iconSize here rather than the infoWindowAnchor because we want to abut the marker either on top or bottom, and not overlap it at all.
			markerType = booking.map.iconTypes[this._record.icon_type],
			ddV = document.defaultView ?
				document.defaultView :
				false,
			halfwidth = ddV ?
				parseFloat(ddV.getComputedStyle(this.div._node, null).width) / 2 :
				Math.round(this.div._node.offsetWidth / 2),
			height = ddV ?
				parseFloat(ddV.getComputedStyle(this.div._node, null).height) :
				this.div._node.offsetHeight,
			pointEN,	
			pointWS,
			mapInfowindowBounds = new GBounds(),
			count = 0,
			text = this.div.p ? this.div.p._node.lastChild : null,
			top = markerAnchor.y + markerType.infoWindowAnchor.y - markerType.iconAnchor.y;
		// If booking.map.display.subject exists, construct a virtual bounds points around the subject marker.
		if (booking.map.display.subject)
		{
			var size = booking.map.obj.getSize(); // a GSize, in pixels
			pointEN  = new GPoint(
				markerAnchor.x + (size.width  / 2),
				markerAnchor.y - (size.height / 2));
			pointWS  = new GPoint(
				markerAnchor.x - (size.width  / 2),
				markerAnchor.y + (size.height / 2));
		}
		// Else get the real map bounds.
		else
		{
			var bounds = this._map.getBounds();
			pointEN    = this._map.fromLatLngToDivPixel(bounds.getNorthEast());
			pointWS    = this._map.fromLatLngToDivPixel(bounds.getSouthWest());
		}
		mapInfowindowBounds.minY = pointEN.y + booking.map.MARGIN_TOP;
		mapInfowindowBounds.maxX = pointEN.x - booking.map.MARGIN_RIGHT;
		mapInfowindowBounds.maxY = pointWS.y - booking.map.MARGIN_BOTTOM;
		mapInfowindowBounds.minX = pointWS.x + booking.map.MARGIN_LEFT;
		// Should be text.truncate method but IE doesn’t allow it. Implement a fallback?
		function truncate (text, parent)
		{
			text.nodeValue = text.nodeValue.slice(0, text.nodeValue.search(/\s{1}\S+$/)) + booking.env.typographical_ellipsis;
			height = ddV ?
				parseFloat(ddV.getComputedStyle(parent, null).height) :
				parent.offsetHeight;
			booking.utils.addClass(parent, 'truncated');
		}
		// If the infowindow is too tall to display below the marker,
		if (top + height > mapInfowindowBounds.maxY)
		{
			// If the marker is also in the bottom half of the viewport,
			if (markerAnchor.y > ((mapInfowindowBounds.maxY - mapInfowindowBounds.minY) / 2))
			{
				// Display it above instead.
				top = markerAnchor.y - markerType.infoWindowAnchor.y - height;
				booking.utils.removeClass(this.div._node, 'below');
				booking.utils.addClass(this.div._node, 'above');
				// If the infowindow is too tall to display above the marker,
				while ((top < mapInfowindowBounds.minY) && (count++ < 200) && text)
				{
					// Truncate the text until it fits.
					truncate(text, this.div._node);
					top = markerAnchor.y - markerType.infoWindowAnchor.y - height;					
				}
			}
			// Else if the marker is in the top half of the viewport,
			else
			{
				// If the infowindow is still too tall to display below the marker,
				while ((top + height > mapInfowindowBounds.maxY) && (count++ < 200) && text)
				{
					// Truncate the text until it fits.	
					truncate(text, this.div._node);
				}
			}
		}
		this.div._node.style.top = top += booking.CSS.units.px;
		// If the infowindow extends past the right boundary, bring it within that boundary.
		if (markerAnchor.x + halfwidth > mapInfowindowBounds.maxX)
		{
			left = mapInfowindowBounds.maxX - (halfwidth * 2) - 5;
		}
		// If the infowindow extends past the GLargeMapControl, adjust it so it doesn’t.
		else
		{
			if (markerAnchor.x - halfwidth < mapInfowindowBounds.minX)
			{
				left = mapInfowindowBounds.minX;
			}
			else
			{
				left = markerAnchor.x - halfwidth;
			}
		}
		this.div._node.style.left = left + booking.CSS.units.px;
		
	};
	// Event handler to hide the infowindow.
	booking.map.InfoWindow2.prototype.hide = function ()
	{
		booking.utils.addClass(this.div._node, 'disabled');
		this._record.marker.decreaseZIndex(booking.map.MARKER_MOUSEOVER_Z_INDEX_OFFSET);
	};
	// Method to construct the URL for our JSON placemarks feed.
	booking.map.buildPlacemarksUrl = function ()
	{
		var bbox = booking.map.box.getSouthWest().lng() + ',' + booking.map.box.getSouthWest().lat() + ',' + booking.map.box.getNorthEast().lng() + ',' + booking.map.box.getNorthEast().lat();
		booking.placemarksUrl = '/hotelsonmap.' + booking.env.b_lang + '.json?BBOX=' + bbox + ';limit=' + booking.map.PLACEMARKS_LIMIT;
	};
	booking.map.inflateBoundsBox = function (boundsBox, env)
	{
		var promo;
		for (var i in booking.promotions) if (booking.promotions.hasOwnProperty(i) && (typeof booking.promotions[i] == 'object'))
		{
			promo = booking.promotions[i];
			if (!promo.latLng)
			{
				promo.latLng = new GLatLng(promo.b_latitude, promo.b_longitude);
				delete promo.b_latitude;
				delete promo.b_longitude;
			}
			// Don’t extend the box for non-hotel promotions on landing pages or non-city promotions on country landing pages.
			if ((env.b_action !== 'searchresults' &&
					promo.b_type === 'hotel') ||
				(env.b_action == 'country' &&
					(promo.b_type === 'city' || promo.b_type === 'airport' )))
			{
				boundsBox.extend(promo.latLng);
			}
		}
	};
	booking.map.inflateBoundsBox.inflate = 'Called when booking.map.box.isEmpty() returns true to expand the box to fit all the page’s promotions, with various exceptions.';
	// Set the zoom level of the map to fit our current bounding box.
	booking.map.computeZoom = function (mapNamespace, mapObject)
	{ // “this” refers to booking.map.
		mapNamespace.boundsZoomLevel = mapObject.getBoundsZoomLevel(this.box);
		// On hotel pages we want to adjust the zoom level to be neither too high nor low.
		if (booking.env.b_action == 'hotel')
		{
			var target = booking.utils.hasClass(booking.map.main, booking.map.CLASS_PREVIEW) ? mapNamespace.ZOOM_TARGET_HOTEL_PREVIEW : mapNamespace.ZOOM_TARGET_HOTEL_NORMAL;
			// Normalize our zoom level to be nearer the specified target.
			mapNamespace.boundsZoomLevel = target + Math.round((mapNamespace.boundsZoomLevel - target) / 2);
		}
	};
	// Shortcut to center the map on our current center.
	booking.map.setCenter = function (center, zoom, mapType)
	{ // “this” refers to booking.map. Arguments are optional.
		this.obj.setCenter(center ? center : this.center, zoom ? zoom : this.boundsZoomLevel, mapType ? mapType : this.mapType);
	};
	// Adds our desired set of controls to the map.
	booking.map.addControls = function()
	{
		if (booking.map.controls.length === 0)
		{
			booking.map.controls.push(
				new GLargeMapControl(),
				new GScaleControl(),
				new GHierarchicalMapTypeControl()
			);
			for (var i = 0; i < booking.map.controls.length; i++)
			{
				booking.map.obj.addControl(booking.map.controls[i]);
			}
		}
	};
	booking.map.removeControls = function()
	{
		while (booking.map.controls.length > 0)
		{
			booking.map.obj.removeControl(booking.map.controls.pop());
		}
	};
	// Event handler for closing the map.
	booking.map.close = function (eventObject)
	{
		booking.event.normalizeExplorerEventObject(eventObject);
		if (booking.map.display.subject)
		{
			GEvent.trigger(booking.map.display.subject.marker, 'mouseout');
			booking.map.display.subject = null;
		}
		if (booking.utils.hasClass(booking.map.main, booking.map.CLASS_NORMAL))
		{
			booking.map.minimize();
		}
		else
		{
			// When does this happen? For affiliates?
			booking.utils.addClass(booking.map.main, 'disabled');
		}
		if (gClientIsIElte6)
		{
			for (var i = 0; i < booking.selects.length; i++)
			{
				booking.selects[i].style.visibility = 'visible';
			}
		}
		eventObject.preventDefault();
		eventObject.stopPropagation();
		return false;
	};
	// Pans the map to the subject placemark or promotion item.
	booking.map.focus = function (subject)
	{
		booking.map.obj.panTo(subject.latLng);
		GEvent.trigger(subject.marker, 'mouseover');
	};
	booking.map.setSubject = function (eventObject, itemId)
	{
		// Only execute this function if the map has been built.
		if (booking.map.obj && booking.map.display.initialized)
		{
			booking.event.normalizeExplorerEventObject(eventObject);
			// If we were passed an eventObject whose currentTarget has an itemId,
			if (!itemId && eventObject.currentTarget && eventObject.currentTarget.itemId)
			{
				itemId = eventObject.currentTarget.itemId;
			}
			booking.map.display.clear();
			if (itemId)
			{
				if (booking.promotions[itemId] || booking.placemarks)
				{
					booking.map.display.subject = booking.promotions[itemId] ? booking.promotions[itemId] : booking.placemarks[itemId];
					booking.map.focus(booking.map.display.subject);
				}
				else
				{
					booking.map.display.subjectID = itemId;
				}
			}
			else
			{
				booking.map.obj.panTo(booking.map.center);
			}
		}
	};
	// Event handler for displaying the map.
	booking.map.display = function (eventObject)
	{
		var
			b_map = booking.map;
		booking.event.normalizeExplorerEventObject(eventObject);
		if (eventObject)
		{
			booking.event.normalizeExplorerEventObject(eventObject);
		}
		// Only execute this function if the map has been built.
		if (!b_map.load.executed)
		{
			b_map.load(b_map);
		}
		// If the container className contains the CLASS_PREVIEW value
		if (booking.utils.hasClass(b_map.main, b_map.CLASS_PREVIEW))
		{
			b_map.maximize();
		}
		else
		{
			b_map.main.style.display = 'block';
		}
		if (!b_map.display.initialized)
		{
			b_map.display.initialize(b_map);
		}
		if (eventObject && eventObject.currentTarget.itemId && !(b_map.display.subject && (b_map.display.subject.b_hotel_id === eventObject.currentTarget.itemId)))
		{
			b_map.setSubject(eventObject);
		}
		else
		{
			b_map.obj.panTo(b_map.center);
		}
		if (gClientIsIElte6)
		{
			b_map.area.hideSelectsUnderneath();
		}
		if (booking.map.display.handle)
		{
			GEvent.removeListener(booking.map.display.handle);
			delete booking.map.display.handle;
		}
		eventObject.preventDefault();
		eventObject.stopPropagation();
		return false;
	};
	booking.map.display.clear = function ()
	{
		if (booking.map.display.subject)
		{
			GEvent.trigger(booking.map.display.subject.marker, 'mouseout');
			booking.map.display.subject = '';
		}
	};
	booking.map.display.initialize = function (b_map)
	{
		if (booking.env.b_action == 'searchresults')
		{
			booking.hotelsMatchingCriteria.load(); // featMapHeader.inc.
		}
		booking.promotions.process();
		b_map.buildPlacemarksUrl();
		var downloadUrl = new GDownloadUrl(booking.placemarksUrl, booking.map.processPlacemarks);
		b_map.display.initialized = true;
		b_map.obj.enableDragging();
		b_map.obj.checkResize();
		b_map.computeZoom(b_map, b_map.obj);
		b_map.setCenter();
		b_map.zoom.normal = b_map.obj.getZoom();
		b_map.addControls();
	};
	booking.map.resetForPreviewMode = function ()
	{
		// Register click-to-maximize listener
		if (!booking.map.maximize.handle)
		{
			booking.map.maximize.handle = GEvent.addDomListener(booking.map.thumbnail, 'click', booking.map.maximize);
		}
		if (booking.map.REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP)
		{
			booking.map.obj.checkResize();
			// Recompute the zoom to fit the whole bbox
			booking.map.computeZoom(booking.map, booking.map.obj);
			// Reset the map to our center
			booking.map.setCenter();
			// Disable map dragging
			booking.map.obj.disableDragging();
		}
	};
	booking.map.maximize = function ()
	{
		booking.map.obj.enableDragging();
		if (booking.map.maximize.handle)
		{
			GEvent.removeListener(booking.map.maximize.handle);
			delete booking.map.maximize.handle;
		}
		booking.utils.removeClass(booking.map.main, booking.map.CLASS_PREVIEW);
		booking.utils.addClass(booking.map.main, booking.map.CLASS_NORMAL);
		if (booking.map.REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP)
		{
			booking.map.obj.checkResize();
			booking.map.computeZoom(booking.map, booking.map.obj);
			booking.map.setCenter();
			booking.map.addControls();
		}
		// For browsers that don’t support position:fixed properly such as IE prior to version 7, we set position:absolute elsewhere (such as in /static/css/ie6lte.css). Here we detect that via currentStyle and set the top value to be within the current viewport.
		if (booking.map.area.currentStyle && (booking.map.area.currentStyle.position !== 'fixed'))
		{
			var adjustedTop = 0;
			booking.utils.addClass(booking.map.area, 'ie6lte');
			if (document.documentElement.scrollTop > 0)
			{
				adjustedTop = document.documentElement.scrollTop;
			}
			else
			{
				if (document.body.scrollTop > 0)
				{
					adjustedTop = document.body.scrollTop;
				}
			}
			booking.map.area.style.top = (adjustedTop + booking.map.CSS_POSITION_TOP).toString() + booking.CSS.units.px;
		}
	};
	booking.map.minimize = function ()
	{
		booking.utils.removeClass(booking.map.main, booking.map.CLASS_NORMAL);
		booking.utils.addClass(booking.map.main, booking.map.CLASS_PREVIEW);
		if (booking.map.REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP)
		{
			booking.map.removeControls();
		}
		booking.map.resetForPreviewMode();
	};
	booking.map.iconTypes = {};
	booking.map.Marker = function (latlng, options)
	{
		this.latlng = latlng;
		this.icon_type = options.icon.icon_type.replace('-', '_');
		GMarker.apply(this, arguments);
	};
	booking.map.Marker.prototype = new GMarker(new GLatLng(0, 0));
	booking.map.Marker.prototype.initialize = function (map)
	{
		GMarker.prototype.initialize.call(this, map);
	};
	booking.map.Marker.prototype.redraw = function (map)
	{
		GMarker.prototype.redraw.call(this, map);
		this.increaseZIndex();
	};
	booking.map.Marker.prototype.determineImgNodePropertyName = function ()
	{
		// The marker object has one property corresponding to the img element. The name of this property changes with each API release, so we have to determine it once.
 		booking.map.Marker.prototype.imgNodePropertyName = false;
		for (var property in this)
		{
			if (this.hasOwnProperty(property) && typeof this[property] === 'object' && this[property] && this[property].nodeName && this[property].nodeName.toLowerCase() === 'img')
			{
				booking.map.Marker.prototype.imgNodePropertyName = property;
				break;
			}
		}
	};
	booking.map.Marker.prototype.getStyleObject = function ()
	{
		if (!this.imgNodePropertyName && this.imgNodePropertyName !== false)
		{
			this.determineImgNodePropertyName();
		}
		return this[this.imgNodePropertyName] ? this[this.imgNodePropertyName].style : null;
	};
	booking.map.Marker.prototype.getZIndex = function ()
	{
		return this.getStyleObject() ? this.getStyleObject().zIndex : null;
	};
	booking.map.Marker.prototype.setZIndex = function (newValue)
	{
		if (this.getStyleObject())
		{
			this.getStyleObject().zIndex = newValue;
		}
	};
	booking.map.Marker.prototype.increaseZIndex = function (incrementInteger)
	{
		if (incrementInteger)
		{
			this.setZIndex(parseInt(this.getZIndex(), 10) + incrementInteger);
		}
		else
		{
			this.setZIndex(parseInt(this.getZIndex(), 10) + booking.map.iconTypes[this.icon_type].zOrder);
		}
	};
	booking.map.Marker.prototype.decreaseZIndex = function (decrementInteger)
	{
		if (decrementInteger)
		{
			this.setZIndex(parseInt(this.getZIndex(), 10) - decrementInteger);
		}
		else
		{
			this.setZIndex(parseInt(this.getZIndex(), 10) - booking.map.iconTypes[this.icon_type].zOrder);
		}
	};
	booking.map.Marker.prototype.remove = function (map)
	{
		GMarker.prototype.remove.call(this);
	};
	booking.map.Icon = function (options)
	{
		// Subclass of GIcon.
		if (!options)
		{
			options = {}; // so we can safely check for its’ properties.
		}
		this.icon_type        = options.icon_type        ? options.icon_type        : this.icon_type;
		if (options.image)
		{
			this.image = options.image;
		}
		else
		{
			this.image = booking.map.MARKER_PATH_PREFIX + '/marker-' + this.icon_type + '.png';
		}
		this.shadow           = options.shadow           ? options.shadow           : this.shadow;
		this.iconSize         = options.iconSize         ? options.iconSize         : this.iconSize;
		this.shadowSize       = options.shadowSize       ? options.shadowSize       : this.shadowSize;
		this.iconAnchor       = options.iconAnchor       ? options.iconAnchor       : this.iconAnchor;
		this.infoWindowAnchor = options.infoWindowAnchor ? options.infoWindowAnchor : (this.infoWindowAnchor ? this.infoWindowAnchor : this.iconAnchor);
		this.printImage       = options.printImage       ? options.printImage       : (this.printImage ? this.printImage : this.image);
		this.mozPrintImage    = options.mozPrintImage    ? options.mozPrintImage    : (this.mozPrintImage ? this.mozPrintImage : this.image);
		this.printShadow      = options.printShadow      ? options.printShadow      : (this.printShadow ? this.printShadow : this.shadow);
		this.transparent      = options.transparent      ? options.transparent      : this.transparent;
		this.imageMap         = options.imageMap         ? options.imageMap         : this.imageMap;
		this.maxHeight        = options.maxHeight        ? options.maxHeight        : this.maxHeight;
		this.dragCrossImage   = options.dragCrossImage   ? options.dragCrossImage   : this.dragCrossImage;
		this.dragCrossSize    = options.dragCrossSize    ? options.dragCrossSize    : this.dragCrossSize;
		this.dragCrossAnchor  = options.dragCrossAnchor  ? options.dragCrossAnchor  : this.dragCrossAnchor;
	};
	booking.map.Icon.prototype = new GIcon();
	booking.map.Icon.prototype.icon_type        = 'hotel';
	booking.map.Icon.prototype.image            = booking.map.MARKER_PATH_PREFIX + '/marker-hotel-current.png';
	booking.map.Icon.prototype.shadow           = booking.map.MARKER_PATH_PREFIX + '/marker-shadow-hotel.png';
	booking.map.Icon.prototype.iconSize         = new GSize(17, 20);
	booking.map.Icon.prototype.shadowSize       = new GSize(28, 20);
	booking.map.Icon.prototype.iconAnchor       = new GPoint(8.5, 20);
	booking.map.Icon.prototype.infoWindowAnchor = new GPoint(8.5, 20);
	booking.map.Icon.prototype.printImage       = undefined;
	booking.map.Icon.prototype.mozPrintImage    = undefined;
	booking.map.Icon.prototype.printShadow      = undefined;
	booking.map.Icon.prototype.transparent      = '';
	booking.map.Icon.prototype.imageMap         = [];
	booking.map.Icon.prototype.maxHeight        = 0;
	booking.map.Icon.prototype.dragCrossImage   = '';
	booking.map.Icon.prototype.dragCrossSize    = new GSize(0, 0);
	booking.map.Icon.prototype.dragCrossAnchor  = new GPoint(0, 0);
	booking.map.SmallIcon = function ()
	{
		// Subclass of booking.map.Icon.
	};
	booking.map.SmallIcon.prototype = new booking.map.Icon(
		{
			icon_type  : 'city',
			image      : booking.map.MARKER_PATH_PREFIX + '/marker-city.png',
			shadow     : booking.map.MARKER_PATH_PREFIX + '/marker-shadow-city.png',
			iconSize   : new GSize(9, 9),
			shadowSize : new GSize(15, 12),
			iconAnchor : new GPoint(4.5, 4.5),
			infoWindowAnchor : new GPoint(4.5, 9)
		}
	);
	booking.map.LargeIcon = function ()
	{
		// Subclass of booking.map.Icon.
	};
	booking.map.LargeIcon.prototype = new booking.map.Icon(
		{
			icon_type  : 'hotel_current',
			image      : booking.map.MARKER_PATH_PREFIX + '/marker-hotel-orange-large.png',
			shadow     : booking.map.MARKER_PATH_PREFIX + '/marker-shadow-hotel-large.png',
			iconSize   : new GSize(26, 27),
			shadowSize : new GSize(40, 27),
			iconAnchor : new GPoint(13, 27),
			infoWindowAnchor : new GPoint(13, 27)
		}
	);
	booking.map.ZoomRange = function (min, max)
	{
		this.min = min ? min : Math.NEGATIVE_INFINITY;
		this.max = max ? max : Math.POSITIVE_INFINITY;
	};
	booking.map.iconTypes.build = function (b_map)
	{
		b_map.iconTypes.hotel = new b_map.Icon();
		b_map.iconTypes.hotel.zoomRange = new b_map.ZoomRange(9);
		b_map.iconTypes.hotel.zOrder = 10000;
		b_map.iconTypes.hotel_current = new b_map.LargeIcon();
		b_map.iconTypes.hotel_current.zoomRange = new b_map.ZoomRange(4);
		b_map.iconTypes.hotel_current.zOrder = 100000;
		b_map.iconTypes.hotel_matching_criteria = new b_map.Icon( { icon_type : 'hotel_matching_criteria', image : booking.map.MARKER_PATH_PREFIX + '/marker-hotel-current.png' } );
		b_map.iconTypes.hotel_matching_criteria.zoomRange = new b_map.ZoomRange(9);
		b_map.iconTypes.hotel_matching_criteria.zOrder = 5000;
		b_map.iconTypes.hotel_not_matching_criteria = new b_map.Icon( { icon_type : 'hotel_not_matching_criteria', image : booking.map.MARKER_PATH_PREFIX + '/marker-hotel-other.png' } );
		b_map.iconTypes.hotel_not_matching_criteria.zoomRange = new b_map.ZoomRange(9);
		b_map.iconTypes.hotel_not_matching_criteria.zOrder = 100;
		b_map.iconTypes.airport = new b_map.Icon( { icon_type : 'airport' } );
		b_map.iconTypes.airport.zoomRange = new b_map.ZoomRange(5);
		b_map.iconTypes.airport.zOrder = 90;
		b_map.iconTypes.landmark = new b_map.Icon( { icon_type : 'landmark' } );
		b_map.iconTypes.landmark.zoomRange = new b_map.ZoomRange(12);
		b_map.iconTypes.landmark.zOrder = 80;
		b_map.iconTypes.city = new b_map.SmallIcon();
		b_map.iconTypes.city.zoomRange = new b_map.ZoomRange(4, 16);
		b_map.iconTypes.city.zOrder = 70;
		b_map.iconTypes.country = new b_map.Icon( { icon_type : 'country' } );
		b_map.iconTypes.country.zoomRange = new b_map.ZoomRange(4, 10);
		b_map.iconTypes.country.zOrder = 60;
		b_map.iconTypes.region = new b_map.Icon( { icon_type : 'region' } );
		b_map.iconTypes.region.zoomRange = new b_map.ZoomRange(5);
		b_map.iconTypes.region.zOrder = 50;
		b_map.iconTypes.district = new b_map.SmallIcon( { icon_type : 'district' } );
		b_map.iconTypes.district.zoomRange = new b_map.ZoomRange(7);
		b_map.iconTypes.district.zOrder = 40;
	};
	booking.map.buildMarker = function (item) // Argument: item Object(icon_type, b_type, latLng)
	{
		if (!item.icon_type)
		{
			item.icon_type = item.b_type;
		}
		item.marker = new booking.map.Marker(item.latLng,
			{// e.g.,	booking.map.iconTypes.country.icon
				icon : this.iconTypes[item.icon_type]
			});
		this.markerManager.addMarker(item.marker,
			this.iconTypes[item.icon_type].zoomRange.min,
			this.iconTypes[item.icon_type].zoomRange.max);
		if (item.url)
		{
			item.marker.go = new booking.Go(item.url);
			GEvent.addDomListener(
				item.marker,
				'click',
				function ()
				{
					this.go.to();
				}
			);
		}
		item.marker.build = new booking.map.BuildInfoWindow(item);
		item.marker.handleBuildInfoWindow = GEvent.addDomListener(
			item.marker,
			'mouseover',
			function ()
			{
				if (booking.utils.hasClass(booking.map.main, booking.map.CLASS_NORMAL))
				{ // Only build infowindows when maximized!
				}
					this.build.it();
					delete this.build;
			}
		);
	};
	booking.promotions.process = function ()
	{ // To be called on first maximize.
		for (var i in booking.promotions) if (booking.promotions.hasOwnProperty(i) && (typeof booking.promotions[i] == 'object'))
		{
			var promo = booking.promotions[i];
			if (!promo.latLng)
			{
				promo.latLng = new GLatLng(promo.b_latitude, promo.b_longitude);
				delete promo.b_latitude;
				delete promo.b_longitude;
			}
			if (!booking.promotions[i].marker)
			{ // Change square90 photo thumbnails to square60. To-do: in actions.
				if (promo.b_image_url)
				{
					promo.b_image_url = promo.b_image_url.replace('square90', 'square60');
				}
				// If the promo matches criteria, make it a hotel_current;
				if (promo.b_type === 'hotel' && booking.env.b_action === 'searchresults')
				{
					if (booking.hotelsMatchingCriteria[i])
					{
						promo.icon_type = 'hotel_matching_criteria';
					}
					// Otherwise make it a hotel_other.
					else
					{
						promo.icon_type = 'hotel_not_matching_criteria';
					}
				}
				booking.map.buildMarker(promo);
				booking.map.markers.push(promo.marker);
			}
		}
	};
	booking.map.processPlacemarks = function (response, code)
	{
		if (response && (code == 200)) // response == null on timeout
		{
			booking.placemarks = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
				 response.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + response + ')');
			if (!booking.placemarks)
			{
				booking.placemarks.hotelsonmap = 'invalid';
				return;
			}
			else
			{
				booking.placemarks.hotelsonmap = 'valid';
			}
			var placemark;
			for (var i in booking.placemarks) if (booking.placemarks.hasOwnProperty(i) && (typeof booking.placemarks[i] == 'object'))
			{
				placemark = booking.placemarks[i];
				if ( !booking.promotions[i] && !( booking.pageSubject && booking.pageSubject.b_hotel_id == i ) )
				{
					placemark.b_type = 'hotel';
					// We must build the GLatLng here because we obviously cannot in JSON.
					placemark.latLng = new GLatLng(placemark.b_latitude, placemark.b_longitude);
					delete placemark.b_latitude;
					delete placemark.b_longitude;
					if (booking.env.b_action === 'searchresults')
					{
						if (booking.hotelsMatchingCriteria[i])
						{
							placemark.icon_type = 'hotel_matching_criteria';
						}
						else
						{
							placemark.icon_type = 'hotel_not_matching_criteria';
						}
					}
					placemark.url += booking.env.b_query_params_with_lang;
					booking.map.buildMarker(placemark);
					booking.map.markers.push(placemark.marker);
				}
				else
				{
					delete booking.placemarks[i];
				}
			}
			// Call loadCurrentHotels() in featMapHeader.inc to ensure current hotels are shown.
			booking.loadCurrentHotels();
			// Focus the marker if a hotel Show Map link was clicked on a search results page.
			if (booking.map.display.subjectID)
			{
				booking.map.display.subject = booking.placemarks[booking.map.display.subjectID];
				booking.map.focus(booking.map.display.subject);
				delete booking.map.display.subjectID;
			}
		}
		else
		{
			booking.placemarks.hotelsonmap = 'failed; code ' + code + '.';
		}
	};
	booking.map.buildCurrentHotel = function (properties_of_a_b_hotels_object_member)
	{
		var p = properties_of_a_b_hotels_object_member;
		if (booking.promotions && !booking.promotions[p.b_id] && !booking.placemarks[p.b_id])
		{
			booking.placemarks[p.b_id] = {
				"b_type"        : "hotel",
				"icon_type"     : booking.hotelsMatchingCriteria[p.b_id] ? "hotel_matching_criteria" : 'hotel_not_matching_criteria',
				"b_image_url"   : booking.env.images_url + p.b_main_photo,
				"b_description" : p.b_description,
				"id"            : "hotel" + p.b_id,
				"title"         : p.b_name,
				"latLng"        : new GLatLng(p.b_latitude, p.b_longitude),
				"url"           : p.b_url
			};
			if (p.b_class)
			{
				booking.placemarks[p.b_id].b_class = p.b_class;
			}
			booking.map.buildMarker(booking.placemarks[p.b_id]);
		}
	};
	booking.map.buildNode = function (map)
	{
		map.featMap = document.getElementById('b_featMap');
		if (map.featMap)
		{
			map.containerTree = new map.Div(booking.env);
			booking.utils.buildHtmlNode(map.containerTree, map.featMap);
			map.containerTree.initialize(map);
			booking.utils.addClass(map.featMap, 'b_map_mode_' + booking.map.display_mode);
		}
	};
	booking.map.buildNode.description = 'Called from the body element descendant after which the map node should appear.';
	booking.map.Div = function (env)
	{
		this.div = {
			"_this" : this,
			"@id" : "b_google_map",
			"@class" : booking.map.CLASS_PREVIEW + ' b_popupInner loading',
			"div" : {
				"@id" : "b_google_map_area",
				"h2" : {
					"@id" : "b_google_map_handle",
					"@class" : "handle b_popupInner",
					"a" : {
						"@id" : "close_map",
						"@href" : booking.map.JS_VOID_URL,
						"#text" : env.close_map
					},
					"#text" : env.map
				},
				"div" : [
					{
						"@id" : "b_google_map_container",
						"@class" : "b_popupInner",
						"div" : [
							{
								"@id" : "b_google_map_parent"
							}
						]
					},
					{
						"@id" : "b_google_map_container_shadow"
					}
				]
			},
			"p" : {
				"@id" : "showMap",
				"a" : {
					"@class" : "show_map",
					"@href" : booking.map.JS_VOID_URL,
					"#text" : env.show_map
				}
			}
		};
		// For bookings2 add a map legend as sibling to the b_google_map_parent div.
		if (booking.map.SHOW_LEGEND)
		{
			this.div["@class"] += ' b_show_legend';
			this.div.div.div[0].div.push(new booking.map.Legend());
		}
	};
	booking.map.Legend = function ()
	{
		var env = booking.env;
		this.div = {
			"_this" : this,
			"@id" : "b_google_map_legend",
			"h3" : {
				"#text" : env.map_legend
			},
			"table" : {
				"col" : [
					{
						"@class" : "b_maps_legend_marker"
					},
					{
						"@class" : "b_maps_marker_legend_description"
					}
				],
				"tbody" : {
					"tr" : [
						new booking.map.Legend.Entry(
							'b_maps_landmark',
							'marker-landmark.png',
							env.map_landmark).tr,
						new booking.map.Legend.Entry(
							'b_maps_city',
							'marker-city.png',
							env.city).tr,
						new booking.map.Legend.Entry(
							'b_maps_airport',
							'marker-airport.png',
							env.airport).tr
					]
				}
			},
			"p" : {
				"#text" : env.map_click_these_markers_on_the_map_for_more_detailed_information
			}
		};
		// For Searchresults pages show in- and out-of-criteria marker definitions.
		if (env.b_action === 'searchresults')
		{
			this.div.table.tbody.tr.unshift(
				new booking.map.Legend.Entry(
					'b_maps_hotel_matching_selection_criteria',
					'marker-hotel-current.png',
					env.map_hotel_matching_your_selection_criteria).tr,
				new booking.map.Legend.Entry(
					'b_maps_hotel_other',
					'marker-hotel-other.png',
					env.map_other_hotel).tr);
		}
		else
		{
		// Otherwise show regular hotel marker definition.
			this.div.table.tbody.tr.unshift(
				new booking.map.Legend.Entry(
					'b_maps_hotel',
					'marker-hotel.png',
					env.map_hotel).tr);
			// On Hotel pages show the current hotel marker definition.
			if (env.b_action === 'hotel')
			{
				this.div.table.tbody.tr.unshift(
					new booking.map.Legend.Entry(
						'b_maps_current_hotel',
						'marker-hotel-orange-large.png',
						env.current_hotel).tr);
			}
		}
	};
	booking.map.Legend.Entry = function (classString, filenameString, textString)
	{
		this.tr = {
			"_this" : this,
			"@class" : classString,
			"td" : {
				"@class" : "b_maps_legend_marker",
				"img" : {
					"@src" : this.constructImageSrcAttributeValue(filenameString)
				}
			},
			"th" : {
				"#text" : textString
			}
		};
	};
	booking.map.Legend.Entry.prototype.constructImageSrcAttributeValue = function (filenameString)
	{
		return booking.map.MARKER_PATH_PREFIX + "/" + filenameString;
	};
	booking.map.Div.prototype.initialize = function (containerObject)
	{
		// To be called after buildHtmlNode is performed on the object since we rely on _node properties being present.
		containerObject.main = this.div._node;
		containerObject.area = this.div.div._node;
		containerObject.handle = this.div.div.h2._node;
		containerObject.close_map = this.div.div.h2.a._node;
		containerObject.container = this.div.div.div[0]._node;
		containerObject.legend = booking.map.SHOW_LEGEND ? this.div.div.div[0].div[1]._node : null;
		containerObject.parent = this.div.div.div[0].div[0]._node;
		containerObject.shadow = this.div.div.div[1]._node;
		containerObject.showMap = this.div.p._node;
		containerObject.show_map = this.div.p.a._node;
		if (booking.map.REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP)
		{
			containerObject.thumbnail = containerObject.area;
		}
		else
		{
			containerObject.thumbnail = document.getElementById('b_google_map_thumbnail');
		}
	};
	booking.map.load = function (b_map)
	{
		var
			i,
			anchor,
			href,
			env = booking.env;
		b_map.mapType = (env.b_googlemaps_maptype == 'satellite') ? G_SATELLITE_MAP : false;
		// If the action provided a box, adopt it, otherwise create an empty box.
		if (env.b_bbox_southwest_latitude  && 
			env.b_bbox_southwest_longitude && 
			env.b_bbox_northeast_latitude  && 
			env.b_bbox_northeast_longitude)
		{
			b_map.box = new GLatLngBounds( // GLatLngBounds(sw?, ne?)
					new GLatLng(
						env.b_bbox_southwest_latitude,
						env.b_bbox_southwest_longitude),
					new GLatLng(
						env.b_bbox_northeast_latitude,
						env.b_bbox_northeast_longitude));
		}
		else
		{
			b_map.box = new GLatLngBounds();
		}
		// If the action provided a center, adopt it, otherwise get the center of our box.
		b_map.center = (env.b_latitude && env.b_longitude) ? 
			new GLatLng(env.b_latitude, env.b_longitude) :
			b_map.box.getCenter();
		booking.promotions.load(env);
		if (b_map.box.isEmpty()) // we didn’t get a box from the action, so we can build one since the promotions are now loaded.
		{
			b_map.inflateBoundsBox(b_map.box, env);
			// Unless we’re on a hotel page recenter the map on the inflated box.
			if (env.b_action != 'hotel')
			{
				b_map.center = b_map.box.getCenter();
			}
		}
		b_map.iconTypes.build(b_map);

		// Create the map object.
		b_map.obj = new GMap2(b_map.parent);
		b_map.obj.addMapType(G_PHYSICAL_MAP);
		GEvent.addDomListener(b_map.obj, 'load', function () { booking.utils.removeClass(b_map.main, 'loading'); } );
		// Initialize the map by calling setCenter().
		b_map.setCenter();
		b_map.obj.enableContinuousZoom();
		b_map.markerManager = new GMarkerManager(b_map.obj);
		// Build a marker for the current page subject (built in featMapHeader.inc).
		if (booking.pageSubject)
		{
			b_map.buildMarker(booking.pageSubject);
			b_map.markers.push(booking.pageSubject.marker);
		}
		b_map.resetForPreviewMode();
		b_map.zoom = 
		{
			preview : b_map.obj.getZoom()
		};
		// Identify those map elements we want to hide via CSS in preview mode.
		b_map.main.anchors = b_map.main.getElementsByTagName('a');
		for (i = 0; i < b_map.main.anchors.length; i++)
		{
			anchor = b_map.main.anchors[i];
			href   = anchor.getAttribute('href');
			if (href && href.indexOf('ct=api_logo') != -1)
			{
				booking.utils.addClass(anchor, 'api_logo');
			}
			if (href && href.indexOf('terms_maps')  != -1)
			{
				booking.utils.addClass(anchor, 'terms_maps');
			}
		}
		b_map.display.initialized = false;
		b_map.close_map.removeAttribute('onclick');
		b_map.close_map.href = booking.map.JS_VOID_URL;
		GEvent.addDomListener(b_map.close_map, 'click', b_map.close);
		// Make the map draggagle using dom-drag.js.
		Drag.init(b_map.area);
		b_map.area.hideSelectsUnderneath = function ()
		{
			booking.utils.ie.hideIntersectingElements(b_map.area, booking.selects);
		};
		if (gClientIsIElte6)
		{
			booking.selects = document.getElementsByTagName('select');
			for (i = 0; i < booking.selects.length; i++)
			{
				booking.selects[i].style.position = 'relative';
			}
			b_map.area.onDrag = b_map.area.hideSelectsUnderneath;
			GEvent.addDomListener(window, 'resize', b_map.area.hideSelectsUnderneath);
		}
		if (b_map.SHOW_INFOWINDOW_ON_SHOWMAP_LINK_MOUSEOVER)
		{
			for (i = 0; i < b_map.showMapAnchors.length; i++)
			{
				anchor = b_map.showMapAnchors[i];
				if (anchor.itemId)
				{
					anchor.mouseoverHandle = GEvent.addDomListener(anchor,
						'mouseover',
						b_map.setSubject);
				}
			}
		}
		if (b_map.load.handle)
		{
			GEvent.removeListener(b_map.load.handle);
		}
		b_map.load.executed = true;
		// If we're in a frameset, make sure the map fits in the visible window
		if ( top != self ) {
			document.getElementById('b_google_map_area').style.left = ( ( self.document.body.offsetWidth - 500 ) / 2 ) + "px";
		}
		GEvent.addDomListener(window, 'unload', GUnload);
	};
	booking.map.initialize = function (b_map, env) // booking.map, booking.env
	{
		var
			i,
			anchor,
			idIndex,
			href;
		// Build the map XHTML node, 
		b_map.buildNode(b_map);
		b_map.showMapAnchors = booking.utils.dom.getElementsByClassName('show_map', document, 'a');
		// Add click listeners to all Show Map anchors.
		for (i = 0; i < b_map.showMapAnchors.length; i++)
		{
			anchor = b_map.showMapAnchors[i];
			if (anchor.id && (anchor.id.substring('show_id') !== -1))
			{
				anchor.itemId = anchor.id.split('show_id')[1];
			}
			anchor.clickHandle = GEvent.addDomListener(anchor,
				'click',
				b_map.display);
			anchor.href = b_map.JS_VOID_URL;
		}
		if (b_map.LOAD_MAP_ON_WINDOW_LOAD)
		{
			b_map.load(b_map);
			b_map.display.initialize(b_map);
		}
		b_map.display.handle = GEvent.addDomListener(b_map.thumbnail, 'click', b_map.display);
		if (b_map.MAP_PREVIEW_THUMBNAIL_IS_REAL_MAP)
		{
			if (!b_map.load.executed)
			{
				b_map.load(b_map);
			}
			if (!b_map.REUSE_PREVIEW_THUMBNAIL_AS_FULL_MAP)
			{
				b_map.preview = new GMap2(b_map.thumbnail);
				b_map.preview.setCenter(b_map.center ? b_map.center : null, b_map.preview.getBoundsZoomLevel(b_map.box), b_map.mapType ? b_map.mapType : null);
				if (b_map.preview.draggingEnabled())
				{
					b_map.preview.disableDragging();
				}
				if (booking.pageSubject)
				{
					b_map.preview.marker = new GMarker(booking.pageSubject.latLng,
						{
							icon : b_map.iconTypes[booking.pageSubject.icon_type],
							"clickable" : false
						});
					b_map.preview.addOverlay(b_map.preview.marker);
				}
			}
		}
	};
};
if ( !gClientIsIE5 && GBrowserIsCompatible() && document.getElementById( 'b_featMap' ) )
{
	booking.buildMapNamespace();
	booking.map.initialize(booking.map, booking.env); 
}
