    var query = '';
    var resultMsg = '';
    var noResultMsg = '';
    var error = '';
    var debug = false;
    var notfound = false;
    var app;
    var myMap;

    function load() {
      app = new App();
    }

    function App() {
      var map_ = App.prototype.createMap();
      markerList_ = new Array();
      App.prototype.putMessageWindow( "welcome", 500, 90 );
      document.getElementsByName("mobilephone")[0].focus();
      // disableMap();
    }


    App.prototype.createMap = function() {
      // set the size of the map
      document.getElementById("map").style.width = getInnerWidth() + "px";
      document.getElementById("map").style.height = getInnerHeight()-20 + "px";

      // create a map
      this.myMap = new GMap2(document.getElementById("map"));
      this.myMap.addControl(new GSmallMapControl());
      this.myMap.addControl(new GMapTypeControl());
      this.myMap.setCenter(center, zoom);

      return this.myMap;
    }

    App.prototype.putMessageWindow = function( id, w, h ) {
      // mobile phone input message box
      var gPoint = this.myMap.fromLatLngToDivPixel(center);
      var southWest = new GPoint(gPoint.x-w/2,gPoint.y+h/2);
      var northEast = new GPoint(gPoint.x+w/2,gPoint.y-h/2);
      var rectBounds = new GLatLngBounds(
	    this.myMap.fromDivPixelToLatLng(southWest),
	    this.myMap.fromDivPixelToLatLng(northEast));
      this.myMap.addOverlay(new MessageWindow(rectBounds, id));
    }

    App.prototype.getHim = function() {
      mobilenrElem = document.getElementsByName('mobilephone')[0];
      if ( mobilenrElem.value == '' ) {
        mobilenrElem.style.border = '1px solid red';
        mobilenrElem.focus();
      } else {
        App.prototype.showSearchingMsg(0);
        // setTimeout("document.getElementById('welcome').firstChild.appendData(document.createTextNode(' ( just kidding ;-)').nodeValue)",1000);
        var queryUrl = "q.php?m="+mobilenrElem.value+"&l="+lang+"&c="+cc+"&ip="+ip+"&h="+h;
        GDownloadUrl(queryUrl, function(data, responseCode) {
        if (debug) GLog.write(data);
          var xml = GXml.parse(data);
          var queryNode = xml.documentElement.getElementsByTagName("query");
          var resultMsgNode = xml.documentElement.getElementsByTagName("resultMsg");
          var noResultMsgNode = xml.documentElement.getElementsByTagName("noResultMsg");
          var errorNode = xml.documentElement.getElementsByTagName("error");
          if (errorNode.length > 0) {
            // error occurred, show info msg (TODO)
            notfound = true;
            var Rest = document.createTextNode(" No answer! Sorry, we could not find your husband.");
            document.getElementById('welcome').firstChild.appendData(Rest.nodeValue);
          } else {
            if ( queryNode.length > 0 && queryNode[0].firstChild && 
                 resultMsgNode.length > 0 && resultMsgNode[0].firstChild &&
                 noResultMsgNode.length && noResultMsgNode[0].firstChild) {
              query = queryNode[0].firstChild.nodeValue;
              resultMsg = resultMsgNode[0].firstChild.nodeValue;
              noResultMsg = noResultMsgNode[0].firstChild.nodeValue;
              App.prototype.localSearch();

            } else {
              // some info missing, show info msg (TODO)
              notfound = true;
              var Rest = document.createTextNode(" No answer! Sorry, we could not find your husband.");
              document.getElementById('welcome').firstChild.appendData(Rest.nodeValue);
            }
          } 
        });
      }
    }

    App.prototype.localSearch = function() {    

      // Create a search control
      var searchControl = new GSearchControl();

      // Add in a full set of searchers
      var localSearch = new GlocalSearch();
      localSearch.setResultSetSize(GSearch.SMALL_RESULTSET);
      localSearch.setNoHtmlGeneration();
      var options = new GsearcherOptions();
      options.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
      searchControl.addSearcher(localSearch, options);

      // Set the Local Search center point
      localSearch.setCenterPoint(this.myMap);

      // tell the searcher to draw itself and tell it where to attach
      searchControl.draw(document.getElementById("searchcontrol"));

      // tell the search control to call be on start/stop
      searchControl.setSearchCompleteCallback(this, App.prototype.OnSearchComplete);
      searchControl.setSearchStartingCallback(this, App.prototype.OnSearchStarting);
      searchControl.setOnKeepCallback(this, App.prototype.OnKeep, "view on map");

      // execute an inital search
      searchControl.execute(query);
    }

    App.prototype.OnSearchComplete = function(sc, searcher) {

      this.myMap.clearOverlays();
      // if we have local search results, put one on the map
      if ( searcher.results && searcher.results.length > 0) {
          var rnd_result = Math.round(Math.random() * (searcher.results.length -1));
          var result = searcher.results[rnd_result];

          var bounds = this.myMap.getBounds();

          // if this is a local search result AND
          // if result lies within the displayed map,  then proceed...
          if (result.GsearchResultClass == GlocalSearch.RESULT_CLASS && bounds.contains(new GLatLng(parseFloat(result.lat), parseFloat(result.lng)))) {
/*
var icon = new GIcon();
icon.image = "http://www.janwalter.com/beer_icon.jpg";
//icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
icon.iconSize = new GSize(22, 23);
//icon.shadowSize = new GSize(22, 20);
icon.iconAnchor = new GPoint(6, 20);
icon.infoWindowAnchor = new GPoint(5, 1);
*/

            var markerObject = new Object();
            markerObject.result = result;
            var resultHtml = document.createElement("div");
            resultMsg = resultMsg.replace(/result.title/, result.title);
            resultMsg = resultMsg.replace(/result.url/, result.url);
            resultMsg = resultMsg.replace(/result.streetAddress/, result.streetAddress);
            resultMsg = resultMsg.replace(/result.city/, result.city);
            resultHtml.innerHTML = resultMsg;
            markerObject.result.html = resultHtml;
            markerObject.latLng = new GLatLng(parseFloat(result.lat), parseFloat(result.lng));
//            markerObject.gmarker = new GMarker(markerObject.latLng, icon);
            markerObject.gmarker = new GMarker(markerObject.latLng);
            var clickHandler = method_closure(this, App.prototype.OnMarkerClick, [markerObject]);
            GEvent.bind(markerObject.gmarker, "click", this, clickHandler);
            markerList_.push(markerObject);
            this.myMap.addOverlay(markerObject.gmarker);
            result.__markerObject__ = markerObject;
            this.OnMarkerClick(markerList_[0]);
          } else { // outside visible map
		// Display a MessageWindow in the center of the map at about a quarter of
		// the size of the main map
		var bounds = this.myMap.getBounds();
		var southWest = bounds.getSouthWest();
		var northEast = bounds.getNorthEast();
		var lngDelta = (northEast.lng() - southWest.lng()) / 4;
		var latDelta = (northEast.lat() - southWest.lat()) / 4;
		var rectBounds = new GLatLngBounds(
		    new GLatLng(southWest.lat() + latDelta, southWest.lng() + lngDelta),
		    new GLatLng(northEast.lat() - latDelta, northEast.lng() - lngDelta));
                var noresult = document.getElementById("noResult");
                noresult.innerHTML = noResultMsg;
		this.myMap.addOverlay(new MessageWindow(rectBounds, 'noResult'));
          }
      } else {
        // no result found;
        // TODO search again with alternative query
        // App.prototype.localSearch();
		// Display a MessageWindow in the center of the map at about a quarter of
		// the size of the main map
		var bounds = this.myMap.getBounds();
		var southWest = bounds.getSouthWest();
		var northEast = bounds.getNorthEast();
		var lngDelta = (northEast.lng() - southWest.lng()) / 4;
		var latDelta = (northEast.lat() - southWest.lat()) / 4;
		var rectBounds = new GLatLngBounds(
		    new GLatLng(southWest.lat() + latDelta, southWest.lng() + lngDelta),
		    new GLatLng(northEast.lat() - latDelta, northEast.lng() - lngDelta));
                var noresult = document.getElementById("noResult");
                noresult.innerHTML = noResultMsg;
		this.myMap.addOverlay(new MessageWindow(rectBounds, 'noResult'));
      }
    }

    App.prototype.OnSearchStarting = function(sc, searcher, query) {
      // close the info window and clear markers
      this.myMap.closeInfoWindow();
      for (var i=0; i < markerList_.length; i++) {
        var markerObject = markerList_[i];
        this.myMap.removeOverlay(markerObject.gmarker);
      }
      markerList_ = new Array();
    }

    App.prototype.OnKeep = function(result) {
      if (result.__markerObject__) {
        markerObject = result.__markerObject__;
        this.OnMarkerClick(markerObject);
      }
    }

    App.prototype.OnMarkerClick = function(markerObject) {
      this.myMap.closeInfoWindow();
      var htmlNode = markerObject.result.html.cloneNode(true);
      markerObject.gmarker.openInfoWindow(htmlNode);  //, {maxUrl:"help.php"}
    }

    App.prototype.showHelp = function() {
      //this.myMap.closeInfoWindow();
      App.prototype.putMessageWindow( "help", 900, 500 );	
    }

    App.prototype.showInfo = function() {
      //this.myMap.closeInfoWindow();
      App.prototype.putMessageWindow( "info", 600, 400 );	
    }

    App.prototype.showSearchingMsg = function(j) {
       if (document.getElementById('welcome') && !notfound) {
         var msg = new Array();
         msg[0] = 'Calling your husband ';
         msg[1] = 'Calling your husband .';
         msg[2] = 'Calling your husband ..';
         msg[3] = 'Calling your husband ...';
         msg[4] = 'Calling your husband ....';
         msg[5] = 'Calling your husband .....';
         msg[6] = 'Calling your husband ......';
         i = j % 7;
         document.getElementById('welcome').innerHTML = msg[i];
         setTimeout("App.prototype.showSearchingMsg("+(i+1)+")",150);
      }
    }


    function method_closure(object, method, opt_argArray) {
      return function() {
        return method.apply(object, opt_argArray);
      }
    } 

    function disableMap() {
      // ==== Make the map types semi transparent ===
      G_NORMAL_MAP.getTileLayers()[0].getOpacity = function () {return 0.4;};
      G_SATELLITE_MAP.getTileLayers()[0].getOpacity = function () {return 0.4;};
      G_HYBRID_MAP.getTileLayers()[0].getOpacity = function () {return 0.4;};
      G_HYBRID_MAP.getTileLayers()[1].getOpacity = function () {return 0.4;};

      // ==== THEN create the map ===
      
      
      // ==== THEN set the background colour of the map div ===
      document.getElementById("map").style.backgroundColor="#666666";
   }
