/* ======= geo-utils-js ======= */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Geodesy representation conversion functions (c) Chris Veness 2002-2010                        */
/*   - www.movable-type.co.uk/scripts/latlong.html                                                */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

var Geo = {};  // Geo namespace, representing static class

/**
 * Parses string representing degrees/minutes/seconds into numeric degrees
 *
 * This is very flexible on formats, allowing signed decimal degrees, or deg-min-sec optionally
 * suffixed by compass direction (NSEW). A variety of separators are accepted (eg 3o 37' 09"W) 
 * or fixed-width format without separators (eg 0033709W). Seconds and minutes may be omitted. 
 * (Note minimal validation is done).
 *
 * @param   {String|Number} dmsStr: Degrees or deg/min/sec in variety of formats
 * @returns {Number} Degrees as decimal number
 * @throws  {TypeError} dmsStr is an object, perhaps DOM object without .value?
 */
Geo.parseDMS = function(dmsStr) {
  if (typeof deg == 'object') throw new TypeError('Geo.parseDMS - dmsStr is [DOM?] object');
  
  if (!isNaN(dmsStr)) return Number(dmsStr);  // ... signed decimal degrees without NSEW
  
  // strip off any sign or compass dir'n & split out separate d/m/s
  var dms = String(dmsStr).trim().replace(/^-/,'').replace(/[NSEW]$/i,'').split(/[^0-9.,]+/);
  if (dms[dms.length-1]=='') dms.splice(dms.length-1);  // from trailing symbol
  
  if (dms == '') return NaN;
  
  // and convert to decimal degrees...
  switch (dms.length) {
    case 3:  // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; 
      break;
    case 2:  // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; 
      break;
    case 1:  // just d (possibly decimal) or non-separated dddmmss
      var deg = dms[0];
      // check for fixed-width unseparated format eg 0033709W
      if (/[NS]/i.test(dmsStr)) deg = '0' + deg;  // - normalise N/S to 3-digit degrees
      if (/[0-9]{7}/.test(deg)) deg = deg.slice(0,3)/1 + deg.slice(3,5)/60 + deg.slice(5)/3600; 
      break;
    default:
      return NaN;
  }
  if (/^-|[WS]$/i.test(dmsStr.trim())) deg = -deg; // take '-', west and south as -ve
  return Number(deg);
}

/**
 * Convert decimal degrees to deg/min/sec format
 *  - degree, prime, double-prime symbols are added, but sign is discarded, though no compass
 *    direction is added
 *
 * @private
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} deg formatted as deg/min/secs according to specified format
 * @throws  {TypeError} deg is an object, perhaps DOM object without .value?
 */
Geo.toDMS = function(deg, format, dp) {
  if (typeof deg == 'object') throw new TypeError('Geo.toDMS - deg is [DOM?] object');
  if (isNaN(deg)) return '';  // give up here if we can't make a number from deg
  
    // default values
  if (typeof format == 'undefined') format = 'dms';
  if (typeof dp == 'undefined') {
    switch (format) {
      case 'd': dp = 4; break;
      case 'dm': dp = 2; break;
      case 'dms': dp = 0; break;
      default: format = 'dms'; dp = 0;  // be forgiving on invalid format
    }
  }
  
  deg = Math.abs(deg);  // (unsigned result ready for appending compass dir'n)
  
  switch (format) {
    case 'd':
      d = deg.toFixed(dp);     // round degrees
      if (d<100) d = '0' + d;  // pad with leading zeros
      if (d<10) d = '0' + d;
      dms = d + '\u00B0';      // add o symbol
      break;
    case 'dm':
      var min = (deg*60).toFixed(dp);  // convert degrees to minutes & round
      var d = Math.floor(min / 60);    // get component deg/min
      var m = (min % 60).toFixed(dp);  // pad with trailing zeros
      if (d<100) d = '0' + d;          // pad with leading zeros
      if (d<10) d = '0' + d;
      if (m<10) m = '0' + m;
      dms = d + '\u00B0' + m + '\u2032';  // add o, ' symbols
      break;
    case 'dms':
      var sec = (deg*3600).toFixed(dp);  // convert degrees to seconds & round
      var d = Math.floor(sec / 3600);    // get component deg/min/sec
      var m = Math.floor(sec/60) % 60;
      var s = (sec % 60).toFixed(dp);    // pad with trailing zeros
      if (d<100) d = '0' + d;            // pad with leading zeros
      if (d<10) d = '0' + d;
      if (m<10) m = '0' + m;
      if (s<10) s = '0' + s;
      dms = d + '\u00B0' + m + '\u2032' + s + '\u2033';  // add o, ', " symbols
      break;
  }
  
  return dms;
}

/**
 * Convert numeric degrees to deg/min/sec latitude (suffixed with N/S)
 *
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} Deg/min/seconds
 */
Geo.toLat = function(deg, format, dp) {
  var lat = Geo.toDMS(deg, format, dp);
  return lat=='' ? '' : lat.slice(1) + (deg<0 ? 'S' : 'N');  // knock off initial '0' for lat!
}

/**
 * Convert numeric degrees to deg/min/sec longitude (suffixed with E/W)
 *
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} Deg/min/seconds
 */
Geo.toLon = function(deg, format, dp) {
  var lon = Geo.toDMS(deg, format, dp);
  return lon=='' ? '' : lon + (deg<0 ? 'W' : 'E');
}

/**
 * Convert numeric degrees to deg/min/sec as a bearing (0o..360o)
 *
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} Deg/min/seconds
 */
Geo.toBrng = function(deg, format, dp) {
  deg = (Number(deg)+360) % 360;  // normalise -ve values to 180..360
  var brng =  Geo.toDMS(deg, format, dp);
  return brng.replace('360', '0');  // just in case rounding took us up to 360o!
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Latitude/longitude spherical geodesy formulae & scripts (c) Chris Veness 2002-2010            */
/*   - www.movable-type.co.uk/scripts/latlong.html                                                */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Note that minimal error checking is performed in this example code!                           */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


/**
 * Creates a point on the earth's surface at the supplied latitude / longitude
 *
 * @constructor
 * @param {Number} lat: latitude in numeric degrees
 * @param {Number} lon: longitude in numeric degrees
 * @param {Number} [rad=6371]: radius of earth if different value is required from standard 6,371km
 */
function LatLon(lat, lon, rad) {
  if (typeof rad == 'undefined') rad = 6371;  // earth's mean radius in km
  this._lat = lat;
  this._lon = lon;
  this._radius = rad;
}


/**
 * Returns the distance from this point to the supplied point, in km 
 * (using Haversine formula)
 *
 * from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine",
 *       Sky and Telescope, vol 68, no 2, 1984
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @param   {Number} [precision=4]: no of significant digits to use for returned value
 * @returns {Number} Distance in km between this point and destination point
 */
LatLon.prototype.distanceTo = function(point, precision) {
  // default 4 sig figs reflects typical 0.3% accuracy of spherical model
  if (typeof precision == 'undefined') precision = 4;  
  
  var R = this._radius;
  var lat1 = this._lat.toRad(), lon1 = this._lon.toRad();
  var lat2 = point._lat.toRad(), lon2 = point._lon.toRad();
  var dLat = lat2 - lat1;
  var dLon = lon2 - lon1;

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.cos(lat1) * Math.cos(lat2) * 
          Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  return d.toPrecisionFixed(precision);
}


/**
 * Returns the (initial) bearing from this point to the supplied point, in degrees
 *   see http://williams.best.vwh.net/avform.htm#Crs
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {Number} Initial bearing in degrees from North
 */
LatLon.prototype.bearingTo = function(point) {
  var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
  var dLon = (point._lon-this._lon).toRad();

  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1)*Math.sin(lat2) -
          Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  var brng = Math.atan2(y, x);
  
  return (brng.toDeg()+360) % 360;
}


/**
 * Returns final bearing arriving at supplied destination point from this point; the final bearing 
 * will differ from the initial bearing by varying degrees according to distance and latitude
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {Number} Final bearing in degrees from North
 */
LatLon.prototype.finalBearingTo = function(point) {
  // get initial bearing from supplied point back to this point...
  var lat1 = point._lat.toRad(), lat2 = this._lat.toRad();
  var dLon = (this._lon-point._lon).toRad();

  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1)*Math.sin(lat2) -
          Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  var brng = Math.atan2(y, x);
          
  // ... & reverse it by adding 180o
  return (brng.toDeg()+180) % 360;
}


/**
 * Returns the midpoint between this point and the supplied point.
 *   see http://mathforum.org/library/drmath/view/51822.html for derivation
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {LatLon} Midpoint between this point and the supplied point
 */
LatLon.prototype.midpointTo = function(point) {
  lat1 = this._lat.toRad(), lon1 = this._lon.toRad();
  lat2 = point._lat.toRad();
  var dLon = (point._lon-this._lon).toRad();

  var Bx = Math.cos(lat2) * Math.cos(dLon);
  var By = Math.cos(lat2) * Math.sin(dLon);

  lat3 = Math.atan2(Math.sin(lat1)+Math.sin(lat2),
                    Math.sqrt( (Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx) + By*By) );
  lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);

  return new LatLon(lat3.toDeg(), lon3.toDeg());
}


/**
 * Returns the destination point from this point having travelled the given distance (in km) on the 
 * given initial bearing (bearing may vary before destination is reached)
 *
 *   see http://williams.best.vwh.net/avform.htm#LL
 *
 * @param   {Number} brng: Initial bearing in degrees
 * @param   {Number} dist: Distance in km
 * @returns {LatLon} Destination point
 */
LatLon.prototype.destinationPoint = function(brng, dist) {
  dist = dist/this._radius;  // convert dist to angular distance in radians
  brng = brng.toRad();  // 
  var lat1 = this._lat.toRad(), lon1 = this._lon.toRad();

  var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + 
                        Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) );
  var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), 
                               Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2));
  lon2 = (lon2+3*Math.PI)%(2*Math.PI) - Math.PI;  // normalise to -180...+180

  if (isNaN(lat2) || isNaN(lon2)) return null;
  return new LatLon(lat2.toDeg(), lon2.toDeg());
}


/**
 * Returns the point of intersection of two paths defined by point and bearing
 *
 *   see http://williams.best.vwh.net/avform.htm#Intersection
 *
 * @param   {LatLon} p1: First point
 * @param   {Number} brng1: Initial bearing from first point
 * @param   {LatLon} p2: Second point
 * @param   {Number} brng2: Initial bearing from second point
 * @returns {LatLon} Destination point (null if no unique intersection defined)
 */
