var markerImage = 'marker4.png';
var markerImageIE6 = 'marker4.gif';
var poiBubbleWidth = 250;
var poiBubbleMinWidth = 105;
var drawingLine = false;
var drawingRouteLine = false;
var isIE = (navigator.appName.indexOf("Microsoft") != -1);
var ieVersion = isIE ? parseFloat(navigator.appVersion.split("MSIE")[1]) : 7;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1);
var tids = "";
var orgLoc = location.hostname;
var orgLocJams = location.hostname;
var isDistShown = false;
var isOverview = true;
var isCover = false;
var isZoom = true;
var isCross = false;
var isScale = true;
var isTrans = true;
var fastZoom = false;
var isUI = true;
function min(a, b) { return Math.min(a, b); }
function max(a, b) { return Math.max(a, b); }
function dummy() {}
function in_array(el, arr) {
  if ( arr.length )
    for (var i = 0; i < arr.length; i++ )
	  if ( arr[i] === el ) return true;
  return false;
}
function sendRequest(url, callback, method)
{
  var xmlhttp;
  if (typeof XMLHttpRequest != 'undefined')
    xmlhttp = new XMLHttpRequest();
  else 
    try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
    catch (e) { try {xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) {} }
  xmlhttp.open(method || "GET", url, true);
  if (method == "POST")
  {
    xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xmlhttp.setRequestHeader('Content-length', '0');
  }
  xmlhttp.onreadystatechange = function() 
  { 
    if (xmlhttp.readyState == 4)
    {
      callback(xmlhttp);
      xmlhttp.onreadystatechange = dummy;
    }
  }
  xmlhttp.send("");
}
var MAX_ZOOM_LEVEL = 14;
var zFromZoomLevel = function(zoomLevel) { return 17 - zoomLevel; }
var zoomLevelFromZ = function(z) { return 17 - z; }
var geoLeft = -20000000;
var geoRight = 22537507;
var geoTop = 16500000;
var geoBottom = -16500000;
var geoFromPxX = function(px) { return geoLeft + px; }
var pxFromGeoX = function(geo) { return geo - geoLeft; }
var geoFromPxY = function(px) { return geoTop - px; }
var pxFromGeoY = function(geo) { return geoTop - geo; }
var getScale = function(zoomLevel) { return Math.pow(2, zoomLevel)*1.194329; }
var trt = 0;
var tileGetter = function(urlFunction, type)
{
  return function(x1, y1, x2, y2, zoomLevel)
  {
    var tileSize = 256*getScale(zoomLevel);
    var worldSize = Math.pow(2, zFromZoomLevel(zoomLevel));
    var i1 = Math.floor(geoFromPxX(x1)/tileSize);
    var i2 = Math.ceil(geoFromPxX(x2)/tileSize);
    var j1 = Math.floor(geoFromPxY(y2)/tileSize);
    var j2 = Math.ceil(geoFromPxY(y1)/tileSize);
    var tiles = [];
    for (var i = i1; i < i2; i++)
      for (var j = j1; j < j2; j++)
      {
        var x = i*tileSize;
        var y = j*tileSize;
        var ii = (i + 3*worldSize/2)%worldSize - worldSize/2;
		var url = urlFunction(zFromZoomLevel(zoomLevel), ii, j);
		if ( (url.indexOf("JamJS") != -1 || url.indexOf("Jams") != -1) && zFromZoomLevel(zoomLevel) < 9 )
			continue;
		if (url.indexOf("JamJS") == -1 && url.indexOf("Jams") == -1) {
			trt = (Math.abs(i) + Math.abs(j)) % 10;
			url = "http://t" + trt + "." + orgLoc + url; }
		else if (url.indexOf("JamJS") == -1 && url.indexOf("Jams") != -1) {
			trt = (Math.abs(i) + Math.abs(j)) % 10;
			url = orgLocJams.indexOf("corp") == -1? "http://j" + trt + "." + orgLocJams + url: "http://" + orgLocJams + url;
		}
        tiles.push({ worldSize: worldSize, i : i, j : j, x: pxFromGeoX(x), y: pxFromGeoY(y + tileSize), width: tileSize, height: tileSize, url: url, type: type });
      }
    return tiles;
  }
}
var getOffsetLeft = function(div)
{
  var ret = 0;
  while (div && div.tagName != 'HTML')
  {
    ret += div.offsetLeft;
    div = div.offsetParent;
  }
  return ret;
}
var getOffsetTop = function(div)
{
  var ret = 0;
  while (div && div.tagName != 'HTML')
  {
    ret += div.offsetTop;
    div = div.offsetParent;
  }
  return ret;
}
var returnFalse = function() { return false; }
var brokenTileSuffixes = {};
var totalImagesLoading = 0;
var regularTileType = {
  create: function(url, callback, useErrorImage)
  {
    var img = document.createElement("img");
    img.style.position = "absolute";
    img.style.visibility = "hidden";
    var dec = 1;
    var decrement = function()
    {
      totalImagesLoading -= dec;
      dec = 0;
    }
    img.onload = function()
    {
      decrement();
      img.onload = "";
      img.onerror = "";
      img.style.visibility = "visible";
      callback();
    }
    img.onerror = function()
    {
      decrement();
      img.onload = "";
      img.onerror = "";
      brokenTileSuffixes[url] = "&" + Math.random();
      if (useErrorImage)
      {
        img.src = "map/noimages_3.jpg";
        img.style.visibility = "visible";
      }
      callback();
    }
    setTimeout(decrement, 10000);
    totalImagesLoading += 1;
    img.src = url;// + (brokenTileSuffixes[url] || "");
    img.onmousedown = returnFalse;
    img.ondragstart = returnFalse;
    return img;
  },
  showOnZoom: true
};
function idFromXYZ(x, y, z)
{
  return ("x" + x + "y" + y + "z" + z + "s" + lastRefreshSuffix);
}
function idFromUrl(url)
{
  return idFromXYZ(/x=([-]?\d+)/.exec(url)[1], /y=([-]?\d+)/.exec(url)[1], /z=(\d+)/.exec(url)[1]);
}
function makeImageMap(img, url)
{
  img.style.zIndex = 9;
  img.border = 0;
}
var overlayTileType;
if (!isIE || (ieVersion > 6))
{
  overlayTileType = {
    create: function(url, callback, useErrorImage)
    {
      var img = regularTileType.create(url, callback, false);
      makeImageMap(img, url);
      return img;
    }
  }
}
else
{
  overlayTileType = {
    create: function(url, callback)
    {
      var overlayDiv = document.createElement("div");
      overlayDiv.style.zIndex = 9;
      var div2 = document.createElement("div");
      div2.style.position = "absolute";
      div2.style.zIndex = 9;
      setBgAbsolute(div2, url);
      size(div2, 256, 256);
      overlayDiv.appendChild(div2);
      overlayDiv.style.position = "absolute";
      overlayDiv.className = "overlay";
      overlayDiv.style.visibility = "visible";
      var img = document.createElement('img');
      img.setAttribute("src","map/black_overlay.png");
      img.style.position = "absolute";
      div2.onmousedown = div2.ondragstart = img.onmousedown = img.ondragstart = returnFalse;
      makeImageMap(img, url);
      overlayDiv.appendChild(img);
      callback();
      return overlayDiv;
    }
  };
};
overlayTileType.showOnZoom = false;

var jamsTooltipDiv = false;
var jamsTooltipAlt = false;
var poiTooltipDiv = false;
var poiTooltipAlt = false;
var poiTooltipFlag = 0;

function poiTooltipTable(html, id) {
	return '<div id="bubbleFrame'+id+'" class="poi-tooltip q1"'+(poiBubbleWidth ? ' style="width:'+poiBubbleWidth+'px;"' : '')+'>\
	<table class="tabright">\
		<tr class="top-tr">\
			<td class="topleft1"><img src="http://img.mail.ru/0.gif" width="16" height="1" alt=""></td>\
			<td class="topleft2"><img src="http://img.mail.ru/0.gif" width="70" height="1" alt=""></td>\
			<td class="top" width="100%">&nbsp;</td>\
			<td class="topright"><img src="http://img.mail.ru/0.gif" width="16" height="1" alt=""></td>\
		</tr>\
		<tr class="center-tr">\
			<td class="left">&nbsp;</td>\
			<td colspan="2" class="center"><span id="contentSpan'+id+'">'+html+'</span></td>\
			<td class="right">&nbsp;</td>\
		</tr>\
		<tr class="bottom-tr">\
			<td class="bottomleft1">&nbsp;</td>\
			<td class="bottomleft2">&nbsp;</td>\
			<td class="bottom">&nbsp;</td>\
			<td class="bottomright">&nbsp;</td>\
		</tr>\
	</table>\
	<table class="tableft">\
		<tr class="top-tr">\
			<td class="topleft1"><img src="http://img.mail.ru/0.gif" width="16" height="1" alt=""></td>\
			<td class="top" width="100%">&nbsp;</td>\
			<td class="topleft2"><img src="http://img.mail.ru/0.gif" width="70" height="1" alt=""></td>\
			<td class="topright"><img src="http://img.mail.ru/0.gif" width="16" height="1" alt=""></td>\
		</tr>\
		<tr class="center-tr">\
			<td class="left">&nbsp;</td>\
			<td colspan="2" class="center"><span id="contentSpan'+id+'">'+html+'</span></td>\
			<td class="right">&nbsp;</td>\
		</tr>\
		<tr class="bottom-tr">\
			<td class="bottomleft1">&nbsp;</td>\
			<td class="bottom">&nbsp;</td>\
			<td class="bottomleft2">&nbsp;</td>\
			<td class="bottomright">&nbsp;</td>\
		</tr>\
	</table>\
</div>';
}
var showJamsTooltip = function(alt)
{
  hidePoiTooltip(0);
  if (drawingLine /*|| drawingRouteLine*/) return;
  if (alt != jamsTooltipAlt)
  {
    jamsTooltipDiv.innerHTML = poiTooltipTable(alt, 'Jams');
    jamsTooltipAlt = alt;
    show(jamsTooltipDiv);
	if( $('contentSpanJams').offsetWidth < poiBubbleWidth - 35 )
		$('bubbleFrameJams').style.width = ($('contentSpanJams').offsetWidth + 35) + 'px';
  }
}
var hideJamsTooltip = function()
{
  if (jamsTooltipAlt)
  {
    hide(jamsTooltipDiv);
    jamsTooltipAlt = false;
  }
}
var showPoiTooltip = function(alt)
{
  if (drawingLine /*|| drawingRouteLine*/) return;
  if (alt != poiTooltipAlt) {
	poiTooltipDiv.innerHTML = poiTooltipTable(alt, 'Poi');
    poiTooltipAlt = alt;
  }
  poiTooltipFlag += 1;
  show(poiTooltipDiv);
	if( $('contentSpanPoi').offsetWidth < poiBubbleWidth - 35 ) {
		var w = $('contentSpanPoi').offsetWidth + 35;
		$('bubbleFramePoi').style.width = (w < poiBubbleMinWidth ? poiBubbleMinWidth : w) + 'px';
	}
}
var hidePoiTooltip = function(mode)
{
  if (mode == 1) { poiTooltipFlag += 1; return; } 
  if (mode == 2) { poiTooltipFlag -= 1; if (poiTooltipFlag > 0) return; }
  poiTooltipFlag = 0;
  if (poiTooltipAlt) hide(poiTooltipDiv);
}
var jamsResponseCache, jamsSpanCache, lastRefreshSuffix;
function makeNewRefreshSuffix()
{
  lastRefreshSuffix = Math.round(Math.random()*1000000);
  jamsResponseCache = {};
  jamsSpanCache = {};
}
makeNewRefreshSuffix();

var textTileType = {
  create: function(url, callback)
  {
    callback();

    var ret = document.createElement("span");
    ret.style.position = 'absolute';

    var callback = function(xmlhttp)
    {
      if ((xmlhttp.status != 200) || (xmlhttp.responseText == ""))
        return;

      jamsResponseCache[url] = { status: xmlhttp.status, responseText: xmlhttp.responseText };

      var lc = [];
      try { lc = eval(xmlhttp.responseText); }
      catch (e) { return; }
      var spans = [];
      for (var i = 0; i < lc.length; i++)
      {
        var c = lc[i];
        var alt = '';
        for (var key in (temp = { "Улица": 5, "Скорость": 1, "Начало": 7, "Конец": 9 }))
          if (c[0][temp[key]] != "")
            alt += key.bold() + ": " + c[0][temp[key]] + ( key == "Скорость" ? " км/ч" : "") + "<br />";
        for (var j = 0; j <= c.length - 4; j += 2)
        {
          var x1 = c[1 + j]/100, y1 = c[2 + j]/100, x2 = c[3 + j]/100, y2 = c[4 + j]/100;
          var dx = x2 - x1, dy = y2 - y1;
          var r = Math.sqrt(dx*dx + dy*dy);
          spans.push([dy/r, -dx/r, (x2*y1 - x1*y2)/r, (dx*(x1 + x2) + dy*(y1 + y2))/(2*r), r, alt]);
        }
      }
      jamsSpanCache[idFromUrl(url)] = spans;
    }

    var interval = setInterval(function()
    {
      if (totalImagesLoading != 0)
        return;
      clearInterval(interval);
      if (jamsResponseCache[url])
        callback(jamsResponseCache[url]);
      else
	  {
	    //debug(url);
        sendRequest(url, callback);
	  }
    }, 2000 + Math.random()*2000);

    return ret;
  }
};

