if (!window['google']) {
window['google'] = {};
}
if (!window['google']['loader']) {
window['google']['loader'] = {};
google.loader.ServiceBase = 'http://www.google.com/uds';
google.loader.GoogleApisBase = 'http://ajax.googleapis.com/ajax';
google.loader.ApiKey = 'notsupplied';
google.loader.KeyVerified = true;
google.loader.LoadFailure = false;
google.loader.AdditionalParams = '';
(function() { 
function w(a){if(a in A){return A[a]}return A[a]=navigator.userAgent.toLowerCase().indexOf(a)!=-1}
var A={};function E(){return w("msie")}
function F(){return w("safari")||w("konqueror")}
function K(a,b){var c=function(){}
;c.prototype=b.prototype;a.G=b.prototype;a.prototype=new c}
function P(a,b){var c=a._JSAPI_boundArgs||[];c=c.concat(Array.prototype.slice.call(arguments,2));if(typeof a._JSAPI_boundSelf!="undefined"){b=a._JSAPI_boundSelf}if(typeof a._JSAPI_boundFn!="undefined"){a=a._JSAPI_boundFn}var d=function(){var e=c.concat(Array.prototype.slice.call(arguments));return a.apply(b,e)}
;d._JSAPI_boundArgs=c;d._JSAPI_boundSelf=b;d._JSAPI_boundFn=a;return d}
function B(a){var b=new Error(a);b.toString=function(){return this.message}
;return b}
;
var g={};var x={};var G={};var U={};var s=null;var M=false;function S(a,b,c){var d=g[":"+a];if(!d){throw B("Module: '"+a+"' not found!");}else{if(c&&!c["language"]&&c["locale"]){c["language"]=c["locale"]}var e=c&&c["callback"]!=null;if(e&&!d.m()){throw B("Module: '"+a+"' must be loaded before DOM onLoad!");}else if(e){if(d.h(b,c)){window.setTimeout(c["callback"],0)}else{d.i(b,c)}}else{if(!d.h(b,c)){d.i(b,c)}}}}
function Z(a,b){if(b){Y(a)}else{z(window,"load",a)}}
function z(a,b,c){if(a.addEventListener){a.addEventListener(b,c,false)}else if(a.attachEvent){a.attachEvent("on"+b,c)}else{var d=a["on"+b];if(d!=null){a["on"+b]=Q([c,d])}a["on"+b]=c}}
function Q(a){return function(){for(var b=0;b<a.length;b++){a[b]()}}
}
var p=[];function Y(a){if(p.length==0){z(window,"load",t);if(!E()&&!F()&&w("mozilla")||window.opera){window.addEventListener("DOMContentLoaded",t,false)}else if(E()){window.setTimeout(H,10);document.attachEvent("onreadystatechange",J)}else if(F()){window.setTimeout(I,10)}}p.push(a)}
function H(){try{if(p.length>0){document.documentElement.doScroll("left")}}catch(a){window.setTimeout(H,10);return}t()}
var L={loaded:true,complete:true};function J(){if(L[document.readyState]){document.detachEvent("onreadystatechange",J);t()}}
function I(){if(L[document.readyState]){t()}else if(p.length>0){window.setTimeout(I,10)}}
function t(){for(var a=0;a<p.length;a++){p[a]()}p.length=0}
function X(a){var b=window.location.href;var c;var d=b.length;for(var e in a){var j=b.indexOf(e);if(j!=-1&&j<d){c=e;d=j}}s=c?a[c]:null}
function r(a,b,c){if(c){var d;if(a=="script"){d=document.createElement("script");d.type="text/javascript";d.src=b}else if(a=="css"){d=document.createElement("link");d.type="text/css";d.href=b;d.rel="stylesheet"}var e=document.getElementsByTagName("head")[0];if(!e){e=document.body.parentNode.appendChild(document.createElement("head"))}e.appendChild(d)}else{if(a=="script"){document.write('<script src="'+b+'" type="text/javascript"><\/script>')}else if(a=="css"){document.write('<link href="'+b+'" type="text/css" rel="stylesheet"></link>'
)}}}
function i(a,b){var c=a.split(/\./);var d=window;for(var e=0;e<c.length-1;e++){if(!d[c[e]]){d[c[e]]={}}d=d[c[e]]}d[c[c.length-1]]=b}
function R(a,b,c){a[b]=c}
function V(a){x=a}
function W(a){for(var b in a){if(typeof b=="string"&&b&&b.charAt(0)==":"&&!g[b]){g[b]=new n(b.substring(1),a[b])}}}
i("google.load",S);i("google.setOnLoadCallback",Z);i("google.loader.writeLoadTag",r);i("google.loader.setApiKeyLookupMap",X);i("google.loader.callbacks",G);i("google.loader.eval",U);i("google.loader.rfm",V);i("google.loader.rpl",W);i("google_exportSymbol",i);i("google_exportProperty",R);
function f(a){this.a=a;this.k={};this.b={};this.initialLoad=true}
f.prototype.d=function(a,b){var c="";if(b!=undefined){if(b["language"]!=undefined){c+="&hl="+encodeURIComponent(b["language"])}if(b["nocss"]!=undefined){c+="&output="+encodeURIComponent("nocss="+b["nocss"])}if(b["nooldnames"]!=undefined){c+="&nooldnames="+encodeURIComponent(b["nooldnames"])}if(b["packages"]!=undefined){c+="&packages="+encodeURIComponent(b["packages"])}if(b["callback"]!=null){c+="&async=2"}if(b["other_params"]!=undefined){c+="&"+b["other_params"]}}if(!this.initialLoad){if(google[this.a]
&&google[this.a].JSHash){c+="&sig="+encodeURIComponent(google[this.a].JSHash)}var d=[];for(var e in this.k){if(e.charAt(0)==":"){d.push(e.substring(1))}}for(var e in this.b){if(e.charAt(0)==":"){d.push(e.substring(1))}}c+="&have="+encodeURIComponent(d.join(","))}if(s!=null&&!M){c+="&key="+encodeURIComponent(s);M=true}return google.loader.ServiceBase+"/?file="+this.a+"&v="+a+google.loader.AdditionalParams+c}
;f.prototype.o=function(a){var b=null;if(a){b=a["packages"]}var c=null;if(b){if(typeof b=="string"){c=[a["packages"]]}else if(b.length){c=[];for(var d=0;d<b.length;d++){if(typeof b[d]=="string"){c.push(b[d].replace(/^\s*|\s*$/,"").toLowerCase())}}}}if(!c){c=["default"]}var e=[];for(var d=0;d<c.length;d++){if(!this.k[":"+c[d]]){e.push(c[d])}}return e}
;f.prototype.i=function(a,b){var c=this.o(b);var d=b&&b["callback"]!=null;if(d){var e=new y(b["callback"])}var j=[];for(var h=c.length-1;h>=0;h--){var l=c[h];if(d){e.s(l)}if(this.b[":"+l]){c.splice(h,1);if(d){this.b[":"+l].push(e)}}else{j.push(l)}}if(c.length){if(b&&b["packages"]){b["packages"]=c.sort().join(",")}if(!b&&x[":"+this.a]!=null&&x[":"+this.a].versions[":"+a]!=null&&!google.loader.AdditionalParams&&this.initialLoad){var m=x[":"+this.a];google[this.a]=google[this.a]||{};for(var u in m.properties)
{if(u&&u.charAt(0)==":"){google[this.a][u.substring(1)]=m.properties[u]}}r("script",google.loader.ServiceBase+m.path+m.js,d);if(m.css){r("css",google.loader.ServiceBase+m.path+m.css,d)}}else{r("script",this.d(a,b),d)}if(this.initialLoad){this.initialLoad=false}for(var h=0;h<j.length;h++){var l=j[h];this.b[":"+l]=[];if(d){this.b[":"+l].push(e)}}}}
;f.prototype.g=function(a){for(var b=0;b<a.components.length;b++){this.k[":"+a.components[b]]=true;var c=this.b[":"+a.components[b]];if(c){for(var d=0;d<c.length;d++){c[d].u(a.components[b])}delete this.b[":"+a.components[b]]}}v("hl",this.a)}
;f.prototype.h=function(a,b){return this.o(b).length==0}
;f.prototype.m=function(){return true}
;function y(a){this.t=a;this.j={};this.l=0}
y.prototype.s=function(a){this.l++;this.j[":"+a]=true}
;y.prototype.u=function(a){if(this.j[":"+a]){this.j[":"+a]=false;this.l--;if(this.l==0){window.setTimeout(this.t,0)}}}
;function T(a){g[":"+a.module].g(a)}
i("google.loader.loaded",T);
function k(a,b,c,d,e,j,h){this.a=a;this.A=b;this.z=c;this.p=d;this.r=e;this.w=j;this.q=h||{};this.e=false;this.n=false;this.f=[];G[this.a]=P(this.g,this)}
K(k,f);k.prototype.i=function(a,b){var c=b&&b["callback"]!=null;if(c){this.f.push(b["callback"]);b["callback"]="google.loader.callbacks."+this.a}else{this.e=true}r("script",this.d(a,b),c)}
;k.prototype.h=function(a,b){var c=b&&b["callback"]!=null;if(c){return this.n}else{return this.e}}
;k.prototype.g=function(){this.n=true;for(var a=0;a<this.f.length;a++){window.setTimeout(this.f[a],0)}this.f=[]}
;k.prototype.d=function(a,b){var c="";if(this.p!=null){c+="&"+this.p+"="+encodeURIComponent(s?s:google.loader.ApiKey)}if(this.r!=null){c+="&"+this.r+"="+encodeURIComponent(a)}var d=this.A;if(b!=null){for(var e in b){if(this.q[":"+e]!=null){var j=b[e];var h=this.q[":"+e];if(typeof h=="string"){c+="&"+h+"="+encodeURIComponent(j)}else{c+="&"+h(j)}}else if(e=="other_params"){c+="&"+b[e]}else if(e=="base_domain"){d=d.replace(/^[^\/]*/,b[e])}}}google[this.a]={};if(!this.z&&c!=""){c="?"+c.substring(1)}v(
"el",this.a);return"http://"+d+c}
;k.prototype.m=function(){return this.w}
;
function n(a,b){this.a=a;this.c=b;this.e=false}
K(n,f);n.prototype.i=function(a,b){this.e=true;r("script",this.d(a,b),false)}
;n.prototype.h=function(a,b){return this.e}
;n.prototype.g=function(){}
;n.prototype.d=function(a,b){if(!this.c["versions"][":"+a]){if(this.c["aliases"]){var c=this.c["aliases"][":"+a];if(c){a=c}}if(!this.c["versions"][":"+a]){throw B("Module: '"+this.a+"' with version '"+a+"' not found!");}}var d=b&&b["uncompressed"]?"uncompressed":"compressed";var e=google.loader.GoogleApisBase+"/libs/"+this.a+"/"+a+"/"+this.c["versions"][":"+a][d];v("el",this.a);return e}
;n.prototype.m=function(){return false}
;
function o(){}
var D=o.v=false;var N=o.B=5;var q=o.F=[];var O=o.D=function(){if(!D){z(window,"unload",C);D=(o.v=true)}}
;var v=o.record=function(a,b){O();var c=a+(b?"|"+b:"");q.push("r"+q.length+"="+encodeURIComponent(c));var d=q.length>N?0:15000;window.setTimeout(C,d)}
;var C=o.C=function(){if(q.length){var a=new Image;a.src=google.loader.ServiceBase+"/stats?"+q.join("&")+"&nocache="+Number(new Date);q.length=0}}
;i("google.loader.recordStat",v);
g[":search"]=new f("search");g[":feeds"]=new f("feeds");g[":language"]=new f("language");g[":elements"]=new f("elements");g[":maps"]=new k("maps","maps.google.com/maps?file=googleapi",true,"key","v",true,{":language":"hl",":callback":function(a){return"callback="+encodeURIComponent(a)+"&async=2"}
});g[":gdata"]=new f("gdata");g[":sharing"]=new k("sharing","www.google.com/s2/sharing/js",false,"key","v",false,{":locale":"hl"});g[":annotations"]=new k("annotations","www.google.com/reviews/scripts/annotations_bootstrap.js",false,"key","v",true,{":language":"hl",":country":"gl",":callback":"callback"});g[":visualization"]=new f("visualization");g[":books"]=new k("books","books.google.com/books/api.js",false,"key","v",true,{":language":"hl",":callback":"callback"});g[":earth"]=new f("earth");

 })()

google.loader.rpl({":scriptaculous":{"versions":{":1.8.1":{"uncompressed":"scriptaculous.js","compressed":"scriptaculous.js"}},"aliases":{":1.8":"1.8.1",":1":"1.8.1"}},":mootools":{"versions":{":1.11":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"}},"aliases":{":1":"1.11"}},":prototype":{"versions":{":1.6.0.2":{"uncompressed":"prototype.js","compressed":"prototype.js"}},"aliases":{":1":"1.6.0.2",":1.6":"1.6.0.2"}},":jquery":{"versions":{":1.2.3":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.2.6":{"uncompressed":"jquery.js","compressed":"jquery.min.js"}},"aliases":{":1":"1.2.6",":1.2":"1.2.6"}},":dojo":{"versions":{":1.1.1":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"}},"aliases":{":1":"1.1.1",":1.1":"1.1.1"}}});
}
if (window['google'] != undefined && window['google']['loader'] != undefined) {
if (!window['google']['search']) {
window['google']['search'] = {};
google.search.Version = '1.0';
google.search.NoOldNames = false;
google.search.JSHash = '4cb6919ade9874b7df7f2ad36a4c7be3';
google.loader.ApiKey = 'notsupplied';
google.loader.KeyVerified = true;
google.loader.LoadFailure = false;
}
google.loader.writeLoadTag("script", google.loader.ServiceBase + "/api/search/1.0/4cb6919ade9874b7df7f2ad36a4c7be3/default+sv.I.js", false);
}


/**
 * Copyright (c) 2008 Google Inc.
 *
 * You are free to copy and use this sample.
 * License can be found here: http://code.google.com/apis/ajaxsearch/faq/#license
*/

(function () {
var afsMode = true;
var afsLoadRequested = false;
function LocalSearch(opt_options) {

  // inline ads
  this.inlineAds = null;
  if (document.getElementById("_gmls_inline_ads_div_")) {
    if (afsMode && afsLoadRequested == false) {
      // defer load afs, now it can safely access the named div from
      // above...
      afsLoadRequested = true;
      var scriptUrl = "http://www.google.com/afsonline/show_dynamic_afs_ads.js";
      setTimeout(methodClosure(this, loadAfs, [scriptUrl]), 0);
    }
    this.inlineAds = new InlineAds();
    if (this.inlineAds.adDiv == null) {
      this.inlineAds = null;
    }
  }
  this.initBuiltinPinsAndLabels();
  this.options = opt_options;
}
LocalSearch.BUILTIN_PIN_SETS = ["red", "blue", "metalred", "metalblue"];
LocalSearch.PINS = [];
LocalSearch.LABELS = [];
LocalSearch.RESULT_LIST_INLINE = "inline";
LocalSearch.RESULT_LIST_SUPPRESS = "suppress";

// Export as google.maps.LocalSearch()
if (!window["google"]) {
  window["google"] = {};
}
if (!window["google"].maps) {
  window["google"].maps = {};
}
window["google"].maps.LocalSearch = LocalSearch;

LocalSearch.prototype = new GControl(false,true);
LocalSearch.prototype.initialize = function(map) {

  this.gmap = map;
  this.parseOptions(this.options);

  var container = document.createElement("div");
  cssSetClass(container, css.control_root);
  this.buildControl(container);


  map.getContainer().appendChild(container);
  if (this.inlineAds && this.inlineAds.facts.parent == "map") {
    map.getContainer().appendChild(this.inlineAds.root);
  }
  return container;
}

LocalSearch.prototype.getDefaultPosition = function() {
  var x = 5;
  var y = 65;
  if (br_IsIE()) {
    x = 2;
  }
  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(y,x));
}

LocalSearch.prototype.initBuiltinPinsAndLabels = function() {

  // build the icons
  var baseIcon = new GIcon();
  baseIcon.image = "http://www.google.com/mapfiles/gadget/markerSmall80.png";
  baseIcon.shadow = "http://www.google.com/mapfiles/gadget/shadow50Small80.png";
  baseIcon.iconSize = new GSize(16, 27);
  baseIcon.shadowSize = new GSize(30, 28);
  baseIcon.iconAnchor = new GPoint(8, 27);
  baseIcon.infoWindowAnchor = new GPoint(5, 1);

  // built in pin sets
  var colors = LocalSearch.BUILTIN_PIN_SETS;
  for (var c = 0; c<colors.length; c++) {
    var color = colors[c];
    LocalSearch.PINS[color] = new Array();
    LocalSearch.LABELS[color] = new Array();
    for ( var i=0; i < 8; i++ ) {
      var icon = new GIcon(baseIcon);
      var iconImageKey =
      icon.image = google.loader.ServiceBase + "/solutions/localsearch/img/pin_"
        + color + "_" + String.fromCharCode(65+i) + ".png";
      LocalSearch.PINS[color][i] = icon;
      var labelUrl =
        google.loader.ServiceBase + "/solutions/localsearch/img/label_"
          + color + "_" + String.fromCharCode(65+i) + ".png";
      LocalSearch.LABELS[color][i] = labelUrl;

    }
  }

}

LocalSearch.prototype.parseOptions = function(options) {
  this.suppressInitialResultSelection = false;
  this.suppressZoomToBounds = false;
  this.zoomLimit = 16;
  this.inlineResultList = true;
  this.externalResultListContainer = null;
  this.externalAds = null;
  this.linkTarget = GSearch.LINK_TARGET_BLANK;
  this.addressLookupMode = GlocalSearch.ADDRESS_LOOKUP_ENABLED;
  this.searchFormHint = GSearch.strings["search-the-map"];
  this.onIdleCallback = null;
  this.onSearchCompleteCallback = null;
  this.onCloseFormCallback = null;
  this.onMarkersSetCallback = null;
  this.onGenerateMarkerHtmlCallback = null;
  this.listingTypes = null;

  // default pins
  this.pins = new Array();
  this.pins["local"] = LocalSearch.PINS["red"];
  this.pins["kml"] = LocalSearch.PINS["blue"];
  this.labels = null;

  if (options) {

    // labels
    if (options.labels) {
      // establish defaults then over-ride
      this.labels = new Array();
      this.labels["local"] = LocalSearch.LABELS["red"];
      this.labels["kml"] = LocalSearch.LABELS["blue"];
      if (options.labels["local"]) {
        this.setLabelOptions(options, "local");
      }
      if (options.labels["kml"]) {
        this.setLabelOptions(options, "kml");
      }
    } else {
      // labels is not being passed so use css mode
      this.labels = null;
    }

    // pins
    if (options.pins) {
      if (options.pins["local"]) {
        this.setPinOptions(options, "local");
      }
      if (options.pins["kml"]) {
        this.setPinOptions(options, "kml");
      }
    }

    // external ads
    if (options.externalAds) {
      this.externalAds = new ExternalAds(options.externalAds);
    }

    // address lookup mode
    if (options.addressLookupMode) {
      this.addressLookupMode = options.addressLookupMode;
    }

    // listingTypes
    if (options.listingTypes) {
      this.listingTypes = options.listingTypes;
    }

    // suppress initial result selection
    if (options.suppressInitialResultSelection) {
      this.suppressInitialResultSelection =
        options.suppressInitialResultSelection;
    }

    // zoom to bounds when results loaded
    if (typeof(options.suppressZoomToBounds) != "undefined") {
      this.suppressZoomToBounds = options.suppressZoomToBounds;
    }

    if (typeof(options.zoomLimit) != "undefined") {
      this.zoomLimit = options.zoomLimit;
    }

    // result list style
    if (options.resultList) {
      if (options.resultList == LocalSearch.RESULT_LIST_INLINE) {
        this.inlineResultList = true;
      } else if (options.resultList == LocalSearch.RESULT_LIST_SUPPRESS) {
        this.inlineResultList = false;
      } else {
        this.inlineResultList = true;
        this.externalResultListContainer = options.resultList;
      }
    }

    // linkTarget
    if (options.linkTarget) {
      this.linkTarget = options.linkTarget;
    }

    // search form hint string
    if (options.searchFormHint) {
      this.searchFormHint = options.searchFormHint;
    }

    // callbacks
    if (options.onIdleCallback) {
      this.onIdleCallback = options.onIdleCallback;
    }
    if (options.onSearchCompleteCallback) {
      this.onSearchCompleteCallback = options.onSearchCompleteCallback;
    }
    if (options.onCloseFormCallback) {
      this.onCloseFormCallback = options.onCloseFormCallback;
    }
    if (options.onMarkersSetCallback) {
      this.onMarkersSetCallback = options.onMarkersSetCallback;
    }
    if (options.onGenerateMarkerHtmlCallback) {
      this.onGenerateMarkerHtmlCallback = options.onGenerateMarkerHtmlCallback;
    }
  }

  // adjust css.app, .app_active, .app_idle, and .app_no_results to account
  // for cull or compact mode
  var browserAdd = "gmls-std-mode";
  if (br_IsIE()) {
    browserAdd = "gmls-ie-mode";
  }
  var classAddOn = " " + css.app_compact_mode + " " + browserAdd;
  if (this.inlineResultList == true) {
    classAddOn = " " + css.app_full_mode + " " + browserAdd;;
  }
  css.app += classAddOn;
  css.app_active += classAddOn;
  css.app_idle += classAddOn;
  css.app_no_results += classAddOn;
}

LocalSearch.prototype.setPinOptions = function(options, type) {
  if (typeof options.pins[type] == "string") {
    // factor this to scan against BUILTIN_PIN_SETS
    if (options.pins[type] == "blue" ||
        options.pins[type] == "red"  ||
        options.pins[type] == "metalred"  ||
        options.pins[type] == "metalblue" ) {
      this.pins[type] = new Array();
      this.pins[type] = LocalSearch.PINS[options.pins[type]];
    }
  } else {
    // otherwise, assume they gave us an array of pins
    this.pins[type] = options.pins[type];
  }
}

LocalSearch.prototype.setLabelOptions = function(options, type) {
  if (typeof options.labels[type] == "string") {
    // factor this to scan against BUILTIN_PIN_SETS
    if (options.labels[type] == "blue" ||
        options.labels[type] == "red"  ||
        options.labels[type] == "metalred"  ||
        options.labels[type] == "metalblue" ) {
      this.labels[type] = new Array();
      this.labels[type] = LocalSearch.LABELS[options.labels[type]];
    }
  } else {
    // otherwise, assume they gave us an array of pins
    this.labels[type] = options.labels[type];
  }
}

LocalSearch.prototype.buildControl = function(container, opt_options) {
  this.root = container;

  this.buildContainerGuts(opt_options);

  // result scroller
  this.currentResultIndex = 0;
  this.markers = new Array();
  this.idle = true;

  // bind up the controls
  this.searchForm.input.onclick = methodClosure(this, LocalSearch.prototype.onPreActive, []);
  this.searchForm.input.onfocus = methodClosure(this, LocalSearch.prototype.onPreActive, []);
  this.searchForm.setOnSubmitCallback(this,LocalSearch.prototype.formSubmit);
  if (this.onCloseFormCallback) {
    this.searchForm.setOnClearCallback(this,LocalSearch.prototype.formClear);
  }
  this.next.onclick = methodClosure(this, LocalSearch.prototype.onNext, []);
  this.prev.onclick = methodClosure(this, LocalSearch.prototype.onPrev, []);

  if (opt_options) {
    if (opt_options.linkTarget) {
      this.linkTarget = opt_options.linkTarget;
    }
  }
  this.bootComplete(null);
}

LocalSearch.prototype.buildContainerGuts = function(opt_options) {

  // build out the control including the form and results popup
  removeChildren(this.root);
  this.appContainer = createDiv(null, css.app);

  // create a container for the ads to sit in. this is their
  // permanent home in the dom
  if (this.inlineAds) {
    this.inlineAds.root = createDiv(null, css.ads[this.inlineAds.facts.format]);
    this.inlineAds.root.appendChild(this.inlineAds.adDiv);
  }

  // the search form
  var enableClear = false;
  if ( this.onCloseFormCallback ) {
    enableClear = true;
    css.search_form_active += " gmls-search-form-withclear";
    css.search_form_idle += " gmls-search-form-withclear";
  }
  this.searchFormDiv = createDiv(null, css.search_form_idle);
  this.searchForm = new GSearchForm(enableClear, this.searchFormDiv);

  // todo(markl):
  // this really needs a home, maybe in the search form user cell
  this.attributionDiv = createDiv(null, css.attribution);

  this.buildPrevNextControl();

  /**
   * This is the basic structure we are building
   *  <resultsPopup>
   *    <resultsList>
   *      <resultsTable/>
   *      <adsBox/>?
   *      <resultsControls/>
   *      <attributionDiv/>
   *    </resultsList>
   *  </resultsPopup>
   */
  this.resultsPopup = createDiv(null, css.results_popup);
  this.resultsList = createDiv(null, css.results_list);
  this.resultsTableDiv = createDiv(null, css.results_table);
  this.resultsTable = createTable(css.results_table);
  this.resultsTableDiv.appendChild(this.resultsTable);

  var adsBox = null;
  if (this.inlineAds && this.inlineAds.facts.parent == "results") {
    adsBox = createDiv(null,css.results_ads_box);
    adsBox.appendChild(this.inlineAds.root);
  }
  this.resultControls = createDiv(null, css.results_controls);

  // bind everything up
  this.resultsPopup.appendChild(this.resultsList);
  this.resultsList.appendChild(this.resultsTableDiv);
  if (adsBox) {
    this.resultsList.appendChild(adsBox);
  }
  this.resultsList.appendChild(this.resultControls);

  this.resultsList.appendChild(this.attributionDiv);

  // IF we have an external ResultListContainer,
  // attach the resultsPopup there, otherwise
  // attach in the appContainer
  if (this.externalResultListContainer) {
    removeChildren(this.externalResultListContainer);
    var appContainer = createDiv(null, css.app);
    appContainer.appendChild(this.resultsPopup);
    this.externalResultListContainer.appendChild(appContainer);
    this.externalResultListContainer = appContainer;
  } else {
    this.appContainer.appendChild(this.resultsPopup);
  }

  this.appContainer.appendChild(this.searchFormDiv);
  this.root.appendChild(this.appContainer);
}

LocalSearch.prototype.resetResultsTable = function() {
  this.resultsTableDiv.innerHTML = "";
  this.resultsTable = createTable(css.results_table);
  this.resultsTableDiv.appendChild(this.resultsTable);
}

LocalSearch.prototype.buildPrevNextControl = function() {
  // controls
  this.prevNext = createDiv(null, css.prev_next_active);
  this.prev = createDiv(null, css.prev);
  this.next = createDiv(null, css.next);

  this.prev.innerHTML = "&nbsp;";
  this.next.innerHTML = "&nbsp;";
  this.prev.title = GSearch.strings["previous"];
  this.next.title = GSearch.strings["next"];

  var prevNextCenter = createDiv(null, css.prev_next_center);
  prevNextCenter.appendChild(this.prev);
  prevNextCenter.appendChild(this.next);

  this.prevNext.appendChild(prevNextCenter);
}

LocalSearch.prototype.bootComplete = function() {
  // create a searcher and bind to the map
  this.gs = new GlocalSearch();
  this.gs.setResultSetSize(GSearch.LARGE_RESULTSET);
  this.gs.setLinkTarget(this.linkTarget);
  this.gs.setCenterPoint(this.gmap);
  this.gs.setAddressLookupMode(this.addressLookupMode);
  if (this.listingTypes) {
    this.gs.setRestriction(GSearch.RESTRICT_TYPE, this.listingTypes);
  }
  if (this.adsenseList) {
    for (var i=0; i<this.adsenseList.length; i++) {
      this.gs.addRelatedSearcher(this.adsenseList[i]);
    }
  }
  this.gs.setSearchCompleteCallback(this, LocalSearch.prototype.searchComplete, [null]);
  GEvent.bind(this.gmap, "click", this, this.onMapClick);
  this.goIdle();
}

// clear the old markers off of the map
LocalSearch.prototype.clearMarkers = function() {
  cssSetClass(this.prevNext, css.prev_next_idle);

  this.gmap.closeInfoWindow();
  for (var i=0; i < this.markers.length; i++) {
    this.gmap.removeOverlay(this.markers[i].marker);
    if ( this.markers[i].resultsListItem &&
         this.markers[i].resultsListItem.onclick ) {
      this.markers[i].resultsListItem.onclick = null;
    }
    this.markers[i].resultsListItem = null;
  }
  this.resetResultsTable();

  // result scroller
  this.currentResultIndex = 0;
  this.markers = new Array();
}

// drop the new markers on the map
LocalSearch.prototype.setMarkers = function() {
  // result scroller
  this.currentResultIndex = 0;
  this.markers = new Array();
  var bestResultUrl = null;
  this.resetResultsTable();
  var zoomToBounds;
  var zoomable = true;
  var useResultViewportBounds = false;
  if (this.gs.resultViewport) {
    useResultViewportBounds = true;
    zoomToBounds = new GLatLngBounds(
      new GLatLng(parseFloat(this.gs.resultViewport.sw.lat),
                  parseFloat(this.gs.resultViewport.sw.lng)),
      new GLatLng(parseFloat(this.gs.resultViewport.ne.lat),
                  parseFloat(this.gs.resultViewport.ne.lng)));
  } else {
    zoomToBounds = new GLatLngBounds();
  }

  if ( this.gs.results && this.gs.results.length > 0) {
    for (var i = 0; i < this.gs.results.length && i < 16; i++) {
      var result = this.gs.results[i];
      var icon = this.pins["local"][i];
      if (result.listingType == "kml") {
        icon = this.pins["kml"][i];
      }
      var localResult = new LocalResult(this, result, icon, i,
                                        this.inlineResultList);
      this.markers.push(localResult);
      if (useResultViewportBounds == false) {
        zoomToBounds.extend(localResult.marker.getPoint());
      }
      // If we have mixed results, don't enable zoom to bounds
      if ( result.addressLookupResult &&
          result.addressLookupResult == "/maps" &&
           this.gs.results.length > 1) {
        if (useResultViewportBounds == false) {
          zoomable = false;
        }
      }

      // find the first, non-address result and hold on to it for the more-link
      if (bestResultUrl == null && !result.addressLookupResult ) {
        bestResultUrl = result.url;
      }
    }
    if (bestResultUrl == null) {
      bestResultUrl = this.gs.results[0].url;
    }

    if (zoomable && this.suppressZoomToBounds == false) {
      var zoomLevel = this.gmap.getBoundsZoomLevel(zoomToBounds);
      // todo(markl): verify this with pamela and brandon...
      // excessive zooming, especially on single point queries
      // seems to be a problem. For instance, a query for
      // nyc returns a valid bounds, but zoom level of 19, which
      // exceeds the resolution of the map.
      if (zoomLevel > this.zoomLimit) {
        zoomLevel = this.zoomLimit;
      }
      this.gmap.setCenter(zoomToBounds.getCenter(), zoomLevel);
    }

    this.idle = false;
    this.selectMarker(0, this.suppressInitialResultSelection);

    this.addResultsControl(bestResultUrl);

    cssSetClass(this.prevNext, css.prev_next_active);
    this.setAppContainerClass(css.app_active);
    return true;
  } else {
    this.showNoResultsMessage();
    this.setAppContainerClass(css.app_active);
    return false;
  }
}

LocalSearch.prototype.addResultsControl = function(bestResultUrl) {
  removeChildren(this.resultControls);

  // NOW, take the URL and nuke from &latlnt.*&near ->&near
  var newUrl = bestResultUrl.replace(/&latlng=.*&near/,"&near");
  var moreDiv = createDiv(null, css.more_results);
  var alink = createLink(newUrl, GSearch.strings["more-results"],
                         this.linkTarget, css.more_results);
  moreDiv.appendChild(alink);

  var clearDiv = createDiv(GSearch.strings["clear-results-uc"],
                           css.clear_results);
  clearDiv.onclick = methodClosure(this,
                                      LocalSearch.prototype.goIdle,
                                      []);
  // create a table for these to sit within
  var prevNextTable = createTable(css.results_controls);
  var row = createTableRow(prevNextTable);
  var moreTd = createTableCell(row, css.more_results);
  var prevNextTd = createTableCell(row, css.prev_next);
  var clearTd = createTableCell(row, css.clear_results);

  moreTd.appendChild(moreDiv);
  prevNextTd.appendChild(this.prevNext);
  clearTd.appendChild(clearDiv);

  this.resultControls.appendChild(prevNextTable);
}

LocalSearch.prototype.showNoResultsMessage = function() {

  var row = createTableRow(this.resultsTable);
  var tdiv = createDiv(GSearch.strings["no-results"], css.result_list_item_warning_text);
  var resultTd = createTableCell(row, null);
  var resultDiv = createDiv(null, css.result_list_item);
  var key = createDiv("!", css.result_list_item_warning_symbol);
  resultDiv.appendChild(key);
  resultDiv.appendChild(tdiv);
  resultTd.appendChild(resultDiv);

  removeChildren(this.resultControls);
  var moreDiv = createDiv("", css.more_results);
  var clearDiv = createDiv(GSearch.strings["close"],
                           css.clear_results);
  clearDiv.onclick = methodClosure(this,
                                      LocalSearch.prototype.goIdle,
                                      []);
  // create a table for these to sit within
  var prevNextTable = createTable(css.results_controls);
  var row = createTableRow(prevNextTable);
  var moreTd = createTableCell(row, css.more_results);
  var prevNextTd = createTableCell(row, css.prev_next);
  var clearTd = createTableCell(row, css.clear_results);

  moreTd.appendChild(moreDiv);
  prevNextTd.appendChild(this.prevNext);
  clearTd.appendChild(clearDiv);

  this.resultControls.appendChild(prevNextTable);
}

// light up the selected marker
LocalSearch.prototype.selectMarker = function(index, opt_suppressInfoWindow) {

  // clear info window and reset icon on current marker
  this.gmap.closeInfoWindow();

  // if we have a results list, clear selected
  if (this.markers[this.currentResultIndex].resultsListItem) {
    cssSetClass(this.markers[this.currentResultIndex].resultsListItem,
                css.result_list_item);
  }

  // snap to current
  this.currentResultIndex = index;

  // light up current
  var result = this.markers[this.currentResultIndex];

  if (result.resultsListItem) {
    cssSetClass(result.resultsListItem, css.result_list_item_selected);
  }

  if (opt_suppressInfoWindow == null ||
      opt_suppressInfoWindow == false ) {
    result.marker.openInfoWindow(result.getHtml(), {maxWidth:300});
  }

  // set scroller
  if (index == 0) {
    cssSetClass(this.prev, css.prev_idle);
  } else {
    cssSetClass(this.prev, css.prev_active);
  }

  if (index == this.markers.length - 1) {
    cssSetClass(this.next, css.next_idle);
  } else {
    cssSetClass(this.next, css.next_active);
  }
}

// clear current markers and start a new search
LocalSearch.prototype.formSubmit = function(form) {
  if (form.input.value) {
    this.newSearch(form.input.value);
  }
  return false;
}

// clear current markers and start a new search
LocalSearch.prototype.formClear = function(form) {
  this.onCloseFormCallback();
  this.goIdle()
  return false;
}

LocalSearch.prototype.focus = function() {
  this.searchForm.input.focus();
}

// clear current markers and start a new search
LocalSearch.prototype.execute = function(opt_query) {
  // hyperlink friendly...
  this.newSearch(opt_query);
}

LocalSearch.prototype.newSearch = function(opt_query) {
  if (opt_query) {
    this.searchForm.input.value  = opt_query;
  }
  if (this.searchForm.input.value) {

    // clear markers, set prev/next
    this.clearMarkers();
    removeChildren(this.attributionDiv);
    this.gs.execute(this.searchForm.input.value);
  }
  return false;
}

LocalSearch.prototype.searchComplete = function() {
  var attribution = this.gs.getAttribution();
  if (attribution) {
    this.attributionDiv.appendChild(attribution);
  }

  if (this.inlineAds) {
    this.inlineAds.hide();
  }
  if (this.externalAds) {
    this.externalAds.hide();
  }
  if (this.onSearchCompleteCallback) {
    this.onSearchCompleteCallback(this.gs);
  }
  if (this.setMarkers()) {
    if (this.onMarkersSetCallback) {
      this.onMarkersSetCallback(this.markers);
    }

    // don't show ads for address lookup results
    if (this.gs.results && this.gs.results.length > 0 &&
        this.gs.results[0].addressLookupResult) {
      return;
    }
    if (this.inlineAds) {
      this.inlineAds.fetch(this.searchForm.input.value, this.gs.results);
      this.inlineAds.show();
    }
    if (this.externalAds) {
      this.externalAds.fetch(this.searchForm.input.value, this.gs.results);
      this.externalAds.show();
    }
  }
}

// forwards through the search results
LocalSearch.prototype.onNext = function() {
  if (this.currentResultIndex < this.markers.length - 1) {
    this.selectMarker(this.currentResultIndex+1);
  }
}

// backwards through the search results
LocalSearch.prototype.onPrev = function() {
  if (this.currentResultIndex > 0) {
    this.selectMarker(this.currentResultIndex-1);
  }
}

// called onboot complete, and on cancel click
LocalSearch.prototype.goIdle = function() {
  if (this.inlineAds) {
    this.inlineAds.hide();
  }
  if (this.externalAds) {
    this.externalAds.hide();
  }
  this.searchForm.input.value = this.searchFormHint;
  this.clearMarkers();
  cssSetClass(this.searchFormDiv, css.search_form_idle);
  this.setAppContainerClass(css.app_idle);
  cssSetClass(this.prevNext, css.prev_next_idle);

  this.idle = true;
  this.resetResultsTable();

  if (this.onIdleCallback) {
    this.onIdleCallback();
  }
}

// call onfocus/onclick for search input cell
LocalSearch.prototype.onPreActive = function() {
  if (this.idle) {
    this.searchForm.input.value = "";
    cssSetClass(this.searchFormDiv, css.search_form_active);
  }
}

LocalSearch.prototype.onMapClick = function(marker, point) {
  if (marker && marker.__ls__) {
    var localResult = marker.__ls__;
    localResult.onClick();
  }
}

LocalSearch.prototype.setAppContainerClass = function(className) {
  cssSetClass(this.appContainer, className);
  if (this.externalResultListContainer) {
    className += " " + css.app_external_results;
    cssSetClass(this.externalResultListContainer, className);
  }
}

// A class representing a single Local Search result returned by the
// Google AJAX Search API.
function LocalResult(gmls, result, icon, index, buildList) {
  this.gmls = gmls;
  this.result = result;
  this.latLng = new GLatLng(parseFloat(result.lat), parseFloat(result.lng));
  this.index = index;

  this.setMarker(icon);

  if (buildList) {
    var div = createDiv(null, css.result_list_item);
    var row = createTableRow(gmls.resultsTable);
    var tdiv = createDiv(result.title, css.gs_title);
    var resultTd = createTableCell(row, null);

    var resultDiv = createDiv(null, css.result_list_item);

    var key;
    var keyClass = css.result_list_item_key;
    var keyCode = String.fromCharCode(65+index);
    if (true) {
      // go with image based key key codes for now. make it an option later
      keyClass += " " + css.result_list_item_key + "-" + keyCode;
      keyClass += " " + css.result_list_item_key + "-" + result.listingType + "-" + keyCode;
      keyClass += " " + css.result_list_item_key + "-" + "keymode";
      key = createDiv(null, keyClass);
      key.innerHTML = "&nbsp;";

      // now, if the labels option is being used,
      // DO NOT use CSS. Instead, directly poke the node
      if (gmls.labels) {
        var bi = gmls.labels[result.listingType][index];
        key.style.backgroundImage = "url('" + bi + "')";
      }
    } else {
      key = createDiv("(" + keyCode + ")", keyClass);
    }
    resultDiv.appendChild(key);

    resultDiv.appendChild(tdiv);

    if (!result.addressLookupResult) {
      if (result.streetAddress && result.streetAddress != "") {
        var str = "&nbsp;-&nbsp;" + result.streetAddress;
        var addrDiv = createDiv(str, css.gs_street);

        resultDiv.appendChild(addrDiv);
      }
    }
    resultTd.appendChild(resultDiv);
    resultDiv.onclick = methodClosure(
                    gmls, LocalSearch.prototype.selectMarker, [index]);
    this.resultsListItem = resultDiv;
  }
}

LocalResult.prototype.getHtml = function() {
  var result = createDiv(null, css.result_wrapper);
  var node = this.result.html.cloneNode(true);

  if (this.gmls.onGenerateMarkerHtmlCallback) {
    node = this.gmls.onGenerateMarkerHtmlCallback(this.marker, node, this.result);
  }

  result.appendChild(node);
  return result;
}

LocalResult.prototype.setMarker = function(icon) {
  this.marker = new GMarker(this.latLng, icon);
  this.marker.__ls__ = this;
  this.gmls.gmap.addOverlay(this.marker);
}

LocalResult.prototype.onClick = function() {
  this.gmls.selectMarker(this.index);
}


/**
 * Various Static DOM Wrappers.
*/
function methodClosure(object, method, opt_argArray) {
  return function() {
    return method.apply(object, opt_argArray);
  }
}

function methodCallback(object, method) {
  return function() {
    return method.apply(object, arguments);
  }
}

function createDiv(opt_text, opt_className) {
  var el = document.createElement("div");
  if (opt_text) {
    el.innerHTML = opt_text;
  }
  if (opt_className) { el.className = opt_className; }
  return el;
}

function removeChildren(parent) {
  while (parent.firstChild) {
    parent.removeChild(parent.firstChild);
  }
}

function cssSetClass(el, className) {
  el.className = className;
}

function createTable(opt_className) {
  var el = document.createElement("table");
  if (opt_className) { el.className = opt_className; }
  return el;
}

function createTableRow(table) {
  var tr = table.insertRow(-1);
  return tr;
}

function createTableCell(tr, opt_className) {
  var td = tr.insertCell(-1);
  if (opt_className) { td.className = opt_className; }
  return td;
}

function createLink(href, text, opt_target, opt_className) {
  var el = document.createElement("a");
  el.href = href;
  el.appendChild(document.createTextNode(text));
  if (opt_className) {
    el.className = opt_className;
  }
  if (opt_target) {
    el.target = opt_target;
  }
  return el;
}

// from common, user agent detector
function br_AgentContains_(str) {
  if (str in br_AgentContains_cache_) {
    return br_AgentContains_cache_[str];
  }

  return br_AgentContains_cache_[str] =
    (navigator.userAgent.toLowerCase().indexOf(str) != -1);
}
var br_AgentContains_cache_ = {};
function br_IsIE() {
  return br_AgentContains_('msie');
}

function br_IsOpera() {
  return br_AgentContains_('opera');
}

FindAndParseScriptArgs = function(){
  //
  // step #1 - find ourselves
  //
  var apiPattern = /gmlocalsearch\.js\?.*/;

  var scripts = document.getElementsByTagName("script");
  if (scripts && scripts.length > 0) {
    for (var i=0; i < scripts.length; i++) {
      var src = scripts[i].src;
      var matches = src.match(apiPattern);
      if (matches) {
        // we found ourselves, WITH Args so crack the args and proceed
        FindAndParseScriptArgs.cgiParams =
          FindAndParseScriptArgs.parseCgiParams(src);
        return;
      }
    }
  }
}
FindAndParseScriptArgs.cgiParams = null;

FindAndParseScriptArgs.parseCgiParams = function(str) {
  var params = {};
  str = str.replace(/#.*$/,"");
  var urlHalves = str.split("?");
  var parts = urlHalves[urlHalves.length - 1].split("&");
  for (var i = 0; i < parts.length; i++) {
    var keyvalue = parts[i].split("=");
    if (keyvalue[0]) {                     // in case parts[i] is empty
      params[keyvalue[0].toLowerCase()] =
        keyvalue.length>1 ? FindAndParseScriptArgs.urlDecode(keyvalue[1]) : "";
    }
  }
  return params;
}

FindAndParseScriptArgs.plus_re_ = /\+/g;
FindAndParseScriptArgs.urlDecode = function(str) {
  return decodeURIComponent(str.replace(FindAndParseScriptArgs.plus_re_, ' '));
}

FindAndParseScriptArgs();


GenerateAds = function(){

  var loadCss = function(css) {
    document.write('<link href="' + css + '" rel="stylesheet" type="text/css"/>');
  }

  if (FindAndParseScriptArgs.cgiParams &&
      FindAndParseScriptArgs.cgiParams["adsense"]) {
    adsenseKeyArg = FindAndParseScriptArgs.cgiParams["adsense"];
  } else {
    return;
  }

  if (adsenseKeyArg) {
    // arg is key[,adstyle[,mode]]
    // ok, now we have the adsense key and optional
    // ad type (inline, links, tower)
    var values=adsenseKeyArg.split(",");
    var adsenseKey = values[0];
    var adStyle = "inline";
    if (values.length > 1) {
      if (values[1] == "inline" ||
          values[1] == "strip" ||
          values[1] == "skyscraper" ||
          values[1] == "wide_skyscraper" ||
          values[1] == "button" ||
          values[1] == "vertical_banner"
          ) {
        adStyle = values[1];
      }
    }

    if (values.length > 2) {
      if (values[2] == "afs") {
        afsMode = true;
      } else if (values[2] == "afc") {
        afsMode = false;
      }
    }

    var adsenseChannel = FindAndParseScriptArgs.cgiParams["channel"] || "";

    // having a problem relocating inline on opera
    // so disable until this is fixed
    if (br_IsOpera() && adStyle == "inline") {
      adStyle = "button";
    }

    if (afsMode) {
      if (LocalSearch.adFacts[adStyle].afsIndex == -1) {
        adStyle = "inline";
      }
    }

    var currentStyle = LocalSearch.adFacts[adStyle];

    // record the selected style
    var obj = new Object();
    for (p in LocalSearch.adFacts[adStyle]) {
      obj[p] = LocalSearch.adFacts[adStyle][p];
      obj["adsenseKey"] = adsenseKey;
    }
    LocalSearch.selectedStyle.push(obj);

    // now, write out an adsense unit using the appropriate
    // key and style

    if (afsMode) {
      document.write('<div id="_gmls_inline_ads_div_" class="gmls_inline_ads" style="display:none; position:absolute;"></div>');
      document.write('<script type="text/javascript">');
      document.write('var googleAdIframeTable = [["_gmls_inline_ads_div_",' +
                     currentStyle.afsIndex + ']];');
      document.write('var googleAdIE = "UTF8";');
      document.write('var googleAdOE = "UTF8";');
      document.write('var googleAdHL = "' + UDS_CurrentLocale + '";');
      document.write('var googleAdClient = "' + adsenseKey + '";');
      document.write('var googleAdChannel = "' + adsenseChannel + '";');
      if (adsenseKey == "ca-google-ajaxapi") {
        document.write('var googleAdtest = "on";');
      }
      var width = currentStyle.width;
      var height = currentStyle.height;
      var format = currentStyle.format;

      var colors = LocalSearch.colorSchemes[currentStyle.colors];
      var color_border = colors.color_border;
      var color_text = colors.color_text;
      var color_url = colors.color_url;
      var color_line = colors.color_line;
      var color_link = colors.color_link;

      // pull from table indexed by style

      document.write('var googleAdColorDiv = "' + color_border + '";');
      document.write('var googleAdColorText = "' + color_text + '";');
      document.write('var googleAdColorAltText = "' + color_url + '";');
      document.write('var googleAdColorLink = "' + color_link + '";');
      document.write('var googleAdColorALink = "' + color_link + '";');
      document.write('var googleAdColorVLink = "' + color_url + '";');

      document.write('</script>');

      // defer load of afs bits until needed. main point of this is to ensure
      // that when this runs, the dynamicly created ad block is available.
    } else {
      document.write('<div id="_gmls_inline_ads_div_" class="gmls_inline_ads" style="display:none; position:absolute;">');
      document.write('<script type="text/javascript">');
      document.write('google_ad_client = "' + adsenseKey + '";');
      document.write('google_ad_channel = "' + adsenseChannel + '";');
      if (adsenseKey == "ca-google-ajaxapi") {
        document.write('google_adtest = "true";');
      }
      var width = currentStyle.width;
      var height = currentStyle.height;
      var format = currentStyle.format;

      var colors = LocalSearch.colorSchemes[currentStyle.colors];
      var color_border = colors.color_border;
      var color_text = colors.color_text;
      var color_url = colors.color_url;
      var color_line = colors.color_line;
      var color_link = colors.color_link;

      // pull from table indexed by style
      document.write('google_ad_width = ' + width + ';');
      document.write('google_ad_height = ' + height + ';');
      document.write('google_ad_format = "' + format + '";');

      document.write('google_color_border = "' + color_border + '";');
      document.write('google_color_text = "' + color_text + '";');
      document.write('google_color_url = "' + color_url + '";');
      document.write('google_color_line = "' + color_line + '";');
      document.write('google_color_link = "' + color_link + '";');

      document.write('google_dynamic_adsense_id = "_gmls_inline_ads_asid_";');
      document.write('google_dynamic_adsense_no_initial_ads = true;');
      document.write('</script>');
      document.write('<script src="http://pagead2.googlesyndication.com/pagead/show_dynamic_ads.js" type="text/javascript"></script>');
      document.write('</div>');
    }
  }
}

function loadAfs(url) {
  var head = document.getElementsByTagName("head")[0];
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.charset = "utf-8";
  script.src = url;

  // add code to notice when this is done and
  // enable gadsense use
  head.appendChild(script);
}

LocalSearch.selectedStyle = [];
LocalSearch.adFacts = {
  "inline" : {
    afsIndex : 12,
    status : "done",
    width : 234,
    height : 60,
    format : "234x60_as",
    colors : "results",
    parent : "results"
  },

  "skyscraper" : {
    afsIndex : 2,
    status : "done",
    width : 120,
    height : 600,
    format : "120x600_as",
    colors : "map",
    parent : "map"
  },

  "wide_skyscraper" : {
    afsIndex : 3,
    status : "done",
    width : 160,
    height : 600,
    format : "160x600_as",
    colors : "map",
    parent : "map"
  },

  "button" : {
    afsIndex : -1,
    status : "done",
    width : 125,
    height : 125,
    format : "125x125_as",
    colors : "map",
    parent : "map"
  },

  "vertical_banner" : {
    afsIndex : -1,
    status : "done",
    width : 120,
    height : 240,
    format : "120x240_as",
    colors : "map",
    parent : "map"
  }
}

LocalSearch.colorSchemes = {
  "results" : {
    color_border : "f9f9f9",
    color_text : "878787",
    color_url : "878787",
    color_line : "878787",
    color_link : "7777cc"
  },

  "map" : {
    color_border : "f0f0f0",
    color_text : "878787",
    color_url : "008000",
    color_line : "878787",
    color_link : "7777cc"
  }
}

GenerateAds();

// an inline ads object
function InlineAds() {
  this.root = null;
  this.adDiv = document.getElementById("_gmls_inline_ads_div_");
  this.facts = LocalSearch.selectedStyle[0];
  this.searcher = null;

  // On IE, we have a little problem... The ad block that
  // we wrote out is not attached in the dom correctly. Its
  // parent is body, not this.adDiv so now we go on a little
  // fishing expedition...
  if (br_IsIE() && !afsMode) {
    var adDiv = this.adDiv;
    this.adDiv = null;
    var asu = window['google_dynamic_adsense_units']['_gmls_inline_ads_asid_'];
    if (asu) {
      // now whip through the object looking for our lost div...
      for (var p in asu) {
        if (asu[p] && asu[p].nodeType && asu[p].nodeType == 1 ) {
          var node = asu[p];
          if (node.parentNode.id != '_gmls_inline_ads_div_') {
            // we have a little problem. The node got
            // attached incorrectly, so now lift it and mode it
            node.parentNode.removeChild(node);
            this.adDiv = adDiv;
            this.adDiv.appendChild(node);
          }
        }
      }
    }
  }

  // detach from the dom. This will be re-attached
  // during super structure build out
  if (this.adDiv != null) {
    this.adDiv.parentNode.removeChild(this.adDiv);
  }
}

InlineAds.prototype.show = function() {
  this.root.style.display = "block";
  // only needed once, but we do it here until we decide
  // otherwise
  this.adDiv.style.display = "block";
}

InlineAds.prototype.hide = function() {
  this.root.style.display = "none";
}

InlineAds.prototype.fetch = function(q, results) {
  var query = q;
  var options = null;
  if (results.length > 1) {

    // if the view port was computed (meaning there is no near city, etc.)
    // in the query, then append on the phrase "near city" in hopes that
    // this will result in better targetting
    if (results[0].viewportmode && results[0].viewportmode == "computed") {
      if (results[0].city) {
        options = {
          google_city : results[0].city
        }
        if (results[0].region) {
          options.google_region = results[0].region;
        }
      }
    }
  }

  if (this.searcher == null) {
    var adId = null;
    if (!afsMode) {
      adId = "_gmls_inline_ads_asid_";
    }
    this.searcher = new GadSenseSearch(adId);
  }
  // todo - pass options when its fully supported
  this.searcher.execute(query);
}

function ExternalAds(adBlock) {
  this.adDiv = null;
  //
  // if we have been given a container then
  // we manage the visibility of the ad block. Note,
  // this will cause the ad block to flash
  if (adBlock.container) {
    this.adDiv = adBlock.container;
  }

  // note, no id passed for afs
  var id = null;
  if ( adBlock.adsense_id ) {
    id = adBlock.adsense_id;
  }
  this.searcher = new GadSenseSearch(id);
}

ExternalAds.prototype.show = function() {
  if (this.adDiv) {
    this.adDiv.style.display = "block";
  }
}

ExternalAds.prototype.hide = function() {
  if (this.adDiv) {
    this.adDiv.style.display = "none";
  }
}

ExternalAds.prototype.fetch = function(q, results) {
  var query = q;
  var options = null;
  if (results.length > 1) {

    // if the view port was computed (meaning there is no near city, etc.)
    // in the query, then append on the phrase "near city" in hopes that
    // this will result in better targetting
    if (results[0].viewportmode && results[0].viewportmode == "computed") {
      if (results[0].city) {
        options = {
          google_city : results[0].city,
          google_language : UDS_CurrentLocale
        }
        if (results[0].region) {
          options.google_region = results[0].region;
        }
      }
    }
  }
  // todo - pass options when its fully supported
  this.searcher.execute(query);
}

// classes used throughout
css = {};

// major states are
// active: search results are visible
// idle: search results are not showing, control is idle
css.control_root = "gmls";
css.app = "gmls-app";
css.app_compact_mode = "gmls-app-compact-mode";
css.app_full_mode = "gmls-app-full-mode";
css.app_active = "gmls-app gmls-active";
css.app_no_results = "gmls-app gmls-active gmls-no-results";
css.app_idle = "gmls-app gmls-idle";
css.app_external_results = "gmls-external-results";

// search form contains input box, search button, and branding
css.search_form_active = "gmls-search-form gmls-search-form-active";
css.search_form_idle = "gmls-search-form gmls-search-form-idle";
css.attribution = "gmls-attribution";

// results
css.results_popup = "gmls-results-popup";
css.results_list = "gmls-results-list";
css.results_table = "gmls-results-table";
css.results_ads_box = "gmls-results-ads-box";
css.results_controls = "gmls-results-controls";

css.result_list_item = "gmls-result-list-item";
css.result_list_item_selected = "gmls-result-list-item gmls-selected";
css.result_list_item_key = "gmls-result-list-item-key";
css.result_wrapper = "gmls-result-wrapper";
css.gs_title = "gs-title";
css.gs_street = "gs-street";

css.result_list_item_warning_symbol = "gmls-result-list-item-warning-symbol";
css.result_list_item_warning_text = "gmls-result-list-item-warning-text";

// scroll controls
css.prev_next = "gmls-prev-next";
css.prev_next_active = "gmls-prev-next gmls-prev-next-active";
css.prev_next_idle = "gmls-prev-next gmls-prev-next-idle";
css.prev_next_center = "gmls-prev-next-center";
css.prev = "gmls-prev";
css.prev_active = "gmls-prev gmls-prev-active";
css.prev_idle = "gmls-prev gmls-prev-idle";
css.next = "gmls-next";
css.next_active = "gmls-next gmls-next-active";
css.next_idle = "gmls-next gmls-next-idle";

// more/clear
css.more_results = "gmls-more-results";
css.clear_results = "gmls-clear-results";


// ads classes
css.ads = {
  "234x60_as" : "gmls-ads-box-234x60_as",               // inline
  "468x15_0ads_al" : "gmls-ads-box-468x15_0ads_al",     // strip
  "120x600_as" : "gmls-ads-box-120x600_as",             // skyscraper
  "160x600_as" : "gmls-ads-box-160x600_as",             // wide_skyscraper
  "125x125_as" : "gmls-ads-box-125x125_as",             // button
  "120x240_as" : "gmls-ads-box-120x240_as",             // vertical_banner
  "120x90_0ads_al" : "gmls-ads-box-120x90_0ads_al"      // links_120x90
}

// check for callback args
function AutoLoad() {
  if (FindAndParseScriptArgs.cgiParams &&
      FindAndParseScriptArgs.cgiParams["callback"] &&
      FindAndParseScriptArgs.cgiParams["key"]) {

    var cb = FindAndParseScriptArgs.cgiParams["callback"];
    var validJsPattern = /^[a-zA-Z\._0-9]*$/;
    if (!cb.match(validJsPattern)) {
      throw "invalid callback or context";
    }

    // now we need to look to see if the Search API is Loaded. If so,
    // we are clear to callback. If not, load the css and code. When this
    // completes, then we can call the specified callback
    if (window["GlocalSearch"] == undefined) {
      // search API is missing. Load it...

      var key = FindAndParseScriptArgs.cgiParams["key"];
      var script = document.createElement("script");
      script.type = "text/javascript";
      script.charset = "utf-8";

      var targetUrl = "http://www.google.com/uds/api?file=uds.js&v=1.0&directload=t&key=" + key + "&callback=" + cb;
      script.src = targetUrl;

      // initiate CSS load...
      AutoLoad.LoadCss("http://www.google.com/uds/css/gsearch.css");
      AutoLoad.LoadCss("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");

      // finally, attach to trigger the load
      var head = document.getElementsByTagName("head")[0];
      head.appendChild(script);
    } else {
      AutoLoad.LoadCss("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");
      cb = cb + "();"
      eval(cb);
    }
  }
}


AutoLoad.LoadCss = function(url) {
  var head = document.getElementsByTagName("head")[0];

  // initiate CSS load...
  var styleSheet = document.createElement("link");
  styleSheet.href = url;
  styleSheet.type = "text/css";
  styleSheet.rel = "stylesheet";
  head.appendChild(styleSheet);
}

AutoLoad.GetEvent = function(event) {
  return (event) ? event : window.event;
}
AutoLoad.GetEventTarget = function(event) {
  return (event.target) ? event.target : event.srcElement;
}
AutoLoad();
})();
