
	var map; 
	var bDoubleClickHappened = false;
	var DEFAULT_LAT = 49.45052;
	var DEFAULT_LNG = 11.08048;
	var DEFAULT_ZOOM = 12;
	var DEFAULT_ELEV_PARAM = "0a";
	var IS_LOADING_FROM_QUERYSTRING = true;
	var NOT_LOADING_FROM_QUERYSTRING = false;
	var IS_CREATING_THERE_AND_BACK = true;
	var NOT_CREATING_THERE_AND_BACK = false;
	var elevationArrayIndex = 0;
	var currentElevationGraphHeight = '0';
	var bAllElevationsWereZero = true;
	var mapHeight;
	var performElevationLookup = false;
	var bAllElevationsFound = false;
	var iFoundElevationsSum = 0;
	var bElevationsArrSum = 0;
	var iPercent = 0;
	var bShowRefreshLink = false;
	var rId = '';
	var routeSaved = true;
	var paramString = location.href;
	var routeIdFromQueryString;
	var ptHash = new Object();
	var routeSegmentsCount = 0;
	var polyLineSegmentsHash = new Object();
	var currentLine = new Array(0);
	var bRecordPoints = false;
	var wf;
	
	CustomGetTileUrl=function(a,b,c) {
		var lULP = new GPoint(a.x*256,(a.y+1)*256);
		var lLRP = new GPoint((a.x+1)*256,a.y*256);
		var lUL = G_NORMAL_MAP.getProjection().fromPixelToLatLng(lULP,b,c);
		var lLR = G_NORMAL_MAP.getProjection().fromPixelToLatLng(lLRP,b,c);
		var lBbox=lUL.x+","+lUL.y+","+lLR.x+","+lLR.y;
		var lSRS="EPSG:4326";
		var lURL=this.myBaseURL;
		lURL+="&REQUEST=GetMap";
		lURL+="&SERVICE=WMS";
		lURL+="&reaspect=false&VERSION=1.1.1";
		lURL+="&LAYERS="+this.myLayers;
		lURL+="&STYLES=default"; 
		lURL+="&FORMAT="+this.myFormat;
		lURL+="&BGCOLOR=0xFFFFFF";
		lURL+="&TRANSPARENT=TRUE";
		lURL+="&SRS="+lSRS;
		lURL+="&BBOX="+lBbox;
		lURL+="&WIDTH=256";
		lURL+="&HEIGHT=256";
		lURL+="&GroupName="+this.myLayers;
		return lURL;
	}

	function drawevelation(){
	
		var sPoints = '';
		if (gLatLngArray.length > 1) {
			
			//elevationvisable(false);
		
			//sPoints = encodePolyline(prepPointArray(gLatLngArray));
			//document.getElementById("eva").src = 'images/bittewarten.png' ;
			sPoints = createPointListForEelation(gLatLngArray);
			//document.getElementById("eva").src = '<?php echo $url?>profile.php?'+sPoints ;
			document.getElementById("eva").src = 'images/bittewarten.png';

		var xmlHttp = null;
		
		// Mozilla, Opera, Safari sowie Internet Explorer 7
		if (typeof XMLHttpRequest != 'undefined') {
   			 xmlHttp = new XMLHttpRequest();
		}
		if (!xmlHttp) {
    		// Internet Explorer 6 und älter
    	try {
        	xmlHttp  = new ActiveXObject("Msxml2.XMLHTTP");
    		} catch(e) {
        
			try {
            	xmlHttp  = new ActiveXObject("Microsoft.XMLHTTP");
       		 	} catch(e) {
           		 xmlHttp  = null;
        		}
    		}
		}

			var request = xmlHttp;
		request.open("POST", "saveprofile.php", true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		request.onreadystatechange = function() {
			if (request.readyState == 4) {
				//alert(request.responseText);
				evaimg=new Image();
				evaimg.src='profile2.php';
				checkimg(evaimg);
			}
		}
		request.send(sPoints);
			
		}
	
	}
	
	function checkimg(evaimg){
		if (evaimg.width<100){
			//alert("nicht fertig");
			window.setTimeout("checkimg(evaimg)", 5000);
		}else{
			//alert("fertig");
			document.getElementById("eva").src = evaimg.src;
		}
	}
	
	function createPointListForEelation(pointArray){
	
		var sResult = '';
		for (var i = 0; i<pointArray.length; i++){
		
			sResult += '&pt' + i + '= '+ pointArray[i].lat() + ',' + pointArray[i].lng() +','+ returnDistanceInChosenUnits(legArray[i]);
			
			if (i < pointArray.length - 1) {
			
				sResult += '';
			
			}
		
		}
		
		return sResult;
		
	}

	function initializeMap(){

		//route may come entirely from querystring or be saved serverside 
		routeIdFromQueryString = getQuerystringParameter('r', paramString);
		//alert(routeIdFromQueryString.length)

		if (routeIdFromQueryString.length > 0) {

			var mapDiv = document.getElementById("map");
			mapDiv.style.fontFamily = "arial";
			mapDiv.style.fontSize = "24pt";
			
			//drawMap() and rehydrateMapFromUrl() get called internally by getRoute
			rId =  routeIdFromQueryString;
			getRoute(routeIdFromQueryString);
			
		} else {
			drawMap();
			//if parameters have been passed in to prepop location and route, parse them and display correct values
			//rehydrateMapFromUrl();

		}

	}
	function drawMap(){		
		
		//intialize the map
		map = new GMap2(document.getElementById("map"), {draggableCursor: 'crosshair', draggingCursor: 'crosshair'});
		//map.setCenter(new GLatLng(DEFAULT_LAT, DEFAULT_LNG), DEFAULT_ZOOM);
		map.setCenter(new GLatLng(49.45052,11.08048), 5);
		map.setUIToDefault();
		map.setMapType(G_PHYSICAL_MAP);
		map.addControl(new GLargeMapControl());
		map.addControl(new GMapTypeControl());

		//map.addMapType(topoMap);

		map.addControl(new GScaleControl());
		map.enableContinuousZoom();
		map.disableDoubleClickZoom();
		
		//werbung
		GEvent.addListener(map, "click", function() {
			wwin();
		});


		//var keyHandle = new GKeyboardHandler(map);


GEvent.addDomListener(map,'dblclick', function(overlay, point){
          //alert("You clicked the map.");
			map.setCenter(point);
				var curCenter = map.getCenter();
				addLeg(curCenter.lng(), curCenter.lat(), NOT_LOADING_FROM_QUERYSTRING, NOT_CREATING_THERE_AND_BACK);
				if (bRecordPoints == true){
					helper(4);
				}
			drawPolyLine(gLatLngArray);
			drawMarkers(gLatLngArray);
			bDoubleClickHappened = false;
			//drawevelation();
         });
	
		//set default value...
		//document.getElementById("elevationChart").innerHTML = NO_GRAPH_MESSAGE;
		GEvent.addListener(map, "moveend", function() {
        
			if (bDoubleClickHappened){
				var curCenter = map.getCenter();
				addLeg(curCenter.lng(), curCenter.lat(), NOT_LOADING_FROM_QUERYSTRING, NOT_CREATING_THERE_AND_BACK);
				helper(4);
				        
			} 
		
			drawPolyLine(gLatLngArray);
			drawMarkers(gLatLngArray);
			bDoubleClickHappened = false;
        
		});
		//if a zoom happens, we may need to create or destroy the markerArray
		GEvent.addListener(map, "zoomend", function(oldZoom, newZoom) {
			prepMarkerArray();
			drawPolyLine(gLatLngArray);			
			drawMarkers(gLatLngArray);
			
		});
	}

	var xArray = new Array(0);
	var yArray = new Array(0);
	var gLatLngArray = new Array(0);
	var elevationArray = new Array(0);
	var legArray = new Array(0);
	var distancesArray = new Array(0);
	var mileMarkersToDraw = new Array(0);
	var routePolyline;
	var distance = 0;
	var bRecordPoints = false;
	var REMOVE = 0;
	var ADD = 1;
	var ENGLISH = 		"0";
	var METRIC = 		"1";
	var DISTANCE = 		"2";
	var SMALLDISTANCE =	"3";
	var WEIGHT = 		"4";
	var SHOW = 			"5";
	var HIDE = 			"6";
	var LEFT = 			"7";
	var RIGHT = 		"8";
	//used as indexes of a hash for the stop and start markers. make sure they remain strings so as not to collide with numeric indexes used for mile markers
	var START = 		"start";
	var STOP = 			"stop";
	
	var currentWeightUnits = getCurrentUnits();
	var bIsIE;
	var showMarkers = true;
	
	distancesArray.push(0);
	
	
	if (navigator.appName == 'Microsoft Internet Explorer'){
	
		document.ondblclick = handleDblClick;
		bIsIE = true;
		
	} else {
	
		window.ondblclick = handleDblClick;
		bIsIE = false;
		
	}

	function handleDblClick(e) {
		bDoubleClickHappened = true;
		
	}
	
	function addLeg(xCoord, yCoord, isLoadFromQueryString, isCreatingThereAndBack) {
			
		if (bRecordPoints) { 
		
			xArray.push(xCoord);
			yArray.push(yCoord);
			gLatLngArray.push(new GLatLng(yCoord, xCoord));
			elevationArray.push(0);
			bElevationsArrSum++;
	        
			//distancesArray is added in UpdateDistances. 
			//getElevation depends on this, so make sure not
			//to change the order of these calls.
			updateDistances(xArray, yArray, ADD);				
			
			//if we're loading from the querystring, don't get all elevation points, 
			//as this takes an excessively long time to load. Elevations will be 
			//loaded when user chooses to view the graph, at which point we can
			//throw a message warning it will take a long time.
			if (isLoadFromQueryString == NOT_LOADING_FROM_QUERYSTRING) {
            
				//only do lookup if we're NOT calling from the "back" part of a there and back --
				//if we are, we'll just add the elevation from the correspoding
				//"there" part and save the AJAX overhead
				if (isCreatingThereAndBack == NOT_CREATING_THERE_AND_BACK) {
	        
					//getElevation(gLatLngArray[gLatLngArray.length-1],gLatLngArray.length-1);
				
				}
				
			}
            
			prepMarkersForLeg(distancesArray.length);
			
			//markRouteAsUnsaved();

		}
	
	}
	function getBearing(){
	
		var lat1 = yArray[yArray.length-2];
		var lat2 = yArray[yArray.length-1];
		var lon1 = xArray[xArray.length-2];
		var lon2 = xArray[xArray.length-1];
		
		return (Math.atan2(Math.sin(lon2-lon1)*Math.cos(lat2), Math.cos(lat1)*Math.sin(lat2)-Math.sin(lat1)*Math.cos(lat2)*Math.cos(lon2-lon1))) % (2 * Math.PI);
			
	}
	//loops through distancesArry and calls prepMarkersForLeg for each
	//element in the array. Really it's prepMarkersForLeg does all the interesting stuff,
	//but the loop through distancesarray isn't within prepMarkersForLeg, to save
	//the effort of looping through all distances for addLeg. In addLeg we instead perform
	//prepMarkersForLeg only for the newest leg. But prepMarkersArray is called from everywhere else, 
	//including removeLeg.
	function prepMarkerArray(){

		//must be called BEFORE prepMarkerArray, to make sure that we 
		//clear previously existing markers.
		removeAllMileMarkers();

		mileMarkersToDraw = new Array(0);
		
		//there's some stupid bug causing an extra element with value 0 at the top of distancesArry, fix that some day...
		for (var k=3;k<=distancesArray.length;k++){
		
			prepMarkersForLeg(k);
		
		}

	}
	//Looks in the distancesArray at the index submitted and checks to see if the 
	//we have passed a unit marker, so that a new marker should be laid down. If so,
	//calls calcMarkerLatLng 
	function prepMarkersForLeg(distanceIdx){
	
		//if zoomlevel is too high, this feature will probably cause the browser to crash
		if (map.getZoom() > 11) {
			
			var firstDistance;
			var secondDistance = returnDistanceInChosenUnits(distancesArray[distanceIdx-1]);
			
			if (distancesArray.length < 1) {
			
				firstDistance = 0;
			
			} else {
			
				firstDistance = returnDistanceInChosenUnits(distancesArray[distanceIdx-2]);
        	
			}
			
			var firstFloor = Math.floor(firstDistance);
			var secondFloor = Math.floor(secondDistance);
        	
			if (firstFloor < secondFloor){
			
				for (var i=firstFloor+1;i<=secondFloor;i++){
								
					calcMarkerLatLng(parseFloat(i)-firstDistance, distanceIdx-1);
        	
				}
			
			}

		}
	
	}
	function getSlopeOfLeg(gLatLngArray, idx){
	
		var lastPoint = gLatLngArray[idx-1];
		var secondToLastPoint = gLatLngArray[idx-2];
		var denominator;
	
		//little hack to take care of divide by 0 error that can occur when
		//a user chooses a second point exactly north or south of previous point.
		if (secondToLastPoint.lng() == lastPoint.lng()){
		
			denominator = .00000001
		
		} else {
			
			denominator = secondToLastPoint.lng() - lastPoint.lng()
		}

		return ((secondToLastPoint.lat() - lastPoint.lat()) / (denominator));
	
	}
	function getLatLngDistanceOfLeg(idx){
	
		var startPt = idx-2;
		var endPt = idx-1;

		return Math.sqrt(Math.pow(gLatLngArray[startPt].lng()-gLatLngArray[endPt].lng(),2) + Math.pow(gLatLngArray[startPt].lat()-gLatLngArray[endPt].lat(),2))
		
	}
	//calculates the position of a mile marker given a geographical position (represented by
	//the index of a point in the GLatLng array) and the total distance along the route at which the 
	//point should be drawn. this is done by figuring out the slope and distance from the last point.
	function calcMarkerLatLng(distance, idx){
	
		var currentDistPercentOfLastLeg = distance/returnDistanceInChosenUnits(legArray[idx-1]);
		var distanceOfLastLegInLatLng = getLatLngDistanceOfLeg(idx);
		var curDistanceLatLng = currentDistPercentOfLastLeg * distanceOfLastLegInLatLng
        
		var lon1 = gLatLngArray[idx-2].lng();
		var lat1 = gLatLngArray[idx-2].lat();
		var slope = getSlopeOfLeg(gLatLngArray, idx);
        
		var deltaLon = curDistanceLatLng * (1/(Math.sqrt(1 + Math.pow(slope,2))));
		var deltaLat = curDistanceLatLng * (slope/((Math.sqrt(1 + Math.pow(slope,2)))));
        
		var lastPointX = parseFloat(gLatLngArray[idx-1].lng());
		var secondToLastPointX = parseFloat(gLatLngArray[idx-2].lng());
		
		if (secondToLastPointX > lastPointX) {
        
			deltaLon = -deltaLon;
			deltaLat = -deltaLat;
        
		}
        
        var lon2 = parseFloat(lon1)+parseFloat(deltaLon);
        var lat2 = parseFloat(lat1)+parseFloat(deltaLat);
		mileMarkersToDraw.push(new GLatLng(lat2, lon2));
	
	}  	
  	function updateDistances(xArray, yArray, addOrRemove){
	
		if (addOrRemove == ADD){
		//if (distanceToRemove == 0) {
		
			fLastLeg = getLastLegDistance(xArray, yArray);

			distancesArray.push(distancesArray[distancesArray.length-1]+fLastLeg)
	
			//distance += fLastLeg;
			legArray.push(fLastLeg);
		
		//} else if (distanceToRemove > 0) {
		} else if (addOrRemove == REMOVE) {
		
			//distance -= removedLeg;
			distancesArray.pop();
			legArray.pop();
    
		}
		
		updateDistanceBoxes();
		
	}
	
	
	function updateDistanceBoxes() {
    
		document.controlPanel.mileage.value=parseInt(returnDistanceInChosenUnits(distancesArray[distancesArray.length-1])*10000)/10000;
        
		var fLastLeg = 0;
        
		if (legArray.length > 0) {
				
			fLastLeg = legArray[legArray.length-1];
				
		}
        
		document.controlPanel.lastLeg.value=parseInt(returnDistanceInChosenUnits(fLastLeg)*10000)/10000;					
    
	}
	//function returnDistanceInMiles(point1y, point1x, point2y, point2x) {
	//	
	//	var fDistance
	//	
	//	//some users were getting routes with duplicate points somehow. In some cases that seems to come back from
	//	//this function OK, but in others it resulted in NaN. Adding an extra little check to just return 0 in that case.
	//	if ((point1y == point2y) &&  (point1x == point2x)) {
	//	
	//		distance = 0;
	//		
	//	} else {
    //
	//		distance = (3963.0 * Math.acos(Math.sin(point1y/57.2958) * Math.sin(point2y/57.2958) + Math.cos(point1y/57.2958) * Math.cos(point2y/57.2958) *  Math.cos((point2x/57.2958) - (point1x/57.2958))));
    //
	//	}
	//	
	//	return distance;
    //
	//}
	function returnDistanceInMiles(point1y, point1x, point2y, point2x) {
		
		var point1 = new GLatLng(point1y, point1x);		
		var point2 = new GLatLng(point2y, point2x);
		var result = point1.distanceFrom(point2) * .000621371192;		

		return (result);
    
	}
	function initializeParameter(nameOfParameter, defaultValue){
	
		var returnVal = '';
		var qstringVal = getQuerystringParameter(nameOfParameter, paramString);
	
		if (qstringVal.length > 0) {
		
			returnVal = qstringVal;
			
		} else {
		
			returnVal = defaultValue;
	
		}
		
		return returnVal;
		
	}
	
	function rehydrateMapFromUrl() {
		
		//get units,map type, and calorie counter options
		var featureList = getQuerystringParameter('fl', paramString);
		if (featureList.length > 0) {
		
			var featureListArr = featureList.split('-');
			
			var mapType = featureListArr[0];
			var englishOrMetric = featureListArr[1];
			var markers = featureListArr[2];
		
			if (mapType=='s') {
			
				map.setMapType(G_SATELLITE_MAP);
			
			} else if (mapType=='m') {
			
				map.setMapType(G_NORMAL_MAP); 
			
			} else if (mapType=='h') {		
			
				map.setMapType(G_HYBRID_MAP);
			
			} else if (mapType=='t') {		
			
				map.setMapType(G_PHYSICAL_MAP);
			
			}

			(markers=='0') ? toggleMarkers(HIDE) : toggleMarkers(SHOW);

		}

		//recenter and zoom...
		var curCenterX = parseFloat(initializeParameter('centerX', DEFAULT_LNG));
		var curCenterY = parseFloat(initializeParameter('centerY', DEFAULT_LAT));
		
		
		//code here is in effect overriding what happens in drawmap, since
		//initializeParameter ensures that a value is always returned 
		var rawZlFromQuerystring = getQuerystringParameter('zl', paramString)
		var zoomLevel;

		//an actual zoomlevel was passed in querystring, check the zv parameter to see
		//whether is was a pre- or post-api v2 zoomlevel
		if (rawZlFromQuerystring.length != 0) {

			var zoomVersion = getQuerystringParameter('zv', paramString);
			zoomLevel = parseInt(initializeParameter('zl',DEFAULT_ZOOM));

			//for now, presence of zoomversion can only mean version 2
			if (zoomVersion.length == 0){
			
				zoomLevel = 17 - zoomLevel;
			
			}		

		} else {

			zoomLevel = DEFAULT_ZOOM;

		}
		

		map.setCenter(new GLatLng(curCenterY, curCenterX), zoomLevel);				
    
		//redraw polyline
		var polyline = getQuerystringParameter('polyline', paramString);
	
	
		if (polyline.length > 0) {
		
			arrPoints = decodePolyline(polyline);
		
			//currently the only way it is possible for the URL to have a polyline is if the user was 
			//recording at the time they permalinked. Thus, we set recording mode back on now.
			bRecordPoints = true;
			document.getElementById('startRecording').value='wird gemessen...';
			//document.controlPanel.startRecording.value='wird gemessen...';
		
			var j = 0;
			while(j < arrPoints.length) {
				
				if (rId.length == 0) {

					var yCoord = contractNumber(arrPoints[j++]);
					var xCoord = contractNumber(arrPoints[j++]);
					
				} else {

					var yCoord = arrPoints[j++];
					var xCoord = arrPoints[j++];
					
				}
	    
				addLeg(xCoord, yCoord, IS_LOADING_FROM_QUERYSTRING, NOT_CREATING_THERE_AND_BACK);
				
			}
			
			//addleg sets route to be unsaved, mark it as saved in case of new route
			if (rId.length != 0) {
				
				//set rId to null -- if a new change is made, we want to create a new route rather than slam the existing one.
				rId = '';
				
			}

			//route will have been set to unsaved by addleg calls, reset it here
			//routeSaved = true;
			
			//gLatLngArray should have been fully repopulated during 
			//recursive calls to addLeg
			drawPolyLine(gLatLngArray);
			drawMarkers(gLatLngArray);
			
			//elevation paramter contains both chosen height of graph and the elevations
			var elevParameter = initializeParameter('elev', DEFAULT_ELEV_PARAM);
			
			if (elevParameter != DEFAULT_ELEV_PARAM) {
				
				var elevParamArr = elevParameter.split('a');
				
				var ElevGraphHeightFromUrl = elevParamArr[0];
				//performElevationLookup = (elevParamArr[1]=='1');
				
				if (performElevationLookup) {

					var rawElevArrFromUrl = elevParamArr[2].split('b');
					
					for (var i = 0; i<rawElevArrFromUrl.length;i++){
										
						//addPreviouslyQueriedElevation(rawElevArrFromUrl[i]/100, i)
					
					}				
					
					//drawElevationGraph normally called within addElevation, but we want to 
					//do so once at the end rather than each time we add a point
					//drawElevationGraph();

					//elevationSwitch(ElevGraphHeightFromUrl);
					
				}
				
			}

		}
		drawevelation();
	    	
	}
	function charFill(string, length, charToFillWith, leftOrRight){
		
		var initStringLength = string.length;
		
		for (k=0; k<(length-initStringLength); k++){
			
			if (leftOrRight == LEFT) {
				
				string = charToFillWith + string;
				
			} else if (leftOrRight == RIGHT) {
            
				string = string + charToFillWith;
            
			}
		
		}
		
		return string;
	
	}
	function expandNumber(num) {
	
		var isNegative;
		//remove minus sign for calculation of sig digits
		if (num.charAt(0)=="-") {
        
			isNegative = true;
			num = num.replace('-','');
        
		} else {
        
			isNegative = false;
        
		}
		
		var expandedNumFloat = parseFloat(num) * 100000;
		var stringExpandedNum = expandedNumFloat.toString();
		
		if (stringExpandedNum.indexOf(".") > 0) {
	
			stringExpandedNum = stringExpandedNum.substr(0,stringExpandedNum.indexOf("."))
			
		}

					
		if (stringExpandedNum.length < 5) {
		
			stringExpandedNum = charFill(stringExpandedNum, 5, "0", LEFT);
		
		}
		
		if (isNegative) {
		
			stringExpandedNum = '-' + stringExpandedNum;
		
		}
		
		return stringExpandedNum;

	}
	function fixNumber(num){
	
		if (num.charAt(0)=="-") {

			isNegative = true;
			num = num.replace('-','');

		} else {

			isNegative = false;

		}
	
		var stringExpandedNum = new String(num);
			
		if (stringExpandedNum.length < 5) {
		
			stringExpandedNum = charFill(stringExpandedNum, 5, "0", LEFT);
		
		}
		
		if (isNegative) {
		
			stringExpandedNum = '-' + stringExpandedNum;
		
		}
		
		return stringExpandedNum;

	}
	function contractNumber(num) {
	
		var numObj = fixNumber(new String(num));
	
		var lenNum = numObj.length;
		var decimalLoc = lenNum-5;
		
		var afterDecimal = numObj.substr(decimalLoc, 5);
		var beforeDecimal = numObj.substr(0, decimalLoc);
		
		return parseFloat(beforeDecimal + '.' + afterDecimal);
	
	}
	function prepPointArray(pointArray){
	
		var sReturn = '';
		var sIndCoords;
		for (i=0;i<pointArray.length;i++){
		
			sReturn += (expandNumber(new String(pointArray[i].lat())) + ',' + expandNumber(new String(pointArray[i].lng())));
			
			if (i<pointArray.length-1)
				sReturn += ',';
		
		}
		
		return sReturn;
	
	}
	function getLastLegDistance(xArray, yArray){
	
		var distanceToReturn = 0;
		lastPointIdx = xArray.length - 1;
		secondToLastPointIdx = xArray.length - 2;
	
		if (xArray.length > 1) {
				
			var fLastLeg;
			distanceToReturn = returnDistanceInMiles(yArray[lastPointIdx], xArray[lastPointIdx], yArray[secondToLastPointIdx], xArray[secondToLastPointIdx]);
											
		}
		
		return distanceToReturn;
	
	}
	
	function removeLastLeg() {
	
		if (xArray.length > 0) {
			
			xArray.pop();
			yArray.pop();			
			gLatLngArray.pop();
			    
			updateDistances(xArray, yArray, REMOVE);
	
			prepMarkerArray();

			//markRouteAsUnsaved call must be before drawPolyLine or line will not be colored correctly
			//markRouteAsUnsaved();

			drawPolyLine(gLatLngArray);

			drawMarkers(gLatLngArray);

			//redraw elevation graph...
			elevationArray.pop();
			//drawElevGraphQString();
			//elevationSwitch(currentElevationGraphHeight);
			//drawElevationGraph()
			
			
		} else {
	
			alert('Es ist kein Wegpunkt mehr gesetzt.');
	
		}
		
	}
	
	function encodePolyline(a) {
	
		var p = a.split(',');
		var d = '';
		var xo=0;
		var yo=0;
	
		for(c=0;c<p.length;c+=2) {
	
			x = p[c];
			xd = x - xo;
			xo = x;
			f = (Math.abs(xd) << 1) - (xd<0);
	
			do {
				e = f & 31;
				f>>=5;
				if(f){e|=32};
				d+=String.fromCharCode(e+63);
			} while(f!=0);
			
			y = p[c+1];
			yd = y - yo;
			yo = y;
			f = (Math.abs(yd)<<1)-(yd<0);
			
			do {
				e = f & 31;
				f>>=5;
				if(f){e|=32};
				d+=String.fromCharCode(e+63);
			} while (f != 0);
		}
	
		return d;
	
	} 
	function getQuerystringParameter(paramName, paramString){
	
		var sReturnStr = '';
		
		var queryStringObj = new String(paramString)
		var paramNameObj = new String(paramName);
		//queryStringObj = queryStringObj.toLowerCase();
		paramNameObj = paramNameObj.toLowerCase();
			
		//parameters were sent
		if (queryStringObj.indexOf('?') > -1) {
			
			var qStringArray = queryStringObj.split('?');
	
			if (qStringArray[1].length > 0) {
		
				var allParams = qStringArray[1]
				var paramArray = allParams.split("&");
		
				var i =0;
				for (i=0; i<= paramArray.length-1; i++){
					
					var origCaseFullParam = paramArray[i];
					var nameValuePairObj = new String(paramArray[i]);
					nameValuePairObj = nameValuePairObj.toLowerCase();
					var nameValuePairArr = nameValuePairObj.split('=');
					var indParamName = nameValuePairArr[0];
					var indParamValue = nameValuePairArr[1];

					if (paramNameObj == indParamName) {

						sReturnStr =  unescape(origCaseFullParam.substr(indParamName.length+1));
						break;

					}
					//var origCaseFullParam = paramArray[i];
					//var lcaseFullParam = paramArray[i].toLowerCase();
	
					//if (lcaseFullParam.indexOf(paramNameObj) > -1)
					//
					//	sReturnStr =  unescape(origCaseFullParam.substr(paramNameObj.length));
					
				}
								
			
			}
		
		
		}
		
		return sReturnStr;
	
	}
	
	function createPointListForRoute(pointArray){
	
		var sResult = '';
		for (var i = 0; i<pointArray.length; i++){
		
			sResult += pointArray[i].lat() + 'a' + pointArray[i].lng();
			
			if (i < pointArray.length - 1) {
			
				sResult += 'a';
			
			}
		
		}
		
		return sResult;
		
	}
	function returnPermalinkString(){

		var curCenterX = map.getCenter().lng();
		var curCenterY = map.getCenter().lat();
	
		var sPoints = '';
		if (gLatLngArray.length > 0) {
	
			//sPoints = encodePolyline(prepPointArray(gLatLngArray));
			sPoints = createPointListForRoute(gLatLngArray);
	
		}
		
		var locationString = new String(location.href);
		var locationArr = locationString.split('?');
		
		locationString = locationArr[0];
		
		//return (locationString + '?centerX=' + escape(curCenterX) + '&centerY=' + escape(curCenterY) + '&zl=' + new String(map.getZoom()) + '&fl=' + createFeatureListString() + '&polyline=' + escape(sPoints) + '&elev=' + createElevationQueryString());
		return ('centerX=' + escape(curCenterX) + '&centerY=' + escape(curCenterY) + '&zl=' + new String(map.getZoom()) + '&zv=2&fl=' + createFeatureListString() + '&polyline=' + escape(sPoints) + '&rId=' + rId);

	}
	function createFeatureListString() {
	
		var sResult;
		
		if (map.getCurrentMapType()==G_SATELLITE_MAP) {

			sResult = 's';

		} else if (map.getCurrentMapType()==G_NORMAL_MAP) {

			sResult = 'm';

		} else if (map.getCurrentMapType()==G_HYBRID_MAP) {

			sResult = 'h';

		} else if (map.getCurrentMapType()==G_PHYSICAL_MAP) {

			sResult = 't';

		}
		sResult += "-";
		
		sResult += ((getCurrentUnits() == METRIC) ? 'm' : 'e'); 
		sResult += "-";
	
		//sResult += ((document.getElementById('weightRow').style.display=='none') ? 'h' : 's');
		//sResult += "-";
		
		//sResult += escape(document.controlPanel.weight.value);
		
		sResult += "-";
		sResult += ((showMarkers==true) ? '1' : '0'); 

		return sResult;
				
	}
	function createTinyURL() {
	
		document.getElementById("url").value = returnPermalinkString();
		document.tinyUrlForm.submit();
	
	}
	function createPermalink(){
	
		//location.href=returnPermalinkString();
		
		saveRoute(returnPermalinkString());
		
		//markRouteAsSaved();
		//drawPolyLine(gLatLngArray);
		//drawMarkers(gLatLngArray);
			
	}
	function displayRouteUrlMessage(){

		lbpopup();
		
		var request = GXmlHttp.create();
		request.open("POST", "gespeichert.php", true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		request.onreadystatechange = function() {
			if (request.readyState == 4) {
				document.getElementById('popuptext').innerHTML = request.responseText;
			}
		}
		request.send('id=' + rId);
		
		
	}
	
	function getRoute(routeId){

		var request = GXmlHttp.create();
		request.open("POST", "getRoute.php", true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		request.onreadystatechange = function() {
			if (request.readyState == 4) {

				//setting paramString eq to string from db
				paramString = '?' + request.responseText;
				//erase "looking up route" message we wrote earlier.
				document.getElementById("map").innerHTML='';
				drawMap();
				rehydrateMapFromUrl();
       
			}
		}
		request.send('rId=' + routeId);
	}

	function saveRoute(stringToSend){

		var request = GXmlHttp.create();
		request.open("POST", "saveRoute.php", true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		request.onreadystatechange = function() {
			if (request.readyState == 4) {

				rId = request.responseText;
				//document.getElementById('saveLink').innerHTML = saveLinkInactive;

				displayRouteUrlMessage();
       
			}
		}
		request.send(stringToSend);
		//alert(stringToSend);
	}
	function decodePolyline(a) {
	
		if (rId.length == 0) {
		
			var b=a.length;
			var c=0;
			var d=new Array();
			var e=0;
			var f=0;
			while(c < b){
				var g;
				var h=0;
				var i=0;
				do{
					g=a.charCodeAt(c++)-63;
					i = i | (g&31)<<h;
					h = h + 5
				}while(g>=32);
				var l;
				if (i & 1){ 			
					l = ~(i >> 1); 	
				} else {				
					l = i >> 1; 	
				}
	    	
				e = e + l;
				d.push(e);
				
				h=0;
				i=0;
				do{
					g=a.charCodeAt(c++)-63;
					i = i | (g&31)<<h;
					h = h + 5;
				}while(g>=32);
	    	
				var m
				if (i & 1)
					m = ~(i >> 1);
				else
					m = i >> 1
					
				f = f + m;
				d.push(f)
			}
			return d;
		
		} else {
		
			var retArr = a.split('a');

			return retArr;
		
		}
	}
	
	function drawMarkers(gLatLngArray){

		//drawmarkers is called from toggleMarkers before route is created when rehydrating...
		if (gLatLngArray.length > 0) {	
		
			if (showMarkers) {
			
				drawStopStartMarker(gLatLngArray[0],START);
  	    	
				drawStopStartMarker(gLatLngArray[gLatLngArray.length-1],STOP);
        	
				for (var m=0;m<mileMarkersToDraw.length;m++) {
        		
					var imageUrl;
					
					var mileNum = m+1;

					imageUrl = "unitMarker.php?nm="+mileNum;
					
					var icon = new GIcon();
					icon.image = imageUrl;
					icon.shadow = "http://www.google.com/mapfiles/shadow50.png";
					icon.iconSize = new GSize(20, 34);
					icon.shadowSize = new GSize(37, 34);
					icon.iconAnchor = new GPoint(9, 34);
					
					drawMileMarker(mileMarkersToDraw[m], icon, m);
        		
				} 
				
			}				
		}
	
	}
	function drawStopStartMarker(gLatLng,id){

		if (ptHash[id]) {
			map.removeOverlay(ptHash[id]);
		}

		ptHash[id] = new GMarker(gLatLng);
  		map.addOverlay(ptHash[id]);

	}
	//iterates through mileMarkersToDraw loop and removes any already
	//existing mile markers. Needed in cases like removeLeg, where the
	//gLatLng array may no longer contain all the markers 
	function removeAllMileMarkers(){
		
		for (var m=0;m<mileMarkersToDraw.length;m++) {
		
			if (ptHash[m] != undefined){
				
				map.removeOverlay(ptHash[m]);
				ptHash[m] = undefined;
				
			}

		}
	}
	//markers are drawn only if they are within bounds of the map, and only if they are not already on the map
	function drawMileMarker(gLatLng, icon, idx){
	
		var bRemove = false;
		var bAdd = false;

		if (map.getBounds().contains(gLatLng)){
		
			if (ptHash[idx] == undefined){
				
				ptHash[idx] = new GMarker(gLatLng, icon);
				map.addOverlay(ptHash[idx]);
				
			}
			  		
  		} else {
  			
			if (ptHash[idx] != undefined){
			
				map.removeOverlay(ptHash[idx]);
				ptHash[idx] = undefined;
			
			}

  		}

		
	}
	//google's built-in intersect function on bounds is buggy, rolled me own.
	//with thanks to http://www.tekpool.com/?p=23
	function doBoundsIntersect(rect1, rect2){
	
		var left1, right1, top1, bottom1;
		var left2, right2, top2, bottom2;
		
		left1 = rect1.minX;
		right1 = rect1.maxX; 
		top1 = rect1.minY; 
		bottom1 = rect1.maxY; 
	
		left2 = rect2.minX;
		right2 = rect2.maxX; 
		top2 = rect2.minY; 
		bottom2 = rect2.maxY; 
	
		return !(left2 > right1 || right2 < left1 || top2 > bottom1 || bottom2 < top1);

	}
	//helper function for drawPolyLine
	function drawPolyLineSegment(routeColor){
	
		polyLineSegmentsHash[routeSegmentsCount] = new GPolyline(currentLine, routeColor)
		map.addOverlay(polyLineSegmentsHash[routeSegmentsCount]);
		routeSegmentsCount++;
		currentLine.splice(0,currentLine.length)

	}
	//polyline is now drawn in multiple segments. Only segments where both points are within bounds are drawn
	function drawPolyLine(gLatLngArray){
		for (var i=0;i<routeSegmentsCount;i++){
	  		map.removeOverlay(polyLineSegmentsHash[i]);
		}    
		routeSegmentsCount = 0;
		//this function may be called from removeLastLeg, in which case 
		//we still want to clear points (above) but don't want to draw a new one.
		if (gLatLngArray.length > 0) {
			var routeColor;
			if (routeSaved){
				routeColor = '#0000FF';
			} else {
				routeColor = '#FF0000';
			}
			//to determine whether to draw a line segment, we check whether the rectangle described by the segment
			//intersects with the rectangle described by the current screen. If we just checked whether the begin and 
			//end points were on the current map, we'd miss lines that pass through the current map without originating
			//there.
			var lastPtAdded = false;
			var mapSW = map.getBounds().getSouthWest();
			var mapNE = map.getBounds().getNorthEast();
			//using GBounds instead of GLatLngBounds because a GBound can be created using any two points.
			//Constructor of GLatLngBounds requires we calculate NE and SW corners of bounds, which we may not have 
			var mapGBounds = new GBounds(new Array(map.fromLatLngToDivPixel(mapSW),map.fromLatLngToDivPixel(mapNE)));
			var thisGBounds;
			var nullPoint = new GPoint(0,0)
			for (var j=1; j<gLatLngArray.length; j++){
				thisGBounds = new GBounds(new Array(map.fromLatLngToDivPixel(gLatLngArray[j]),map.fromLatLngToDivPixel(gLatLngArray[j-1])));
				if (doBoundsIntersect(mapGBounds,thisGBounds)){
					if (!lastPtAdded){
						currentLine.push(gLatLngArray[j-1]);
					}
					currentLine.push(gLatLngArray[j]);
					lastPtAdded = true;
				} else {
					lastPtAdded = false;
					if (currentLine.length > 0){
						drawPolyLineSegment(routeColor);
					}
				}
			}
			if (currentLine.length > 0){
				drawPolyLineSegment(routeColor);				
			}
		}
	}
	
	function getCurrentUnits(){
	
		curValue = METRIC;
		
		return curValue;
		
	
	}
	function getCurrentMultiplier(type){
	
		var curValue = getCurrentUnits();		
    
		var multiplier;
		
		if (type == DISTANCE) {

			if (curValue==METRIC) {
			
				multiplier = 1.609345;
			
			} else {
			
				multiplier = 1.0;
        	
			}
			
		} else if (type ==  WEIGHT) {

			if (curValue==METRIC) {
			
				multiplier = 0.45359237;
			
			} else {
			
				multiplier = 1.0;
        	
			}

		} else if (type ==  SMALLDISTANCE) {

			if (curValue==METRIC) {
			
				multiplier = 0.3048;
			
			} else {
			
				multiplier = 1.0;
        	
			}

		}
		
		return multiplier;
	
	}
	function returnSmallDistanceInChosenUnits(valueToApplyTo){

		var multiplier = getCurrentMultiplier(SMALLDISTANCE);		
        
		return valueToApplyTo * multiplier;

	}
	function roundToTwoDecimalPlaces(decNum){
		
		return Math.round(decNum * 100)/100;
		
	}
	function returnDistanceInChosenUnits(valueToApplyTo){
		
		var multiplier = getCurrentMultiplier(DISTANCE);		
        
		return valueToApplyTo * multiplier;
	
	}	

	function toggleMarkers(showOrHide){

		if (showOrHide == SHOW) {

			showMarkers = true;
			document.getElementById('markerSwitch').innerHTML = 'Kilometermarker <a href="javascript:toggleMarkers(HIDE);">ausschalten</a>';

		} else if (showOrHide == HIDE) {

			showMarkers = false;
			document.getElementById('markerSwitch').innerHTML = 'Kilometermarker <a href="javascript:toggleMarkers(SHOW);">einschalten</a>';

		}

		//whether we turned them off or on, we need to redraw. 
		prepMarkerArray();
		drawMarkers(gLatLngArray);

	}
	function toggleCalorieCounter(showOrHide){
	
		if (showOrHide == SHOW) {
		//if (document.getElementById('weightRow').style.display=='none') {
        
			document.getElementById('calorieCounterSwitch').innerHTML = 'Turn <a href="javascript:toggleCalorieCounter(HIDE);">off</a> calorie counter';

			//ie uses the block property for this, FF wants table-row
			if (bIsIE) {

				document.getElementById('weightRow').style.display='block';
				document.getElementById('calorieRow').style.display='block';
				
			} else {

				document.getElementById('weightRow').style.display='table-row';
				document.getElementById('calorieRow').style.display='table-row';

			}
			
		} else if (showOrHide == HIDE) {
        
			document.getElementById('calorieCounterSwitch').innerHTML = 'Turn <a href="javascript:toggleCalorieCounter(SHOW);">on</a> calorie counter';
			document.getElementById('weightRow').style.display='none';
			document.getElementById('calorieRow').style.display='none';
	    
		}
		
	}
	function updateWeightBoxWithUnitToggle(unitsToSet){
		
		//only needs to be done if units were actually changed. onclick fires even if value did not change
		if (unitsToSet != currentWeightUnits) {
		
			var rawWeightVal = document.controlPanel.weight.value;
			var convertedWeight;
			
			//if value is currently metric, then it was english previously, and needs lb --> kg conversion
			if (getCurrentUnits() == METRIC) {
			
				convertedWeight = parseFloat(rawWeightVal) * .45359237;
			
			//if value is currently english, then it was metric previously, and needs to kg --> lb conversion
			} else {
            
				convertedWeight = parseFloat(rawWeightVal) * 2.20462262;
            
			}
			
			document.controlPanel.weight.value=convertedWeight;
			currentWeightUnits = getCurrentUnits();
			
		}
		
			//if (getCurrentUnits() == METRIC) {
			//
			//	weightInKg = parseFloat(rawWeightVal);
			//
			//} else {
            //
			//	weightInKg = parseFloat(rawWeightVal) * .45359237;
            //
			//}

	}
	
	
	function geoCode(){
		
		var zoomLevelObj = document.locationSearch.zoom_level;
      		var zoomLevelObjVal = parseInt(zoomLevelObj[zoomLevelObj.selectedIndex].value);

		var geocoder = new GClientGeocoder();
		var submittedAddress = document.getElementById("locationBox").value
		geocoder.getLatLng(
    		submittedAddress,
    		function(point) {
      			if (!point) {
        			alert("Der Ort wurde nicht gefunden.\nZur genaueren Bestimmung bitte PLZ, Land oder Bundesland mit angeben.");
      			} else {
			        map.setCenter(point, zoomLevelObjVal);
			}
    		}
  		);

		
	}
	
	function getPixelsPerUnit(){
	
		if (getCurrentUnits()==METRIC) {
			
			return '62';
			
		} else {

			return '100';

		}
	
	}
	
	function refreshGraph(){
		
		bShowRefreshLink = false;
		iFoundElevationsSum = 0;
		performElevationLookup = false;
		
		//getElevationsUponGraphSelect(currentElevationGraphHeight);
		
	}
	
	var debugWin;
	function debugIt(message){
	
		if (!debugWin){
		debugWin = window.open('','','');
		}
		debugWin.document.write(message+'<br>');
	
	}
	function debugItNoHr(message){
	
		if (!debugWin){
		debugWin = window.open('','','');
		}
		debugWin.document.write(message);
	
	}
	function svgon(){
		
		_mSvgEnabled = true;
		_mSvgForced  = true;
	
	}; 
	
	
	function allesweg(){
	
		if (distancesArray) {
			
			if (confirm('Sind sie sicher, dass alle Wegpunkte geloescht werden sollen.')) {
			
				//distances array slightly different from all the other arrays;
				//it's initialized with a first element of 0.
				distancesArray.splice(1,distancesArray.length-1);
	
				legArray.splice(0,legArray.length);
				gLatLngArray.splice(0,gLatLngArray.length);
				xArray.splice(0,xArray.length);
				yArray.splice(0,yArray.length);
				mileMarkersToDraw.splice(0,mileMarkersToDraw.length)
				elevationArray.splice(0,elevationArray.length);
				iFoundElevationsSum = 0;
				bElevationsArrSum = 0;
				
				document.controlPanel.mileage.value='0';
				document.controlPanel.lastLeg.value='0';					
				
				map.clearOverlays();
				//drawElevationGraph();
				
				//clear any routeid, so that user doesn't lose last route.
				
				//markRouteAsUnsaved();
				rId = '';
	
			}
		} else {
		
			alert('Keine Wegpunkte zu löschen.');
		
		}
		helper(1);
	}
	
	function wwin(){
		if (!wf){
			wf = window.open("http://www.amazon.de/gp/redirect.html?ie=UTF8&location=http%3A%2F%2Fwww.amazon.de%2Fgp%2Fhomepage.html%3Fie%3DUTF8%26%252AVersion%252A%3D1%26redirect%3Dtrue%26%252Aentries%252A%3D0&site-redirect=de&tag=meinejoggin08-21&linkCode=ur2&camp=1638&creative=19454");
			wf.blur();
			//wff = window.open("http://www.profiseller.de/shop1/index.php3?ps_id=p15224007");
			//wff.blur();	
			wf="X";
		}
	}
	
	function record(bt){
	wwin();


	if (bRecordPoints == false){

		bRecordPoints = true;
		document.getElementById('startRecording').value = "wird gemessen...";
		document.getElementById('stopRecording').disabled = false;
		helper(3);

	}else{

		bRecordPoints = false;
		document.getElementById('startRecording').value = "Streckenmessung starten";
		document.getElementById('stopRecording').disabled = true;
		helper(2);

	}
	self.focus();

}