var poiTileType = {
  showOnZoom: false,
  create: function(url, callback)
  {
    callback();
    var ret = document.createElement("div");
    ret.style.position = 'absolute';
    ret.style.zIndex = 10;
    position(ret, 0, 0);
    sendRequest(url, function(xmlhttp)
    {
      if ((xmlhttp.status == 200) && (xmlhttp.responseText != ""))
      { 
        SearchResults = [];
        eval(xmlhttp.responseText);
        aPoi = SearchResults;
        var im = aPoi.length;
        var g = getScale(map.getZoomLevel()); 
        var k = merc_x(1)/g;
        var xPxG2 = $("around_map").clientWidth*g/2;
        var yPxG2 = $("around_map").clientHeight*g/2;
        var a;
        var stats = {};
    var dX = 0, dY = 0, xRem = 170, yRem = 110;
        for (var i = 0; i < im; i++)
        {
          aPoi[i].xPx = (aPoi[i].Lon - lon(map.getX() - xPxG2))*k;
          aPoi[i].yPx = (-merc_y(aPoi[i].Lat) + merc_y(lat(map.getY() - yPxG2)))/g;
          var imgRet = document.createElement("img");
          imgRet.id = 'poi' + i;
          var code = aPoi[i].TypeCode;
          imgRet.src = aPoi[i].Image;
          imgRet.style.position = 'absolute';
		  //var iconSize = map.getZoomLevel() < 6 ? 29 - 2 * map.getZoomLevel() : 19;
          positionSize(imgRet, (aPoi[i].xPx - 9).toFixed(0), (aPoi[i].yPx - 9).toFixed(0), 19, 19); //iconSize, iconSize);
          imgRet.style.cursor = 'default';
          aPoi[i].html = '<b>' + aPoi[i].Title.replace(/\\'/g,"'") + '</b>';
      switch (aPoi[i].Flags) {
        case '1': {
          var titleRet = document.createElement("div");
          titleRet.className = 'poi_topright';
          if ( aPoi[i].xPx + xRem > $("around_map").offsetWidth ) {
            if ( aPoi[i].yPx - yRem < 0 ) { titleRet.className = 'poi_bottomleft'; dX = -200; dY = 0; } 
            else { titleRet.className = 'poi_topleft'; dX = -200; dY = -120; }
          } else if ( aPoi[i].yPx - yRem < 0 ) { titleRet.className = 'poi_bottomright'; dX = -9; dY = 0; } 
            else { dX = -9; dY = -120; }
          positionSize(titleRet, (aPoi[i].xPx + dX).toFixed(0), (aPoi[i].yPx + dY).toFixed(0), 199, 118);
          titleRet.innerHTML = '<div class="inner"><iframe frameborder="0" scrolling="no" allowTransparency="true" src="' + aPoi[i].Link + '"></iframe></div>';
          ret.appendChild(titleRet); } break;
        case '2': {
          var titleRet = document.createElement("div");
          titleRet.onmousedown = cancelEvent;
          titleRet.className = 'type2_topright';
          if ( aPoi[i].xPx + xRem > $("around_map").offsetWidth ) {
            if ( aPoi[i].yPx - yRem < 0 ) { titleRet.className = 'type2_bottomleft'; dX = -200; dY = 0; } 
            else { titleRet.className = 'type2_topleft'; dX = -200; dY = -120; }
          } else if ( aPoi[i].yPx - yRem < 0 ) { titleRet.className = 'type2_bottomright'; dX = -9; dY = 0; } 
            else { dX = -9; dY = -120; }
          positionSize(titleRet, (aPoi[i].xPx + dX).toFixed(0), (aPoi[i].yPx + dY).toFixed(0), 199, 118);
          if (aPoi[i].Address.length > 0) aPoi[i].html += '<br>' + aPoi[i].Address;
          if (aPoi[i].Link.length > 0) aPoi[i].html += ' <br><a href="' + aPoi[i].Link + '" target="_blank">Подробнее...</a>';
          titleRet.innerHTML = '<div class="inner">' + aPoi[i].html + '</div>';
          ret.appendChild(titleRet); }
	  break;
	  case '3' :
        if (aPoi[i].Link.length > 0) {
			aPoi[i].html = '<a href="' + aPoi[i].Link + '" target="_blank"><b>' + aPoi[i].Title.replace(/\\'/g,"'") + '</b></a>';
	        imgRet.onmouseover = poiViewHint;
    	    imgRet.onmouseout = poiViewHint;
		}
	  break;
	  case '4' :
	  	var titleRet = document.createElement("div");
		titleRet.className = 'poi_topright';
		titleRet.style.visibility = 'hidden';
		position(titleRet, aPoi[i].xPx.toFixed(0), aPoi[i].yPx.toFixed(0));
		titleRet.innerHTML = '<iframe style="width:500px; height:500px; position:absolute; bottom:0; left:0;" frameborder="0" scrolling="auto" allowTransparency="true" src="'+aPoi[i].Link+'"></iframe>';
		(function(i) {
			var t = null;
			i.onmouseover = function() {
				var _t = this;
				this.previousSibling.style.visibility = 'visible';
				this.onmouseout = this.previousSibling.onmouseout = function() {
					t = setTimeout(function() {
						_t.previousSibling.style.visibility = 'hidden';
					}, 300);
				}
				this.onmousemove = this.previousSibling.onmousemove = this.onmouseover = this.previousSibling.onmouseover = function() {
					clearTimeout(t);
					_t.previousSibling.style.visibility = 'visible';
				}
			}
		})(imgRet);
		ret.appendChild(titleRet);
	  break;
      default: {
        if (aPoi[i].Address.length > 0) aPoi[i].html += '<br>' + aPoi[i].Address;
        if (aPoi[i].Link.length > 0) aPoi[i].html += ' <br><a href="' + aPoi[i].Link + '" target="_blank">Подробнее...</a>';
        imgRet.onmouseover = poiViewHint;
        imgRet.onmouseout = poiViewHint; }
      }
          imgRet.onmousedown = imgRet.ondragstart = returnFalse;
          ret.appendChild(imgRet);
          stats[code] = (stats[code] || 0) + 1;
        }
        if (poiTileType.onUpdatePoi)
          poiTileType.onUpdatePoi(stats);
      }
    });
    return ret;
  }
}
var aPoi = [];
var poiViewHint = function(e)
{
  if (!e) e = window.event;
  var n = e.target || e.srcElement;
  var poiI = parseInt(n.id.substr(3));
  if (e.type == "mouseover") {
  	showPoiTooltip(aPoi[poiI].html);
	position(poiTooltipDiv, parseInt(n.style.left) + 8, parseInt(n.style.top) + 8);
	 if ( poiTooltipDiv.style.display == 'block' ) {
	  	var aroundTop = getOffsetTop($("around_map"));
		var aroundLeft = getOffsetLeft($("around_map"));
		var key = aroundTop + $('bubbleFramePoi').offsetHeight > eventY(e) ? 'b' : 't';
		key += aroundLeft + $("around_map").offsetWidth < eventX(e) + $('bubbleFramePoi').offsetHeight ? 'l' : 'r';
		$('bubbleFramePoi').className = "poi-tooltip q" + { tr:1, tl:4, br:2, bl:3 }[key];
	  }
  }
  if (e.type == "mouseout") setTimeout(function() {hidePoiTooltip(2);}, 3000);
}

var imageTileUrlFunction = function(t, isRefreshing)
{
  return function(z, i, j) { return "/TileSender.aspx?ModeKey=tiles&t=" + t + "&z=" + z + "&x=" + i + "&y=" + j + (isRefreshing ? ("&" + lastRefreshSuffix) : ""); }
}
var getMap = tileGetter(imageTileUrlFunction("Maps"), regularTileType);
var getTiles = tileGetter(imageTileUrlFunction("Images"), regularTileType);
var getJams = tileGetter(imageTileUrlFunction("Jams", true), overlayTileType);
var getTextTiles = tileGetter(imageTileUrlFunction("JamJS", true), textTileType);
var getPoiTile = function(x1, y1, x2, y2, zoomLevel, poiTypes, minIndex, maxIndex)
{
  return {
    x: x1, y: y1, width: 0, height: 0,
    url: "/POIInArea.aspx"
      + "?x1=" + lon(x1).toFixed(4)
      + "&y1=" + lat(y1).toFixed(4)
      + "&x2=" + lon(x2).toFixed(4)
      + "&y2=" + lat(y2).toFixed(4)
	  + "&z=" + zFromZoomLevel(zoomLevel)
      + "&types=" + poiTypes.join(",")
      + "&ids=" + tids,
    type: poiTileType
  };
} 

var getMapAndJams = function(x1, y1, x2, y2, zoomLevel)
{ 
  var t1 = getMap(x1, y1, x2, y2, zoomLevel);
  var t2 = getJams(x1, y1, x2, y2, zoomLevel);
  var t3 = getTextTiles(x1, y1, x2, y2, zoomLevel);
  for (var i = 0; i < t2.length; i++) t1.push(t2[i]); 
  for (var i = 0; i < t3.length; i++) t1.push(t3[i]);
  return t1;
}
var getTilesAndJams = function(x1, y1, x2, y2, zoomLevel)
{
  var t1 = getTiles(x1, y1, x2, y2, zoomLevel);
  var t2 = getJams(x1, y1, x2, y2, zoomLevel);
  var t3 = getTextTiles(x1, y1, x2, y2, zoomLevel);
  for (var i = 0; i < t2.length; i++) t1.push(t2[i]);
  for (var i = 0; i < t3.length; i++) t1.push(t3[i]);
  return t1;
}
function prettify(length)
{
  if (length < 1000) return Math.round(length) + " м";
  if (length < 100000) return (Math.round(length/10)/100) + " км";
  return Math.round(length/1000) + " км";
}
function prettifyArea(area)
{
  if (area < 100000) return Math.round(area) + " кв. м";
  if (area < 100000000) return ("" + (Math.round(area/10000)/100)).replace(".", ",") + " кв. км";
  return (Math.round(area/1000000)) + " кв. км";
}
function compatEvent(event) {return event || window.event; }
function eventX(event)
{
  if (document.documentElement && document.documentElement.scrollLeft) theLeft = document.documentElement.scrollLeft;
  else theLeft = document.body.scrollLeft;
  return compatEvent(event).clientX + theLeft;
}
function eventY(event)
{
  if (document.documentElement && document.documentElement.scrollTop) theTop = document.documentElement.scrollTop;
  else theTop = document.body.scrollTop;
  return compatEvent(event).clientY + theTop;
}
function isLeftMouseButton(event)
{
  event = event || window.event;
  return (!event.shiftKey && (
    (isIE && (event.button == 1)) ||
    (!isIE && (event.button == 0))
  ));
}
function HandlerMode(div, event, handler)
{
  this.div = div;
  this.event = event;
  this.handler = handler;
}
function htmlspecialchars(html) {
	return html
		.replace(/&/g, "&amp;")
		.replace(/</g, "&lt;")
		.replace(/>/g, "&gt;")
		.replace(/"/g, "&quot;");
	;
}
HandlerMode.prototype.set = function()
{
  if (this.div.attachEvent) this.div.attachEvent("on"+this.event, this.handler);
  if (this.div.addEventListener) this.div.addEventListener(this.event, this.handler, false);
}
HandlerMode.prototype.clear = function()
{
  if (this.div.detachEvent) this.div.detachEvent("on"+this.event, this.handler);
  if (this.div.removeEventListener) this.div.removeEventListener(this.event, this.handler, false);
}
function GlobalHandlerMode(event, handler)
{
  return new HandlerMode(document.documentElement, event, handler);
}
function VisibilityMode(div) {this.div = div; }
VisibilityMode.prototype.set = function() { show(this.div); }
VisibilityMode.prototype.clear = function() { hide(this.div); }
function HoverMode(div, mode)
{
  return new Modes(
    new HandlerMode(div, "mouseover", function(event) 
    {
      event = compatEvent(event);
      var reltg = event.relatedTarget || event.fromElement;
	  try {
        while (reltg && reltg != div && reltg.tagName != 'HTML')
          reltg = reltg.parentNode;
	  } catch(e) {}
      if (reltg != div) 
        mode.set();
    }),
    new HandlerMode(div, "mouseout", function(event) 
    {
      event = compatEvent(event);
      var reltg = event.relatedTarget || event.toElement;
	  try {
        while (reltg && reltg != div && reltg.tagName != 'HTML')
          reltg = reltg.parentNode;
	  } catch(e) {}
      if (reltg != div) 
        mode.clear();
    })
  );
}
function Modes() {this.modes = Modes.arguments; }
Modes.prototype.set = function() 
{
  for (var i = 0; i < this.modes.length; i++) 
   if (this.modes[i]) 
     this.modes[i].set();
}
Modes.prototype.clear = function()
{
  for (var i = 0; i < this.modes.length; i++) 
    if(this.modes[i]) 
      this.modes[i].clear();
}
function deferred(func, dt)
{
  var timeout = false;
  if (!dt) dt = 100;
  return function() {
    if (dontReloadMapAreas) return;
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(function() { timeout = false; func(); }, dt);
  }
}
function newElement(tagName, props)
{
  var elem = document.createElement(tagName);
  if (props)
    for (var key in props)
      if (props[key]) elem[key] = props[key];
  return elem;
}
function newDiv(className, innerHTML)
{
  return newElement("div", { className: className, innerHTML: innerHTML });
}
function appendText(div, text)
{
  var span = document.createElement("span");
  span.innerHTML = text;
  div.appendChild(span);
}
function show(div)
{
  div.style.visibility = "visible";
  div.style.display = "block";
}
function hide(div)
{
  div.style.visibility = "hidden";
  div.style.display = "none";
}
function position(div, x, y)
{
  if (isNaN(x) || isNaN(y)) return;
  div.style.left = x + "px";
  div.style.top = y + "px";
}
function size(div, w, h)
{
  if (isNaN(w) || isNaN(h) || w < 0 || h < 0) return;
  div.style.width = w + "px";
  div.style.height = h + "px";
}
function positionSize(div, x, y, w, h)
{
  position(div, x, y);
  size(div, w, h);
}
function setVisible(div, flag) { (flag ? show : hide)(div); }
function setOpacity(div, opacity)
{
  div.style.opacity = opacity;
  div.style["-moz-opacity"] = opacity;
  if ((opacity == "") || (opacity == 1))
    div.style.filter = "";
  else
    div.style.filter = "alpha(opacity=" + Math.round(opacity*100) + ")";
}
function $(id) { return document.getElementById(id); }
function $1(name) { window[name + "$"] = function(id, a, b, c, d) { window[name]($(id), a, b, c, d); } }
$1('show'); $1('hide'); $1('setVisible'); $1('size'); $1('positionSize');
function setBgAbsolute(t, imageName)
{
  if (isIE && (ieVersion < 7))
    t.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imageName + "',sizingMethod='scale')";
  else t.style.backgroundImage = "url('" + imageName + "')";
}
function setBg(t, imageName) { setBgAbsolute(t, "map/" + imageName); }
function constrain(a, t, b) { return t < a ? a : t > b ? b : t; }
function World(div, funcs)
{
  var callbacks = [];
  var getSemiWidth = function() { return div.clientWidth/2; }
  var getSemiHeight = function() { return div.clientHeight/2; }
  var ret = {
    div: div,
    worldX: function(x) { return (x - getSemiWidth() - getOffsetLeft(div))*ret.getScale() + ret.getX(); },
    worldY: function(y) { return (y - getSemiHeight() - getOffsetTop(div))*ret.getScale() + ret.getY(); },
    getScale: function() { return getScale(ret.getZoomLevel()); },
    screenX: function(x) { return Math.round((x - ret.getX())/ret.getScale() + getSemiWidth()); },
    screenY: function(y) { return Math.round((y - ret.getY())/ret.getScale() + getSemiHeight()); },
    onRepaint: function(callback, flag) { callbacks.push(callback); },
    repaint: function() { for (var i = 0; i < callbacks.length; i++) callbacks[i](); }
  };
  for (var name in funcs) ret[name] = funcs[name];
  return ret;
}
function FreeWorld(div, width, height, maxZoomLevel)
{
  var position = false;
  var ret = new World(div, {
    navigateTo: function(x, y, zoomLevel){
	  /* 535745 */
	  x = (x = x % width) < 0 ? width + x : x;
	  /* / 535745 */
      position = {
        x: constrain(0, x, width),
        y: constrain(0, y, height),
        zoomLevel: constrain(0, zoomLevel, maxZoomLevel)
      };
      ret.repaint();
    },
    getX: function() { return position.x; },
    getY: function() { return position.y; },
    getZoomLevel: function() { return position.zoomLevel; },
    setZoomLevel: function(zLevel) { position.zoomLevel = zLevel; } 
  });
  return ret;
}
function TiedWorld(div, world, zoomFunction)
{
  var ret = new World(div, {
    getX: world.getX,
    getY: world.getY,
    getZoomLevel: zoomFunction
  });
  world.onRepaint(ret.repaint);
  return ret;
}
var dontReloadMapAreas = false;
function MapArea(world, tileFunction, useErrorImage)
{
  var div = world.div;
  var tiles = {};
  var loadedInThisGeneration = 0;
  var totalInThisGeneration = 0;
  var currentGeneration = 0;
  var tilesAreLoading = false;
  var tileLoadTimeout = false;
  var removeTilesIf = function(callback){
    var toRemove = [];
    for (var id in tiles) if(callback(tiles[id]))toRemove.push(id);
    for (var i in toRemove){
      var tile = tiles[toRemove[i]];
      var d = tile.div;
      d.onmousedown = d.onmouseup = onmouseout = d.onmousemove = "";
      div.removeChild(d);
      delete tiles[toRemove[i]];
    }
  }
  var markTileLoaded = function(tile){
    tile.loaded = true;
    if(tile.generation == currentGeneration)loadedInThisGeneration += 1;
    if (loadedInThisGeneration == totalInThisGeneration) removeTilesIf(function(tile) { return (tile.generation != currentGeneration); });
  }
  var tileLoadedMarker = function(tile){ return function() { markTileLoaded(tile); }; }
  var canLoad = true;
  var ret = {
    div: div,
    repaint: function(){
      ret.moveTiles();
      if (!tilesAreLoading && !dontReloadMapAreas)
	  {
        tilesAreLoading = true;
        tileLoadTimeout = setTimeout(ret.loadTiles, 50/*150*/);
		//ret.loadTiles();
		//tilesAreLoading = false;
      }
    },
    moveTiles: function(){
      if (tilesAreLoading){
        tilesAreLoading = false;
        clearTimeout(tileLoadTimeout);
      }
      for (var id in tiles)
        ret.moveTile(tiles[id]);
      removeTilesIf(function(tile){
        return ((!tile.type.showOnZoom/* || fastZoom*/) && (tile.zoomLevel != world.getZoomLevel()));
      });
    },
    moveTile: function(tile, sw, sh){
	  /* 535745 */
	  if ( tile.url.match(/TileSender/) ) {
		  var direct = lon(world.getX());
		  if ( Math.abs(direct) > 90 && (direct > 0 && tile.i < 0 || direct < 0 && tile.i > 0) ) {
		    var i = tile.worldSize - Math.abs(tile.i);
			tile.i = tile.i > 0 ? -i : i;
		  }
		  tile.x = pxFromGeoX(tile.i * tile.width);
	  }
	  /* / 535745 */
      var left = world.screenX(tile.x);
      var top = world.screenY(tile.y);
      positionSize(
        tile.div,
        left,
        top,
        (world.screenX(tile.x + tile.width) - left),
        (world.screenY(tile.y + tile.height) - top)
      );
    },
    loadTiles: function(){
      tilesAreLoading = false;
      var scale = world.getScale();
      var semiWidth = div.clientWidth*scale/2;
      var semiHeight = div.clientHeight*scale/2;
      var left = world.getX() - semiWidth;
      var right = world.getX() + semiWidth;
      var top = world.getY() - semiHeight;
      var bottom = world.getY() + semiHeight;
      var newTiles = tileFunction(left, top, right, bottom, Math.round(world.getZoomLevel()));
      if (newTiles){
        for (var i in newTiles)
          newTiles[i].zoomLevel = world.getZoomLevel();
        currentGeneration += 1;
        loadedInThisGeneration = 0;
        totalInThisGeneration = newTiles.length;
        for (var i in newTiles){
          var tile = newTiles[i];
          var oldTile = tiles[tile.url];
          if (oldTile){
            oldTile.generation = currentGeneration;
            if(oldTile.loaded)markTileLoaded(oldTile);
            continue;
          }

          tile.generation = currentGeneration;
          tile.div = tile.type.create(
            tile.url,
            tileLoadedMarker(tile),
            useErrorImage
          );
          div.appendChild(tile.div);
          tiles[tile.url] = tile;
          ret.moveTile(tile);
        }
      }

      removeTilesIf(function(tile){
        var z = world.getZoomLevel();
        return (
          (((!tile.loaded || !tile.type.showOnZoom/* || fastZoom*/)&& (tile.zoomLevel != z))) ||
          (
            (tile.generation != currentGeneration) &&
            (
              (tile.x > right) ||
              (tile.x + tile.width < left) ||
              (tile.y > bottom) ||
              (tile.y + tile.height < top)
            )
          )
        );
      });
    }
  };
  disableSelect(div);
  world.onRepaint(ret.repaint);
  return ret;
}
function disableSelect(div)
{
  new HandlerMode(div, "mousemove", function(){
    if(window.disableDeselect)return;
    if(document.selection && document.selection.empty)
      try{document.selection.empty();}
      catch(e){}
    else if(window.getSelection)window.getSelection().removeAllRanges();
  }).set();
}
var disableDeselect = false;
function cancelEvent(e)
{
  e = e || window.event;
  if(e.preventDefault)e.stopPropagation();
  else{
    e.returnValue = false;
    e.cancelBubble = true;
  }
}
function cancelRightClick(e)
{
  e = e || window.event;
  if (e.preventDefault)
    e.preventDefault();
}
function parseHex(hex) { return parseInt("0x" + hex); }
function clipSegment(segment, a, b, c)
{
  if (!segment)
    return false;
  var x1 = segment.x1, x2 = segment.x2, y1 = segment.y1, y2 = segment.y2;
  var s1 = a*x1 + b*y1 + c;
  var s2 = a*x2 + b*y2 + c;
  var f1 = (s1 >= 0);
  var f2 = (s2 >= 0);
  if (f1 && f2)
    return segment;
  if (!f1 && !f2)
    return false;
  var t = (s2/(s2-s1));
  return {
    x1: f1 ? x1 : x2,
    y1: f1 ? y1 : y2,
    x2: t*x1 + (1-t)*x2,
    y2: t*y1 + (1-t)*y2
  }
}
function removeChildrenByTagName(elem, tagName)
{
  var toRemove = [];
  for (var i = 0; i < elem.childNodes.length; i++)
  {
    var node = elem.childNodes[0];
    if (node.tagName == tagName)
      toRemove.push(node);
  }
  for (var i = 0; i < toRemove.length; i++)
    elem.removeChild(toRemove[i]);
}
var DrawableArea = function(element, getWidth, getHeight)
{
  this.element = element;
  this.getWidth = getWidth;
  this.getHeight = getHeight;
}
DrawableArea.prototype.clear = function()
{
  if (isIE) this.element.innerHTML = "";
  else {
    while (this.element.childNodes.length > 0)
      this.element.removeChild(this.element.childNodes[0]);
  }
}
var svgns = "http://www.w3.org/2000/svg";
DrawableArea.prototype.drawLine = function(x1, y1, x2, y2, color, thickness, dash)
{
  var seg = { x1: x1, x2: x2, y1: y1, y2: y2 };
  seg = clipSegment(seg, 1, 0, 0);
  seg = clipSegment(seg, 0, 1, 0);
  seg = clipSegment(seg, -1, 0, this.getWidth());
  seg = clipSegment(seg, 0, -1, this.getHeight());
  if (!seg)
    return;
  if (isIE)
  {
    var elem = document.createElement('v:line');
    elem.from = seg.x1 + "," + seg.y1;
    elem.to = seg.x2 + "," + seg.y2;
    elem.strokeweight = thickness;
    elem.strokeColor = color;
    if (dash)
    {
      var stroke = document.createElement("v:stroke");
      stroke.dashStyle = "dash";
      elem.appendChild(stroke);
    }
    this.element.appendChild(elem);
    this.element.appendChild(document.createTextNode(""));
  } 
  else
  {
    var elem = document.createElementNS(svgns, "line");
    elem.setAttribute("x1", seg.x1);
    elem.setAttribute("x2", seg.x2);
    elem.setAttribute("y1", seg.y1);
    elem.setAttribute("y2", seg.y2);
    elem.setAttribute("stroke", 'rgb(' + 
      parseHex(color.substring(1, 3)) + ',' + 
      parseHex(color.substring(3, 5)) + ',' + 
      parseHex(color.substring(5, 7)) + 
    ')');
    elem.setAttribute("stroke-width", thickness);
    if (dash)
      elem.style.setProperty('stroke-dasharray', '5,2', '');
    this.element.appendChild(elem);
  }
}
DrawableArea.prototype.addPath = function(coords, color, thickness, opacity)
{
  var elem;
  if (isIE)
  {
    elem = document.createElement('v:shape');
    elem.filled = "false";
    elem.stroked = "true";
    elem.style.position = "absolute";
    var w = 0, h = 0;
    for (var i = 0; i < coords.length; i++)
    {
      w = Math.max(w, coords[i][0]);
      h = Math.max(h, coords[i][1]);
    }
    elem.coordsize = w + " " + h;
    size(elem, w, h);
    var attr = "m " + coords[0][0] + ", " + coords[0][1] + " l ";
    for (var i = 1; i < coords.length; i++)
    {
      attr += coords[i][0] + ", " + coords[i][1];
      if (i < coords.length - 1)
        attr += ",";
    }
    attr += " e";
    elem.path = attr;
    this.element.appendChild(elem);
    this.element.appendChild(document.createTextNode(""));
  }
  else
  {
    elem = document.createElementNS(svgns, "path");
    elem.setAttribute("stroke-linecap", "round");
    elem.setAttribute("fill", "none");
    var attr = "M " + coords[0][0] + " " + coords[0][1];
    for (var i = 1; i < coords.length; i++)
      attr += " L " + coords[i][0] + " " + coords[i][1];
    elem.setAttribute("d", attr);
    var aroundElem = document.createElementNS(svgns, "a");
    aroundElem.appendChild(elem);
    this.element.appendChild(aroundElem);
  }
  setPathStyle(elem, color, thickness, opacity);
  return elem;
}
DrawableArea.prototype.removePath = function(path)
{
  if (isIE)
    this.element.removeChild(path);
  else
    this.element.removeChild(path.parentNode);
}
function setPathPosition(elem, x, y)
{
  if (isIE) position(elem, x, y);
  else elem.setAttribute("transform", "translate(" + x + "," + y + ")");
}
function setPathStyle(elem, color, thickness, opacity)
{
  if (isIE)
  {
    removeChildrenByTagName(elem, "stroke");
    elem.strokeweight = thickness - 1;
    elem.strokecolor = color;
    var stroke = document.createElement("v:stroke");
    stroke.endcap = "round";
    stroke.opacity = opacity;
    elem.appendChild(stroke);
  }
  else
  {
    elem.setAttribute("stroke-width", thickness);
    elem.setAttribute("stroke-opacity", opacity);
    elem.setAttribute("stroke", 'rgb(' + 
      parseHex(color.substring(1, 3)) + ',' + 
      parseHex(color.substring(3, 5)) + ',' + 
      parseHex(color.substring(5, 7)) + 
    ')');
  }
}
function setPathTitle(elem, title)
{
  if (isIE) elem.title = title;
  else if (isOpera)
  {
    removeChildrenByTagName(elem, "title");
    var titleElem = document.createElementNS(svgns, "title");
    titleElem.setAttribute("role", "tooltip");
    titleElem.appendChild(document.createTextNode(title));
    elem.appendChild(titleElem);
  }
  else elem.parentNode.setAttributeNS("http://www.w3.org/1999/xlink", "title", title);
}
function newCanvas(div, className)
{
  var canvas;
  if (isIE)
  {
    canvas = document.createElement("div");
    canvas.className = className;
  } 
  else 
  {
    canvas = document.createElementNS(svgns, "svg");
    canvas.setAttribute("class", className);
  }
  div.appendChild(canvas);
  var w, h;
  var ret = new DrawableArea(canvas, function() { return w; }, function() { return h; });
  ret.resize = function()
  {
    w = div.clientWidth;
    h = div.clientHeight;
    if (isIE)
    {
      canvas.style.width = w + "px";
      canvas.style.height = h + "px";
    } 
    else 
    {
      canvas.setAttribute("width", w);
      canvas.setAttribute("height", h);
    }
  }
  ret.show = function() 
  {
    if (canvas.style)
      canvas.style.display = "block";
  }
  ret.hide = function()
  {
    if (canvas.style)
      canvas.style.display = "none";
  }
  return ret;
}
function lon(x) { return from_merc_x(geoFromPxX(x)); }
function lat(y) { return from_merc_y(geoFromPxY(y)); }
function formatDegreesSimple(angle)
{
  if (angle > 180) angle -= 360;
  var str = "" + Math.round(angle*100000)/100000;
  if (str.indexOf(".") == -1) str += ".";
  for (var i = str.length; i < 8; i++) str += "0";
  return str;
}
function pad2(t) { return (t < 10) ? ("0" + t) : ("" + t); }
function formatDegrees(angle)
{
  var a1 = Math.floor(angle);
  var a2 = Math.floor(60*(angle - a1));
  var a3 = pad2(3600*(angle - a1 - a2/60)).substring(0, 5);
  return pad2(a1) + "°" + pad2(a2) + "'" + a3 + '"';
}
function formatDegrees2(angle)
{
  var a1 = Math.floor(angle);
  var a2 = pad2(60*(angle - a1)).substring(0, 6);
  return pad2(a1) + "°" + pad2(a2) + "'";
}
function truncate(f) { return ("" + f).substring(0, 9); }
function Markers(world, getLineColor, onMouseMove)
{
  var div = world.div;
  var canvas = newCanvas(div, "map_canvas");
  canvas.show();
  var canvasX, canvasY;
  world.onRepaint(function()
  {
    canvasX = getOffsetLeft(div);
    canvasY = getOffsetTop(div);
  });

  var sunscreen = newDiv("map_sunscreen");
  div.appendChild(sunscreen);
  var polygonCenters = [];
  var polygonOutlines = [];
  
  var showLineDist = function(parent, dist, summ, coor) {
    var canvas, tooltip;
	if ( $("dist_tooltip_canvas") == null ) {
	  canvas = newDiv("dist_tooltip_canvas", "");
	  canvas.id = "dist_tooltip_canvas";
	  parent.appendChild(canvas);
	}
	canvas = $("dist_tooltip_canvas");

	if (coor) {
      tooltip = newDiv("dist_tooltip", "");
	  canvas.appendChild(tooltip);
	  tooltip.innerHTML = prettify(dist) + (summ ? "<br><span>" + prettify(summ) + "</span>" : "");
	  if ( Math.pow(coor.y2 - coor.y1, 2) + Math.pow(coor.x2 - coor.x1, 2) < Math.pow(tooltip.offsetHeight, 2) + Math.pow(tooltip.offsetWidth, 2) ) {
	    canvas.removeChild(tooltip);
	  } else {
		tooltip.style.top =  (coor.y1 + (coor.y2 - coor.y1) / 2 - tooltip.offsetHeight / 2) + 'px';
		tooltip.style.left = (coor.x1 + (coor.x2 - coor.x1) / 2 - tooltip.offsetWidth / 2 ) + 'px';
	  }
	} else canvas.innerHTML = "";
  }
  var hideLineDist = function(id) {
    if ( $(id) )
	  hide($(id));
  }
  
  var showMarkers = function()
  {
    markersDiv.style.display = "block";
    var scale = world.getScale();
    var sw = div.clientWidth/2;
    var sh = div.clientHeight/2;
    var wx = world.getX();
    var wy = world.getY();
    for (var i in markers)
    {
      var marker = markers[i];
      var markerDiv = marker.div;
      var left = world.screenX(marker.x);
      var top = world.screenY(marker.y);
      position(markerDiv, left, top + 10);
      var textDiv = marker.textDiv;
	  setVisible(textDiv, marker.textShown);
      //position(marker.crossDiv, left + (marker.isCorner ? 3 : 10), top - (marker.isCorner ? 18 : 30));
      markerDiv.title = (marker.textShown || marker.isCorner) ? "" : (marker.text == "") ? "кликните, чтобы ввести текст" : marker.text;
      if (marker.isCorner)
      {
        var dx = (marker.verticalNeighbor.x - marker.x);
        var dy = (marker.horizontalNeighbor.y - marker.y);
        marker.div.className = "map_corner_" + (dx > 0 ? dy > 0 ? "lb" : "rb" : dy > 0 ? "lt" : "rt");
        //setVisible(marker.crossDiv, (marker.div.className == "map_corner_lt"));
		setVisible(marker.crossDiv, true);
      }
    }
    for (var i in polygonCenters) polygonCenters[i].position();
    for (var i in polygonOutlines) polygonOutlines[i].position();
    canvas.resize();
    canvas.clear();
	showLineDist(div);
	var addDistText = true;
	var allDistLength = 0;
	var arrayDist = [], arrayDistItems = [];
	var i, j, add, poly;
	for (i in markers) {
	  poly = false;
	  markers[i].index = i;
	  if (i == 0)
	    arrayDist[0] = ["0"];
	  else {
	    if ( markers[i].connectedMarkers.length > 0 ) {
		  add = false;
		  for (j in markers[i].connectedMarkers)
		    if ( markers[i].connectedMarkers[j] == markers[i - 1] )
			  add = true;
			if ( arrayDist[arrayDist.length - 1] && markers[arrayDist[arrayDist.length - 1][0]] == markers[i].connectedMarkers[j] )
			  poly = true;
	      if (add) {
			arrayDist[arrayDist.length - 1].push(i);
			if (arrayDist[arrayDist.length - 1].length < 3) poly = false;
	      } else
			arrayDist[arrayDist.length] = [i];
		} else
		  arrayDist[arrayDist.length] = [i];
	  }
	  arrayDistItems[i] = {
	    arr : arrayDist[arrayDist.length - 1],
		pos : arrayDist[arrayDist.length - 1].length - 1,
		poly : poly
	  }
	}
	var is_all_dist = false;
    for (i in markers)
    {
      var m1 = markers[i];
	  //m1.setText( i );
	  if ( arrayDistItems[i] && arrayDistItems[i].arr.length > 2 && arrayDistItems[i].pos > 0 ) {
	    allDistLength += markerDistance(m1, markers[i - 1]);
	  } else allDistLength = 0;
      for (var j in m1.connectedMarkers)
      {
        var m2 = m1.connectedMarkers[j];
        var x1 = world.screenX(m1.x);
        var y1 = world.screenY(m1.y);
        var x2 = world.screenX(m2.x);
        var y2 = world.screenY(m2.y);
        //if ((x1 + y1) <= (x2 + y2)) {
		if (m2.index < m1.index) {
		  is_all_dist = arrayDistItems[i].pos > 1 && in_array(m1.index, arrayDistItems[i].arr) && in_array(m2.index, arrayDistItems[i].arr);
          canvas.drawLine(x1, y1, x2, y2, getLineColor(), m1.isCorner ? 1 : 2, m1.isCorner);
		  showLineDist(div, markerDistance(m1, m2), (is_all_dist ? allDistLength + (arrayDistItems[i].poly && arrayDistItems[i].arr[0] == m2.index ? markerDistance(m1, m2) : 0) : 0), {
		    x1 : x1,
			y1 : y1,
			x2 : x2,
			y2 : y2
		  });
		}
      }
    }
    updateRouteSearchPane();
  }
  var markers = [];
  var markersDiv = newDiv("map_markers");
  div.appendChild(markersDiv);
  var addMarker = function(x, y, text, isCorner, isHtml)
  {
    var textDiv = newDiv("map_marker_text");
    var input = document.createElement("textarea");
    var mode = text;
    input.value = text;
    var updateText = function()
    {
      var newText = input.value;
      var rows = 1;
      var lines = newText.split("\n");
	  input.rows = lines.length;
      var cols = 0;
      for (var i in lines)
        cols = max(cols, lines[i].length + 1);
      input.cols = cols;
      ret.text = newText;
      var ww = textDiv.clientWidth, hh = textDiv.clientHeight;
      topBorder.style.width = max(ww - 14, 0) + "px";
      bottomBorder.style.width = max(ww - 47, 0) + "px";
      leftBorder.style.height = max(hh - 27, 0) + "px";
      rightBorder.style.height = max(hh - 27, 0) + "px";
      updateMarkerList();
    };
    input.onkeydown = function() {
		breakLine();
		updateText();
	}
	input.onkeyup = function() {
		breakLine();
		updateText();
	}
    input.onfocus = function() {
	  window.disableDeselect = input;
	}
    input.onblur = function() { window.disableDeselect = false; }
    textDiv.appendChild(input);
    if (isHtml) 
    {
      input.style.display = 'none';
      var thtml = newDiv("map_html_content", input.value);
      thtml.style.backgroundColor = '#0070fb';
      textDiv.appendChild(thtml);
    }
    var tl = newDiv("map_tooltip_top_left");
    setBg(tl, "left_top_corner.png");
    textDiv.appendChild(tl);
    var tr = newDiv("map_tooltip_top_right");
    setBg(tr, "right_top_corner.png");
    textDiv.appendChild(tr);
    var bl = newDiv("map_tooltip_bottom_left");
    setBg(bl, "left_bottom_corner.png");
    textDiv.appendChild(bl);
    var br = newDiv("map_tooltip_bottom_right");
    setBg(br, "right_bottom_corner.png");
    textDiv.appendChild(br);
    var leftBorder = newDiv("map_tooltip_left");
    setBg(leftBorder, "left_corner.png");
    textDiv.appendChild(leftBorder);
    var rightBorder = newDiv("map_tooltip_right");
    setBg(rightBorder, "right_corner.png");
    textDiv.appendChild(rightBorder);
    var topBorder = newDiv("map_tooltip_top");
    setBg(topBorder, "top_corner.png");
    textDiv.appendChild(topBorder);
    var bottomBorder = newDiv("map_tooltip_bottom");
    setBg(bottomBorder, "bottom_corner.png");
    textDiv.appendChild(bottomBorder);
    //markersDiv.appendChild(textDiv);
    var markerDiv = newDiv("map_marker");
    
	//if (!isCorner) setBg(markerDiv, markerImage);
	markerDiv.innerHTML = '<img style="-moz-user-select:none; cursor:pointer;" src="'+(isIE && ieVersion < 7 ? '/map/' + markerImageIE6 : '/map/' + markerImage)+'" width="19" height="19" align="absbottom">';
  if ( markerDiv.firstChild ) {
    markerDiv.firstChild.onmousedown = function(e) {
      e = e || window.event;
      if (e.preventDefault) e.preventDefault();
      return false;
    }
    markerDiv.firstChild.ondragstart = function(e) { return false; }
  }
    var crossDiv = newElement("div", {
      className: "map_close_marker",
      title: "удалить маркер",
      onmousedown: cancelEvent,
      onclick: function(event)
      {
	    breakLine();
        deleteMarker(ret);
        recalculateRoutes();
        cancelEvent(event);
      }
    });
	new VisibilityMode(crossDiv).set();
    var cd = crossDiv;
    new HoverMode(crossDiv, {
      set: function() { cd.className = "map_close_marker_hovered"; },
      clear: function() { cd.className = "map_close_marker"; }
    }).set();
    if (isCorner)
    {
      //new VisibilityMode(crossDiv).set();
      var outDiv = newDiv("map_halo");
      outDiv.appendChild(crossDiv);
      crossDiv = outDiv;
    }
    var isInMarkerClick = false;
    var startX, startY;
    var dropCallback = false;
    var moveMode = new Modes(
      new HandlerMode(div, "mousemove", function(event)
      {
	    breakLine();
        cancelEvent(event);
        var scale = world.getScale();
        var dx = eventX(event) - startX;
        var dy = eventY(event) - startY;
        if ((dx*dx) + (dy*dy) >= 1)
          isInMarkerClick = false;
        ret.x = startMarkerX + dx*scale;
        ret.y = startMarkerY + dy*scale;
        if (ret.isCorner)
        {
          ret.horizontalNeighbor.x = ret.x;
          ret.verticalNeighbor.y = ret.y;
        }
        showMarkers();
        recalculateTotalLength();
        recalculateRoutes();
      }),
      new HandlerMode(div, "mouseup", function(event)
      {
        if (!ret.isCorner) {
          var nearby = findNearbyMarker(eventX(event), eventY(event), ret);
          if ((nearby != -1)) {
            var m = markers[nearby];
            if (!m.incomingRoute && !ret.outgoingRoute && !m.outgoingRoute && !m.incomingRoute)
            {
              for (var i in ret.connectedMarkers)
                addLine(m, ret.connectedMarkers[i]);
              lastTouchedMarker = m;
              deleteMarker(ret);
            }
          } else snapMarkerToLine(ret);
        }
        moveMode.clear();
        if (dropCallback)
        {
          dropCallback(); 
          dropCallback = false;
        }
        world.repaint();
      })
    );
    var startMarkerX, startMarkerY;
    var startDrag = function(event, callback)
    {
      lastTouchedMarker = ret;
      recalculateTotalLength();
      event = event || window.event;
      if (!isLeftMouseButton(event))
        return;
      startX = eventX(event);
      startY = eventY(event);
      startMarkerX = ret.x;
      startMarkerY = ret.y;
      moveMode.set();
      cancelEvent(event);
      isInMarkerClick = true;
      dropCallback = callback;
    }
    markerDiv.onmousedown = startDrag;
	var markerDblClicked = function(event) {
	  if (isIE) {
	      ret.textShown = !ret.textShown;
    	  showMarkers();
	  }
	  startLine(eventX(event), eventY(event));
	  input.blur();
	}
    var markerClicked = function(event)
    {
      if (isInMarkerClick) {
        ret.textShown = !ret.textShown;
        showMarkers();
        //if (ret.textShown) input.focus();
      }
      isInMarkerClick = false;
	  if (drawingLine) { finishLine(eventX(event), eventY(event)); }
	  if ( ret.textShown ) {
	  	input.focus();
	  }
      cancelEvent(event);
    }
    if (!isCorner)
    {
      markerDiv.onclick = markerClicked;
      markerDiv.ondblclick = markerDblClicked;
    }
    textDiv.onmousedown = cancelEvent;
    textDiv.onmouseup = cancelEvent;
    textDiv.onclick = cancelEvent;
    textDiv.ondblclick = cancelEvent;
	textDiv.appendChild(crossDiv);
	markerDiv.appendChild(textDiv);
    markersDiv.appendChild(markerDiv);
    var ret = {
      isHtml: isHtml,
      x: x,
      y: y,
      text: text,
      div: markerDiv,
      startDrag: startDrag,
      textDiv: textDiv,
      crossDiv: crossDiv,
      connectedMarkers: [],
      incomingRoute: false,
      outgoingRoute: false,
      textShown: true,//(text != ""),
      mode: mode,
      setText: function(newText) { input.value = newText; updateText(); },
      activate: function() {}
    };
    markers.push(ret);
    lastTouchedMarker = ret;
    updateText();
    return markers.length - 1;
  }
  var oldFrameM1 = false;
  var addFrame = function(x1, y1, x2, y2, text)
  {
    if (!text) text = "";
    if (oldFrameM1) deleteMarker(oldFrameM1);
    var setCorner = function(m, m1, m2)
    {
      m.isCorner = true;
      m.horizontalNeighbor = m1;
      m.verticalNeighbor = m2;
      m.crossDiv.title = "удалить рамку";
    }
    var m1 = markers[addMarker(x1, y1, text, true)];
    var m2 = markers[addMarker(x1, y2, text, true)];
    var m3 = markers[addMarker(x2, y2, text, true)];
    var m4 = markers[addMarker(x2, y1, text, true)];
    addLine(m1, m2);
    addLine(m2, m3);
    addLine(m3, m4);
    addLine(m4, m1);
    setCorner(m1, m2, m4);
    setCorner(m2, m1, m3);
    setCorner(m3, m4, m2);
    setCorner(m4, m3, m1);
    oldFrameM1 = m1;
  }
  var find = function(arr, elem)
  {
    for (var i in arr)
      if (arr[i] == elem)
        return i;
    return -1;
  }
  var findAndRemove = function(arr, elem)
  {
    var idx = find(arr, elem);
    if (idx != -1)
      arr.splice(idx, 1);
  }
  var connectIdx = function(m1, m2) { return find(m1.connectedMarkers, m2); }
  var addLine = function(m1, m2)
  {
    if ((m1 != m2) && !m1.isCorner && !m2.isCorner && (connectIdx(m1, m2) == -1))
    {
      m1.connectedMarkers.push(m2);
      m2.connectedMarkers.push(m1);
      recalculateTotalLength();
    }
  }
  var removeLine = function(m1, m2)
  {
    findAndRemove(m1.connectedMarkers, m2);
    findAndRemove(m2.connectedMarkers, m1);
    recalculateTotalLength();
  }
  var snapMarkerToLine = function(m)
  {
	var ends = [];
    var dist = function(m1, m2)
    {
      var dx = m1.x - m2.x;
      var dy = m1.y - m2.y;
      return Math.sqrt(dx*dx + dy*dy);
    }
    var scale = world.getScale();
    for (var i in markers)
    {
      var m1 = markers[i];
      if ((m1 == m) || (m1.isCorner))
        continue;
      for (var j in m1.connectedMarkers)
      {
        var m2 = m1.connectedMarkers[j];
        if (m2 == m)
          continue;
        //if (dist(m, m1) + dist(m, m2) - dist(m1, m2) < 3*scale)
		if (dist(m, m1) + dist(m, m2) - dist(m1, m2) < scale)
          ends.push([m1, m2])
      }
    }
    for (var i in ends)
    {
      var m1 = ends[i][0], m2 = ends[i][1];
      removeLine(m1, m2);
      addLine(m, m1);
      addLine(m, m2);
    }
  }
  var markerDistance = function(m1, m2) { return parseFloat(distVincenty(lon(m1.x), lat(m1.y), lon(m2.x), lat(m2.y))); }
  var lastM1 = false, lastM2 = false;
  var deleteMarker = function(marker)
  {
    var c1 = false, c2 = false;
    if (marker.isCorner)
    {
      doDeleteMarker(marker.horizontalNeighbor.verticalNeighbor);
      doDeleteMarker(marker.verticalNeighbor);
      doDeleteMarker(marker.horizontalNeighbor);
      oldFrameM1 = false;
    }
    doDeleteMarker(marker);
    if (c1)
    {
      addLine(c1, c2);
      lastTouchedMarker = c1;
    }
    drawingLine = false;
    if (marker == firstRouteMarker) stopDrawingRoute();
    var m1 = marker.incomingRoute, m2 = marker.outgoingRoute;
    if (m1 || m2)
    {
      if ((m1 && !m2 && !m1.incomingRoute) || (m2 && !m1 && !m2.outgoingRoute))
         marker.route.remove();
      if (m1)
        removeRoute(m1, marker);
      if (m2)
        removeRoute(marker, m2);
      if (m1 && m2)
        addRoute(m1, m2, m1.routeMode);
    }
    world.repaint();
  }
  var doDeleteMarker = function(marker)
  {
    var idx = 0;
    for (var i in markers) {
		if (markers[i] == marker)
			idx = i;
	}
	if (marker.connectedMarkers.length == 2)
		addLine(marker.connectedMarkers[0], marker.connectedMarkers[1]);
    while (marker.connectedMarkers.length > 0)
		removeLine(marker, marker.connectedMarkers[0]);
//	if (marker.textDiv) marker.div.removeChild(marker.textDiv);
//	marker.div.removeChild(marker.crossDiv);
    markersDiv.removeChild(marker.div);
    markers.splice(idx, 1);
  }
  var clearMarkers = function()
  {
    breakLine();
    while (markers.length > 0) deleteMarker(markers[0]);
    recalculateRoutes();
  }
  var findNearbyMarker = function(x, y, except)
  {
    return findNearbyMarkerByWorld(world.worldX(x), world.worldY(y), except);
  }
  var findNearbyMarkerByWorld = function(x, y, except)
  {
    var threshold = world.getScale()*15;
    threshold = threshold*threshold;
    for (var i in markers){
      var marker = markers[i];
      if(marker == except)continue;
      var dx = x - marker.x;
      var dy = y - marker.y;
      if ((dx*dx + dy*dy) < threshold){
        recalculateTotalLength();
        return i;
      }
    }
    return -1;
  }
  var findOrAddMarker = function(x, y) { return findOrAddMarkerByWorld(world.worldX(x), world.worldY(y)); }
  var findOrAddMarkerByWorld = function(x, y, text)
  {
    var nearby = findNearbyMarkerByWorld(x, y);
    if (nearby != -1)
    {
      if (text)
      {
        markers[nearby].setText(text);
        showMarkers();
      }
      return nearby;
    }
    addMarker(x, y, text || "");
    snapMarkerToLine(markers[markers.length - 1]);
    return (markers.length - 1);
  }
  var lastTouchedMarker = false;
  var recalculateTotalLength = function()
  {
    var dist = 0;
    for (var i in markers)
    {
      if (markers[i].isCorner)
        continue;
      for (var j in markers[i].connectedMarkers) 
        dist += markerDistance(markers[i], markers[i].connectedMarkers[j]);
    }
    dist /= 2;
    writeTotalLength(dist);
    writeLastLength(false);
    if (lastTouchedMarker)
    {
      var arr = [];
      for (var i = 0; i < lastTouchedMarker.connectedMarkers.length; i++)
	    arr.push({
		  dist : markerDistance(lastTouchedMarker, lastTouchedMarker.connectedMarkers[i])
		});
      if (arr.length >= 1) writeLastLength( arr );
    }
    unwriteArea();
    var totalArea = 0;
    if (markers.length >= 3)
    {
      for (var k in markers) markers[k].touched = false;
      var pieces = [];
      for (var k in markers)
      {
        var ms = [];
        var startM = markers[k];
        if (startM.touched) continue;
        var m = startM;
        var previousM = false;
        var pts = [], rpts = [];
        var isLastTouched = false;
        while (true)
        {
          m.touched = true;
          if (m == lastTouchedMarker)
            isLastTouched = true;
          ms.push(m);
          pts.push([m.x, m.y]);
          rpts.push([lon(m.x), lat(m.y)]);
          if (m.connectedMarkers.length != 2) break;
          var nextM = m.connectedMarkers[(m.connectedMarkers[0] == previousM) ? 1 : 0];
          previousM = m;
          m = nextM;
          if (m == startM)
          {
            var minx = pts[0][0], maxx = pts[0][0], miny = pts[0][1], maxy = pts[0][1];
            for (var i in pts)
            {
              if(pts[i][0] < minx)minx = pts[i][0];
              if(pts[i][0] > maxx)maxx = pts[i][0];
              if(pts[i][1] < miny)miny = pts[i][1];
              if(pts[i][1] > maxy)maxy = pts[i][1];
            }
            var area = fragmentArea(rpts);
            var isIrs = (m.mode == "irs");
            totalArea += area;
            pieces.push({ minx: minx, miny: miny, maxx: maxx, maxy: maxy, sides: pts.length, area: area, isRect: m.isCorner, markers: ms });
            break;
          }
        }
      }
      if (pieces.length > 0) writeArea(totalArea, pieces);
    }
    var around_dist = $("around_dist");
    if (around_dist) 
    {
      var nNonRouteMarkers = 0;
      for (var i = 0; i < markers.length; i++)
      {
        var m = markers[i];
        if (!m.incomingRoute && !m.outgoingRoute && (m != firstRouteMarker)) nNonRouteMarkers += 1;
      }
      setVisible(around_dist, (dist > 0) || (nNonRouteMarkers > 0));
      if (!isDistShown && (dist > 0) && isFullScreen)
      {
        //isFullScreen = false;
        isDistShown = true;
        resizeMap();
        world.repaint();
      }   
    }
  }
  var formatWkt = function(ms)
  {
    var ret = [];
    for (var i = 0; i < ms.length; i++) ret.push(truncate(lon(ms[i].x)) + " " + truncate(lat(ms[i].y)));
    return "(" + ret.join(",") + ")";
  }
  var updateMarkerList = deferred(function()
  {
    var text = "";
    for (var i in markers)
    {
      var m = markers[i];
      if (m.isCorner || (m.text == ""))
        continue;
      text += "<a href='#' onclick='map.navigateTo(map.markers.get(" + i + ").x, map.markers.get(" + i + ").y, map.getZoomLevel())'>";
      text += "&raquo; ";
      text += (m.text != "") ? htmlspecialchars(m.text) : (
        formatDegreesSimple(lat(m.y)) + ", " +
        formatDegreesSimple(lon(m.x))
        );
      text += "</a><br />";
    }
    if ($("marker_list")) $("marker_list").innerHTML = text;
  });
  world.onRepaint(showMarkers);
  world.onRepaint(updateMarkerList);
  world.onRepaint(recalculateTotalLength);
  var startX = 0, startY = 0;
  var startMarkerIdx = -1;
  var addingMarker = false;
  window.tempCanvas = newCanvas(div, "map_temp_canvas");
  tempCanvas.hide();
  var startLine = function(x, y)
  {
    continueLineLengthHide();
    drawingLine = true;
    var oldMarkersLength = markers.length;
    startMarkerIdx = findOrAddMarker(x, y);
    addingMarker = (markers.length > oldMarkersLength);
    showMarkers();
    tempCanvas.clear();
    tempCanvas.resize();
    tempCanvas.show();
    var startMarker = markers[startMarkerIdx];
	try {
		startMarker.textDiv.firstChild.focus();
	} catch(e) {}
	lastMarkersMarker = startMarker;
    startX = canvasX + world.screenX(startMarker.x);
    startY = canvasY + world.screenY(startMarker.y);
  }
  var continueLineLengthShow = function(coor, dist) {
    var contDist;
    if ( $('contDist') == null ) {
	  contDist = newDiv('cont_dist');
	  contDist.id = 'contDist';
	  div.appendChild(contDist);
	}
	contDist = $('contDist');
	contDist.innerHTML = prettify(dist);
	show(contDist);
	contDist.style.left = (coor.x1 + (coor.x2 - coor.x1) / 2 - contDist.offsetWidth / 2) + 'px';
	contDist.style.top  = (coor.y1 + (coor.y2 - coor.y1) / 2 - contDist.offsetHeight / 2) + 'px';
  }
  var continueLineLengthHide = function() {
    if ( $('contDist') )
	  hide($('contDist'));
  }
  var continueLine = function(x, y, dX, dY)
  {
    if (!drawingLine) return;
    dX = dX ? dX : 0;
	dY = dY ? dY : 0;
    tempCanvas.clear();
	var x1 = lastMarkersMarker ? world.screenX(lastMarkersMarker.x) : startX - canvasX - dX;
    var y1 = lastMarkersMarker ? world.screenY(lastMarkersMarker.y) : startY - canvasY - dY;
    tempCanvas.drawLine(
      x1,
      y1,
      x - canvasX,
      y - canvasY,
      getLineColor(),
      1,
      false
    );
	var dist = parseFloat(distVincenty(
      lon(world.worldX(x1 + getOffsetLeft(div))),
      lat(world.worldY(y1 + getOffsetTop(div))),
      lon(world.worldX(x)),
      lat(world.worldY(y))
    ));
	continueLineLengthShow({
		x1 : x1,
		y1 : y1,
		x2 : x - canvasX,
		y2 : y - canvasY
	}, dist);
    writeLastLength([{dist : dist}]);
  }
  var finishLine = function(x, y)
  {
    if (!drawingLine) return;
    drawingLine = false;
    var m1 = markers[startMarkerIdx];
    var m2 = markers[findOrAddMarker(x, y)];
	lastMarkersMarker = m2;
    var t = (connectIdx(m1, m2) == -1);
    lastM1 = t && m1;
    lastM2 = t && m2;
    (t ? addLine : removeLine)(m1, m2);
    showMarkers();
    tempCanvas.hide();
	continueLineLengthHide();
  }
  var hideLine = function() {
    tempCanvas.clear();
  }
  var breakLine = function(x, y) {
    if (!drawingLine) return;
    drawingLine = false;
	tempCanvas.clear();
	writeLastLength(false);
	showMarkers();
	tempCanvas.hide();
	continueLineLengthHide();
  }
  Markers.breakLine = breakLine;
  Markers.hideLine = hideLine;

  var routeToolActive = false;
  var firstRouteMarker = false;
  var routeArrowMode = false;
  var markerLineMode = false;
  var lastMarkersMarker = false;
  var stopDrawingRoute = function()
  {
    firstRouteMarker = false;
    if (routeToolActive) map.restoreDefaultMode();
    else updateRouteSearchPane();
  }
  var updateRouteSearchPane = function()
  {
    if ($("route_stuff")) {
      setVisible$("route_stuff", routeToolActive);
      setVisible$("common_header", !routeToolActive);
      setVisible$("routes_header", routeToolActive);
      if (firstRouteMarker) $("route_start_address").value = formatCoordinatesCurrently(firstRouteMarker.x, firstRouteMarker.y, 0);
    }
  }
  var addRoute = function(m1, m2, routeMode)
  {
    if ((m1 != m2) && !m1.isCorner && !m2.isCorner && !m1.outgoingRoute && !m2.incomingRoute)
    {
      m1.outgoingRoute = m2;
      m2.incomingRoute = m1;
      m1.routeMode = routeMode;
      m2.routeMode = routeMode;
    }
  }
  var removeRoute = function(m1, m2)
  {
    if ((m1.outgoingRoute == m2) && (m2.incomingRoute == m1))
    {
      m1.outgoingRoute = false;
      m2.incomingRoute = false;
    }
  }
  var recalculateRoutes = function()
  {
    var idx = 0;
    for (var i = 0; i < markers.length; i++)
    {
      var m = markers[i];
      if (m.outgoingRoute && !m.incomingRoute) (function()
      {
        idx += 1;
        var arr = [];
        var route = false;
        while (m)
        {
          arr.push(m);
          route = route || m.route;
          m = m.outgoingRoute;
        }
        if (!route)
        {
          var elem = newDiv("info_block2");
          var aroundTitle = newDiv("title");
          elem.appendChild(aroundTitle);
          var inAroundTitle = newDiv();
          aroundTitle.appendChild(inAroundTitle);
          var titleDiv = document.createElement("span");
          inAroundTitle.appendChild(titleDiv);
          var closeLink = newElement("a", {
            href: "#",
            className: "close",
            title: "удалить маршрут",
            innerHTML: '<img src="close-white.gif">'
          });
          inAroundTitle.appendChild(closeLink);
          var infoDiv = newDiv("info");
          infoDiv.innerHTML = '<img src="progress.gif" alt="" id="search_progress"/>'
          elem.appendChild(infoDiv);
          if ($("all_routes"))
          $("all_routes").appendChild(elem);
          var lastLoadedP = "";
          var requiredP = "";
          var requestPending = false;
          var paths = [];
          var coords, minX, minY;
          var removePaths = function()
          {
            for (var k = 0; k < paths.length; k++)
              routeCanvas.removePath(paths[k]);
            paths = [];
          }
          var removeThisRoute;
          var routeMarkers;
          route = {
            update: function(idx, arr)
            {
              titleDiv.innerHTML = "Маршрут " + idx;
              routeMarkers = arr;
              removeThisRoute = function()
              {
                for (var j = 0; j < arr.length; j++)
                  deleteMarker(arr[j]);
                recalculateRoutes();
            blockClose('route_stuff');
              }
              closeLink.onclick = removeThisRoute;
              requiredP = "mode=" + arr[0].routeMode;
              for (var j = 0; j < arr.length; j++)
                requiredP += "&x" + j + "=" + lon(arr[j].x) + "&y" + j + "=" + lat(arr[j].y);
              if ((requiredP != lastLoadedP) && !requestPending)
              {
                var callback = function()
                {
                  if (requiredP != lastLoadedP)
                  {
                    var loadingP = requiredP;
                    requestPending = true;
					infoDiv.innerHTML = '<img src="progress.gif" alt="" id="search_progress"/>'
                    loadRouteInfo(requiredP, function(result)
                    {
                      infoDiv.innerHTML = "";
                      var wayPointIdx = 0;
                      var wayPointDelta = 0;
                      var lspan = newElement("span");
                      infoDiv.appendChild(createRouteModeSelector(arr[0].routeMode, function(newMode)
                      {
                        for (var l = 0; l < arr.length; l++)
                          arr[l].routeMode = newMode;
                        recalculateRoutes();
                      }));
                      infoDiv.appendChild(lspan);
            if (result=="") {
            lspan.innerHTML = "<b>К сожалению, маршрут до данной точки не может быть построен.</b><br><br>Точка старта или назначения находится в месте, проехать в которое невозможно.";
            return;
            }
                      var addWayPoint = function(item)
                      {
                        wayPointIdx += 1;
                        wayPointDelta += item.length ? 0 : 1;
                        infoDiv.appendChild(newElement("span", { innerHTML: item.length ?
                             (wayPointIdx - wayPointDelta + ". ") :
                             ("<img src='/map/"+markerImage+"' width=13 height=13 align='absbottom'>&nbsp;")
                        }));
                        infoDiv.appendChild(newElement("a", {
                          href: "#" + Math.random(),
                          innerHTML: item.length ? 
						    (item.text + ", " + prettify(item.length)) :
                            ("<b>" + item.text + "</b>"),
                          onclick: function() 
                          {
							map.markers.findOrAdd(pxFromGeoX(merc_x(parseFloat(item.x))), pxFromGeoY(merc_y(parseFloat(item.y))), item.text);
                            map.navigateTo(
                              pxFromGeoX(merc_x(parseFloat(item.x))),
                              pxFromGeoY(merc_y(parseFloat(item.y))),
                              map.getZoomLevel()
                            );
                            return false;
                          }
                        }));
                        infoDiv.appendChild(newElement("br"));
                        if (isIE) 
                          infoDiv.style.height = "1%";
                      }
                      addWayPoint(result.A);
                      var totalLength = 0, totalTime = 31;
                      for (var k = 0; k < result.parts.length; k++)
                      {
                        var part = result.parts[k];
                        totalLength += parseInt(part.totalLength);
                  		totalTime += parseInt(part.totalTime);
                        for (var l = 0; l < part.items.length; l++)
                          addWayPoint(part.items[l]);
                        addWayPoint(part.B);
                      }
                      lspan.innerHTML = "Общая протяженность: <b>" + prettify(totalLength) + "</b><br>Примерное время в пути: <b>" + ( Math.round(totalTime/60) < 90 ? Math.round(totalTime/60) : "" + Math.round(totalTime/3600) + " ч. " + Math.round(totalTime/60)%60 ) +" мин.</b><br><br>";
                      coords = [];
                      minX = 100000000;
                      minY = 100000000;
                      for (var l = 0; l < result.parts.length; l++)
                      {
                        var p = result.parts[l].points;
                        var c = [];
                        for (var k = 0; k < p.length; k++)
                        {
                          var x = pxFromGeoX(merc_x(parseFloat(p[k].x)));
                          var y = pxFromGeoY(merc_y(parseFloat(p[k].y)));
                          minX = Math.min(x, minX);
                          minY = Math.min(y, minY);
                          c.push([x, y]);
                        }
                        coords.push(c);
                      }
                      route.repaint();

                      requestPending = false;
                      lastLoadedP = loadingP;
                      callback();
                    });
                  }
                }
                callback();
              }
            },
            remove: function()
            {
              if (elem)
                $("all_routes").removeChild(elem);
              elem = false;
              removePaths();
            },
            repaint: function()
            {
              removePaths();
              if (coords)
              {
                var scale = world.getScale();
                for (var l = 0; l < coords.length; l++) (function(l)
                {
                  var c = [];
                  for (var k = 0; k < coords[l].length; k++)
                    c.push([
                      Math.round((coords[l][k][0] - minX)/scale), 
                      Math.round((coords[l][k][1] - minY)/scale)
                    ]);
                  var path = routeCanvas.addPath(c, "#0020ff", 5, 0.6);
                  setPathTitle(path, "перетащить маршрут");
                  path.onmouseover = function() { setPathStyle(path, "#0020ff", 5, 1); }
                  path.onmouseout = function() { setPathStyle(path, "#0020ff", 5, 0.6); }
                  path.style.cursor = "pointer";
                  path.onclick = cancelEvent;
                  path.onmousedown = function(event)
                  {
                    if (isLeftMouseButton(event))
                    {
                      var m = markers[addMarker(
                        world.worldX(eventX(event)),
                        world.worldY(eventY(event)),
                        ""
                      )];
                      var m1 = routeMarkers[l];
                      var m2 = routeMarkers[l + 1];
                      removeRoute(m1, m2);
                      addRoute(m1, m, m1.routeMode);
                      addRoute(m, m2, m1.routeMode);
                      recalculateRoutes();
                      setOpacity(m.div, 0.01);
                      size(m.crossDiv, 0, 0);
                      m.div.style.cursor = path.style.cursor;
                      m.startDrag(event, function()
                      {
                        setOpacity(m.div, 1);
                        setBg(m.div, markerImage);
                        m.crossDiv.style.width = "";
                        m.crossDiv.style.height = "";
                        m.div.style.cursor = "";
                        show(m.crossDiv);
                      });
                      showMarkers();
                    }
                    else
                      removeThisRoute();
                    cancelEvent(event);
                    return false;
                  }                 
                  paths.push(path);
                })(l);
                this.reposition();
              }
            },
            reposition: function()
            {
              var dx = (minX - world.worldX(canvasX))/world.getScale();
              var dy = (minY - world.worldY(canvasY))/world.getScale();
              for (var l = 0; l < paths.length; l++)
                setPathPosition(paths[l], dx, dy);
            }
          }
        }
        for (var j = 0; j < arr.length; j++)
          arr[j].route = route;
        route.update(idx, arr);
      })();
    }
  }
  var routeDiv = newDiv();
  div.appendChild(routeDiv);
  routeDiv.style.position = "absolute";
  routeDiv.style.zIndex = 10;
  var routeCanvas = newCanvas(routeDiv, "map_canvas");
  routeCanvas.clear();
  var lastRouteRepaintZ = 0;
  world.onRepaint(function() 
  { 
    var z = world.getZoomLevel();
    if (z != Math.round(z))
      routeCanvas.hide();
    else 
    {
      routeDiv.style.width = div.clientWidth + "px";
      routeDiv.style.height = div.clientHeight + "px";
      routeCanvas.resize();
      routeCanvas.show();
      for (var i = 0; i < markers.length; i++)
      {
        var m = markers[i];
        if (m.outgoingRoute && !m.incomingRoute)
        {
          if (z != lastRouteRepaintZ)
            m.route.repaint();
          else
            m.route.reposition();
        }
      }
      lastRouteRepaintZ = z;
    }
  });
  var loadRouteInfo = function(params, callback)
  {
    sendRequest("/stamperx/getPath.aspx?" + params, function(xmlhttp) 
    { 
    if (xmlhttp.responseText=="") callback(xmlhttp.responseText);
      else callback(eval("(" + xmlhttp.responseText + ")")); 
    });
  }

  if (isIE)
  {
    new HandlerMode(div, "mousemove", function()
    {
      if (onMouseMove && (event.srcElement.parentNode == div))
        onMouseMove();
    }).set();
    new HandlerMode(div, "mouseout", hideJamsTooltip).set();
  }
  else
  {
    if (onMouseMove)
      new HandlerMode(routeDiv, "mousemove", onMouseMove).set();
    new HandlerMode(routeDiv, "mouseout", hideJamsTooltip).set();
  }

  var offX = 0; // 11;
  var offY = 0; // 22;

  var defaultRouteMode = "deftime";
  if ($("route_stuff_body"))
    $("route_stuff_body").appendChild(createRouteModeSelector(defaultRouteMode, function(newMode) { defaultRouteMode = newMode; }));

  return {
    add: addMarker,
    findOrAdd: findOrAddMarkerByWorld,
    showMarkers: showMarkers,
    clear: clearMarkers,
    deleteMarker: deleteMarker,
    get: function(i) { return markers[i]; },
  setText: function(i, text) { markers[i].setText(text); },
    length: function() { return markers.length; },
    save: function()
    {
      var ret = "";
      for (var i = 0; i < markers.length; i++)
      {
        var m = markers[i];
        var text = base64Encode(utf8Encode(m.text));

        ret += (m.isHtml ? "&mhtml=1" : "") + 
      "&mx=" + truncate(lon(m.x)) + 
          "&my=" + truncate(lat(m.y)) + 
          "&mt=" + text;
  
        for (var j in m.connectedMarkers)
          for (var k = 0; k < markers.length; k++)
            if ((i > k) && (markers[k] == m.connectedMarkers[j]))
              ret += "&ml=" + i + "-" + k;
      }
      for (var i = 0; i < markers.length; i++)
      {
        var dest = markers[i].outgoingRoute;
        if (dest)
          for (var k = 0; k < markers.length; k++)
            if (markers[k] == dest)
              ret += "&mr=" + i + "-" + k + "," + markers[k].routeMode;
      }
      return ret;
    },
    restore: function(q)
    {
      var mx = false, my = false, mt = false, mhtml = false;
      var fx1 = false, fx2 = false, fy1 = false, fy2 = false, ft = false;
      var kvp = (q.length > 0) ? q.replace("#", "").split("&") : [];
      for (var i = 0; i < kvp.length; i++)
      {
        var pName = kvp[i].split("=")[0];
        var pValue = kvp[i].split("=")[1];
        if (pName == "mx")
          mx = pValue;
        if (pName == "my")
          my = pValue;
        if (pName == "mt")
          mt = pValue;
        if (pName == "mhtml")
          mhtml = !!pValue;
        if ((mx !== false) && (my !== false) && (mt !== false))
        {
          addMarker(
            pxFromGeoX(merc_x(parseFloat(mx))), 
            pxFromGeoY(merc_y(parseFloat(my))),
            utf8Decode(base64Decode(mt)),
            0,
            mhtml
          );
          mx = false;
          my = false;
          mt = false;
        }
        if (pName == "ml")
        {
          var is = pValue.split("-");
          addLine(markers[is[0]], markers[is[1]]);
        }
        if (pName == "mr")
        {
          var a = pValue.split(",");
          var is = a[0].split("-");
          addRoute(markers[is[0]], markers[is[1]], (a.length > 1) ? a[1] : defaultRouteMode);
        }
      }
      recalculateRoutes();
    },
    markerHandlers: {
	  first : false,
	  right: false,
	  startX: 0,
      startY: 0,
      startWorldX: 0,
      startWorldY: 0,
	  switchOn: function() {
	    show(sunscreen);
		markerLineMode = new Modes(
          new HoverMode(div, { 
            set: function() 
            { 
              tempCanvas.show(); 
            },
            clear: function()
            { 
              tempCanvas.clear();
              tempCanvas.hide();
			  continueLineLengthHide();
            }
          })
        );
        markerLineMode.set();
	  },
      switchOff: function() {
	    hide(sunscreen);
		if (markerLineMode)
        {
          markerLineMode.clear();
          markerLineMode = false;
          tempCanvas.clear();
          tempCanvas.hide();
		  continueLineLengthHide();
        }
	  },
	  onDrag : { dX:0, dY:0, dX0:0, dY0:0 },
      click: function(x, y, right)
      {
	    if ( this.right ) {
	      breakLine(x, y);
		  this.onDrag = { dX:0, dY:0, dX0:0, dY0:0 };
		  this.right = false;
		  return;
		}
        lastMarkersMarker = findOrAddMarker(x + offX, y + offY);
        world.repaint();
        tempCanvas.hide();
		if (this.first) {
		  var lastMarker = markers[markers.length - 1];
		  var markerX = world.screenX(lastMarker.x);
		  var markerY = world.screenY(lastMarker.y);
		  finishLine(x, y);
		  this.onDrag = { dX:0, dY:0, dX0:0, dY0:0 };
		  startLine(x - (world.screenX(lastMarker.x) - markerX), y - (world.screenY(lastMarker.y) - markerY));
		} else {
		  this.first = true;
		  startLine(x, y);
		}
      },
	  move: function(x, y)
	  {
	    div.style.cursor = "default";
	    if (this.first) {
		  continueLine(x, y, this.onDrag.dX, this.onDrag.dY);
		}
	  },
      pick: function(x, y, right)
      {
	    this.right = right;
        this.startX = x;
        this.startY = y;
		this.onDrag.dX0 = this.onDrag.dX;
		this.onDrag.dY0 = this.onDrag.dY;
        this.startWorldX = world.getX();
        this.startWorldY = world.getY();
      },
      drag: function(x, y, right)
      {
	    if (right) {
		  breakLine(x, y);
		  return;
		}
		div.style.cursor = "url('map/move.cur'), move";//"move";
		if ( this.first && drawingLine ) {
		  this.onDrag.dX = this.startX - x + this.onDrag.dX0;
		  this.onDrag.dY = this.startY - y + this.onDrag.dY0;
		  continueLine(x, y, this.onDrag.dX, this.onDrag.dY);
		}
        world.navigateTo(
          this.startWorldX - world.worldX(x) + world.worldX(this.startX),
          this.startWorldY - world.worldY(y) + world.worldY(this.startY),
          world.getZoomLevel()
        );
      },
      drop: function(x, y)
      {
	    div.style.cursor = "default";
        world.repaint();
      },
	  wheel : function(x, y) {
		if (this.first) {
		  var lastMarker = markers[markers.length - 1];
		  startX = world.screenX(lastMarker.x) + getOffsetLeft(div);
		  startY = world.screenY(lastMarker.y) + getOffsetTop(div);
		  this.onDrag = { dX:0, dY:0, dX0:0, dY0:0 };
		  //continueLine(x, y);
		}
	  }
    },
    drawHandlers: {
      click: function(x, y)
      {
        if (addingMarker)
          findOrAddMarker(x, y);
        else 
        {
          deleteMarker(markers[findNearbyMarker(x, y)]);
          recalculateRoutes();
        }
        world.repaint();
        tempCanvas.hide();
      },
      pick: startLine,
      //drag: continueLine,
      drop: finishLine
    },

    cancelDrawingRoute: function()
    {
      if (firstRouteMarker)
        deleteMarker(firstRouteMarker);
      stopDrawingRoute();
    },

    addRoute: function(x1, y1, t1, x2, y2, t2)
    {
      addRoute(markers[addMarker(x1, y1, t1)], markers[addMarker(x2, y2, t2)], defaultRouteMode);
      recalculateRoutes();
      stopDrawingRoute();
      isFullScreen = false;
      resizeMap();
      world.repaint();
    },

    routeHandlers: {
      switchOn: function()
      {
        routeToolActive = true;
        if (firstRouteMarker)
        {
          tempCanvas.clear();
          tempCanvas.resize();
          tempCanvas.show();
          routeArrowMode = new Modes(
            new HoverMode(div, { 
              set: function() 
              { 
                tempCanvas.show(); 
              },
              clear: function()
              { 
                tempCanvas.clear();
                tempCanvas.hide();
              }
            })
          );
          routeArrowMode.set();
        }
        updateRouteSearchPane();
      },
      switchOff: function()
      {
        if (routeArrowMode)
        {
          routeArrowMode.clear();
          routeArrowMode = false;
          tempCanvas.clear();
          tempCanvas.hide();
        }
        routeToolActive = false;
        updateRouteSearchPane();
      },
      addPoint: function(x, y)
      {
        var m = markers[findOrAddMarker(x, y)];
        if (!firstRouteMarker)
        {
          firstRouteMarker = m;
          this.switchOn();
          showMarkers();
        }
        else if (m != firstRouteMarker)
        {
          addRoute(firstRouteMarker, m, defaultRouteMode);
          recalculateRoutes();
          stopDrawingRoute();
          isFullScreen = false;
          resizeMap();
          world.repaint();
        }
      },
	  move: function(x, y) {
	    drawingRouteLine = true;
	    var x1 = world.screenX(firstRouteMarker.x);
        var y1 = world.screenY(firstRouteMarker.y);
        var x2 = x - canvasX - (this.onDrag ? this.onDrag.dX : 0);
        var y2 = y - canvasY - (this.onDrag ? this.onDrag.dY : 0);
        var phi = Math.atan2(y2 - y1, x2 - x1);
        var dphi = 2.6, l = 13;
        tempCanvas.clear();
        tempCanvas.drawLine(x1, y1, x2, y2, "#0020ff", 2, true);
        tempCanvas.drawLine(x2, y2, x2 + l*Math.cos(phi - dphi), y2 + l*Math.sin(phi - dphi), "#0020ff", 2, false);
        tempCanvas.drawLine(x2, y2, x2 + l*Math.cos(phi + dphi), y2 + l*Math.sin(phi + dphi), "#0020ff", 2, false);
	  },
	  startX: 0,
      startY: 0,
      startWorldX: 0,
      startWorldY: 0,
	  onDrag : false,
	  right: false,
      drag: function(x, y) {
	    if (this.right) return;
		div.style.cursor = "url('map/move.cur'), move";
	    this.onDrag = {
		  dX : this.startX - x,
		  dY : this.startY - y
		};
		this.move(this.startX, this.startY);
	    world.navigateTo(
          this.startWorldX - world.worldX(x) + world.worldX(this.startX),
          this.startWorldY - world.worldY(y) + world.worldY(this.startY),
          world.getZoomLevel()
        );
	  },
      click: function(x, y) {
	    drawingRouteLine = false;
	    if (!this.right)
          this.addPoint(x, y);
		else if (firstRouteMarker)
		  deleteMarker(firstRouteMarker);
		this.right = false;
      },
      drop: function(x, y) {
	    div.style.cursor = "default";
	    this.onDrag = false;
	  },
      pick: function(x, y, right) 
      {
	    this.right = right;
		this.startX = x;
        this.startY = y;
        this.startWorldX = world.getX();
        this.startWorldY = world.getY();
      }
    } 
  };
}
function createRouteModeSelector(routeMode, callback)
{
  var update = function()
  {
    for (var i = 0; i < s.childNodes.length; i++)
    {
      var tag = s.childNodes[i];
      if ((tag.tagName == "OPTION") && tag.selected)
        callback(tag.value);
    }
  }
  var div = newDiv();
  div.style.marginTop = "1px";
  div.style.marginBottom = "8px";
  div.appendChild(newElement("span", { innerHTML: "Режим прокладки маршрута: " }));
  var s = newElement("select", { onchange: update });
  for (var key in (temp = { distance: "по расстоянию", time: "по времени", deftime: "по времени с учетом пробок" }))
    s.appendChild(newElement("option", { value: key, innerHTML: temp[key], selected: (key == routeMode) }));
  div.appendChild(s);
  update();
  return div;
}
function formatCoordinatesCurrently(x, y, coordMode) {
  if(coordMode == 3)return Math.round(geoFromPxX(x)) + ", " + Math.round(geoFromPxY(y));
  var lat_ = lat(y); var lon_ = lon(x);
  var degreeFormat = [formatDegreesSimple, formatDegrees2, formatDegrees][coordMode];
  return  (lat_ > 0 ? "N" : "S") + degreeFormat(Math.abs(lat_)) +
    (lon_ > 0 ? " E" : " W") + degreeFormat(Math.abs(lon_));
}
function Map(aroundDiv)
{
  var ad2 = newDiv("");
  ad2.style.position = "relative";
  ad2.style.width = "100%";
  ad2.style.height = "100%";
  aroundDiv.appendChild(ad2);
  aroundDiv = ad2;

  if (!jamsTooltipDiv)
  {
    jamsTooltipDiv = newDiv("map_jams_tooltip");
    document.body.appendChild(jamsTooltipDiv);
    new HandlerMode(document.body, "mousemove", function(event)
    {
      position(jamsTooltipDiv, eventX(event) + 5, eventY(event));
	  if ( jamsTooltipDiv.style.display == 'block' ) {
	  	var aroundTop = getOffsetTop($("around_map"));
		var aroundLeft = getOffsetLeft($("around_map"));
		var key = aroundTop + $('bubbleFrameJams').offsetHeight > eventY(event) ? 'b' : 't';
		key += aroundLeft + $("around_map").offsetWidth < eventX(event) + $('bubbleFrameJams').offsetHeight ? 'l' : 'r';
		$('bubbleFrameJams').className = "poi-tooltip q" + { tr:1, tl:4, br:2, bl:3 }[key];
		if (key == 'tl' || key == 'bl') position(jamsTooltipDiv, eventX(event) - 5, eventY(event));
	  }
    }).set();
  }
  if (!poiTooltipDiv)
  {
    poiTooltipDiv = newDiv("map_jams_tooltip");
    //document.body.appendChild(poiTooltipDiv);
	$('around_map').appendChild(poiTooltipDiv);
    new HandlerMode(poiTooltipDiv, "mouseover", function(event)
    { show(poiTooltipDiv); hidePoiTooltip(1); }).set();
  new HandlerMode(poiTooltipDiv, "mouseout", function(event)
    { hidePoiTooltip(2); }).set();
  }

  var fileref = document.createElement("link");
  fileref.setAttribute("rel", "stylesheet");
  fileref.setAttribute("type", "text/css");
  fileref.setAttribute("href", "map/map.css?11");
  document.getElementsByTagName("head")[0].appendChild(fileref);

  var width = pxFromGeoX(geoRight);
  var height = pxFromGeoY(geoBottom);

  var div = newDiv("map");
  aroundDiv.appendChild(div);

  function startResize(event, outerDiv, innerDiv, direction, hack)
  {
    event = event || window.event;
    var tg = event.srcElement || event.target;
    if(tg != outerDiv)
      return;
    var startT = (eventX(event) - eventY(event))/2;
    var startInnerW = parseInt(innerDiv.offsetWidth);
    var startInnerH = parseInt(innerDiv.offsetHeight);
    var startOuterW = parseInt(outerDiv.offsetWidth);
    var startOuterH = parseInt(outerDiv.offsetHeight);
    var modes = new Modes(
      new HandlerMode(document.documentElement, "mousemove", function(event){
        var dt = direction*((eventX(event) - eventY(event))/2 - startT);
        var innerW = startInnerW + hack*2 + dt;
        var innerH = startInnerH + hack*2 + dt;
        var outerW = startOuterW + hack + dt;
        var outerH = startOuterH + hack + dt;
        if((innerW < 0) || (outerW < 0) || (innerH < 0) || (outerH < 0))
          return;
        size(outerDiv, outerW, outerH);
        size(innerDiv, innerW, innerH);
        world.repaint();
      }),
      new HandlerMode(document.documentElement, "mouseup", function(event){
    navigationTopUpdate();
        modes.clear();
      })
    );
    modes.set();
    var e = event;
    if (e.preventDefault){
      e.preventDefault();
      e.stopPropagation();
    }else{
      e.returnValue = false;
      e.cancelBubble = true;
    }
  }

  var divHideOverview = document.createElement("img");
  divHideOverview.src = "map/close_map2b.png";
  divHideOverview.className = "map_hide_overview";
  divHideOverview.onclick = function() { 
    minimize2(divAroundOverview, divHideOverview);
  var overviewScale = overviewWorld.getScale()/world.getScale();
  navigationTopUpdate();
    var width = div.clientWidth/overviewScale;
    var height = div.clientHeight/overviewScale;
    positionSize(frameIndicatorDiv,
      (divOverview.clientWidth - width)/2,
      (divOverview.clientHeight - height)/2,
      width,
      height
    );
  overviewWorld.repaint(); }
  aroundDiv.appendChild(divHideOverview);
  var divAroundOverview = newDiv("map_around_overview");
  divAroundOverview.onmousedown = function(event) { startResize(event, divAroundOverview, divOverview, -1, 0); }
  divAroundOverview.id = "map_around_overview_id";
  
  
  var divOverview = newDiv("map_overview");
  divAroundOverview.appendChild(divOverview);
  aroundDiv.appendChild(divAroundOverview);
  var divHideZoomer = document.createElement("img");
  divHideZoomer.src = "map/close_map2.png";
  divHideZoomer.className = "map_hide_zoomer";
  divHideZoomer.onclick = function() { minimize2(divAroundZoomer, divHideZoomer); detailWorld.repaint() }
  aroundDiv.appendChild(divHideZoomer);
  var divAroundZoomer = newDiv("map_around_zoomer");
  divAroundZoomer.onmousedown = function(event) { startResize(event, divAroundZoomer, divZoomer, 1, isIE ? 0 : -1); }
  var divZoomer = newDiv("map_zoomer");
  divAroundZoomer.appendChild(divZoomer);
  aroundDiv.appendChild(divAroundZoomer);
  
  if (!isOverview) minimize2(divAroundOverview, divHideOverview);
  if (!isZoom) minimize2(divAroundZoomer, divHideZoomer);

  var divCoord = newDiv("map_coord");
  var divCoordinates = document.createElement("u");
  divCoordinates.className = "map_coordinates";
  divCoordinates.onclick = function() 
  { 
    var x = world.getX(), y = world.getY();
    markers.findOrAdd(x, y, formatCoordinatesCurrently(x, y, currentCoordMode));
    world.repaint();
    return false;
  }
  divCoord.appendChild(divCoordinates);
  appendText(divCoord, "&nbsp;&nbsp;");
  var divChangeCoordFormat = document.createElement("img");
  divChangeCoordFormat.src = "img/logo_maps2.gif";
  divChangeCoordFormat.title = "изменить формат";
  divChangeCoordFormat.className = "map_change_coord_format";
  divCoord.appendChild(divChangeCoordFormat);
  if (!isCross) divCoord.style.display = "none";
  aroundDiv.appendChild(divCoord);

  var divTerms = newDiv("map_terms");
  var createTermsA = function(title, text)
  {
    var a = document.createElement("a");
    a.href = "terms.html";
    a.title = title;
    a.innerHTML = text;
    appendText(divTerms, " ");
    divTerms.appendChild(a);
    return a;
  }
  var termsA = createTermsA("пользовательское соглашение", "&laquo;СканЭкс&raquo;");
  var termsB = createTermsA("ANTRIX Corporation Ltd.", "&copy; ANTRIX"); 
  var termsC = createTermsA("European Space Imaging GmBH", "&copy; EUSI GmBH");
  var termsD = createTermsA("ImageSat International N.V., (Netherlands Antilles)", "&copy; ImageSat");
  var termsE = createTermsA("пользовательское соглашение", "&copy; &laquo;Прозрачный мир&raquo;");
  var termsF = createTermsA("пользовательское соглашение", "&copy; ЗАО &laquo;Геоцентр-Консалтинг&raquo;");

  var currentlyInMoscow = function() { return inMoscowMap(lon(world.getX()), lat(world.getY())); }

  var mode = "";
  var jamsFlag = false;
  var poiTypes = [];
  var poiMinIndex = 1, poiMaxIndex = 100;
  var getMainTiles = function(x1, y1, x2, y2, zoomLevel)
  {
/*    var ret = (
      (mode == "map") ? jamsFlag ? getMapAndJams : getMap : 
      (mode == "satellite") ? jamsFlag ? getTilesAndJams : getTiles : getMap
    )(x1, y1, x2, y2, zoomLevel);*/
	var ret;
	if (mode == "map")
	{
		ret = (jamsFlag ? getMapAndJams : getMap)(x1, y1, x2, y2, zoomLevel);
	}
	else if (mode == "satellite")
	{
		ret = (jamsFlag ? getTilesAndJams : getTiles)(x1, y1, x2, y2, zoomLevel);
	}
    if (poiTypes.length > 0)
      ret.push(getPoiTile(x1, y1, x2, y2, zoomLevel, poiTypes, poiMinIndex, poiMaxIndex));
    return ret;
  }

  div.oncontextmenu = function() { return false; }
  var world = new FreeWorld(div, width, height, MAX_ZOOM_LEVEL);
  var largeMap = new MapArea(world, getMainTiles, true);
  var crosshair = newDiv("map_crosshair");
  setBg(crosshair, "crosshair.png");
  div.appendChild(crosshair);
  if (!isCross) crosshair.style.display = "none";
  var overviewMap = false;
  var frameIndicatorDiv = false;
  var detailMap = false;
  var detailZoom = 3;
  var minMapZoom = 0;
  var overviewWorld, detailWorld;
  var zoomerTileFunction = getMainTiles;

  var l = Math.round(aroundDiv.clientWidth/6);
  size(divAroundOverview, l, l);
  size(divOverview, l - 6, l - 6);
  size(divAroundZoomer, l - 1, l);
  size(divZoomer, l - 7, l - 7);

  frameIndicatorDiv = newDiv("map_frame_indicator");
  divOverview.appendChild(frameIndicatorDiv);
  var overviewWorld = new TiedWorld(divOverview, world,
    function() { return 3 + constrain(3, world.getZoomLevel(), 13); });
  overviewMap = new MapArea(overviewWorld, getMap, false);
  detailWorld = new TiedWorld(divZoomer, world, function() { return detailZoom; })
  detailMap = new MapArea(detailWorld, function(x1, y1, x2, y2, zoomLevel)
  {
    return zoomerTileFunction(x1, y1, x2, y2, zoomLevel);
  }, false);

  var getLineColor = function() { return (mode.indexOf("map") == -1) ? "#ffffff" : "#0020ff"; };
  var markers = new Markers(world, getLineColor, function(event)
  {
    var worldX = world.worldX(eventX(event));
    var worldY = world.worldY(eventY(event));
    var worldZoomLevel = world.getZoomLevel();
    if (!jamsFlag || isMouseDown)
      return;
    var scale = getScale(worldZoomLevel);
    var tileSize = 256*scale;
    var idxX = Math.floor(geoFromPxX(worldX)/tileSize);
    var idxY = Math.floor(geoFromPxY(worldY)/tileSize);
    var x = (worldX - pxFromGeoX(idxX*tileSize))/scale;
    var y = 256 - (pxFromGeoY(idxY*tileSize) - worldY)/scale;
    var spans = jamsSpanCache[idFromXYZ(idxX, idxY, zFromZoomLevel(worldZoomLevel))];
    if (!spans)
      return;
    var i;
    for (i = 0; i < spans.length; i++)
    {
      var span = spans[i];
      if (
        (Math.abs(x*span[0] + y*span[1] + span[2]) <= 5) && 
        (Math.abs(x*span[1] - y*span[0] + span[3]) <= (span[4]/2 + 5))
      )
        break;
    }
    if (i < spans.length)
      showJamsTooltip(spans[i][5]);
    else if (jamsTooltipAlt)
      hideJamsTooltip();
  });
  var testImage = new Image();
  var testImage2 = new Image();
  var testImage3 = new Image();
  var testImage4 = new Image();
  var testIsLoading = false;
  world.onRepaint(function()
  {
    if (dontReloadMapAreas) return;
    position(crosshair, div.clientWidth/2 - 8, div.clientHeight/2 - 8);
    var isMap = (mode.indexOf("map") != -1);
    divZoomer.style.backgroundColor = isMap ? "white" : "black";
    div.style.backgroundColor = isMap ? "white" : "black";
    var overviewScale = overviewWorld.getScale()/world.getScale();
    var width = div.clientWidth/overviewScale;
    var height = div.clientHeight/overviewScale;
    positionSize(
      frameIndicatorDiv,
      (divOverview.clientWidth - width)/2,
      (divOverview.clientHeight - height)/2,
      width,
      height
    );
  });
  world.onRepaint(deferred(function()
  {
    if (dontReloadMapAreas || testIsLoading)
      return;
    testIsLoading = true;
    var isMap = (mode.indexOf("map") != -1);
    var haveIKONOS = false, haveIRS = false, haveDetailMap = false, haveDetailMap2 = false;
    var x = world.getX(), y = world.getY();
    var updateDetailZoom = function()
    {
      var mm = minMapZoom, dz = detailZoom, zt = zoomerTileFunction;
      var xx = geoFromPxX(x), yy = geoFromPxY(y);
      if (isMap && !((xx > 3014274 && yy > 5181134) && ( xx < 21231976 && yy < 14185832 ) ||
                     (xx > 4129643 && yy > 5008494) && ( xx < 5479828 && yy < 6299974 ) ||
                     (xx > 2202818 && yy > 7206212) && ( xx < 2541587 && yy < 7387215 ))) 
      {
        minMapZoom = 10;
        detailZoom = 11;
      } 
      else 
      {
        minMapZoom = isMap ? haveDetailMap ? 0 : haveDetailMap2 ? 4 : 7: haveIKONOS ? 0 : haveIRS ? 4 : haveDetailMap2 ? 9 : 11;
        detailZoom = haveIKONOS ? 1 : haveIRS ? 5 : haveDetailMap ? 1 : haveDetailMap2 ? 4 : 11;
      }
      zoomerTileFunction = ((mode == "satellite") ? getTiles : getMap);
      if (minMapZoom > world.getZoomLevel()) 
        world.setZoomLevel(minMapZoom); 
      if ((mm != minMapZoom) || (dz != detailZoom) || (zt != zoomerTileFunction))
        world.repaint();
    testIsLoading = false;
    }
    var checkDetailMap2 = function()
    {
      testImage4.onload = function() { haveDetailMap2 = true; updateDetailZoom(); }
      testImage4.onerror = function() { haveDetailMap2 = false; updateDetailZoom(); }
      testImage4.src = getMap(x, y, x + 1, y + 1, 6)[0].url;
    }
    var checkDetailMap = function(){
      testImage3.onload = function() { haveDetailMap = true; haveDetailMap2 = true; updateDetailZoom(); }
      testImage3.onerror = function() { haveDetailMap = false; checkDetailMap2(); }
      testImage3.src = getMap(x, y, x + 1, y + 1, 3)[0].url;
    }
    var checkIRS = function(){
      testImage2.onload = function() { haveIRS = true; checkDetailMap(); }
      testImage2.onerror = function() { haveIRS = false; checkDetailMap(); }
      testImage2.src = getTiles(x, y, x + 1, y + 1, 4)[0].url;
    }
    testImage.onload = function() { haveIKONOS = true; haveIRS = true; checkDetailMap(); }
    testImage.onerror = function() { haveIKONOS = false; checkIRS(); }
    if (isNaN(x) || isNaN(y)) { updateDetailZoom(); } else
	{
      testImage.src = getMap(x, y, x + 1, y + 1, 2)[0].url;
	}
  }));

  var currentCoordMode = 0;
  new HandlerMode(divChangeCoordFormat, "click", function()
  {
    currentCoordMode = (currentCoordMode + 1)%4;
    refreshCoordinates();
  }).set();
  var refreshCoordinates = function()
  {
    divCoordinates.innerHTML = formatCoordinatesCurrently(world.getX(), world.getY(), currentCoordMode);
  }
  world.onRepaint(function()
  {
    if (!dontReloadMapAreas)
    {
      refreshCoordinates();
      var isMap = (mode.indexOf("map") != -1);
      for (var j in (temp = [divCoordinates, divChangeCoordFormat, divTerms, termsA, termsB, termsC, termsD, termsE, termsF]))
        temp[j].style.color = isMap ? "black" : "white";
      for (var j in (temp = [termsB, termsC, termsD]))
        temp[j].style.display = isMap ? "none" : "inline";
      var isMoscowMap = currentlyInMoscow() && (world.getZoomLevel() < 11);
      termsE.style.display = (isMap && !isMoscowMap) ? "inline" : "none";
      termsF.style.display = (isMap && isMoscowMap) ? "inline" : "none";
      if (scaleBarDiv1)
        scaleBarDiv1.style.color = isMap ? "black" : "white";
    }
  });
  var zooming = false;
  var frameInterval = 20;
  var gradually = function(n, callback)
  {
    if (zooming)
      return;
    zooming = true;
    window.dontReloadMapAreas = true;
    callback(1.0/n);
    for (var i = 1; i < n; i++) (function(ii) 
    {
      setTimeout(function() { callback((ii + 1.0)/n); }, ii*frameInterval);
    })(i);
    setTimeout(function()
    {
      zooming = false;
      window.dontReloadMapAreas = false;
      world.repaint();
    }, frameInterval*n-1);	
  }
  var zoomBy = function(dz)
  {
    if ((dz < 0) && ((world.getZoomLevel() + dz) < minMapZoom))
      return;
    var z = world.getZoomLevel();
    gradually(fastZoom? 1: 4, function(t) 
    { 
      world.navigateTo(world.getX(), world.getY(), z + t*dz); 
    });
  }
  var moveTo = function(x, y)
  {
    var oldX = world.getX();
    var oldY = world.getY();
    var dx = x - oldX;
    var dy = y - oldY;
    gradually(fastZoom? 1: 4, function(t) 
    { 
      world.navigateTo(oldX + t*dx, oldY + t*dy, world.getZoomLevel()); 
    });
  }
  var moveHandlers = {
    startX: 0,
    startY: 0,
    startWorldX: 0,
    startWorldY: 0,
    click: function(x, y)
    {
      //zoomToMouse(x, y, -1);
    },
	dblclick : function(x, y)
	{
	  zoomToMouse(x, y, -1);
	},
    pick: function(x, y)
    {
      this.startX = x;
      this.startY = y;
      this.startWorldX = world.getX();
      this.startWorldY = world.getY();
    },
    drag: function(x, y)
    {
	  div.style.cursor = "url('map/move.cur'), move"
      world.navigateTo(
        this.startWorldX - world.worldX(x) + world.worldX(this.startX),
        this.startWorldY - world.worldY(y) + world.worldY(this.startY),
        world.getZoomLevel()
      );
    },
    drop: function(x, y)
    {
	  div.style.cursor = "move"
      world.repaint();
    }
  };
  var zoomToMouse = function(x, y, dz)
  {
    //Markers.breakLine();
    var oldZ = world.getZoomLevel();
    if((oldZ + dz < minMapZoom) || (oldZ + dz > 14))return;
    var k = Math.pow(2, dz);
    var oldX = world.getX();
    var oldY = world.getY();
    var dx = (1 - k)*(world.worldX(x) - oldX);
    var dy = (1 - k)*(world.worldY(y) - oldY);
    gradually(fastZoom? 1: 4, function(t) {
     var t2 = (Math.pow(2, t*dz) - 1)/(Math.pow(2, dz) - 1);
     world.navigateTo(oldX + t2*dx, oldY + t2*dy, oldZ + t*dz);
    });
  }
  var zoomHandlers = {
    startX: 0,
    startY: 0,
    canvasX: 0,
    canvasY: 0,
    click: function(x, y)
    {
      zoomToMouse(x, y, isLeft ? -1 : 1);
      tempCanvas.hide();
    },
    pick: function(x, y)
    {
      tempCanvas.clear();
      tempCanvas.resize();
      tempCanvas.show();
      this.startX = x;
      this.startY = y;
      this.canvasX = getOffsetLeft(div);
      this.canvasY = getOffsetTop(div);
    },
    drag: function(x, y)
    {
      tempCanvas.clear();
      var x1 = this.startX - this.canvasX;
      var y1 = this.startY - this.canvasY;
      var x2 = x - this.canvasX;
      var y2 = y - this.canvasY;
      var color = getLineColor();
      tempCanvas.drawLine(x1, y1, x1, y2, color, 1, true);
      tempCanvas.drawLine(x1, y2, x2, y2, color, 1, true);
      tempCanvas.drawLine(x2, y2, x2, y1, color, 1, true);
      tempCanvas.drawLine(x2, y1, x1, y1, color, 1, true);
    },
    drop: function(x, y)
    {
      tempCanvas.clear();
      tempCanvas.hide();
      if (isLeft) 
      {
        var oldX = world.getX();
        var oldY = world.getY();
        var oldZ = world.getZoomLevel();
        var dx = world.worldX((x + this.startX)/2) - oldX;
        var dy = world.worldY((y + this.startY)/2) - oldY;
        var dz = -Math.floor(Math.log(Math.max(
          div.clientWidth/Math.abs(x - this.startX),
          div.clientHeight/Math.abs(y - this.startY)
        ))/Math.log(2));
        if (oldZ + dz < minMapZoom)
          dz = minMapZoom - oldZ;
        gradually(fastZoom? 1: 6, function(t) 
        {
          var t2 = (dz != 0) ? (Math.pow(2, t*dz) - 1)/(Math.pow(2, dz) - 1) : t;
          world.navigateTo(oldX + t2*dx, oldY + t2*dy, oldZ + t*dz);
        });
    selectTool(0);
      } 
      else 
        zoomBy(1);
      world.repaint();
    }
  };
  var leftHandlers = false;
  var switchLeftHandlers = function(newHandlers)
  {
    if (leftHandlers.switchOff)
      leftHandlers.switchOff();
    leftHandlers = newHandlers;
    if (leftHandlers.switchOn)
      leftHandlers.switchOn();
  }
  var restoreDefaultMode = function(){
    div.style.cursor = "";
    switchLeftHandlers(moveHandlers);
  }
  restoreDefaultMode();
  var switchToMarkerMode = function()
  {
    try { div.style.cursor = 'default'/*"url('map/cursor-marker.cur'), move"*/; }
    catch (e) { div.style.cursor = "move"; }
    switchLeftHandlers(markers.markerHandlers);
  }
  var switchToZoomMode = function()
  {
    div.style.cursor = "default";
    switchLeftHandlers(zoomHandlers);
  }
  var switchToRouteMode = function()
  {
    try { div.style.cursor = 'default'/*"url('map/cursor-marker.cur'), move"*/; }
    catch (e) { div.style.cursor = "move"; }
    switchLeftHandlers(markers.routeHandlers);
  }
  var currentHandlers = function() {
    return isLeft || leftHandlers == markers.markerHandlers || leftHandlers == markers.routeHandlers ? leftHandlers : 
      ((leftHandlers == zoomHandlers) || (leftHandlers == moveHandlers)) ? 
      zoomHandlers : markers.drawHandlers;
  };

  var isAfterClick = false;
  var isMouseDown = false;
  var isInClick = false;
  var isLeft = 0;
  var mouseDownX, mouseDownY;
  mapMouseDown = function(event)
  {
    hideJamsTooltip();
    hidePoiTooltip(0);
    event = event || window.event;
    isLeft = isLeftMouseButton(event);
    cancelEvent(event);
    if (!isLeft)
      cancelRightClick(event);
    var x = eventX(event), y = eventY(event);
    mouseDownX = x;
    mouseDownY = y;
    isMouseDown = true;
    crosshair.className = "map_crosshair_pushed";
    isInClick = true;
    currentHandlers().pick(x, y, !isLeft);
  }
  new HandlerMode(div, "mousedown", mapMouseDown).set();
  var onClick = function(event)
  {
    if (isMouseDown && isInClick)
      currentHandlers().click(eventX(event), eventY(event), !isLeft);
    if (!isLeft)
      cancelRightClick(event);
  }
  new HandlerMode(div, "mouseup", onClick).set();
  new HandlerMode(div, "dblclick", function(event)
  {
    if (isInClick)
    {
      var handlers = currentHandlers();
      handlers.click(eventX(event), eventY(event));
      if(handlers.dblclick)handlers.dblclick(eventX(event), eventY(event));
    }
    if (!isLeft)
      cancelRightClick(event);
  }).set();
  var currentMouseX, currentMouseY;
  new HandlerMode(div, "mousemove", function(event)
  {
    var x = eventX(event), y = eventY(event);
    currentMouseX = x;
    currentMouseY = y;
    if (!isMouseDown)
    {
      if (currentHandlers().move)
        currentHandlers().move(x, y);
      return;
    }
    if ((Math.abs(x - mouseDownX) > 1) || (Math.abs(y - mouseDownY) > 1))
      isInClick = false;
    if (isMouseDown)
      currentHandlers().drag(x, y, !isLeft);
  }).set();
  new GlobalHandlerMode("mouseup", function(event)
  {
    if (moveInterval)
    {
      clearInterval(moveInterval);
      world.repaint();
    }
    moveInterval = false;
    crosshair.className = "map_crosshair";
    if (isMouseDown && !isInClick)
      currentHandlers().drop(eventX(event), eventY(event));
    isMouseDown = false;
    isMouseDown2 = false;
  }).set();
  var moveInterval = false;
  var clearMoveInterval = function()
  {
    if(moveInterval)clearInterval(moveInterval);
    moveInterval = false;
  }
  document.documentElement.onkeydown = function(event)
  {
    event = event || window.event;
    var tg = event.srcElement || event.target;
    if ((tg.tagName == "BODY") || (tg.tagName == "HTML") || (tg == div)){
      var code = event.which || event.keyCode;
      var dx = (code == 37) ? -1 : (code == 39) ? 1 : 0;
      var dy = (code == 38) ? -1 : (code == 40) ? 1 : 0;
      if (((dx != 0) || (dy != 0)) && !moveInterval){
        clearMoveInterval();
        var speed = world.getScale()*35;
        moveInterval = setInterval(function(){
          world.navigateTo(
            world.getX() + dx*speed,
            world.getY() + dy*speed,
            world.getZoomLevel()
          );
        }, 30);
      }
    switch (code) {
      case 32: minimizeUI(divHide, iHide, !isUI); break;
      case 49: selectTool(0); break;
      case 50: selectTool(1); break;
      case 51: selectTool(2); break;
      case 52: selectTool(3); break;
      case 86: if(map.getMode() == "map") selectSwitch(1); else selectSwitch(0); break;
      case 107: zoomBy(-1); break;
      case 109: zoomBy(1); break;
    }
    }
  }
  document.documentElement.onkeyup = clearMoveInterval;
  var onWheel = function(e){
    if(!e)e = window.event;
    var inMap = false;
    var elem = e.srcElement || e.target;
    while(elem != null)
    {
      if ((elem == div) || (elem == divOverview))
      {
        inMap = true;
        break;
      }
      elem = elem.parentNode;
    }
    if (!inMap)
      return;
    var delta = 0;
    if (e.wheelDelta) 
      delta = e.wheelDelta;
    else if(e.detail) 
      delta = -e.detail;
    if (delta) {
      zoomToMouse(currentMouseX, currentMouseY, delta < 0 ? 1 : -1);
	  var handlers = currentHandlers();
	  var event = e;
      if (handlers.wheel) {
	    Markers.hideLine();
	    setTimeout(function() {
		  try {
	  	    handlers.wheel(currentMouseX, currentMouseY);
		  } catch(e) {}
	    }, 100);
	  }
	}
    cancelEvent(e);

    if (jamsTooltipDiv) 
      hideJamsTooltip();
    if (poiTooltipDiv) 
      hidePoiTooltip(0);    
  }
  new HandlerMode(window, "mousewheel", onWheel).set();
  new HandlerMode(document, "mousewheel", onWheel).set();
  if (window.addEventListener)
    window.addEventListener('DOMMouseScroll', onWheel, false);
  var isMouseDown2 = false, isInClick2 = false;
  var addMoves = function(w)
  {
    var startX, startY;
    var startWorldX, startWorldY;
    new HandlerMode(w.div, "mousedown", function(event)
    {
      isMouseDown2 = true;
      crosshair.className = "map_crosshair_pushed";
      isInClick2 = true;
      startX = eventX(event);
      startY = eventY(event);
      startWorldX = world.getX();
      startWorldY = world.getY();
      var isLeft2 = isLeftMouseButton(event);
      if (!isLeft2){
        showMarkers();
        cancelRightClick(event);
      }
    }).set();
    new HandlerMode(w.div, "mousemove", function(event)
    {
      if ((isIE && (event.button != 1)) || !isMouseDown2)
        return;
      var x = eventX(event), y = eventY(event);
      if ((Math.abs(x - startX) > 5) || (Math.abs(y - startY) > 5))
        isInClick2 = false;
      world.navigateTo(
        startWorldX - w.worldX(x) + w.worldX(startX),
        startWorldY - w.worldY(y) + w.worldY(startY),
        world.getZoomLevel()
      );
    }).set();
    new HandlerMode(w.div, "click", function(event)
    {
      if (isInClick2)
        moveTo(w.worldX(eventX(event)), w.worldY(eventY(event)));
      isInClick2 = false;
    }).set();
  }
  addMoves(overviewWorld);
  addMoves(detailWorld);
  var moveInterval = false;
  var startMove = function(dx, dy)
  {
    var s = word.getScale()*30;
    var moveSome = function()
    {
      world.navigateTo(world.getX() + dx*s, world.getY() + dy*s, world.getZoomLevel());
    }
    moveSome();
    moveInterval = setInterval(moveSome, 50);
  }
  var navDiv = newDiv("map_nav");
  div.appendChild(navDiv);
  var t;
  t = newDiv("map_button_plus");
  t.onmousedown = function(event) { zoomBy(-1); cancelEvent(event); };
  t.onclick = cancelEvent;
  setBg(t, "final_zoom_plus.png");
  navDiv.appendChild(t);
  var plusButtonDiv = t;
  var scaleDivs = [];
  function setScaleDivOnClick(d, k){
    d.onmousedown = function(event){
      zoomBy(k - world.getZoomLevel());
      cancelEvent(event);
    }
    d.onclick = cancelEvent;
  }
  for (var i = 0; i <= MAX_ZOOM_LEVEL; i++){
    var scaleDiv = newDiv("map_button_scale");
    setScaleDivOnClick(scaleDiv, i);
    navDiv.appendChild(scaleDiv);
    scaleDivs[i] = scaleDiv;
  }
  world.onRepaint(function(){
    if(dontReloadMapAreas)return;
    for (var i = 0; i <= MAX_ZOOM_LEVEL; i++)
      setVisible(scaleDivs[i], (i >= minMapZoom));
  });
  world.onRepaint(deferred(function(){
    if(dontReloadMapAreas)return;
    var j = Math.round(world.getZoomLevel());
    for (var i in scaleDivs)
      setBg(scaleDivs[i], (i == j) ?
        "final_zoom_active.png" : "final_zoom_raw.png");
    if (scaleBarDiv1){
      x1 = lon(world.getX());
      x2 = lon(world.getX() + 40);
      y1 = lat(world.getY());
      y2 = lat(world.getY() + 30);
      var metersPerPixel = distVincenty(x1, y1, x2, y2)*world.getScale()/50;
      for (var name in (temp = {"1 м": 1, "2 м": 2, "5 м": 5, "10 м": 10, "20 м": 20, "50 м": 50, "100 м": 100, "200 м": 200, "500 м": 500, "1 км": 1000, "2 км": 2000, "5 км": 5000, "10 км": 10000, "20 км": 20000, "50 км": 50000, "100 км": 100000, "200 км": 200000, "500 км": 500000, "1000 км": 1000000, "2000 км": 2000000})){
        if (metersPerPixel*100 < temp[name]){
          var l = temp[name]/metersPerPixel;
          scaleBarDiv1.innerHTML = name;
          scaleBarDiv1.style.width = Math.round(l) + "px";
          scaleBarDiv2.innerHTML = "&nbsp;";
          scaleBarDiv2.style.width = (Math.round(l) - 2 + (isIE ? 4 : 0)) + "px";
          break;
        }
      }
    }
  }));
  t = newDiv("map_button_minus");
  t.onmousedown = function(event) { zoomBy(1); cancelEvent(event); };
  t.onclick = cancelEvent;
  t.style.top = 0;
  setBg(t, "final_zoom_minus.png");
  navDiv.appendChild(t);
  var scaleBarDiv1 = newDiv("map_scalebar1");
  var scaleBarDiv2 = newDiv("map_scalebar2");
  div.appendChild(scaleBarDiv1);
  div.appendChild(scaleBarDiv2);

  var divTools = newDiv("map_tools");
  aroundDiv.appendChild(divTools);
  var tools = [];
  function createTool(title, name, switcher)
  {
    var a = document.createElement("span");
    a.className = "map_tool";
    a.title = title;
    tools.push(function(flag)
    {
      if (flag)
        switcher();
      a.blur();
      setBg(a, "final_" + name + (flag ? "_a" : "") + ".png");
    });
    var idx = tools.length - 1;
    a.onclick = function() { selectTool(idx); return false; }
    divTools.appendChild(a);
  }
  function selectTool(idx)
  {
    for (var i = 0; i < tools.length; i++)
      tools[i](i == idx);
  }
  createTool("движение", "move_tool", restoreDefaultMode);
  createTool("увеличение", "zoom_tool", switchToZoomMode);
  createTool("точки и расстояния", "marker_tool", switchToMarkerMode);
  createTool("поиск маршрута", "route_tool", switchToRouteMode);
  selectTool(0);

  var divSwitch = newDiv("map_switch");
  divSwitch.id = "map_switch_id";
  aroundDiv.appendChild(divSwitch);
  var switches = [];
  var modes = [];
  function createSwitch(mode, text)
  {
    var span = document.createElement("span");
    span.innerHTML = text;
    span.style.width = isIE ? "61px" :"60px";
    span.style.height = isIE ? "29px" : "22px";
    switches.push(function(flag)
    {
      setBg(span, "final_mode_bg" + (flag ? "_a" : "") + ".png");
      span.style.cursor = flag ? "default" : isIE ? "hand" : "pointer";
    });
    modes.push(mode);
    divSwitch.appendChild(span);
    var idx = switches.length - 1;
    span.onclick = function() { selectSwitch(idx); }
  }

  function selectSwitch(idx)
  {
    for (var i = 0; i < switches.length; i++)
      switches[i](i == idx);
    mode = modes[idx];

    if (mode == "satellite")
       world.navigateTo(world.getX(), world.getY(), world.getZoomLevel());
    else
       world.repaint();
  }

  createSwitch("map", "схема");
  createSwitch("satellite", "спутник");
  
  var divHide = newDiv("map_hide");
  var iHide = document.createElement("img");
  iHide.src = "map/UI_close.png";
  iHide.title = "Спрятать инструменты";
  iHide.onclick = function() { minimizeUI(divHide, iHide, !isUI) }
  divHide.appendChild(iHide);
  aroundDiv.appendChild(divHide);

  new HandlerMode(window, "resize", world.repaint).set();

  poiTileType.onUpdatePoi = function(stats) { if (ret.onUpdatePoi) ret.onUpdatePoi(stats); }

  setInterval(function()
  {
    makeNewRefreshSuffix();
    if (jamsFlag)
      world.repaint();
  }, 120000);

  var ret = {
    navigateTo: function(x, y, z, force)
    {
      world.navigateTo(x, y, force ? z : Math.max(z, minMapZoom));
    },
    moveTo: function(x, y, z, force)
    {
      this.navigateTo(pxFromGeoX(x), pxFromGeoY(y), zoomLevelFromZ(z), force);
    },
    getX: world.getX,
    getY: world.getY,
    getZoomLevel: world.getZoomLevel,
    repaint: world.repaint,
    markers: markers,
    setMode: function(m) { for (var i = 0; i < modes.length; i++) if (m == modes[i]) selectSwitch(i); },
    getMode: function() { return mode; },
    setTool: function(i) { selectTool(i) },
    setJams: function(flag) { jamsFlag = flag; world.repaint(); },
    setPoi: function(newPoiTypes, newPoiMinIndex, newPoiMaxIndex)
    { 
      poiTypes = newPoiTypes; 
      poiMinIndex = newPoiMinIndex;
      poiMaxIndex = newPoiMaxIndex;
      if (poiTypes.length == 0)
        if (ret.onUpdatePoi)
          ret.onUpdatePoi({});
      this.repaint(); 
    },
    setCross: function(flag)
    {
      isCross = flag;
      setVisible(crosshair, flag);
      setVisible(divCoord, flag);
    },
	setScale: function(flag)
    {
      isCross = flag;
      setVisible(scaleBarDiv1, flag);
      setVisible(scaleBarDiv2, flag);
    },
  setUI: function(flag)
  {
    isUI = flag;
    setVisible(navDiv, flag);
    setVisible(divSwitch, flag);
    setVisible(divTools, flag);
  },
    showUI: function(flag) { this.setUI(flag); setVisible(divHide, flag); },
    showMini: function(flag) { setVisible(divHideOverview, flag); setVisible(divHideZoomer,flag); },
	showMiniZoomer: function(flag) { setVisible(divHideZoomer,flag); },
    getJams: function() { return jamsFlag },
    restoreDefaultMode: function() { selectTool(0); }
  };
  return ret;
}
function inMoscowMap(x, y)
{
  return  ((x > 34.979180) && (y < 57.328328) && (x < 41.021662) && (y > 53.969947)) ||
    ((x > 43.365488) && (y > 56.181617) && (x < 43.702632) && (y < 56.294805)) ||
  ((x > 29.73929) && (y > 59.77301) && (x < 30.72120) && (y < 60.10034));
}
function writeTotalLength(totalLength)
{
  if (!$("around_total_length"))
    return;
  setVisible$("around_total_length", (Math.round(totalLength) != 0));
  $("total_length").innerHTML = prettify(totalLength);
}
function writeLastLength(data)
{
  if (!$("around_total_length"))
    return;
  if ( data !== false ) {
    setVisible$("around_last_length", true);
    if( $("last_length_caption") )
      $("last_length_caption").innerHTML = data.length > 1 ? "Длины отрезков:" : "Длина отрезка:";
    var count = [];
	for (var i = 0; i < data.length; i++)
	  count[count.length] = prettify(data[i].dist);
      $("last_length").innerHTML = count.join(", ");
  } else setVisible$("around_last_length", false);
}
var nFragments = 0;
function unwriteArea()
{
  if (!$("around_area"))
    return;
  hide$("around_area");
  hide$("around_fragments");
  nFragments = 0;
}
function writeArea(area, pieces)
{
  if (!$("around_area"))
    return;
  setVisible$("around_area", (pieces.length > 1));
  $("area").innerHTML = prettifyArea(area);
  setVisible$("around_fragments", (pieces.length > 0));
  var text = "";
  nFragments = pieces ? pieces.length : 0;
  $("fragments").innerHTML = "";
  for (var i in pieces) (function(){
    var piece = pieces[i];
    var name = "&raquo; " + (
      piece.isRect ? "прямоугольник" :
      (piece.sides == 3) ? "треугольник" :
      (piece.sides == 4) ? "четырехугольник" :
      "многоугольник");
    name += " (" + prettifyArea(piece.area) + ")";
    var x = (piece.minx + piece.maxx)/2;
    var y = (piece.miny + piece.maxy)/2;
    var a = document.createElement("a");
    a.href = "#";
    a.onclick = function(){
      var z = Math.round(Math.log(Math.max(piece.maxx - piece.minx, piece.maxy - piece.miny))/Math.log(2));
      piece.markers[0].activate();
      map.navigateTo(x, y, z - 9);
      return false;
    }
    a.innerHTML = name;
    a.style.display = "block";
    $("fragments").appendChild(a);
  })();
}
function minimize2(div, button, flag)
{
  var t = !flag && (div.style.display == 'none');
  setVisible(div, t);
  if (div.className == "map_around_zoomer") {
    button.src = t ? 'map/close_map2.png' : 'map/open_map2.png';
    isZoom = t;
  } else {
    button.src = t ? 'map/close_map2b.png' : 'map/open_map2b.png';
    isOverview = t;
  }
}
function minimizeUI(div, button, flag)
{
  map.setUI(flag);
  button.src = flag ? 'map/UI_close.png' : 'map/UI_open.png';
  button.title = flag ? 'Спрятать инструменты' : 'Показать инструменты';
  div.className = flag ? "map_hide" : "map_hide_open";
}
function strip(s)
{
  return s.replace(/^\s*/, "").replace(/\s*$/, "");
}

/* geo.js */

var PI = 3.14159265358979;

function deg_rad(ang)
{
    return ang * (PI/180.0)
}

function deg_decimal(rad)
{ 
  return (rad/PI) * 180.0;
}

function merc_x(lon) 
{
  var r_major = 6378137.000;
  return r_major * deg_rad(lon);
}

function from_merc_x(x) 
{
  var r_major = 6378137.000;
  return deg_decimal(x/r_major);
}

function merc_y(lat) 
{
  if (lat > 89.5)
    lat = 89.5;
  if (lat < -89.5)
    lat = -89.5;
  var r_major = 6378137.000;
  var r_minor = 6356752.3142;
  var temp = r_minor / r_major;
  var es = 1.0 - (temp * temp);
  var eccent = Math.sqrt(es);
  var phi = deg_rad(lat);
  var sinphi = Math.sin(phi);
  var con = eccent * sinphi;
  var com = .5 * eccent;
  con = Math.pow(((1.0-con)/(1.0+con)), com);
  var ts = Math.tan(.5 * ((PI*0.5) - phi))/con;
  var y = 0 - r_major * Math.log(ts);
  return y;
}

function from_merc_y (y)
{
  var r_major = 6378137.000;
  var r_minor = 6356752.3142;
    var temp = r_minor / r_major;
    var es = 1.0 - (temp * temp);
    var eccent = Math.sqrt(es);
  var ts = Math.exp(-y/r_major);
  var HALFPI = 1.5707963267948966;

  var eccnth, Phi, con, dphi;
  eccnth = 0.5 * eccent;

  Phi = HALFPI - 2.0 * Math.atan(ts);

  var N_ITER = 15;
  var TOL = 1e-7;
  var i = N_ITER;
  dphi = 0.1;
  while ((Math.abs(dphi)>TOL)&&(--i>0))
  {
    con = eccent * Math.sin (Phi);
      dphi = HALFPI - 2.0 * Math.atan(ts * Math.pow((1.0 - con)/(1.0 + con), eccnth)) - Phi;
    Phi += dphi;
  }

  return deg_decimal(Phi);
}

function distVincenty(lon1,lat1,lon2,lat2)
{
    var p1 = new Object();
    var p2 = new Object();
  
    p1.lon =  deg_rad(lon1);
    p1.lat =  deg_rad(lat1);
    p2.lon =  deg_rad(lon2);
    p2.lat =  deg_rad(lat2);

    var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;  // WGS-84 ellipsiod
    var L = p2.lon - p1.lon;
    var U1 = Math.atan((1-f) * Math.tan(p1.lat));
    var U2 = Math.atan((1-f) * Math.tan(p2.lat));
    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
  
    var lambda = L, lambdaP = 2*Math.PI;
    var iterLimit = 20;
    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
    var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
    var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + 
        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
    if (sinSigma==0) return 0;
    var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
    var sigma = Math.atan2(sinSigma, cosSigma);
    var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
    var cosSqAlpha = 1 - sinAlpha*sinAlpha;
    var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
    if (isNaN(cos2SigmaM)) cos2SigmaM = 0;
    var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
    lambdaP = lambda;
    lambda = L + (1-C) * f * sinAlpha *
        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
    }
    if (iterLimit==0) return NaN;

    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
    var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
      B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
    var s = b*A*(sigma-deltaSigma);
  
    s = s.toFixed(3);
    return s;
}

var lambertCoefX = 100*distVincenty(0, 0, 0.01, 0);
var lambertCoefY = 100*distVincenty(0, 0, 0, 0.01)*180/PI;

function fragmentArea(points)
{
  var pts = [];
  for (var i in points)
    pts.push([points[i][0]*lambertCoefX, Math.sin(points[i][1]*PI/180)*lambertCoefY]);
  var area = 0;
  for (var i in pts)
  {
    var ipp = (i == (pts.length - 1) ? 0 : (parseInt(i) + 1));
    area += (pts[i][0]*pts[ipp][1] - pts[ipp][0]*pts[i][1]);
  }
  return Math.abs(area/2);
}

function base64Encode( data ) {
  var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
    do {
        o1 = data.charCodeAt(i++);
        o2 = data.charCodeAt(i++);
        o3 = data.charCodeAt(i++);
        bits = o1<<16 | o2<<8 | o3;
        h1 = bits>>18 & 0x3f;
        h2 = bits>>12 & 0x3f;
        h3 = bits>>6 & 0x3f;
        h4 = bits & 0x3f;
        enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
    } while (i < data.length);
    switch( data.length % 3 ){
        case 1: enc = enc.slice(0, -2) + '=='; break;
        case 2: enc = enc.slice(0, -1) + '='; break;
    }
  enc = enc.replace(new RegExp("=", "g"), "%3D");
  enc = enc.replace(new RegExp("\/", "g"), "%2F");  
    return enc;
}

function base64Decode( data ) {
  if (data == "AAAA") return "";
  var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
  data = data.replace(new RegExp("%2B", "ig"), "+");
  data = data.replace(new RegExp("%3D", "ig"), "=");
  data = data.replace(new RegExp("%2F", "ig"), "/");
    do {
        h1 = b64.indexOf(data.charAt(i++));
        h2 = b64.indexOf(data.charAt(i++));
        h3 = b64.indexOf(data.charAt(i++));
        h4 = b64.indexOf(data.charAt(i++));
        bits = h1<<18 | h2<<12 | h3<<6 | h4;
        o1 = bits>>16 & 0xff;
        o2 = bits>>8 & 0xff;
        o3 = bits & 0xff;
        if (h3 == 64) enc += String.fromCharCode(o1);
        else if (h4 == 64) enc += String.fromCharCode(o1, o2);
        else enc += String.fromCharCode(o1, o2, o3);
    } while (i < data.length);
    return enc;
}

function chr(code)
{
  return String.fromCharCode(code);
}

function code2utf(code)
{
  if (code < 128) return chr(code);
  if (code < 2048) return chr(192+(code>>6)) + chr(128+(code&63));
  if (code < 65536) return chr(224+(code>>12)) + chr(128+((code>>6)&63)) + chr(128+(code&63));
  if (code < 2097152) return chr(240+(code>>18)) + chr(128+((code>>12)&63)) + chr(128+((code>>6)&63)) + chr(128+(code&63));
}

function _utf8Encode(str)
{ 
  var utf8str = new Array();
  for (var i = 0; i < str.length; i++)
    utf8str[i] = code2utf(str.charCodeAt(i));
  return utf8str.join('');
}

function utf8Encode(str)
{ 
  var utf8str = new Array();
  var pos,j = 0;
  var tmpStr = '';
  
  while ((pos = str.search(/[^\x00-\x7F]/)) != -1) {
    tmpStr = str.match(/([^\x00-\x7F]+[\x00-\x7F]{0,10})+/)[0];
    utf8str[j++] = str.substr(0, pos);
    utf8str[j++] = _utf8Encode(tmpStr);
    str = str.substr(pos + tmpStr.length);
  }
  
  utf8str[j++] = str;
  return utf8str.join('');
}

function _utf8Decode(utf8str)
{ 
  var str = new Array();
  var code,code2,code3,code4,j = 0;
  for (var i = 0; i < utf8str.length; ) 
  {
    code = utf8str.charCodeAt(i++);
    if (code > 127) code2 = utf8str.charCodeAt(i++);
    if (code > 223) code3 = utf8str.charCodeAt(i++);
    if (code > 239) code4 = utf8str.charCodeAt(i++);
    
    if (code < 128) str[j++]= chr(code);
    else if (code < 224) str[j++] = chr(((code-192)<<6) + (code2-128));
    else if (code < 240) str[j++] = chr(((code-224)<<12) + ((code2-128)<<6) + (code3-128));
    else str[j++] = chr(((code-240)<<18) + ((code2-128)<<12) + ((code3-128)<<6) + (code4-128));
  }
  return str.join('');
}

function utf8Decode(utf8str)
{
  var str = new Array();
  var pos = 0;
  var tmpStr = '';
  var j=0;
  while ((pos = utf8str.search(/[^\x00-\x7F]/)) != -1) {
    tmpStr = utf8str.match(/([^\x00-\x7F]+[\x00-\x7F]{0,10})+/)[0];
    str[j++]= utf8str.substr(0, pos) + _utf8Decode(tmpStr);
    utf8str = utf8str.substr(pos + tmpStr.length);
  }
  
  str[j++] = utf8str;
  return str.join('');
}

var suggest = { // Namespace
  archive : {},
  get : function(id) {
    if (typeof this.archive[id] == 'undefined')
      this.archive[id] = new this.create(id);
    return this.archive[id];
  },
  create : function(id) { // Constructor
    this.input = null;
    this.drop = null;
    this.oldValue = '';
    this.newValue = '';
    this.charsLimit = 0;
    this.itemLimit = 20;
    this.itemCount = 20;
    this.curItem = 0;
    this.isShow = false;
    this.inFocus = false;
    // delay
    this.delayTimer = null;
    this.delayInterval = 500;
    this.id = id;
  }
}
suggest.create.prototype = {
  addHandler : function(object, event, handler, useCapture) { 
      if (object.addEventListener) object.addEventListener(event, handler, useCapture ? useCapture : false);
    else if (object.attachEvent) object.attachEvent('on' + event, handler);
  },
  init : function(iId, dropId, noActions) {
    var _this = this;
    this.input = $(iId);
    this.drop = $(dropId);
    if (!(this.input && this.drop)) return;
    if (!noActions) {
      this.input.onkeyup = function() { _this.keyup(); }
      this.input.onkeydown = function() { _this.keydown(); }
      this.input.onkeypress = function() { _this.keypress(); }
      this.input.onclick = function(e) { _this.click(e); }
    }
    // Add handlers
    var _this = this;
    this.input.onfocus = function() {
      _this.unfocus();
      _this.inFocus = true;
    };
    this.addHandler(document, 'click', function() {
      _this.hide();
    });
    this.addHandler(document, 'keydown', function(evt) {
      evt = evt || window.event;
      switch (evt.keyCode) {
        case 13 : // Enter
          _this.enter(evt);
        break;
        case 27 : // Esc
          _this.hide();
        break;
        case 38 : // Up
          if (_this.inFocus) {
            _this.moveUp();
            if (evt.preventDefault)
              evt.preventDefault();
            return false;
          }
        break;
        case 40 : // Down
          if (_this.inFocus) {
            _this.moveDown();
            if (evt.preventDefault)
              evt.preventDefault();
            return false;
          }
        break;
        default :
        break;
      }
    });
    this.addHandler(document, 'keypress', function(evt) {
      evt = evt || window.event;
      switch (evt.keyCode) {
        case 13 : // Enter
          _this.enter(evt);
        break;
        default :
        break;
      }
    });
  },
  unfocus : function() {
    try {
      for (var i in suggest.archive)
          if (suggest.archive.hasOwnProperty(i))
            suggest.archive[i].inFocus = false;
    } catch(e) {}
  },
  click : function(evt) {
    evt = evt || window.event;
    evt.cancelBubble = true;
    this.change();
  },
  keydown : function() {
    this.change();
  },
  keypress : function() {
    this.change();
  },
  keyup : function() {
    this.change();
  },
  show : function() {
    this.drop.style.display = 'block';
    this.drop.scrollTop = 0;
    this.parseResult();
    this.isShow = true;
  },
  hide : function() {
    this.drop.style.display = 'none';
    this.isShow = false;
  },
  moveDown : function() {
    if (!this.isShow) return true;
    if (this.curItem == this.itemCount) return false;
    var item;
    for (var i = 1; i <= this.itemLimit; i++) if (item = $(this.id + i)) item.className = 'item_out';
    this.curItem += 1;
    $(this.id + this.curItem).className = 'item_over';
    $(this.id + this.curItem).focus();
    this.input.focus();
  },
  moveUp : function() {
    if (!this.isShow) return true;
    if (this.curItem == 1) return false;
    var item;
    for (var i = 1; i <= this.itemLimit; i++) if (item = $(this.id + i)) item.className = 'item_out';
    this.curItem -= 1;
    $(this.id + this.curItem).className = 'item_over';
    $(this.id + this.curItem).focus();
    this.input.focus();
  },
  enter : function(evt) {
    if (this.isShow) {
      var item;
      if (item = $(this.id + this.curItem)) {
        if(evt.preventDefault) evt.preventDefault();
        evt.returnValue = false;
        evt.cancelBubble = true;
        this.oldValue = item.getAttribute('alt');
        this.input.value = item.getAttribute('alt').replace(', государство;', '');
        if (suggest.selected)
          suggest.selected[this.id] = this.input.value;
                if (suggest.selected.rend && suggest.selected.rstart) {
                    findRoute();
                    suggest.selected.rend = false;
                    suggest.selected.rstart = false;
                }
        this.hide();
      }
    }
  },
  parseResult : function() {
    var item;
    var _this = this;
    for (var i = 1; i <= this.itemLimit; i++) {
      if (item = $(this.id + i)) {
        item.index = i;
        item.carret = _this;
        item.onmouseover = _this.itemOver;
        item.onclick = function(e) {
          _this.itemClick(e);
        }
        this.itemCount = i;
      }
    }
    this.curItem = 0;
  },
  itemOver : function() {
    var item;
    this.carret.input.focus();
    for (var i = 1; i <= this.carret.itemLimit; i++) if (item = $(this.carret.id + i)) item.className = '';
    this.className = 'item_over';
    this.carret.curItem = this.index;
  },
  itemClick : function(evt) {
    evt = evt || window.event;
    this.enter(evt);
    return false;
  },
  change : function(doit) {
    if (!doit) {
      clearTimeout(this.delayTimer);
      this.delayTimer = setTimeout("suggest.get('"+this.id+"').change(1)", this.delayInterval);
      return;
    }
    
    this.newValue = this.input.value;
    if (this.newValue.length < this.charsLimit) {
      this.hide();
      return;
    }
    this.request();
  },
  request : function() {
    var _this = this;
        if (!this.newValue)
            return;
	  this.newValue = this.newValue.replace('«', '').replace('»', '').replace('"', '');
      var url2 = "/GeoObjectSearch.aspx?SearchStringKey=" + escape(this.newValue);// + "&parts=1";
    	sendRequest(url2, function(xmlhttp){
        var respText = xmlhttp.responseText;
        if ( respText && respText.match( /GeoObjectInfo\((.*?)\)\)/ ) ) {
        var res = [];
        respText = respText.replace( /GeoObjectInfo\((.*?)\)\)/g, function( a, b ) {
                    if (res.length < _this.itemLimit) {
                        eval("res[res.length] = " + b);
                        return '';
                    }
        } );
        if ( res.length ) {
          if ( res.length == 1 ) {
            _this.input.value = res[0]['Path'].replace(', государство', '');
            suggest.selected[_this.id] = res[0]['Path'].replace(', государство', '');
             if (suggest.selected.rend && suggest.selected.rstart) {
                 findRoute();
                 suggest.selected.rend = false;
                 suggest.selected.rstart = false;
             }
            return;
          }
          var html = '', items;
          for ( var i = 0; i < Math.min(res.length, _this.itemLimit); i++ ) {
            items = res[i]['Path'].split(";");
            html += '<a alt="'+res[i]['Path']+'" id="' + _this.id + (i + 1) + '" href="#">' + items[0] + (items[1] ? ', ' + items[1].replace(', государство', '') : '') + (items[2] ? ', ' + items[2].replace(', государство', '') : '') + '</a>';
          }
          _this.drop.innerHTML = html;
          _this.show();
        } else 
          _this.hide();
      } else {
        _this.hide();
        if (_this.id == 'rstart') alert('Точка старта не найдена');
        else if (_this.id == 'rend') alert('Точка финиша не найдена');
      }
    });
    
    this.oldValue = this.newValue;
  }
};