LatLon.intersection = function(p1, brng1, p2, brng2) {
  lat1 = p1._lat.toRad(), lon1 = p1._lon.toRad();
  lat2 = p2._lat.toRad(), lon2 = p2._lon.toRad();
  brng13 = brng1.toRad(), brng23 = brng2.toRad();
  dLat = lat2-lat1, dLon = lon2-lon1;
  
  dist12 = 2*Math.asin( Math.sqrt( Math.sin(dLat/2)*Math.sin(dLat/2) + 
    Math.cos(lat1)*Math.cos(lat2)*Math.sin(dLon/2)*Math.sin(dLon/2) ) );
  if (dist12 == 0) return null;
  
  // initial/final bearings between points
  brngA = Math.acos( ( Math.sin(lat2) - Math.sin(lat1)*Math.cos(dist12) ) / 
    ( Math.sin(dist12)*Math.cos(lat1) ) );
  if (isNaN(brngA)) brngA = 0;  // protect against rounding
  brngB = Math.acos( ( Math.sin(lat1) - Math.sin(lat2)*Math.cos(dist12) ) / 
    ( Math.sin(dist12)*Math.cos(lat2) ) );
  
  if (Math.sin(lon2-lon1) > 0) {
    brng12 = brngA;
    brng21 = 2*Math.PI - brngB;
  } else {
    brng12 = 2*Math.PI - brngA;
    brng21 = brngB;
  }
  
  alpha1 = (brng13 - brng12 + Math.PI) % (2*Math.PI) - Math.PI;  // angle 2-1-3
  alpha2 = (brng21 - brng23 + Math.PI) % (2*Math.PI) - Math.PI;  // angle 1-2-3
  
  if (Math.sin(alpha1)==0 && Math.sin(alpha2)==0) return null;  // infinite intersections
  if (Math.sin(alpha1)*Math.sin(alpha2) < 0) return null;       // ambiguous intersection
  
  //alpha1 = Math.abs(alpha1);
  //alpha2 = Math.abs(alpha2);
  // ... Ed Williams takes abs of alpha1/alpha2, but seems to break calculation?
  
  alpha3 = Math.acos( -Math.cos(alpha1)*Math.cos(alpha2) + 
                       Math.sin(alpha1)*Math.sin(alpha2)*Math.cos(dist12) );
  dist13 = Math.atan2( Math.sin(dist12)*Math.sin(alpha1)*Math.sin(alpha2), 
                       Math.cos(alpha2)+Math.cos(alpha1)*Math.cos(alpha3) )
  lat3 = Math.asin( Math.sin(lat1)*Math.cos(dist13) + 
                    Math.cos(lat1)*Math.sin(dist13)*Math.cos(brng13) );
  dLon13 = Math.atan2( Math.sin(brng13)*Math.sin(dist13)*Math.cos(lat1), 
                       Math.cos(dist13)-Math.sin(lat1)*Math.sin(lat3) );
  lon3 = lon1+dLon13;
  lon3 = (lon3+Math.PI) % (2*Math.PI) - Math.PI;  // normalise to -180..180o
  
  return new LatLon(lat3.toDeg(), lon3.toDeg());
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/**
 * Returns the distance from this point to the supplied point, in km, travelling along a rhumb line
 *
 *   see http://williams.best.vwh.net/avform.htm#Rhumb
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {Number} Distance in km between this point and destination point
 */
LatLon.prototype.rhumbDistanceTo = function(point) {
  var R = this._radius;
  var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
  var dLat = (point._lat-this._lat).toRad();
  var dLon = Math.abs(point._lon-this._lon).toRad();
  
  var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
  var q = (!isNaN(dLat/dPhi)) ? dLat/dPhi : Math.cos(lat1);  // E-W line gives dPhi=0
  // if dLon over 180o take shorter rhumb across 180o meridian:
  if (dLon > Math.PI) dLon = 2*Math.PI - dLon;
  var dist = Math.sqrt(dLat*dLat + q*q*dLon*dLon) * R; 
  
  return dist.toPrecisionFixed(4);  // 4 sig figs reflects typical 0.3% accuracy of spherical model
}

/**
 * Returns the bearing from this point to the supplied point along a rhumb line, in degrees
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {Number} Bearing in degrees from North
 */
LatLon.prototype.rhumbBearingTo = function(point) {
  var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
  var dLon = (point._lon-this._lon).toRad();
  
  var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
  if (Math.abs(dLon) > Math.PI) dLon = dLon>0 ? -(2*Math.PI-dLon) : (2*Math.PI+dLon);
  var brng = Math.atan2(dLon, dPhi);
  
  return (brng.toDeg()+360) % 360;
}

/**
 * Returns the destination point from this point having travelled the given distance (in km) on the 
 * given bearing along a rhumb line
 *
 * @param   {Number} brng: Bearing in degrees from North
 * @param   {Number} dist: Distance in km
 * @returns {LatLon} Destination point
 */
LatLon.prototype.rhumbDestinationPoint = function(brng, dist) {
  var R = this._radius;
  var d = parseFloat(dist)/R;  // d = angular distance covered on earth's surface
  var lat1 = this._lat.toRad(), lon1 = this._lon.toRad();
  brng = brng.toRad();

  var lat2 = lat1 + d*Math.cos(brng);
  var dLat = lat2-lat1;
  var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
  var q = (!isNaN(dLat/dPhi)) ? dLat/dPhi : Math.cos(lat1);  // E-W line gives dPhi=0
  var dLon = d*Math.sin(brng)/q;
  // check for some daft bugger going past the pole
  if (Math.abs(lat2) > Math.PI/2) lat2 = lat2>0 ? Math.PI-lat2 : -(Math.PI-lat2);
  lon2 = (lon1+dLon+3*Math.PI)%(2*Math.PI) - Math.PI;
 
  return new LatLon(lat2.toDeg(), lon2.toDeg());
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


/**
 * Returns the latitude of this point; signed numeric degrees if no format, otherwise format & dp 
 * as per Geo.toLat()
 *
 * @param   {String} [format]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to display
 * @returns {Number|String} Numeric degrees if no format specified, otherwise deg/min/sec
 *
 * @requires Geo
 */
LatLon.prototype.lat = function(format, dp) {
  if (typeof format == 'undefined') return this._lat;
  
  return Geo.toLat(this._lat, format, dp);
}

/**
 * Returns the longitude of this point; signed numeric degrees if no format, otherwise format & dp 
 * as per Geo.toLon()
 *
 * @param   {String} [format]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to display
 * @returns {Number|String} Numeric degrees if no format specified, otherwise deg/min/sec
 *
 * @requires Geo
 */
LatLon.prototype.lon = function(format, dp) {
  if (typeof format == 'undefined') return this._lon;
  
  return Geo.toLon(this._lon, format, dp);
}

/**
 * Returns a string representation of this point; format and dp as per lat()/lon()
 *
 * @param   {String} [format]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to display
 * @returns {String} Comma-separated latitude/longitude
 *
 * @requires Geo
 */
LatLon.prototype.toString = function(format, dp) {
  if (typeof format == 'undefined') format = 'dms';
  
  return Geo.toLat(this._lat, format, dp) + ', ' + Geo.toLon(this._lon, format, dp);
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for converting degrees/radians

/** Convert numeric degrees to radians */
if (typeof(String.prototype.toRad) === "undefined") {
  Number.prototype.toRad = function() {
    return this * Math.PI / 180;
  }
}

/** Convert radians to numeric (signed) degrees */
if (typeof(String.prototype.toDeg) === "undefined") {
  Number.prototype.toDeg = function() {
    return this * 180 / Math.PI;
  }
}

/** 
 * Format the significant digits of a number, using only fixed-point notation (no exponential)
 * 
 * @param   {Number} precision: Number of significant digits to appear in the returned string
 * @returns {String} A string representation of number which contains precision significant digits
 */
if (typeof(String.prototype.toDeg) === "undefined") {
  Number.prototype.toPrecisionFixed = function(precision) {
    var numb = this < 0 ? -this : this;  // can't take log of -ve number...
    var sign = this < 0 ? '-' : '';
    
    if (numb == 0) { n = '0.'; while (precision--) n += '0'; return n };  // can't take log of zero
  
    var scale = Math.ceil(Math.log(numb)*Math.LOG10E);  // no of digits before decimal
    var n = String(Math.round(numb * Math.pow(10, precision-scale)));
    if (scale > 0) {  // add trailing zeros & insert decimal as required
      l = scale - n.length;
      while (l-- > 0) n = n + '0';
      if (scale < n.length) n = n.slice(0,scale) + '.' + n.slice(scale);
    } else {          // prefix decimal and leading zeros if required
      while (scale++ < 0) n = '0' + n;
      n = '0.' + n;
    }
    return sign + n;
  }
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* ======= mobile-core-js ======= */
function $(id)
{
	return document.getElementById( id );
}

/* page bus */
if(!window["OpenAjax"]){OpenAjax=new function(){var t=true;var f=false;var g=window;var _4;var _5="org.openajax.hub.";var h={};this.hub=h;h.implementer="http://tibco.com";h.implVersion="0.6";h.specVersion="0.6";h.implExtraData={};var _4={};h.libraries=_4;h.registerLibrary=function(_7,_8,_9,_a){_4[_7]={prefix:_7,namespaceURI:_8,version:_9,extraData:_a};this.publish(_5+"registerLibrary",_4[_7]);};h.unregisterLibrary=function(_b){this.publish(_5+"unregisterLibrary",_4[_b]);delete _4[_b];};h._subscriptions={c:{},s:[]};h._cleanup=[];h._subIndex=0;h._pubDepth=0;h.subscribe=function(_c,_d,_e,_f,_10){if(!_e){_e=window;}var _11=_c+"."+this._subIndex;var sub={scope:_e,cb:_d,fcb:_10,data:_f,sid:this._subIndex++,hdl:_11};var _13=_c.split(".");this._subscribe(this._subscriptions,_13,0,sub);return _11;};h.publish=function(_14,_15){path=_14.split(".");this._pubDepth++;this._publish(this._subscriptions,path,0,_14,_15);this._pubDepth--;if((this._cleanup.length>0)&&(this._pubDepth==0)){for(var i=0;i<this._cleanup.length;i++){this.unsubscribe(this._cleanup[i].hdl);}delete (this._cleanup);this._cleanup=[];}};h.unsubscribe=function(sub){var _18=sub.split(".");var sid=_18.pop();this._unsubscribe(this._subscriptions,_18,0,sid);};h._subscribe=function(_1a,_1b,_1c,sub){var _1e=_1b[_1c];if(_1c==_1b.length){_1a["."].push(sub);}else{if(!_1a[_1e]){_1a[_1e]={".":[]};this._subscribe(_1a[_1e],_1b,_1c+1,sub);}else{this._subscribe(_1a[_1e],_1b,_1c+1,sub);}}};h._publish=function(_1f,_20,_21,_22,msg){if(typeof _1f!="undefined"){var _24;if(_21==_20.length){_24=_1f;}else{this._publish(_1f[_20[_21]],_20,_21+1,_22,msg);this._publish(_1f["*"],_20,_21+1,_22,msg);_24=_1f["**"];}if(typeof _24!="undefined"){var _25=_24["."];var max=_25.length;for(var i=0;i<max;i++){if(_25[i].cb){var sc=_25[i].scope;var cb=_25[i].cb;var fcb=_25[i].fcb;var d=_25[i].data;if(typeof cb=="string"){cb=sc[cb];}if(typeof fcb=="string"){fcb=sc[fcb];}try{if((!fcb)||(fcb.call(sc,_22,msg,d))){cb.call(sc,_22,msg,d);}}catch(err){if(err.message=="PageBus.StackOverflow"){throw err;}h.publish("com.tibco.pagebus.error.callbackError",{name:escape(_22),error:escape(err.message)});}}}}}};h._unsubscribe=function(_2c,_2d,_2e,sid){if(typeof _2c!="undefined"){if(_2e<_2d.length){var _30=_2c[_2d[_2e]];this._unsubscribe(_30,_2d,_2e+1,sid);if(_30["."].length==0){for(var x in _30){return;}delete _2c[_2d[_2e]];}return;}else{var _32=_2c["."];var max=_32.length;for(var i=0;i<max;i++){if(sid==_32[i].sid){if(this._pubDepth>0){_32[i].cb=null;this._cleanup.push(_32[i]);}else{_32.splice(i,1);}return;}}}}};};OpenAjax.hub.registerLibrary("OpenAjax","http://openajax.org/hub","0.6",{});}if(!window["PageBus"]){PageBus=new function(){var _35="1.2.0";var D=0;var Q=[];var Reg={};var _39=[];var RD=0;_throw=function(n){throw new Error("PageBus."+n);};_badName=function(n){_throw("BadName");};_fix=function(p){if(typeof p=="undefined"){return null;}return p;};_valPub=function(_3e){if((_3e==null)||(_3e.indexOf("*")!=-1)||(_3e.indexOf("..")!=-1)||(_3e.charAt(0)==".")||(_3e.charAt(_3e.length-1)==".")){_badName();}};_valSub=function(_3f){var _40=_3f.split(".");var len=_40.length;for(var i=0;i<len;i++){if((_40[i]=="")||((_40[i].indexOf("*")!=-1)&&(_40[i]!="*")&&(_40[i]!="**"))){_badName();}if((_40[i]=="**")&&(i<len-1)){_badName();}}return _40;};this.subscribe=function(_43,_44,_45,_46,_47){_47=_fix(_47);_46=_fix(_46);var _48=_valSub(_43);return OpenAjax.hub.subscribe(_43,_45,_44,_46,_47);};this.publish=function(_49,_4a){_valPub(_49);if(D>20){_throw("StackOverflow");}Q.push({n:_49,m:_4a,d:(D+1)});if(D==0){while(Q.length>0){var _4b=Q.shift();var _4c=_4b.n.split(".");try{D=_4b.d;OpenAjax.hub.publish(_4b.n,_4b.m);D=0;}catch(err){D=0;throw (err);}}}};this.unsubscribe=function(sub){try{OpenAjax.hub.unsubscribe(sub);}catch(err){_throw("BadParameter");}};this.store=function(_4e,msg,_50){_store=function(_51,_52,_53,_54,msg){var tok=_52[_53];var len=_52.length;if(typeof _51[tok]=="undefined"){_51[tok]={};}var n=_51[tok];if(_53==len-1){if(typeof n["."]!="undefined"){if(RD==0){delete n["."];}else{n["."].v=null;_39.push(n["."]);}}if(msg!=null){n["."]={n:_54,v:msg};}}else{_store(n,_52,_53+1,_54,msg);if(msg==null){for(var x in n[_52[_53+1]]){return;}if(RD==0){delete n[_52[_53+1]];}else{_39.push(n[_52[_53+1]]);n[_52[_53+1]]=null;}}}};_valPub(_4e);var _5a=_4e.split(".");_store(Reg,_5a,0,_4e,msg);if(!_50||!_50.quiet){PageBus.publish(_4e,msg);}};this.query=function(_5b,_5c,cb,_5e,fcb){_query=function(_60,_61,idx,_63){function _doRCB(_64,_65){var z=_65.z;var cb=_65.c;var d=_65.d;var fcb=_65.f;var n=_64["."];if(!n||!n.v){return true;}if((fcb==null)||fcb.call(z,n.n,n.v,d)){return cb.call(z,n.n,n.v,d);}return true;};var len=_61.length;var tok=_61[idx];var _6d=(idx==len-1);if(tok=="**"){for(tok in _60){if(tok!="."){if(!_doRCB(_60[tok],_63)){return false;}if(!_query(_60[tok],_61,idx,_63)){return false;}}}}else{if(tok=="*"){for(tok in _60){if(tok!="."){if(_6d){if(!_doRCB(_60[tok],_63)){return false;}}else{if(!_query(_60[tok],_61,idx+1,_63)){return false;}}}}}else{if(typeof _60[tok]!="undefined"){if(_6d){return _doRCB(_60[tok],_63);}else{return _query(_60[tok],_61,idx+1,_63);}}}}return true;};if(_5c==null){_5c=window;}var _6e=_valSub(_5b);var len=_6e.length;var res;try{RD++;var _71={z:_5c,c:cb,d:_5e,f:fcb};res=_query(Reg,_6e,0,_71);RD--;}catch(err){RD--;throw err;}if(RD==0){while(_39.length>0){var p=_39.pop();delete p;}}if(!res){return;}var _73="com.tibco.pagebus.query.done";if((fcb==null)||fcb.call(_5c,_73,null,_5e)){cb.call(_5c,_73,null,_5e);}};};OpenAjax.hub.registerLibrary("PageBus","http://tibco.com/PageBus","1.2.0",{});}
/* end of page bus */

function isEnterKey( E )
{
	var k = E.keyCode;
	return k == 13;
}

function preventBubble( E )
{
	if( E && ( typeof E.stopPropagation != 'undefined' ) ) {
		E.stopPropagation();
	}
	else if( E && ( typeof E.preventBubble != 'undefined' ) ) {
		E.preventBubble();
	}
    
	if( E && ( typeof E.preventDefault != 'undefined' ) ) {
		E.preventDefault();
	}
}

function isNumeric(sText) {
   var ValidChars = "0123456789.";
   var Char;
   for (i = 0; i < sText.length; i++) {
       Char = sText.charAt(i);
       if (ValidChars.indexOf(Char) == -1) {
          return false;
       }
    }
   return true;
}

function prettyNumberIfNecessary(nStr,prefix)
{
	if( !isNumeric(nStr) ) {
		return nStr;
	}
	if( prefix ) {
		nStr = prefix + nStr;
	}
	else {
		nStr += '';
	}
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

function crossPublishToGlobalBus( subject, msg )
{
	try
	{
		if( window.opener != null && window.opener != window && window.opener["PageBus"] ) {
			window.opener["PageBus"].publish( subject, msg );
		}
	}
	catch( e ) {}
	try
	{
		if( window.parent != null && window.parent != window && window.parent["PageBus"] ) {
			window.parent["PageBus"].publish( subject, msg );
		}
	}
	catch( e ) {}
	}

function publishToBus( subject, msg, crossPublish )
{
	if( typeof window.PageBus == 'undefined' ) {
		return false;
	}
	window.PageBus.publish( subject, msg );
	if( crossPublish ) {
		crossPublishToGlobalBus( subject, msg );
	}
	return false;
}

function subscribeToBus( subject, callback, data, ns )
{
	if( typeof window.PageBus == 'undefined' ) {
		return false;
	}
	if( !data ) {
		data = null;
	}
	if( !ns ) {
		ns = null;
	}
	var sub = window.PageBus.subscribe( subject, ns, callback, data );
	return false;
}

if( typeof window.PageBus != 'undefined' ) {
	subscribeToBus( "global.alert", function( s, m, d ) {
		if( m ) {
			alert( m );
		}
	}, null );
}

// jsonp support
function do_j( url, msg, callback, timeout ) {
	if( url.indexOf( '?' ) == -1 ) {
		url += '?';
	}
	else {
		url += '&';
	}
	var r = '' + Math.random();
	var idx = r .indexOf( '.' );
	r = r.substring( idx + 1 );
	r = 'cb' + r;
	url += '_cb=' + escape( r );
	
	//alert( url );
	
	window[r] = function( payload, error ) { callback( payload, error ), window[r] = null };
	
	for( var i in msg ) {
		var val = msg[i];
		if( ( typeof val == 'number' ) || ( typeof val == 'string' ) ) {
			url += '&' + escape(i) + '=' + escape( val );
		}
	}
	
	if( ( typeof timeout == 'number' ) && timeout > 0 ) {
		setTimeout( function() {
			if( window[r] ) {
				window[r]( null, { "error" : "Timeout" } );
				window[r] = null;
			}
		}, timeout );
	}
	
	var s = document.createElement( "script" );
	s.type = "text/javascript";
	s.src = url;
	document.body.appendChild( s );
}

function testJSONP()
{
	do_j( "http://localhost:8080/wps/rest/5/l/outertest", { }, function( payload, error ) {
		if( payload ) {
			alert( payload );
		}
		else if( error ) {
			alert( error["error"] );
		}
	}, 5000 );
}
// /jsonp support

function getXY( elem ) {
	var x = elem.offsetLeft;
	var y = elem.offsetTop;
	
	if( elem.offsetParent ) {
		var xy = getXY( elem.offsetParent );
		x += xy[0];
		y += xy[1];
	}
	var out = new Array(2);
	out[0] = x;
	out[1] = y;
	return out;
}

function getCookie( c_name )
{
	if (document.cookie.length>0)
	{
		var c_start=document.cookie.lastIndexOf(c_name + "=");
		if (c_start != -1)
		{
			c_start=c_start + c_name.length + 1;
			var c_end=document.cookie.indexOf( ";" , c_start );
			if( c_end == -1 ) 
				c_end=document.cookie.length;
    		return unescape(document.cookie.substring(c_start,c_end));
  		}
 	}
	return "";
}

function setCookie(c_name,value,expiredays)
{
	var exdate=new Date();
	exdate.setDate(exdate.getDate()+expiredays);
	document.cookie=c_name+ "=" +escape(value)+
		";path=/" +
		((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
}

function elemAddClassName(element, className) 
{
    elemRemoveClassName(element, className);
    element.className += ' ' + className;
}

function elemRemoveClassName(element, className) {
    if (!element)
      return;
    var newClassName = '';
    var a = element.className.split(' ');
    for (var i = 0; i < a.length; i++) {
      if (a[i] != className) {
        if (i > 0)
          newClassName += ' ';
        newClassName += a[i];
      }
    }
    element.className = newClassName;
}
/* ======= mobile-toolbar-js ======= */
var mrpMobile = {};

mrpMobile.toolbarIdx = 0;
mrpMobile.toolbarButtonIdx = 0;

mrpMobile.$ = function(id)
{
	return document.getElementById( id );
}

mrpMobile.toolbarButton = function( toolbar, data )
{
	function init( toolbar, button )
	{
		var nodes = toolbar.getElementsByTagName( "td" );
		var td = null;
		var targetClass = "mrp-center-toolbar-cell";
		if( data.position == "left" ) {
			targetClass = "mrp-left-toolbar-cell";
		}
		else if( data.position == "right" ) {
			targetClass = "mrp-right-toolbar-cell";
		}
		
		for( var i=0; i<nodes.length; ++i ) {
			if( nodes[i].className == targetClass ) {
				td = nodes[i];
				break;
			}
		}
		if( !td ) {
			return;
		}
		
		var b = document.createElement( "div" );
		td.appendChild( b );
		
		if( button.label ) {
			var c = document.createElement( "div" );
			b.className = "mrp-toolbar-button mrp-toolbar-label-button";
			b.appendChild( c );
			c.appendChild( document.createTextNode( button.label ) );
			
			if( data.disabled ) {
				c.className = "disabled";
			}
		}
		else if( button.img ) {
			var img = document.createElement( "img" );
			b.className = "mrp-toolbar-button mrp-toolbar-icon-button";
			img.src = button.img;
			b.appendChild( img );	
			
			if( data.disabled ) {
				img.className = "disabled";
			}	
			if( data.tooltip ) {
				img.alt = data.tooltip;
			}
		}
		
		if( button.id ) {
			b.id = button.id;
		}
		
		return b;
	}
	
	var b = init( toolbar, data );
	var _image = data.img;
	var _label = data.label;
	var _callback = data.callback;
	
	var out = {
		getElement : function() {
			return b;
		},
		getImage : function() {
			return _image;
		},
		getLabel : function() {
			return _label;
		},
		pulse : function()
		{
			elemAddClassName( b.getElementsByTagName( "img" )[0], "pulsing" );
		},
		stopPulse : function()
		{
			elemRemoveClassName( b.getElementsByTagName( "img" )[0], "pulsing" );
		},
		setImage : function( src )
		{
			b.className = "mrp-toolbar-button mrp-toolbar-icon-button";
			img = document.createElement( "img" );
			b.innerHTML = "";
			b.appendChild( img );
			img.src = src;
			_image = src;
		},
		setLabel : function( lbl )
		{
			b.innerHTML = "";
			var c = document.createElement( "div" );
			b.className = "mrp-toolbar-button mrp-toolbar-label-button";
			b.appendChild( c );
			c.appendChild( document.createTextNode( lbl ) );
			_label = lbl;
		},
		setCallback : function( cb )
		{
			_callback = cb;
		}
	};
	
	b.addEventListener( "click", function(e) {
		preventBubble(e);
		if( _callback ) {
			_callback( out, data );
		}
	}, false );
	
	return out;
};

mrpMobile.toolbar = function( opts )
{
	if( !opts ) 
		opts = {};
		
	var _outer = null;
	var _elem = init();
	var _msg = initMessage();
	var _infoElem = null;
	var _dialogs = {};
	var parent = opts.parent;
	
	function init()
	{
		var t = document.createElement( "div" );
		t.className = "mrp-mobile-toolbar";
		var table = document.createElement( "table" );
		table.cellspacing = "0";
		table.cellpadding = "0";
		t.appendChild( table );
		var tbody = document.createElement( "tbody" );
		table.appendChild( tbody );
		
		var tr = document.createElement( "tr" );
		tbody.appendChild( tr );
		
		var leftTd = document.createElement( "td" );
		tr.appendChild( leftTd );
		leftTd.className = "mrp-left-toolbar-cell";
		
		var centerTd = document.createElement( "td" );
		centerTd.noWrap = "true";
		tr.appendChild( centerTd );
		centerTd.className = "mrp-center-toolbar-cell";
		
		var rightTd = document.createElement( "td" );
		tr.appendChild( rightTd );
		rightTd.className = "mrp-right-toolbar-cell";
		
		_outer = document.createElement( "div" );
		_outer.className = "mrp-mobile-toolbar-wrapper";
		_outer.appendChild( t );
		
		if( opts.parent ) {
			opts.parent.appendChild( _outer );
		}
		else {
			document.body.appendChild( _outer );
		}
		//document.body.appendChild( t );
		
		return t;
	}
	
	function initMessage()
	{
		var msg = document.createElement( "div" );
		msg.className = "mrp-toolbar-message";
		_outer.appendChild( msg );
		//document.body.appendChild( msg );
		
		var txt = document.createElement( "div" );
		txt.className = "mrp-toolbar-message-txt";
		msg.appendChild( txt );
		
		/*
		var close = document.createElement( "img" );
		close.src = mrpSettings.imgURL + "cross.png";
		close.style.display = "block";
		close.style.position = "absolute";
		close.style.right = "10px";
		close.style.top = "10px";
		close.style.cursor = "pointer";
		close.onclick = function() {
			msg.className = "mrp-toolbar-message mrp-toolbar-message-off";
		};
		msg.appendChild( close );
		*/
		
		return msg;
	}
	var out = {
		getWrapperElement : function()
		{
			return _outer;
		},
		getElement : function()
		{
			return _elem;
		},
		addButton : function( data )
		{
			return mrpMobile.toolbarButton( _elem, data);
		},
		removeButton : function( button )
		{
			if( button.getElement() != null ) {
				button.getElement().parentNode.removeChild( button.getElement() );
			}
		},
		removeInfoText : function()
		{
			if( _infoElem != null ) {
				_infoElem.parentNode.removeChild( _infoElem );
				_infoElem = null;
			}
		},
		setInfoText : function( content )
		{
			this.removeInfoText();
			var div = document.createElement( "div" );
			div.className = "mrp-info-cell";
			_elem.appendChild( div );
			div.innerHTML = content;
			_infoElem = div;
		},
		hideMessage : function()
		{
			_msg.className = "mrp-toolbar-message mrp-toolbar-message-off";
		},
		showMessage : function( text, autoClose, autoCloseTime )
		{
			_msg.getElementsByTagName( "div" )[0].innerHTML = text;
			_msg.className = "mrp-toolbar-message mrp-toolbar-message-on";
			_msg.autoClose = autoClose;
			if( autoClose ) {
				setTimeout( function() {
					if( _msg.autoClose ) {
						out.hideMessage();
					}
				}, autoCloseTime ? autoCloseTime : 3000 );
			}
		},
		addDialog : function( name, elem )
		{
			var w = elem.offsetWidth;
			var h = elem.offsetHeight;
			_dialogs[name] = elem;
			_outer.appendChild( elem );
			elem.style.top = (-h) + "px";
		},
		showDialog : function( name )
		{
			var e = _dialogs[name];
			if( e ) {
				e.style.zIndex = 1;
				e.style.display = "";
				e.style.top = ( _outer.offsetTop + _elem.offsetHeight - 5 ) + "px";
			}
			elemAddClassName( e, "toolbar-dialog-on" );
		},
		hideDialog : function( name )
		{
			var e = _dialogs[name];
			if( e ) {
				e.style.top = ( -( _outer.offsetTop + e.offsetHeight ) ) + "px";
			}
			elemRemoveClassName( e, "toolbar-dialog-on" );
		}
	};
	
	return out;
};

// preload
new Image().src = mrpSettings.imgURL + "bubble.png";
new Image().src = mrpSettings.imgURL + "cross.png";
new Image().src = mrpSettings.imgURL + "check.png";

/* ======= mobile-stacker-js ======= */
subscribeToBus( "orientation-change", function( s,m,d) {
	var _w = innerWidth;
	setTimeout( function() {
		for( var i=1; i<=window._mrpStack; ++i ) {
			var e = document.getElementById( "mrp_stack" + i );
			if( e ) {
				e.style.width = _w + "px";
			}
			e = document.getElementById( "mrp_toolbar" + i );
			if( e ) {
				e.style.width = _w + "px";
			}
		}
	}, 100 );
});

window._mrpMobileStacks = [];

subscribeToBus( "**", function( s,m,d ) {
	for( var i=0; i<window._mrpMobileStacks.length; ++i ) {
		try
		{
			window._mrpMobileStacks[i].onBusEvent( s,m,d );
		}
		catch( e )
		{
		}
	}
});

function MrpMobileStack( opts )
{
	function hideStack( index, toolbar )
	{
		var e = document.getElementById( "mrp_stack" + index );
		if( e ) {
						//e.style.display = "none";
			e.style.visibility = "hidden";
		}
	}
	
	function destroyStack( index, toolbar )
	{
		var e = document.getElementById( "mrp_stack" + index );
		if( e ) {
			e.parentNode.removeChild( e );
		}
		--window._mrpStack;
		var stack = window._mrpMobileStacks.pop();
		
		toolbar.getWrapperElement().parentNode.removeChild( toolbar.getWrapperElement() );
		
		publishToBus( "mrp.stack.destroyed", stack );
		
		setTimeout( function() {
			showStack( _index - 1 );
			window.scrollTo( 0, 1 );
		}, 100 );
	}
	
	function showStack( index, toolbar )
	{
		var e = document.getElementById( "mrp_stack" + index );
		if( e ) {
			//e.style.display = "";
			e.style.visibility = "visible";
		}
	}
	
	var url = opts.url;
	
	if( typeof window._mrpStack == 'undefined' ) {
		window._mrpStack = 0;
	}
	
	var _index = ++window._mrpStack;
	var _name = opts.name;
	
	hideStack( _index - 1 );
	
	var iframe = document.createElement( "iframe" );
	iframe.id = "mrp_stack" + _index;
	iframe.style.position = "absolute";
	iframe.style.left = "0";
	iframe.style.top = "0";
	iframe.style.marginTop = "70px";
	iframe.style.zIndex = 20;
	
	iframe.width = "100%";
	iframe.height = "100%";
	iframe.vspace = "0";
	iframe.hspace = "0";
	iframe.scrolling = "0";
	iframe.frameborder = "0";
	iframe.marginheight = "0";
	iframe.marginwidth = "0";
	iframe.style.border = "0";
	iframe.allowtransparency = false;
	iframe.src = url;
	
	iframe.style.width = window.innerWidth;
	iframe.style.height = "100%";
	iframe.style.minHeight = "310px";
	iframe.style.backgroundColor = "white";
	document.body.appendChild( iframe );
	
	publishToBus( "mrp.hide-message" );
	
	var toolbar = opts.toolbar;
	
	if( !toolbar ) {
		toolbar = mrpMobile.toolbar( {
			//parent: div
		});
		
		//toolbar.getWrapperElement().style.position = "fixed";
		
		var label = opts.backButtonLabel;
		if( !label ) {
			label = "Back";
		}
		var b = toolbar.addButton( {
			label : label,
			position : "left",
			callback : function() {
				setTimeout( function() {
					destroyStack( _index, toolbar );
				}, 100 );
			}
		});
		if( b && opts.noBackButton ) {
			b.getElement().style.visibility = "hidden";
		}
	}
	
	toolbar.getWrapperElement().id = "mrp_toolbar" + window._mrpStack;
	toolbar.getWrapperElement().style.zIndex = 20;
	
	var out = {
		getToolbar : function() {
			return toolbar;
		},
		getIFrame: function() {
			return iframe;
		},
		hide : function()
		{
			hideStack( _index );
		},
		show : function()
		{
			showStack( _index );
		},
		destroy: function()
		{
			destroyStack( _index, toolbar );
		},
		reload : function()
		{
			iframe.src = url;
		},
		getName : function()
		{
			return _name;
		},
		onBusEvent: function( s, m, d ) {
			// to be overriden
		}
	};
	
	window._mrpMobileStacks.push( out );
	
	publishToBus( "mrp.stack.created", out );
	
	return out;
}

/* ======= mobile-map-toolbar-js ======= */
function initMrpMobileMapToolbar( infoText, homeLabel, homeURL )
{
	var t = mrpMobile.toolbar( );
	var dropDown = document.createElement( "div" );
	dropDown.className = "mrp-mobile-toolbar-dropdown";
	document.body.appendChild( dropDown );
	
	function createDropDownItem( label, first )
	{
		var item = document.createElement( "div" );
		item.className = "dropdown-item";
		if( first ) {
			item.className += " dropdown-item-first";
		}
		item.innerHTML = label;
		dropDown.appendChild( item );
		return item;
	}
	
	function saveFilterValues()
	{
		var e = document.getElementById( "sdlg" );
		e.priceFrom = document.getElementById( "price-from" ).value;
		e.priceTo = document.getElementById( "price-to" ).value;
		e.propType = document.getElementById( "property-type" ).value;
		e.bedrooms = document.getElementById( "bedrooms" ).value;
	}
	function restoreFilterValues()
	{
		var e = document.getElementById( "sdlg" );
		document.getElementById( "price-from" ).value = e.priceFrom || "";
		document.getElementById( "price-to" ).value = e.priceTo || "";
		document.getElementById( "property-type" ).value = e.propType || "";
		document.getElementById( "bedrooms" ).value = e.bedrooms || "";
	}
	function runFilter()
	{
		publishToBus( "mrp.hide-all-dialogs" );
		saveFilterValues();
		var e = document.getElementById( "sdlg" );
		if( e.priceFrom || e.priceTo || e.propType || e.bedrooms ) { 
			elemAddClassName( searchCriteriaButton, "dropdown-item-on" );
		}
		else {
			elemRemoveClassName( searchCriteriaButton, "dropdown-item-on" );
		}
		
		publishToBus( "mrp.geo-location-refresh" );
		return false;
	}
	function closeFilterDialog()
	{
		restoreFilterValues();
		publishToBus('mrp.hide-all-dialogs');
		return false;
	}
	
	var manualLocationButton = createDropDownItem( "Go To Location", true );
	var searchCriteriaButton = createDropDownItem( "Set Search Criteria", false );
	var loginButton = createDropDownItem( "Login", false );
	var contactButton = createDropDownItem( "Contact", false );
	var zoomInButton = createDropDownItem( "Zoom in", false );
	var zoomOutButton = createDropDownItem( "Zoom out", false );
	var aboutButton = createDropDownItem( "About", false );
	
	// adjust top
	dropDown.style.top = ( -( dropDown.offsetHeight + 10 ) ) + "px";
	
	var pos = "center";
	if( homeURL ) {
		pos = "right";
		var home = t.addButton( { "label" : homeLabel, position : "left", callback: function( b, data ) {
			window.location = homeURL;
		} } );
	}
	
	var reloadButton = t.addButton( {
		img : mrpSettings.imgURL + "reload2.png", 
		id : "mrp_mobile_refresh_button",
		position: pos, callback: function( b, data ) {
		publishToBus( "mrp.geo-location-refresh" );
	} } );
	
	var listButton = t.addButton( { 
		img : mrpSettings.imgURL + "list.png", 
		id : "mrp_mobile_list_button",
		position: pos, disabled: true, tooltip : 'View results as a list', 
			callback: function( b, data ) {
		if( listButton.isDisabled() ) {
			return;
		}
		new MrpMobileStack( { url: mrpSettings.baseAppURL + 
			'browse/SearchResults.form', backButtonLabel: 'Back to Map' } );
	} } );
	listButton.isDisabled = function()
	{
		return listButton.getElement().getElementsByTagName( "img" )[0].className == "disabled";
	};
	
	var radioButton = t.addButton( { img : mrpSettings.imgURL + "compass.png",
		id : "mrp_mobile_follow_button", 
		position: pos, callback: function( b, data ) {
		if( radioButton.following ) {
			radioButton.following = false;
			elemRemoveClassName( radioButton.getElement(), "following" );
			publishToBus( "mrp.geo-follow-done" );
			radioButton.setImage( mrpSettings.imgURL + "compass.png" );
			radioButton.stopPulse();
		}
		else {
			radioButton.following = true;
			elemAddClassName( radioButton.getElement(), "following" );
			publishToBus( "mrp.geo-follow" );
			radioButton.setImage( mrpSettings.imgURL + "compass-on.png" );
			radioButton.pulse();
		}
	} } );
	
	var moreButton = t.addButton( { img : mrpSettings.imgURL + "more.png", 
		id : "mrp_mobile_more_button",
		position: "right", callback: function( b, data ) {
		if( dropDown.down ) {
			moreButton.close();
		}
		else {
			moreButton.open();			
		}
	} } );
	
	moreButton.open = function() {
		moreButton.setImage( mrpSettings.imgURL + "less.png" ); 
		dropDown.style.display = "block";
		dropDown.style.top = t.getElement().offsetHeight + "px";
		dropDown.down = true;
	};
	moreButton.close = function() {
		moreButton.setImage( mrpSettings.imgURL + "more.png" );
		dropDown.style.top = ( -( dropDown.offsetHeight + 10 ) ) + "px";
		setTimeout( function() {
			dropDown.style.display = "none";
		}, 500 );
		dropDown.down = false;
	};
	
	manualLocationButton.addEventListener( "click", function() {
		moreButton.close();
		publishToBus( "mrp.open-manual-location" );
	}, false );
	
	searchCriteriaButton.addEventListener( "click", function() {
		moreButton.close();
		publishToBus( "mrp.open-search-dialog" );
	}, false );
	
	contactButton.addEventListener( "click", function() {
		moreButton.close();
		publishToBus( "mrp.hide-all-dialogs" );
		var stack = new MrpMobileStack( {
			url : mrpSettings.baseRestURL + "vow/contact?mobile=1",
			backButtonLabel: 'Back to Map'
		});
		
	}, false );
	
	loginButton.addEventListener( "click", function() {
		moreButton.close();
		var stack = null;
		if( mrpSettings.vowUser ) {
			stack = window.openURL( mrpSettings.logoutURL, "Back To Map" );
		}
		else {
			stack = window.openURL( mrpSettings.loginURL, "Back To Map" );
		}
		
		createLoginWithButtons( stack.getToolbar() );
	}, false );
	
	if( window.mrpSettings.facebookLoginURL || window.mrpSettings.googleLoginURL ||
		window.mrpSettings.yahooLoginURL ) {
	
		var span = document.createElement( "span" );
		span.style.padding = "0 5px 0 5px";
		span.innerHTML = "|";
		loginButton.appendChild( span );
		
		if( window.mrpSettings.facebookLoginURL ) {
			var img = document.createElement( "img" );
			img.src = "/wps/img/classifieds/facebook.png";
			img.style.margin= "0 10px 0 5px";
			img.style.verticalAlign = "text-bottom";
			img.addEventListener( "click", function(e) {
				preventBubble(e);
				window.location = window.mrpSettings.facebookLoginURL; 
			});
			loginButton.appendChild( img );
		}
		if( window.mrpSettings.googleLoginURL ) {
			var img = document.createElement( "img" );
			img.src = "/wps/img/classifieds/google.png";
			img.style.margin= "0 10px 0 5px";
			img.style.verticalAlign = "text-bottom";
			img.addEventListener( "click", function(e) {
				preventBubble(e);
				window.location = window.mrpSettings.googleLoginURL; 
			});
			loginButton.appendChild( img );
		}
		if( window.mrpSettings.yahooLoginURL ) {
			var img = document.createElement( "img" );
			img.src = "/wps/img/classifieds/yahoo.png";
			img.style.margin= "0 10px 0 5px";
			img.style.verticalAlign = "text-bottom";
			img.addEventListener( "click", function(e) {
				preventBubble(e);
				window.location = window.mrpSettings.yahooLoginURL; 
			});
			loginButton.appendChild( img );
		}
	}
	
	zoomInButton.addEventListener( "click", function() {
		moreButton.close();
		publishToBus( "mrp.zoom-in" );
	}, false );
	
	zoomOutButton.addEventListener( "click", function() {
		moreButton.close();
		publishToBus( "mrp.zoom-out" );
	}, false );
	
	aboutButton.addEventListener( "click", function() {
		moreButton.close();
		publishToBus( "mrp.open-about-dialog" );
	}, false );
	
	t.setInfoText( infoText );
	
	
	// dialogs
	var searchDlg = document.getElementById( "sdlg" );
	t.addDialog( "search-dialog", searchDlg );

	var manualLocationDlg = document.getElementById( "ldlg" );
	t.addDialog( "location-dialog", manualLocationDlg );
	var s = document.getElementById( "price-from" );
	for( var i=0; i<5000000; i+= 50000 ) {
		var o = document.createElement( "option" );
		o.value = "" +i;
		o.innerHTML = prettyNumberIfNecessary(i,"$") + "+";
		s.appendChild( o );
	}
	s = document.getElementById( "price-to" );
	for( var i=50000; i<5000000; i+= 50000 ) {
		var o = document.createElement( "option" );
		o.value = "" +i;
		o.innerHTML = prettyNumberIfNecessary(i,"$");
		s.appendChild( o );
	}
	document.getElementById( "sdlg-filter-button" ).onclick = runFilter;
	document.getElementById( "sdlg-close-filter-button" ).onclick = closeFilterDialog;
	
	var aboutDlg = document.getElementById( "adlg" );
	t.addDialog( "about-dialog", aboutDlg );
	document.getElementById( "about-dialog-close-button" ).onclick = function() {
		publishToBus( "mrp.hide-all-dialogs" ); return false;
	};
	
	subscribeToBus( "mrp.quick-message", function( s, m, d ) {
		t.showMessage( m, true, 3000 );
	});
	
	subscribeToBus( "mrp.message", function( s, m, d ) {
		t.showMessage( m, false );
	});
	
	subscribeToBus( "mrp.hide-message", function( s, m, d ) {
		t.hideMessage();
	});
	
	subscribeToBus( "mrp.geo-refine", function( s, m, d ) {
		radioButton.pulse();
	} );
	
	subscribeToBus( "mrp.geo-refine-done", function( s, m, d ) {
		radioButton.stopPulse();
	} );
	
	subscribeToBus( "mrp.open-search-dialog", function( s, m, d ) {
		publishToBus( "mrp.hide-all-dialogs" );
		restoreFilterValues();
		setTimeout( function() {
			t.showDialog( "search-dialog" );
		}, 100 );
	});
	
	subscribeToBus( "mrp.open-manual-location", function( s, m, d ) {
		publishToBus( "mrp.hide-all-dialogs" );
		setTimeout( function() {
			t.showDialog( "location-dialog" );
			document.getElementById( "manual-location" ).focus();
		}, 100 );
	});
	
	subscribeToBus( "mrp.open-about-dialog", function( s, m, d ) {
		publishToBus( "mrp.hide-all-dialogs" );
		setTimeout( function() {
			t.showDialog( "about-dialog" );
		}, 100 );
	});
	
	subscribeToBus( "mrp.hide-all-dialogs", function() {
		t.hideDialog( "search-dialog" );
		t.hideDialog( "location-dialog" );
		t.hideDialog( "about-dialog" );
		window.scrollTo( 0, 1 );
	});
	
	subscribeToBus( "mrp.find-listings", function() {
		elemAddClassName( listButton.getElement().getElementsByTagName("img")[0], "disabled" );
	});
	subscribeToBus( "mrp.find-listings", function() {
		elemRemoveClassName( listButton.getElement().getElementsByTagName("img")[0], "disabled" );
	});
	
	subscribeToBus( "vow.login.success", function(s,m,d) {
		loginButton.innerHTML = "Logout";
	});
	subscribeToBus( "vow.logout", function(s,m,d) {
		loginButton.innerHTML = "Login";
	});
	
	t.getWrapperElement().addEventListener( "click", function() {
		moreButton.close();
	});
	return t;
}
/* ======= mobile-map-js ======= */
if( !window.mrpMobile ) {
	window.mrpMobile = {};
}

mrpMobile.idxMap = function( containerId )
{
	var _DISTANCE = 0.5; // km
	var _FIXED_GEO_PRECISION = 3;
	
	var _containerId = containerId;
	var _gmap = init();
	var _geocoder = new google.maps.Geocoder();
	var _geoMarker = null;
	var _geoCircle = null;
	
	var _minAccuracyThreshold = 300;
	var _maxAccuracyThreshold = 5;
	
	var _refineGeoLocationTask = null;
	var _refiningAttempt = 0;
	
	var _followGeoLocationTask = null;
	
	var _autoCenter = null;
	var _userCenter = null;
	
	var _lastManualLocation = "";
	
	var _activeCenter;
	var _activeDistance;
	var _activeSW;
	var _activeNE;
	var _activeRect;
	
	var _activeCenterMarker;
	var _activeSWMaker;
	var _activeNEMarker;
	
	var _jsonpScripts = [];
	var _jsonSeq = 0;
	
	var _listingMarkers = {};
	var _currentInfoWindow = null;
	
	var _fakeOverlay = null;
	var _refiningWatchId = 0;
	var _refineAttempt = 1;
	var _refineCancelled = false;
	var _accuracyMessageDisplayed = false;
	
	function init()
	{
		var myLatlng = new google.maps.LatLng( 0, 0 );
		var myOptions = {
			zoom: 16,
			center: myLatlng,
			disableDefaultUI: false,
			navigationControl: false,
     			//navigationControlOptions: {style: google.maps.NavigationControlStyle.ANDROID},
			mapTypeControl: false,
			scaleControl: false,
			scrollwheel: false,
			disableDoubleClickZoom: true,
			mapTypeId: google.maps.MapTypeId.ROADMAP
		}
		
		//document.getElementById( containerId ).style.visibility = "hidden";
		return new google.maps.Map(document.getElementById( containerId ), myOptions);
	}
	
	var out = {
		getMap : function() {
			return _gmap;
		},
		getGeocoder : function() {
			return _geocoder;
		},
		setGeoPosition : function( latLng )
		{
			_gmap.setCenter( latLng );
		},
		
		getActiveCenter : function()
		{
			return _activeCenter;
		},
		
		geoLocate : function()
		{
			if( _refineCancelled ) {
				return;
			}
			publishToBus( "mrp.quick-message", "Hold on, locating you now..." );
			navigator.geolocation.getCurrentPosition( 
				function( p ) {
					if( p.coords ) {
						p = p.coords;
					}
					var latLng = new google.maps.LatLng( p.latitude, p.longitude );
					publishToBus( "mrp.geo-location-done", { latLng: latLng, accuracy : p.accuracy } );
				},
				function( e ) {
					publishToBus( "mrp.geo-locate-failed", null );
				},
				{ 'enableHighAccuracy': true, 'maximumAge' : 20000  } 
			);
		},
		
		geoLocateFailed : function( data )
		{
			if( !data ) {
				setTimeout( function() {
					if( confirm( "We were unable to determine your position...\n" +
						"Would you like to set your location manually?" ) ) {
						publishToBus( "mrp.open-manual-location" );
					}
					else {
						setTimeout( function() {
							publishToBus( "mrp.geo-location-ready" );
						}, 100 );
					}
					// bill: disabling for now, need to test more
					/*
					else {
						out.maybeRefineGeoLocation( data.latLng, data.accuracy );
					}
					*/
				}, 200 );
			}
			else {
				if( _refineCancelled ) {
					return;
				}
				setTimeout( function() {
					if( confirm( "We are  " +
							data.accuracy + " meters off your possible location...\n" +
						"Would you like to set your location manually?" ) ) {
						
						publishToBus( "mrp.open-manual-location" );
					}
					else {
						setTimeout( function() {
							publishToBus( "mrp.geo-location-ready" );
						}, 100 );
					}
					// bill: disabling for now , need to test more
					/*
					else {
						out.setGeoMarker( data.latLng, data.accuracy );
						out.maybeRefineGeoLocation( data.latLng, data.accuracy );
					}
					*/
				}, 200 );
			}
		},
		
		finishGeoLocate : function( latLng, accuracy )
		{
			if( !latLng ) {
				return;
			}
			
			if( !accuracy ) {
				accuracy = 0;
			}
			else {
				accuracy = parseInt( accuracy );
			}
			
			// TODO: comment out
			//accuracy = 300;
			
			//document.getElementById( _containerId ).style.visibility = "visible";
					
			if( accuracy > _minAccuracyThreshold ) {
				_gmap.setCenter( latLng );
				if( !_refineCancelled && _refineAttempt == 1 ) {
					_refiningWatchId = navigator.geolocation.watchPosition(function( p ) {
						// do nothing, just a refining thing
					});
				}
				if( !_refineCancelled && _refineAttempt < 4 ) {
					_refineAttempt++;
					publishToBus( "mrp.quick-message", "Trying to refine your location (" +
						_refineAttempt + ")..." );
					setTimeout( function() {
						out.geoLocate();
					}, 5000 );
					return;
				}
				else {
					if( !_refineCancelled && !_accuracyMessageDisplayed ) {
						publishToBus( "mrp.geo-locate-failed", { latLng: latLng, accuracy : accuracy } );
						_accuracyMessageDisplayed = true;
					}
					try
					{
						if( !_refineCancelled ) {
							publishToBus( "mrp.quick-message", "Location within " + accuracy + " m" );
						}
						if( _refiningWatchId ) {
							navigator.geolocation.clearWatch( _refiningWatchId );
						}
					}
					catch( e )
					{
					}
				}
			}
			else {
				out.setGeoMarker( latLng, accuracy );
				setTimeout( function() {
					publishToBus( "mrp.geo-location-refresh" );
				}, 1000 );
				try
				{
					if(  !_accuracyMessageDisplayed ) {
						publishToBus( "mrp.quick-message", "Location within " + accuracy + " m" );
						_accuracyMessageDisplayed = true;
					}
					if( _refiningWatchId ) {
						navigator.geolocation.clearWatch( _refiningWatchId );
					}
				}
				catch( e )
				{
				}
				//out.maybeRefineGeoLocation( data.latLng, data.accuracy );
			}
		},
		
		setGeoMarker : function( latLng, accuracy, ignoreAccuracy )
		{
			if( _geoMarker == null ) {
				_geoMarker = new mrpAnimMarker( latLng, _gmap, 
					mrpSettings.imgURL + "center.png?1", 16, 16, 8, 8 );
			}
			else {
				_geoMarker.setPosition( latLng );
			}
		
			if( ignoreAccuracy || ( accuracy > _maxAccuracyThreshold && accuracy < _minAccuracyThreshold ) ) {
				setTimeout( function() {
					if( _geoCircle != null ) {
						_geoCircle.setRadius( accuracy );
						_geoCircle.setCenter( latLng );
					}
					else {
						_geoCircle = new google.maps.Circle( {
							center: latLng,
							radius: accuracy,
							strokeColor: "#0000ff",
							strokeWeight: 3,
							strokeOpacity: 0.2,
							fillColor: "#0000ff",
							fillOpacity: 0.1,
							map : _gmap
						} );
					}
				}, 100 );
			}
			
			if( !_userCenter ) {
				_gmap.setCenter( latLng );
				
			}
		},
		
			
		maybeRefineGeoLocation : function( latLng, accuracy )
		{
			if( !navigator.geolocation || navigator.geolocation.shim ) {
				return;
			}
			if( accuracy > _maxAccuracyThreshold ) {
				publishToBus( "mrp.geo-refine" );
			}
		},
		
		refineGeoLocation : function()
		{
			out._refineGeoLocationTask = navigator.geolocation.watchPosition( 
				function( p ) {
					var now = new Date().getTime();
					if( ( now - _refiningAttempt ) > 5000 ) {
						clearInterval( out._refineGeoLocationTask );
						out._refineGeoLocationTask = null;
						publishToBus( "mrp.geo-refine-done" );
						return;
					}
					if( p.coords ) {
						p = p.coords;
					}
					var latLng = new google.maps.LatLng( p.latitude, p.longitude );
					out.setGeoMarker( latLng, p.accuracy, true /* ignore accuracy */ );
					if( p.accuracy < _maxAccuracyThreshold ) {
						if( out._refineGeoLocationTask ) {
							navigator.geolocation.clearWatch( out._refineGeoLocationTask );
							out._refineGeoLocationTask = null;
							publishToBus( "mrp.geo-refine-done" );
						}
					}
				},
				function( e ) {
					// silent
				},
				{ 'enableHighAccuracy': true, 'maximumAge' : 20000  } 
			);
		},
		
		stopRefineGeoLocation : function()
		{
			if( out._refineGeoLocationTask ) {
				navigator.geolocation.clearWatch( out._refineGeoLocationTask );
				out._refineGeoLocationTask = null;
			}
		},
		
		updateActiveBounds : function( force )
		{
			var center = _gmap.getCenter();
			var bnds = _gmap.getBounds();
			
			var ne = _fakeOverlay.getProjection().fromContainerPixelToLatLng( 
				new google.maps.Point( innerWidth, 70 ), true );
			bnds = new google.maps.LatLngBounds( bnds.getSouthWest(), ne );
			
		  	if( !force && _activeCenter && 
		  		this.distance( center.lat(), center.lng(), 
		  			_activeCenter.lat(), _activeCenter.lng() ) < _activeDistance * 1.2 ) {
		  		return;
		  	}
		  	
		  	var currDistance = this.distance( bnds.getNorthEast().lat(), center.lng(),
		  		center.lat(), center.lng()  );
		  	
		  	if( currDistance > _DISTANCE ) {
		  		currDistance = _DISTANCE;
		  		
		  		var centerP = new LatLon( center.lat(), center.lng() );
			  	var rightP = centerP.destinationPoint( 90, _DISTANCE );
			  	var leftP = centerP.destinationPoint( -90, _DISTANCE );
			  	var topP = centerP.destinationPoint( 0, _DISTANCE );
			  	var bottomP = centerP.destinationPoint( 180, _DISTANCE );
			  	
			  	_activeNE = new google.maps.LatLng( topP.lat(), rightP.lon() );
		  		_activeSW = new google.maps.LatLng( bottomP.lat(), leftP.lon() );
		  	}
		  	else {
		  		_activeNE = bnds.getNorthEast();
		  		_activeSW = bnds.getSouthWest();
		  	}
		  	
		  	_activeDistance = currDistance;
		  	_activeCenter = center;
		  	
		  	/*
		  	if( _activeCenterMarker ) {
		  		_activeCenterMarker.setPosition( _activeCenter );
		  		_activeNEMarker.setPosition( _activeNE );
		  		_activeSWMarker.setPosition( _activeSW );
		  		
		  	}
		  	else {
		  		_activeCenterMarker = new google.maps.Marker({
			      position: _activeCenter, 
			      map: _gmap, 
			      title:"Center"
			    });
		  		_activeNEMarker = new google.maps.Marker({
				      position: _activeNE, 
				      map: _gmap, 
				      title:"NE"
		  		});   
		  		_activeSWMarker = new google.maps.Marker({
				      position: _activeSW, 
				      map: _gmap, 
				      title:"SW"
		  		});   
		  	}
		  	*/
		  	
		  	var activeBnds = new google.maps.LatLngBounds( _activeSW, _activeNE );
		  	
		  	if( !bnds.equals( activeBnds ) ) {
		  		if( _activeRect ) {
		  			_activeRect.setMap( _gmap );
		  			_activeRect.setBounds( activeBnds );
		  		}
		  		else {
		  			_activeRect = new google.maps.Rectangle( {
		  				bounds : activeBnds,
		  				map: _gmap,
		  				fillColor : "#ffff00",
		  				fillOpacity : 0.2,
		  				strokeColor : "#ffff00",
		  				strokeOpacity : 0.3,
		  				strokeWeight : 3
		  			});
		  		}
		  	}
		  	else {
		  		if( _activeRect ) {
		  			_activeRect.setMap( null );
		  			_activeRect.setBounds( activeBnds );
		  		}
		  	}
		  	publishToBus( "mrp.find-listings", { "sw" : _activeSW, "ne" : _activeNE } );
		},
		clearJsonpScripts : function()
		{
			for( var i=0; i<_jsonpScripts.length; ++i ) {
   				var existing = document.getElementById( _jsonpScripts[i] );
   				if( existing != null ) {
   					existing.parentNode.removeChild( existing );
   					existing = null;
   				}
   			}
   			_jsonpScripts = [];
		},
		findListings : function( m )
		{
			publishToBus( "mrp.message", "Searching listings..." );
			
			this.clearJsonpScripts();
			
			var url = mrpSettings.searchURL;
			if( url.indexOf( "?" ) == -1 ) {
   				url += "?";
   			}
   			else if( url.charAt( url.length - 1 ) != "&" ) {
   				url += "&";
   			}
			
			var sw = m.sw;
			var ne = m.ne;
			var polyPoints = "";
   			polyPoints += sw.lat().toFixed(_FIXED_GEO_PRECISION) + "," + sw.lng().toFixed(_FIXED_GEO_PRECISION) + ",";
   			polyPoints += sw.lat().toFixed(_FIXED_GEO_PRECISION) + "," + ne.lng().toFixed(_FIXED_GEO_PRECISION) + ",";
   			polyPoints += ne.lat().toFixed(_FIXED_GEO_PRECISION) + "," + ne.lng().toFixed(_FIXED_GEO_PRECISION) + ",";
   			polyPoints += ne.lat().toFixed(_FIXED_GEO_PRECISION) + "," + sw.lng().toFixed(_FIXED_GEO_PRECISION) + ",";
   			polyPoints += sw.lat().toFixed(_FIXED_GEO_PRECISION) + "," + sw.lng().toFixed(_FIXED_GEO_PRECISION);
   			
			var polySpec = sw.lat() + "," + sw.lng() + "," + ne.lat() + "," + ne.lng();
   			
   			url += "__free_poly_type=rect&";
   			url += "__free_poly_spec=" + polySpec + "&";
   			url += "__free_poly_points=" + polyPoints + "&";
   			url += "_cb=onListingsFound";
   			
   			var sdlg = document.getElementById( "sdlg" );
   			if( sdlg ) {
   				var price = "";
   				if( sdlg.priceFrom ) {
   					price = sdlg.priceFrom + "-";
   				}
   				if( sdlg.priceTo ) {
   					if( !price ) {
   						price = "0-";
   					}
   					price += sdlg.priceTo;
   				}
   				if( price ) {
   					url += "&PRICE=" + price;
   				}
   				if( sdlg.propType ) {
   					url += "&PROPERTY_TYPE=" + sdlg.propType;
   				}
   				if( sdlg.bedrooms ) {
   					url += "&TOTAL_BEDROOMS=" + sdlg.bedrooms;
   				}
   			}
   			
			url += "&_r=" + Math.random();
			
			//prompt( "", url );
			
			var s = document.createElement( "script" );
   			s.src = url;
   			s.type = "text/javascript";
   			var id = "jsonp" + ( ++_jsonSeq );
   			s.id = id;
   			_jsonpScripts.push( id );
   			
   			// timeout
   			setTimeout( function() {
   				if( document.getElementById( id ) != null ) {
   					out.clearJsonpScripts();
   					publishToBus( "mrp.message", "Sorry, listing search timed out..." );
   				}
   			}, 10000 ); // 10 secs
   			
   			document.body.appendChild( s );
		},
		placeListings : function( json )
		{
			out.clearJsonpScripts();
			publishToBus( "mrp.quick-message", "Found " + json.results.length + " listings" );
			out.clearListingMarkers();
			var res = json["results"];
   			for( var i=0; i<res.length; ++i ) {
   				out.addListingMarkerAsync( res[i] );
   			}
   			publishToBus( "mrp.listings-found", { results: json } );
		},
		addListingMarkerAsync : function( listing )
		{
			setTimeout( function() {
				out.addListingMarker( listing );
			}, 10 );
		},
		addListingMarker : function( listing )
		{
			var latLng = new google.maps.LatLng( listing["LATITUDE"], listing["LONGITUDE"] );
			var key = this.latLngToKey(latLng);
			var existing = _listingMarkers[key];
			if( existing ) {
   				existing.data.push( listing );
   				/*
   				existing.setIcon( mrpSettings.imgURL + "house-marker-multi.png",
   					 36, 40, 17, 40 );
   				*/
   				
   				/*
   				existing.setIcon( new google.maps.MarkerImage(
	   					mrpSettings.imgURL + "house-marker-multi.png",
	   					new google.maps.Size( 36, 40 ),
	   					new google.maps.Point( 0, 0 ),
	   					new google.maps.Point( 17, 40 )
	   				) );
	   			*/
	   			//var icon = "pin-multi-lots.png?a";
	   			//if( existing.data.length <= 9 ) {
				//	icon = "pins.png?a";  			
	   			//}
	   			var icon = "pins.png?a";  
	   			var idx = existing.data.length-1;
	   			if( existing.data.length > 9 ) {
	   				idx = 9;
	   			}
	   			existing.setIcon( new google.maps.MarkerImage(
	   					mrpSettings.imgURL + icon,
	   					new google.maps.Size( 27, 30 ),
	   					new google.maps.Point( idx*27, 0 ),
	   					new google.maps.Point( 9, 30 )
	   				) );
   			} 
   			else {
   				/*
   				var marker = new mrpAnimMarker( latLng, _gmap, 
					mrpSettings.imgURL + "house-marker.png", 36, 40, 17, 40 );
				*/
				
	   			var marker = new google.maps.Marker( {
	   				position: latLng,
	   				map: _gmap,
	   				flat: true,
	   				zIndex: 100,
	   				draggable : false,
	   				//shape: {
      				//	coord: [0,0,36,0,36,40,0,40],
      				//	type: 'poly'
  					//},
	   				icon: new google.maps.MarkerImage(
	   					//mrpSettings.imgURL + "house-marker.png",
	   					//new google.maps.Size( 36, 40 ),
	   					//new google.maps.Point( 0, 0 ),
	   					//new google.maps.Point( 17, 40 )
	   					mrpSettings.imgURL + "pins.png?d",
	   					new google.maps.Size( 27, 30 ),
	   					new google.maps.Point( 0, 0 ),
	   					new google.maps.Point( 9, 30 )
	   				)
	   			} );
	   			
	   			marker.data = [ listing ];
	   			google.maps.event.addListener( marker, "click", function(e) {
	   				out.onMarkerClick( marker, 0 );
	   			});
	   			_listingMarkers[key] = marker;
	   		}
		},
		clearListingMarkers : function()
   		{
   			for( var i in _listingMarkers ) {
   				try
   				{
	   				if( _listingMarkers[i] && 
	   					(typeof _listingMarkers[i].setMap != 'undefined' ) ) {
	   					_listingMarkers[i].setMap( null );
	   				}
	   			}
	   			catch( e ) 
	   			{
	   			}
   			}
   			_listingMarkers = {};
   			if( _currentInfoWindow != null ) {
   				try
   				{
   					_currentInfoWindow.close();
   				}
   				catch( e )
   				{
   				}
   			}
   		},
		latLngToKey : function( latLng ) 
   		{
   			return latLng.lat().toFixed(_FIXED_GEO_PRECISION) + ":" + latLng.lng().toFixed(_FIXED_GEO_PRECISION);
   		},
   		onMarkerClick : function( marker, idx )
   		{
   			if( _currentInfoWindow == null ) {
   				_currentInfoWindow = new InfoBox( { "map" : _gmap } );
   			}
   			if( _currentInfoWindow != null ) {
   				try
   				{
	   				_currentInfoWindow.close();
	   			}
	   			catch( e )
	   			{
	   			}
   			}
   			
   			var listing = marker.data[idx];
   			
   			var len = marker.data.length;
   			if( len > 1 ) {
   				_currentInfoWindow.set_size( new google.maps.Size(  280, 170 ) );
   			}
   			else {
   				_currentInfoWindow.set_size( new google.maps.Size( 280, 140 ) );
   			}
   			
   			mrpMakeListingInfoWindowContent( _currentInfoWindow, marker, idx, out );
   		
   			_currentInfoWindow.open( _gmap, marker );
   			
   			window.scrollTo( 0, 1 );
   		},
   		lookupMarkerAndClick : function( key, idx )
   		{
   			var marker = _listingMarkers[key];
   			if( marker ) {
   				this.onMarkerClick( marker, idx );
   			}
   		},
		follow : function()
		{
			publishToBus( "mrp.geo-refine-done" );
			_followGeoLocationTask = navigator.geolocation.watchPosition( 
				function( p ) {
					if( p.coords ) {
						p = p.coords;
					}
					var latLng = new google.maps.LatLng( p.latitude, p.longitude );
					out.setGeoMarker( latLng, p.accuracy, false /* ignore accuracy */ );
					_gmap.setCenter( latLng );
					setTimeout( function() {
						publishEvent( "mrp.geo-location-ready" );
					}, 100 );
				},
				function( e ) {
					// silent
				},
				{ 'enableHighAccuracy': true, 'maximumAge' : 20000  } 
			);
		},
		
		unfollow : function()
		{
			if( _followGeoLocationTask ) {
				navigator.geolocation.clearWatch( _followGeoLocationTask );
				_followGeoLocationTask = null;
			}
		},
		
		distance : function( lat1, lon1, lat2, lon2 )
   		{
   			var R = 6371; // km
			var dLat = (lat2-lat1).toRad();
			var dLon = (lon2-lon1).toRad(); 
			var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
			Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
			Math.sin(dLon/2) * Math.sin(dLon/2); 
			var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
			var d = R * c;
			return d;
   		}
	};
	
	_fakeOverlay = new google.maps.OverlayView();
   	_fakeOverlay.draw = function() {};
   	_fakeOverlay.setMap(_gmap);
    
	
	if( navigator.geolocation ) {
		setTimeout( function() {
			out.geoLocate();
		}, 100 );
	}
	else {
		publishToBus( "mrp.message", "Sorry, your browser doesn't support geo-location" );
	}
	
	// subscriptions
	
	subscribeToBus( "mrp.zoom-in", function() {
		_gmap.setZoom( _gmap.getZoom()+1 );
	});
	subscribeToBus( "mrp.zoom-out", function() {
		_gmap.setZoom( _gmap.getZoom()-1 );
	});
	
	subscribeToBus( "mrp.geo-refine", function( s, m, d ) {
		publishToBus( "mrp.quick-message", "Will try to refine your position..." );
		out._refiningAttempt = ( new Date().getTime() );
		out.refineGeoLocation();
	});
	subscribeToBus( "mrp.geo-refine-done", function( s, m, d ) {
		out.stopRefineGeoLocation();
	});
	
	subscribeToBus( "mrp.geo-follow", function( s, m, d ) {
		publishToBus( "mrp.quick-message", "Following your location...", true );
		out.follow();
	});
	subscribeToBus( "mrp.geo-follow-done", function( s, m, d ) {
		out.unfollow();
	});
	
	subscribeToBus( "mrp.geo-locate", function( s, m, d ) {
		out.geoLocate();
	});
	subscribeToBus( "mrp.geo-locate-failed", function( s, m, d ) {
		out.geoLocateFailed( m );
	});
	subscribeToBus( "mrp.geo-location-done", function( s, m, d ) {
		out.finishGeoLocate( m.latLng, m.accuracy ); 
	} );
	subscribeToBus( "mrp.geo-location-ready", function( s, m, d ) {
		out.updateActiveBounds(); 
	} );
	subscribeToBus( "mrp.geo-location-refresh", function( s, m, d ) {
		_refineCancelled = true;
		out.updateActiveBounds( true /*force*/ ); 
	} );
	
	subscribeToBus( "orientation-change", function(s,m,d) {
		var latLng = _gmap.getCenter();
		setTimeout( function() {
			_gmap.setCenter( latLng );
		}, 200 );
	});
	
	subscribeToBus( "mrp.goto-manual-location", function( s, m, d ) {
		_refineCancelled = true;
		_geocoder.geocode( { address: m }, 
 			function(results, status) {
			    if (status == google.maps.GeocoderStatus.OK && results.length) {
					if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
						out._userCenter = results[0].geometry.location;
						_gmap.setCenter( results[0].geometry.location );
						setTimeout( function() {
							out.updateActiveBounds();
						}, 100 );
					}
				} else {
					publishToBus( "mrp.message", "Sorry, couldn't find the location" );
				}
			}
		);
	} );
	
	subscribeToBus( "mrp.find-listings", function( s, m, d ) {
		out.findListings( m );
	});
	subscribeToBus( "mrp.next-listing", function( s, m, d ) {
		out.lookupMarkerAndClick( m.key, m.idx );
	});
	subscribeToBus( "mrp.listing-details", function( s, m, d ) {
		openURL( mrpSettings.baseAppURL + "browse/details-" + m.id,
			"Back to Map" );
	});
	
	google.maps.event.addListener( _gmap, 'zoom_changed', function() {
		setTimeout( function() {
			out.updateActiveBounds();
		}, 200 );
	});
	google.maps.event.addListener( _gmap, 'dragend', function() {
		setTimeout( function() {
			out.updateActiveBounds();
		}, 200 );
	});
	
	/*
	google.maps.event.addListener( _gmap, 'bounds_changed', function() {
		setTimeout( function() {
			out.updateActiveBounds();
		}, 200 );
	});
	*/
	
	window.onListingsFound = function( json ) {
		out.placeListings( json );
	};
	
	return out;
};
/* ======= mobile-listing-info-window-js ======= */
function mrpMakeListingInfoWindowContent( win, marker, idx, map )
{
	if( !win ) {
		return;
	}
	
	var recipLogo = null;
	
	var listing = marker.data[idx];
	
	var out = [];
	
	out.push( "<div class='info_listingInfoContainer2'>" );
	out.push( "<table width='100%' border='0'>" );
	out.push( "<tr><td colspan='2' align='left'>" );
	
	var addr = [];
	if( "" != listing["UNIT_NUMBER"] ) {
		addr.push( listing["UNIT_NUMBER"] );
	}
	if( "" != listing["STREET_NUMBER"] ) {
		if( addr.length > 0 ) {
			addr.push( "-" );
		}
		addr.push( listing["STREET_NUMBER"] );
		addr.push( " " );
	}
	if( "" != listing["STREET_NAME"] ) {
		addr.push( listing["STREET_NAME"] );
		addr.push( " " );
	}
	if( "" != listing["STREET_TYPE"] ) {
		addr.push( listing["STREET_TYPE"] );
		addr.push( " " );
	}
	if( "" != listing["STREET_DIR"] ) {
		addr.push( listing["STREET_DIR"] );
		addr.push( " " );
	}
	
	out.push( "<div class='info_listingAddress'>" );
	out.push( addr.join( "" ) );
	out.push( "</div>" );
	
	out.push( "</td></tr>" );
	
	out.push( "<tr>" );
	out.push( "<td align='left' valign='middle'>" );
	out.push( "<div style='width: 120px; height: 80px; margin: auto; margin-top: 5px; margin-bottom: 0px; position: relative'>" );
   	
   	out.push( "<img width='120' height='80' src='" );
   	var photoUrl = mrpSettings.baseRestURL + listing["LIST_ID"] + "/image/first?w=120&h=80";
   	out.push( photoUrl );
   	out.push( "' " );
   	out.push( "onclick='mrpListingDetails(" );
   	out.push( listing["LIST_ID"] );
   	out.push( ")' style='cursor: pointer'>" );
	out.push( "<img border='0' width='80' height='80' style='cursor: pointer; position: absolute; left: 0; top: 0' " );
	out.push( "src='");
    out.push( mrpSettings.baseRestURL );
	out.push( listing["LIST_ID"] );
	out.push( "/img/ribbon/auto' " );
	out.push( "' " );
    out.push( "onclick='mrpListingDetails(" );
	out.push( listing["LIST_ID"] );
	out.push( ")'>" );
	out.push( "</div>" );
	out.push( "</td>" );
			
	out.push( "<td align='left' valign='middle'>" );
			
	out.push( "<div class='info_listingPrice'>" );
    var price = listing["PRICE"].replace( ".00", "" );
    out.push( price );
    out.push( "</div>" );
      
	out.push( "<div class='info_propertyType'>" );
	out.push( listing["PROPERTY_TYPE"] );
	out.push( "</div>" );
      
	out.push( "<div class='info_listingBedsBaths'>" );
	out.push( "Beds: " );
	out.push( listing["TOTAL_BEDROOMS"] );
	out.push( "&nbsp;&nbsp;Baths: " );
	out.push( listing["TOTAL_BATHS"] );
	out.push( "</div>" );
      
	out.push( "<div class='info_listingMlsNumber'>" );
	out.push( "MLS&reg;#: " );
	out.push( listing["MLS_NUM"] );
	out.push( "</div>" );
	
	out.push( "<div class='info_listingDetailsLink' onclick='mrpListingDetails(" );
    out.push( listing["LIST_ID"] );
    out.push( ")'>Listing Details</div>" );
     	
	out.push( "</td>" );
	out.push( "</tr>" );
	out.push( "</table>" );
			
	if( recipLogo ) {
		out.push( recipLogo );
	}
			
	out.push( "<div style='font-size: 11px; height: 13px; overflow: hidden; ' " +
      	"id='attribution" + listing["LIST_ID"] + "'>Listed by: ...</div>" );
    out.push( "</div>" );
			
	var len = marker.data.length;
	if( len > 1 ) {
		var key = map.latLngToKey( marker.getPosition() );
	 	out.push( "<div class='info_listingNav' style='border-top: 1px solid gray; padding: 5px;'>" );
	 	out.push( "<table width='100%' cellspacing='0' cellpadding='0'><tbody>" );
	 	out.push( "<tr>" );
	 	out.push( "<td width='33%' align='left'>" );
	 	if( idx > 0 ) {
		 	out.push( "<a class='info_listingPrev' href='javascript:;' onclick='mrpLookupMarkerAndClick(\"" +
		 		key + "\", " + (idx-1) + "); return false;'>" );
		 	out.push( "&#171; Prev" );
		 	out.push( "</a>" );
	 	}
	 	out.push( "</td><td width='34%' align='center'>" );
	 	out.push( "" + (idx+1) );
	 	out.push( " of " );
	 	out.push( len + "" );
		out.push( "</td><td width='33%' align='right'>" );
		if( idx + 1 < len ) {
			out.push( "<a class='info_listingNext' href='javascript:;' onclick='mrpLookupMarkerAndClick(\"" +
				key + "\", " + (idx+1) + "); return false;'>" );
			out.push( "Next &#187;" );
			out.push( "</a>" );
		}
		out.push( "</td></tr>" );
		out.push( "</tbody></table>" );
		out.push( "</div>" );
	 			
		if( mrpSettings.rebLogo ) {
			recipLogo = "<div style='position: absolute; right: 5px; bottom: 40px;'>" + 
				mrpSettings.rebLogo + "</div>";
		}
	}
    else {
    	if( mrpSettings.rebLogo ) {
			recipLogo = "<div style='position: absolute; right: 5px; bottom: 5px;'>" + 
				mrpSettings.rebLogo + "</div>";
		}
	}
	if( recipLogo ) {
		out.push( recipLogo );
	}
       
	win.set_content( out.join( "" ) );
 			
	setTimeout( function() {
		var getAttributionURL = mrpSettings.baseRestURL + listing["LIST_ID"] + "/attribution?firstOnly=true&_cb=mrpInsertAttribution";
		var _s = document.createElement( "script" );
		_s.id = "attribution_call_" + listing["LIST_ID"];
		_s.src = getAttributionURL;
		document.body.appendChild( _s );
 	}, 100 );
 }
 
function mrpInsertAttribution( txt, listingId )
{
	var s = $("attribution_call_" + listingId );
	if( s ) {
		s.parentNode.removeChild( s );
	}
	var insert = $("attribution" + listingId);
	if( insert && txt ) {
		insert.innerHTML = "Listed by: " + txt;
	}
}

function mrpListingDetails( listingId )
{
	publishToBus( "mrp.listing-details", { id: listingId } );
}

function mrpLookupMarkerAndClick( key, idx )
{
	publishToBus( "mrp.next-listing", { key : key, idx : idx } );
}
/* ======= mobile-search-dialog-js ======= */
function mrpMobileSearchDialog()
{
	var dlg = document.getElementById( "sdlg" );
	dlg.style.display = "block";
	dlg.style.opacity = 0.9;
	dlg.className = "search-dialog search-dialog-on";
}


