isDOM=document.getElementById; //DOM1 browser (MSIE 5+, Netscape 6, Opera 5+)
isOpera=isOpera5=window.opera && isDOM; //Opera 5+
isOpera6=isOpera && window.print; //Opera 6+
isOpera7=isOpera && document.readyState; //Opera 7+
isMSIE=document.all && document.all.item && !isOpera; //Microsoft Internet Explorer 4+
isMSIE5=isDOM && isMSIE; //MSIE 5+
isNetscape4=document.layers; //Netscape 4.*
isMozilla=isDOM && navigator.appName=="Netscape"; //Mozilla или Netscape 6.*
isSAFARI = (navigator.userAgent.toLowerCase().indexOf('safari') != -1) || (navigator.userAgent.toLowerCase().indexOf('konqueror') != -1);


RMAP_VERSION = '1508073';
TILE_SIZE = 256;
TILE_CACHE_SIZE = .1;
MAP_MAX_STEP = 20;
MAP_INC_STEP = 2;
IMAGE_SERVER = 'tiles/';
FINDER_SERVER = '';
globalsettings = {};
globalsettings.virtualmaps = {
	kirov43_ru: {
		status: false,
		defaultcenter: {
			x: 9740.31,
			y: 14033.95,
			z: 4
		},
		makeobjurl : function (id, typeid) {
			if (typeid == 'roads' || typeid == 'buildings') {
				return '';
			}
			return "http://www.ikirov.ru/firminfo_firmid_"+id+"_mid_50.htm"
		},
		description: 'Киров (бизнес)',
		linkto: 'kirov_ru',
		search_mapid: 'kirov43_ru',
		path: 'kirov43'
	},
	dmitrov_ru: {
		status: true,
		description: 'Дмитров',
		defaultcenter: {
			x: 1740.06,
			y: 75351.74,
			z: 3
		},
		linkto: 'moscow_ru',
		path: 'dmitrov'
	},
	domodedovo_ru: {
		status: true,
		description: 'Домодедово',
		defaultcenter: {
			x: 16336.53,
			y: -25180.48,
			z: 3
		},
		linkto: 'moscow_ru',
		path: 'domodedovo'
	},
	zgrad_ru: {
		status: true,
		description: 'Зеленоград',
		defaultcenter: {
			x: -18139.6,
			y: 36896.52,
			z: 3
		},
		linkto: 'moscow_ru',
		path: 'zgrad'
	},
	kolomna_ru: {
		status: true,
		description: 'Коломна',
		defaultcenter: {
			x: 83070.964844,
			y: -64459.738281,
			z: 5
		},
		linkto: 'moscow_ru',
		path: 'kolomna'
	},
	mozhaisk_ru: {
		status: true,
		description: 'Можайск',
		defaultcenter: {
			x: -93854.500000,
			y: -17090.826172,
			z: 4
		},
		linkto: 'moscow_ru',
		path: 'mozhaisk'
	},
	noginsk_ru: {
		status: true,
		description: 'Ногинск',
		defaultcenter: {
			x: 59516.36,
			y: 21659.81,
			z: 4
		},
		linkto: 'moscow_ru',
		path: 'noginsk'
	},
	pavlovsk_ru: {
		status: true,
		description: 'Павловск',
		defaultcenter: {
			x: -59085.83,
			y: -34866.01,
			z: 3
		},
		linkto: 'piter_ru',
		path: 'pavlovsk'
	},
	podolsk_ru: {
		status: true,
		description: 'Подольск',
		defaultcenter: {
			x: 2961.778107,
			y: -25365.986328,
			z: 3
		},
		linkto: 'moscow_ru',
		path: 'podolsk'
	},
	pushkino_ru: {
		status: true,
		description: 'Пушкино',
		defaultcenter: {
			x: 21504.459961,
			y: 38122.490234,
			z: 3
		},
		linkto: 'moscow_ru',
		path: 'pushkino'
	},
	serpuhov_ru: {
		status: true,
		description: 'Серпухов',
		defaultcenter: {
			x: -5552.821783,
			y: -82799.262741,
			z: 5
		},
		linkto: 'moscow_ru',
		path: 'serpuhov'
	},
	sposad_ru: {
		status: true,
		description: 'Сергиев Посад',
		defaultcenter: {
			x: 39918.92,
			y: 72145.73,
			z: 3
		},
		linkto: 'moscow_ru',
		path: 'sposad'
	},
	chekhov_ru: {
		status: true,
		description: 'Чехов',
		defaultcenter: {
			x: -2903.433620,
			y: -57196.347656,
			z: 5
		},
		linkto: 'moscow_ru',
		path: 'chekhov'
	}
};
/*
дедовск
троицк
обнинск
пущино
жуковский
Павловский посад
орехово-зуево
балашиха
дмитров
королев
щелково
фрязино
химки
сходня
солнечногорск
клин
дубна
*/
globalsettings.datums = {
	datum1: {
		Semimajor : 6378135.0,
		Semiminor : 0.0,
		Flattering : 298.257223563,
		InversFlattering : 1.0/298.257223563,
		MetersPerUnit : 1,
		base: {
			esq : 0.00669342,
			e1sq : 0.00673853,
			e1 : 0.00167898,
			A0 : 0.998325,
			A2 : 0.00251425,
			A4 : 2.63822e-06,
			A6 : 3.38728e-09,
			A8 : -4.82385e-12,
			a : 6378245, // semimajor
			x0 : 0,
			y0 : -6.1716e+06,
			k0 : 1,
			lon0 : 37.5
		}
	},
	wgs84: {
		Semimajor : 6378135.0,
		Semiminor : 0.0,
		Flattering : 298.257223563,
		InversFlattering : 1.0/298.257223563,
		MetersPerUnit : 111180.0
	}
}
globalsettings.maps = {
	samara_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		status: true,
		description: 'Самара',
		extent: {
			x1: 1131.652832,
			y1: -26869.195312,
			x2: 25106.271484,
			y2: 10007.001953
		},
		defaultcenter: {
			x: 14014.944140,
			y: -12816.122089
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 4,
		path: 'samara',
		datum: 'datum1'
	},
	vgrad_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		status: true,
		description: 'Волгоград',
		extent: {
			x1: -15440.069335938,
			y1: -39501.019531250,
			x2: 12978.388671875,
			y2: 3681.806884766
		},
		defaultcenter: {
			x: 1258.74,
			y: -12507.52
		},
		scalelist: [4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 4,
		path: 'vgrad',
		datum: 'datum1'
	},
	togliatti_ru: {
		description: 'Тольятти',
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		status: true,
		extent: {
			x1: -52576.992173233,
			y1: 12345.934141124,
			x2: 0.000000000,
			y2: 28960.407259675
		},
		defaultcenter: {
			x: -38291.18,
			y: 20766.04
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 3,
		path: 'togliatti',
		datum: 'datum1'
	},
	piter_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		description: 'Санкт-Петербург и Ленинградская область',
		status: true,
		extent: {
			x1: -259841.045940,
			y1: -222696.177113,
			x2: 259841.045447,
			y2: 155814.605728
		},
		defaultcenter: {
			x: -67466.55,
			y: -4984.72
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000],
		defaultscalenum : 8,
		path: 'piter',
		datum: 'datum1'
	},
	russia_ru: {
		lastupdate: '01.08.2007 (v7.2)',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		description: 'Российская Федерация',
		status: false,
		extent: {
			x1:-4939238.639235619,
			y1:-1900188.129279211,
			x2:3703387.599662378,
			y2:2938054.665307145
		},
		defaultcenter: {
			x: -1183874.7288,
			y: 714792.112
		},
		scalelist: [
		1000000,
		2000000,
		5000000,
		10000000,
		20000000],
		defaultscalenum : 4,
		path: 'russia',
		datum: 'datum1',
		isgeo : true
	},
	world_ru: {
		description: 'Мир (политическая карта)',
		status: false,
		extent: {
			x1: -331.634241340 ,
			y1: -200.000000000,
			x2: 332.021021340,
			y2: 221.041565000
		},
		defaultcenter: {
			x: -27.99,
			y: 56.48
		},
		scalelist: [5000000, 10000000, 20000000, 40000000, 80000000, 160000000],
		defaultscalenum : 2,
		path: 'world',
		datum: 'wgs84'
	},
	omsk_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		description: 'Омск',
		status: true,
		extent: {
			x1: -21214.755859375,
			y1: -14928.646484375,
			x2: 1762.463134766,
			y2: 9143.850585938
		},
		defaultcenter: {
			x: -8715.6,
			y: -1808.46
		},
		scalelist: [4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 3,
		path: 'omsk',
		datum: 'datum1'
	},
	kazan_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		description: 'Казань',
		status: true,
		extent: {
			x1: -26091.979543339,
			y1: -18002.811587189,
			x2: 4951.189878539,
			y2: 11527.763280369
		},
		defaultcenter: {
			x: -6991.96,
			y: -110.62
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 4,
		path: 'kazan',
		datum: 'datum1'
	},
	eburg_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		description: 'Екатеринбург',
		status: true,
		extent: {
			x1: -3725.903907,
			y1: -30015.585938,
			x2: 20770.285156,
			y2: 0.0
		},
		defaultcenter: {
			x: 7527.88,
			y: -24505.61
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 4,
		path: 'eburg',
		datum: 'datum1'
	},
	nnov_ru: {
		lastupdate: '14.08.2006',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		description: 'Нижний Новгород',
		status: true,
		extent: {
			x1: -18081.865234375,
			y1: -16988.314453125,
			x2: 10695.836914062,
			y2: 10142.624023438
		},
		defaultcenter: {
			x: -5493.74,
			y: -2186.54
		},
		scalelist: [4000, 8000, 16000, 32000, 64000, 128000],
		defaultscalenum : 3,
		path: 'nnov',
		datum: 'datum1'
	},
	moscow_ru: {
		makeobjurl : function (id, agent) {
			switch (agent) {
				case 'afishasearch' :
				//				case 'afisha' :
				return 'http://afisha.rambler.ru/place.html?id='+id;
				break;
			}
			return '';
		},
		lastupdate: '26.06.2007 (v7.1)',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		status: true,
		description: 'Москва и Московская область',
		extent: {
			x1:-161294.640625000,
			y1:-185458.562500000,
			x2:225789.625000000,
			y2:186546.187500000
//			x1:-161294.640636731,
//			y1:-185458.562477162,
//			x2:225789.623006343,
//			y2:186546.195520016
		},
		defaultcenter: {
			x: 7502.29,
			y: 9888.56
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000],
		defaultscalenum : 7,
		path: 'moscow',
		datum: 'datum1',
		isgeo : true
	},
	tele2x2_ru: {
		makeobjurl : function (id, typeid) {
			return "";
		},
		lastupdate: '26.06.2007 (v7.1)',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		author2: 'Телеканал 2x2',
		author2href: 'http://www.2x2tv.ru/',
		author2date: '26.06.07',
		status: true,
		description: 'Телеканал 2x2',
		extent: {
			x1:-161294.640636731,
			y1:-185458.562477162,
			x2:225789.623006343,
			y2:186546.195520016
		},
		defaultcenter: {
			x: 7502.29,
			y: 9888.56
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000],
		defaultscalenum : 7,
		path: 'tele2x2',
		datum: 'datum1'
	},
	tv3_ru: {
		makeobjurl : function (id, typeid) {
			return "";
		},
		lastupdate: '26.06.2007 (v7.1)',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		author2: 'Телеканал TV3',
		author2href: 'http://www.2x2tv.ru/',
		author2date: '26.06.07',
		status: true,
		description: 'Телеканал TV3',
		extent: {
			x1:-161294.640636731,
			y1:-185458.562477162,
			x2:225789.623006343,
			y2:186546.195520016
		},
		defaultcenter: {
			x: 7502.29,
			y: 9888.56
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000],
		defaultscalenum : 7,
		path: 'tv3',
		datum: 'datum1'
	},
	mtv_ru: {
		makeobjurl : function (id, typeid) {
			return "";
		},
		lastupdate: '26.06.2007 (v7.1)',
		author: 'Геоцентр-Консалтинг',
		authorhref: 'http://www.digimap.ru/',
		author2: 'Телеканал MTV',
		author2href: 'http://www.2x2tv.ru/',
		author2date: '26.06.07',
		status: true,
		description: 'Телеканал MTV',
		extent: {
			x1:-161294.640636731,
			y1:-185458.562477162,
			x2:225789.623006343,
			y2:186546.195520016
		},
		defaultcenter: {
			x: 7502.29,
			y: 9888.56
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000, 512000],
		defaultscalenum : 7,
		path: 'mtv',
		datum: 'datum1'
	},
	kirov_ru: {
		lastupdate: '01.11.2006',
		author: 'Роскартография',
		authorhref: 'http://www.vagp.nn.ru/',
		authortitle: 'Картографическая основа предоставлена Федеральным государственным унитарным Верхневолжским аэрогеодезическим предприятием (филиал - Кировский геодезический центр), 610033 г. Киров, ул. Ломоносова, 22, Тел.(8332) 53-17-15. Все права защищены. Незаконное копирование, публичное воспроизведение без разрешения правообладателя запрещены.',
		author2: 'Народный телефон',
		author2href: 'http://www.ikirov.ru/',
		status: true,
		description: 'Киров',
		extent: {
			x1: 975.161033582,
			y1: 1267.323300000,
			x2: 17048.445600000,
			y2: 24031.293300000
		},
		defaultcenter: {
			x: 9740.31,
			y: 14033.95
		},
		scalelist: [2000, 4000, 8000, 16000, 32000, 64000],
		defaultscalenum : 4,
		path: 'kirov',
		datum: 'datum1'
	}
};
globalsettings.object_types = {
	theatre : 'Театры',
	intown : 'В городе',
	child : 'Детям',
	cinema : 'Кинотеатры',
	club : 'Клубы',
	hall : 'Концертные залы',
	shop : 'Магазины',
	museum : 'Музеи',
	cafe : 'Рестораны',
	sport : 'Спорт'
};
function encode_utf8( s ) {
	return unescape( encodeURIComponent( s ) );
}
function decode_utf8( s ){
	return decodeURIComponent( escape( s ) );
}
function addhandler(element, event_type, func) {
	if (event_type == 'dblclick' /*&& BROWSER==safari*/) {
		element.ondblclick = func;
		return;
	}
	if (element.attachEvent) { // IE
		element.attachEvent('on' + event_type, func);
	} else if (element.addEventListener) { // W3C
		element.addEventListener(event_type, func, false);
	} else { // should not happen
		element['on' + event_type] = func;
	}
}
function addhandlerCont(element, event_type, func) {
	if (event_type == 'dblclick' /*&& BROWSER==safari*/) {
		element.ondblclick = func;
		return;
	}
	if (element.attachEvent) { // IE
		element.attachEvent('on' + event_type, func);
	} else if (element.addEventListener) { // W3C
		element.addEventListener(event_type, func, true);
	} else { // should not happen
		element['on' + event_type] = func;
	}
}
function removehandler(element, func, event_type) {
	if (element.attachEvent) { // IE
		element.detachEvent('on' + event_type, func);
	} else if (element.addEventListener) { // W3C
		element.removeEventListener(event_type, func, false);
	} else { // should not happen
		delete element['on' + event_type];
	}
}
function cancelevent(e) {
	if (isMSIE) {
		e = event;
	}
	e.returnValue = false;
	e.cancelBubble = true;
	if (e.preventDefault) {
		e.preventDefault();
	}
	if (e.stopPropagation) {
		e.stopPropagation();
	}
}
function BoxInBox(box1, box2) {
	if( (box1.x2 <  box2.x1) || (box1.x1 >  box2.x2) || (box1.y2 <  box2.y1) || (box1.y1 >  box2.y2) ) {
		return false;
	}
	if( (box1.x1 >= box2.x1) && (box1.x2 <= box2.x2) && (box1.y1 >= box2.y1) && (box1.y2 <= box2.y2) ) {
		return 'in';
	}
	if( (box1.x1 <  box2.x1) && (box1.x2 >  box2.x2) && (box1.y1 <  box2.y1) && (box1.y2 >  box2.y2) ) {
		return 'over';
	}
	return 'cross';
}
function Geo2Pix(geocoords, extent, scale, datum) {
	var geo_width, geo_height, pix_width, pix_height, pix_center_left, pix_center_top;
	geo_width = extent.x2-extent.x1;
	geo_height = extent.y2-extent.y1;
	pix_width = Math.round(geo_width*(28.346472)/(scale/(datum.MetersPerUnit*100)));
	pix_height = Math.round((geo_height * pix_width) / geo_width);
	pix_center_left = Math.round((geocoords.x - extent.x1) * (pix_width/geo_width));
	pix_center_top = Math.round((extent.y2 - geocoords.y) * (pix_height/geo_height));
	return {
		x: Math.floor(pix_center_left/TILE_SIZE),
		y: Math.floor(pix_center_top/TILE_SIZE),
		left: pix_center_left % TILE_SIZE,
		top: pix_center_top % TILE_SIZE
	}
}
function Pix2Geo(tileinfo, extent, scale, datum) {
	var geo_width, geo_height, pix_width, pix_height, pixx, pixy;
	geo_width = extent.x2-extent.x1;
	geo_height = extent.y2-extent.y1;
	pix_width = Math.round(geo_width*(28.346472)/(scale/(datum.MetersPerUnit*100)));
	pix_height = Math.round((geo_height * pix_width) / geo_width);
	pixx = (tileinfo.x)*TILE_SIZE+tileinfo.left;
	pixy = (tileinfo.y)*TILE_SIZE+tileinfo.top;
	return {
		x: extent.x1 + (pixx * (geo_width/pix_width)),
		y: extent.y2 - (pixy * (geo_height/pix_height))
	}
}
function ComprehensiveScale(r, viewbounds, datum) {
	r.width = Math.abs(r.x2-r.x1);
	r.height = Math.abs(r.y2-r.y1);
	if(r.width > r.height) {
		return (r.width*datum.MetersPerUnit*100)/(viewbounds.width/28.346472);
	} else {
		return (r.height*datum.MetersPerUnit*100)/(viewbounds.height/28.346472);
	}
}
function NearestScale(scale) {
	for(var i in control.map.scalelist) {
		if (control.map.scalelist[i] > scale) {
			return i;
		}
	}
	return 0;
}
function FromLonLat(lon, lat, base) {
	lon = lon * (Math.PI/180);
	lat = lat * (Math.PI/180);
	lon0 = base.lon0 * (Math.PI/180);

	var sinlat = Math.sin(lat);
	var coslat = Math.cos(lat);
	var tanlat = sinlat / coslat;
	var sinsqlat = sinlat*sinlat;
	var cossqlat = coslat*coslat;
	var T = tanlat*tanlat;
	var N = base.a/Math.sqrt(1-base.esq*sinsqlat);
	var C = base.e1sq*cossqlat;
	var Q = coslat*(lon-lon0);
	var Q2 = Q * Q;
	var Q3 = Q2 * Q;
	var Q4 = Q3 * Q;
	var Q5 = Q4 * Q;
	var Q6 = Q5 * Q;

	var M = base.a*(base.A0*lat-base.A2*Math.sin(2*lat)+base.A4*Math.sin(4*lat)-base.A6*Math.sin(6*lat)+base.A8*Math.sin(8*lat));
	var x = (base.k0*N*(Q+(1-T+C)*Q3/6+ (5-18*T+T*T+72*C-58*base.e1sq)*Q5/120) + base.x0);
	var y = (base.k0*(M+N*tanlat*(Q*Q/2+(5-T+9*C+4*C*C)*Q4/24 + (61-58*T+T*T+600*C-330*base.e1sq)*Q6/720))+ base.y0);
	return {x:x,y:y};
}

function ToLonLat(x, y, base) {
	var epsilon = 2.0E-12;
	var highPrecision = false;
	var errmax = highPrecision ? epsilon / 100000 : epsilon;
	var maxiter = highPrecision ? 1000 : 100;
	var lon0 = base.lon0 * (Math.PI/180);

	x = x - base.x0;
	y = y - base.y0;

	M = y / base.k0;
	mu = M/(base.a*base.A0);

	phi1 = mu + (3*base.e1/2-27*base.e1*base.e1*base.e1/32)*Math.sin(2*mu)+ (21*base.e1*base.e1/16-55*base.e1*base.e1*base.e1*base.e1/32)*Math.sin(4*mu)+(151*base.e1*base.e1*base.e1/96)*Math.sin(6*mu);

	var iter = 0;
	var sinphi1, cosphi1, eff, eff1, delta;
	do {
		sinphi1 = Math.sin(2*phi1);
		cosphi1 = Math.cos(2*phi1);
		eff = base.A0*phi1 - base.A2 * sinphi1 - M/base.a;
		eff1 = base.A0 - 2*base.A2*cosphi1;

		sinphi1 = Math.sin(4*phi1);
		cosphi1 = Math.cos(4*phi1);
		eff += base.A4*sinphi1;
		eff1 += 4*base.A4*cosphi1;

		sinphi1 = Math.sin(6*phi1);
		cosphi1 = Math.cos(6*phi1);
		eff -= base.A6*sinphi1;
		eff1 -= 6*base.A6*cosphi1;

		sinphi1 = Math.sin(8*phi1);
		cosphi1 = Math.cos(8*phi1);
		eff += base.A8*sinphi1;
		eff1 -= 8*base.A8*cosphi1;

		delta = eff/eff1;

		phi1 -= delta;
	} while ((Math.abs(delta) > errmax) && (++iter < maxiter));

	sinphi1 = Math.sin(phi1);
	cosphi1 = Math.cos(phi1);

	var tanphi1 = sinphi1 / cosphi1;
	var sinsqphi1 = sinphi1 * sinphi1;
	var cossqphi1 = cosphi1 * cosphi1;
	var tansqphi1 = tanphi1 * tanphi1;

	var N1 = base.a/Math.sqrt(1-base.esq*sinsqphi1);
	var T1 = tansqphi1;
	var C1 = base.e1sq*cossqphi1;
	var R1 = base.a*(1-base.esq)/Math.pow(1-base.esq*sinsqphi1, 1.5);
	var D = x/(N1*base.k0);

	var lon = (D-(1+2*T1+C1)*D*D*D/6+ (5-2*C1+28*T1-3*C1*C1+8*base.e1sq+24*T1*T1)*D*D*D*D*D/120) / cosphi1;
	lon = (lon + lon0) * (180/Math.PI);

	var lat = (phi1 - (N1*tanphi1/R1) * (D*D/2- (5+3*T1+10*C1-4*C1*C1-9*base.e1sq)*D*D*D*D/24+ (61+90*T1+298*C1+45*T1*T1-252*base.e1sq-3*C1*C1)*D*D*D*D*D*D/720));
	lat = lat * (180/Math.PI);

	return {lon: lon, lat: lat};
}



function Max(arr) {
	ret = arr[0];
	for(var i in arr) {if (arr[i] > ret) ret = arr[i]}
	return ret;
}
function Min(arr) {
	ret = arr[0];
	for(var i in arr) {if (arr[i] < ret) ret = arr[i]}
	return ret;
}
function URL2Array() {
	var vars, str, query, keypairs, numKP, keyName, keyValue;
	vars = new Object();
	str = window.location + '';
	query = str.substring((str.indexOf('#')) + 1);
	keypairs = new Object();
	numKP = 1;
	while (query.indexOf('&') > -1) {
		keypairs[numKP] = query.substring(0,query.indexOf('&'));
		query = query.substring((query.indexOf('&')) + 1);
		numKP++;
	}
	keypairs[numKP] = query;
	for (var i in keypairs) {
		keyName = keypairs[i].substring(0,keypairs[i].indexOf('='));
		keyValue = keypairs[i].substring((keypairs[i].indexOf('=')) + 1);
		while (keyValue.indexOf('+') > -1) {
			keyValue = keyValue.substring(0,keyValue.indexOf('+')) + ' ' + keyValue.substring(keyValue.indexOf('+') + 1);
		}
		keyValue = unescape(keyValue);
		vars[keyName] = keyValue;
	}
	delete vars[''];
	for (var key in vars) {
		if (key.indexOf('.') > -1) {
			keyName = key.substring(0,key.indexOf('.'));
			subkeyName = key.substring((key.indexOf('.')) + 1);
			if (!vars[keyName]) {
				vars[keyName] = {};
			}
			vars[keyName][subkeyName] = vars[key];
			delete vars[key];
		}
	}
	vars['hostname'] = window.location.hostname;
	vars['pathname'] = window.location.pathname;
	return vars;
}
function addStyleSheet(url) {
	var style;
	if (typeof url == 'undefined')
	{
		style = document.createElement('style');
	}
	else
	{
		style = document.createElement('link');
		style.rel = 'stylesheet';
		style.type = 'text/css';
		style.href = url;
	}
	document.getElementsByTagName('head')[0].appendChild(style);

	//	style = document.styleSheets[document.styleSheets.length - 1];
	//	return StyleSheet_makeCompatible(style);
}
function StyleSheet_makeCompatible(style) {
	try {
		style.cssRules;
	} catch (e) {
		return style;
	}
	if (typeof style.cssRules == 'undefined' && typeof style.rules != 'undefined')
	style.cssRules = style.rules;

	if (typeof style.insertRule == 'undefined' && typeof style.addRule != 'undefined')
	style.insertRule = StyleSheet_insertRule;
	if (typeof style.deleteRule == 'undefined' && typeof style.removeRule != 'undefined')
	style.deleteRule = style.removeRule;

	if (typeof style.cssRules == 'undefined' || typeof style.insertRule == 'undefined' || typeof style.deleteRule == 'undefined')
	return null;
	else
	return style;
}
function StyleSheet_insertRule(rule, index) {
	//	if (rule.match(/^([^{]+)\{(.*)\}\s*$/)) {
	//		this.addRule(RegExp.$1, RegExp.$2, index);
	//		return index;
	//	}
	//	throw "Syntax error in CSS rule to be added";
	//
}

function GetMouse(e) {
	if (isMSIE) {
		e = window.event;
	}
	return {x:e.clientX, y:e.clientY}
}
function GetMouseWheel(e) {
	if (isMSIE) {
		e = window.event;
	}
	return {x:e.screenX, y:e.screenY}
}
function GetMouseButton(e) {
	if (isMSIE) {
		return window.event.button;
	}
	return e.which;
}
function GetKeyboardCode(e) {
	if (isMSIE) {
		e = window.event;
	}
	if (e.keyCode) {
		return e.keyCode;
	} else { // for FireFox/Win
		return e;
	}
}
function GetAltKey(e) {
	if (isMSIE) {
		e = window.event;
	}
	return e.altKey;
}
function GetShiftKey(e) {
	if (isMSIE) {
		e = window.event;
	}
	return e.shiftKey;
}
function GetTarget(e) {
	if (isMSIE) {
		return window.event.srcElement;
	}
	return e.target;
}
function Count(data){
	var c = 0;
	for(var i in data) {
		c++;
	}
	return c;
}
function GetFirst(data){
	for(var i in data) {
		return data[i];
	}
	return false;
}
function cleanUpText(text) {
	if (text != undefined) {
		text = text.replace('&#8470;', '№');
	}
	return text;
}
function Tile(tileinfo, tileborder) {
	this.image = document.createElement('IMG');
	this.Show(false);
	this.image.ondragstart="return false";
	this.image.ondrag="return false";
	this.image.style.cursor = 'move';
	this.image.style.position = 'absolute';
	this.image.style.zIndex = '500';
	this.tileborder = tileborder;
	if (tileborder) {
		this.image.style.border = '1px solid #FF0000';
	}
	this.image.width = TILE_SIZE;
	this.image.height = TILE_SIZE;
	this.image.id = tileinfo.x+'x'+tileinfo.y;
	this.image.drag = true;
	this.x = tileinfo.x;
	this.y = tileinfo.y;
	this.left = tileinfo.left;
	this.top = tileinfo.top;
	this.markers = {};
	for(var i in control.matrix.markers) {
		k = control.matrix.markers[i];
		if (k.tiles[control.currentscalenum] && k.tiles[control.currentscalenum].x == this.x && k.tiles[control.currentscalenum].y == this.y) {
			this.markers[i] = k;
			k.Show(true);
		}
	}
}
Tile.prototype.Show = function(state) {
	this.image.style.visibility = (state) ? 'visible' : 'hidden';
}
Tile.prototype.SetPosition = function(to) {
	this.image.style.left = to.x;
	this.image.style.top = to.y;
	for(var i in this.markers) {
		this.markers[i].SetPosition({
			x: this.image.offsetLeft+this.markers[i].tiles[control.currentscalenum].left,
			y: this.image.offsetTop+this.markers[i].tiles[control.currentscalenum].top
		});
	}
}
function Matrix(divid, currentscale, mapid, params) {
	this.params = params;
	this.div = document.getElementById(divid);
	this.div.style.overflow = 'hidden';
	this.mapid = mapid;
	this.currentscale = currentscale;
	this.MakeBox();
	this.tiles = new Object();
	this.divs = new Object();
	this.keyboardflags = {
		left : false,
		up : false,
		right : false,
		down : false,
		plus : false,
		minus : false,
		esc : false
	}
	this.keyboardmovingstep = 1;
	this.needupdate = false;
	this.moving = false;
	this.stopnow = false;
	this.markers = {};
	this.selection = {};
	this.selection.process = false;
}
Matrix.prototype.AddInterface = function(object, state) {
	this.div.appendChild(object.div);
	if (state != undefined && state == false) {
		object.div.style.display = 'none';
	}
}
Matrix.prototype.MakeBox = function() {
	this.box = {
		x1: this.div.offsetLeft,
		y1: this.div.offsetTop,
		x2: this.div.offsetLeft+this.div.offsetWidth,
		y2: this.div.offsetTop+this.div.offsetHeight,
		width: this.div.offsetWidth,
		height: this.div.offsetHeight,
		center : {
			x : Math.round(this.div.offsetWidth/2),
			y : Math.round(this.div.offsetHeight/2)
		}
	}
	this.bigbox = {
		x1 : -TILE_CACHE_SIZE*this.box.width,
		y1 : -TILE_CACHE_SIZE*this.box.height,
		x2 : this.box.width+TILE_CACHE_SIZE*this.box.width,
		y2 : this.box.height+TILE_CACHE_SIZE*this.box.height,
		width : this.box.width*(1+TILE_CACHE_SIZE*2),
		height : this.box.height*(1+TILE_CACHE_SIZE*2)
	}
	this.matrixsize = {x: Math.ceil(this.bigbox.width / TILE_SIZE), y: Math.ceil(this.bigbox.height / TILE_SIZE)}
	if (this.params.showcenter) {
		var t;
		t = document.getElementById('showcenter1');
		if (t) {
			this.div.removeChild(t);
		}
		t = document.getElementById('showcenter2');
		if (t) {
			this.div.removeChild(t);
		}
		t = document.createElement('IMG');
		t.style.width = 1;
		t.style.zIndex = '1005';
		t.style.height = this.box.height;
		t.style.background = '#FF00FF';
		t.style.position = 'absolute';
		this.div.appendChild(t);
		t.style.left = this.box.width / 2;
		t.id = 'showcenter1';
		t.style.top = 0;

		t = document.createElement('IMG');
		t.style.height = 1;
		t.style.zIndex = '1006';
		t.style.width = this.box.width;
		t.style.background = '#FF00FF';
		t.style.position = 'absolute';
		this.div.appendChild(t);
		t.id = 'showcenter2';
		t.style.left = 0;
		t.style.top = this.box.height / 2;
	}
}
Matrix.prototype.SwitchGrid = function() {
	for(var i in this.tiles) {
		if(this.params.tileborders) {
			this.tiles[i].tileborder = false;
			this.tiles[i].image.style.border = 'none';
		} else {
			this.tiles[i].tileborder = true;
			this.tiles[i].image.style.border = '1px solid #FF0000';
		}
	}
	this.params.tileborders = !this.params.tileborders;
}

Matrix.prototype.CreateMatrix = function(centertile) {
	tile = new Tile({
		x: centertile.x,
		y: centertile.y,
		left: Math.round(this.box.width/2)-centertile.left,
		top: Math.round(this.box.height/2)-centertile.top
	}, this.params.tileborders);
	this.AppendTile(tile);

	this.needupdate = true;
	this.AddTiles();
	this.stopnow = false;

}

function FillByZero(str, count) {
	var newstr = '';
	str = str+'';
	count = count-str.length;
	for(var i=1;i<=count;i++){
		newstr += '0';
	}
	return newstr+str;
}
Matrix.prototype.AppendTile = function(tile) {
	var x, y;
	if (this.tiles[tile.image.id]) return false;
	this.tiles[tile.image.id] = tile;
	this.div.appendChild(tile.image);
	tile.SetPosition({x:tile.left, y:tile.top});
	if (tile.x < 0 || tile.y < 0 || tile.x > control.mosttile.x || tile.y > control.mosttile.y) {
		tile.image.src = 'i/nodata.png';
	} else {
		tile.image.src = IMAGE_SERVER + this.mapid + '/' + FillByZero(this.currentscale, 11) + '/' + FillByZero(tile.y, 6) + '/' + FillByZero(tile.x, 6) + FillByZero(tile.y, 6) + '.png';
	}
	tile.Show(true);
}
Matrix.prototype.ReanimateMarkers = function() {
	for (var i in this.markers) {
		this.markers[i].Show(true);
	}
}
Matrix.prototype.RemoveAllTiles = function() {
	this.stopnow = true;
	for(var i in this.tiles) {
		this.RemoveTile(this.tiles[i]);
	}
}
Matrix.prototype.RemoveTile = function(tile) {
	for(var i in this.tiles[tile.image.id].markers) {
		this.tiles[tile.image.id].markers[i].Show(false);
	}
	this.div.removeChild(tile.image);
	this.tiles[tile.image.id] = null;
	delete this.tiles[tile.image.id];
	this.changed = true;
}
Matrix.prototype.StartSelection = function(e) {
	this.selection = {};
	this.selection.process = true;
	this.selection.position = GetMouse(e);
	this.selection.div = document.createElement('DIV');
	this.selection.div.style.position = 'absolute';
	this.selection.div.style.zIndex = '1000';
	this.selection.div.style.left = this.selection.position.x;
	this.selection.div.style.top = this.selection.position.y;
	this.selection.div.style.width = 0;
	this.selection.div.style.height = 0;
	this.selection.div.style.border = '2px dotted #FF0000';
	this.selection.div.style.cursor = 'move';
	this.div.appendChild(this.selection.div);
	return false;
}
Matrix.prototype.DoSelection = function(e) {
	if (!this.selection.process) {
		return true;
	}
	var mouse = GetMouse(e);
	if (mouse.x > this.selection.position.x && mouse.y > this.selection.position.y) {
		this.selection.div.style.width = mouse.x-this.selection.position.x;
		this.selection.div.style.height = mouse.y-this.selection.position.y;
	}
	return false;
}
Matrix.prototype.EndSelection = function(e) {
	if (!this.selection.process) {
		return true;
	}
	var mouse = GetMouse(e);
	var width = mouse.x-this.selection.position.x;
	var height = mouse.y-this.selection.position.y;
	if (width != 0 && height != 0) {
		var tile = control.matrix.GetTileAtPix({left: Math.round(this.selection.position.x+width/2),top: Math.round(this.selection.position.y+height/2)});
		var center = Pix2Geo(tile, control.map.extent, control.currentscale, control.map.datum);
		var zdiff = Math.round(Min([this.box.width / width, this.box.height / height])-1);
		var z = (control.currentscalenum-zdiff);
		if (z < 0) {
			z = 0;
		}
		if (z >= control.maxscalenum) {
			z = control.maxscalenum;
		}
		control.Goto(center.x, center.y, z);
	}
	this.div.removeChild(this.selection.div);
	return false;
}
Matrix.prototype.StartDrag = function(e) {
	var mouse;
	if (this.disablehandmove || (GetMouseButton(e) != 1)) {
		return true;
	}
	this.leader = GetTarget(e);
	if (!this.leader.drag) return true;
	this.needupdate = true;
	this.moving = true;
	mouse = GetMouse(e);
	this.dx = mouse.x-this.tiles[this.leader.id].image.offsetLeft;
	this.dy = mouse.y-this.tiles[this.leader.id].image.offsetTop;
	return false;
}
Matrix.prototype.Drag = function(e) {
	var mouse, x_add, y_add, to;
	if (this.disablehandmove || !this.moving) {
		return true;
	}
	mouse = GetMouse(e);
	for(i in this.tiles) {
		x_add = (this.tiles[i].x-this.tiles[this.leader.id].x)*TILE_SIZE;
		y_add = (this.tiles[i].y-this.tiles[this.leader.id].y)*TILE_SIZE;
		to = {x: (mouse.x-this.dx+x_add), y: (mouse.y-this.dy+y_add)}
		this.tiles[i].SetPosition(to);
	}
	return false;
}
Matrix.prototype.EndDrag = function(e) {
	if (this.disablehandmove || !this.moving) {
		return true;
	}
	this.moving = false;
	this.needupdate = true;
	control.UpdateLocation();
	return false;
}
Matrix.prototype.GetTileIdAtPix = function(pix) {
	var tile;
	tile = this.GetTileAtPix(pix);
	if (tile) {
		return tile.x+'x'+tile.y;
	}
	return false;
}
Matrix.prototype.SlideFromTo = function(from, to, finishfunc) {
	if (!finishfunc) {
		finishfunc = function() {};
	}
	control.SmoothExec(
	function() {control.matrix.PrepareSlideMoving(from, to)},
	function() {control.matrix.doSlideMoving()},
	function() {return control.matrix.checkEndSlideMoving()},
	function() {control.matrix.EndSlideMoving(); finishfunc()},
	1
	);
}
Matrix.prototype.PrepareSlideMoving = function(from, to) {
	this.slide = {};
	this.slide.worktileid = this.GetTileIdAtPix({left:from.x, top:from.y});
	if (!this.slide.worktileid) {
		return false;
	}
	this.stopnow = false;
	this.disablehandmove = true;
	this.moving = true;
	this.slide.bre = {};
	this.slide.bre.xn = this.tiles[this.slide.worktileid].image.offsetLeft;
	this.slide.bre.yn = this.tiles[this.slide.worktileid].image.offsetTop;
	this.slide.bre.addX = from.x-this.slide.bre.xn;
	this.slide.bre.addY = from.y-this.slide.bre.yn;
	this.slide.bre.xk = to.x-this.slide.bre.addX;
	this.slide.bre.yk = to.y-this.slide.bre.addY;

	this.slide.bre.sx = 0;
	if ((this.slide.bre.dx = (this.slide.bre.xk-this.slide.bre.xn)) < 0) {
		this.slide.bre.dx = -this.slide.bre.dx;
		--this.slide.bre.sx;
	} else if (this.slide.bre.dx>0) {
		++this.slide.bre.sx;
	}
	this.slide.bre.sy = 0;
	if ((this.slide.bre.dy = this.slide.bre.yk-this.slide.bre.yn) < 0) {
		this.slide.bre.dy = -this.slide.bre.dy;
		--this.slide.bre.sy;
	} else if (this.slide.bre.dy>0) {
		++this.slide.bre.sy;
	}
	this.slide.bre.swap = 0;
	if ((this.slide.bre.kl = this.slide.bre.dx) < (this.slide.bre.s = this.slide.bre.dy)) {
		this.slide.bre.dx = this.slide.bre.s;
		this.slide.bre.dy = this.slide.bre.kl;
		this.slide.bre.kl = this.slide.bre.s;
		++this.slide.bre.swap;
	}
	this.slide.bre.s = (this.slide.bre.incr1 = 2*this.slide.bre.dy)-this.slide.bre.dx;
	this.slide.bre.incr2 = 2*this.slide.bre.dx;
	this.slide.bre.npos = 0;
	this.slide.bre.mass = new Array();
	while (--this.slide.bre.kl >= 0) {
		if (this.slide.bre.s >= 0) {
			if (this.slide.bre.swap) {
				this.slide.bre.xn += this.slide.bre.sx;
			} else {
				this.slide.bre.yn += this.slide.bre.sy;
			}
			this.slide.bre.s -= this.slide.bre.incr2;
		}
		if (this.slide.bre.swap) {
			this.slide.bre.yn += this.slide.bre.sy;
		} else {
			this.slide.bre.xn += this.slide.bre.sx;
		}
		this.slide.bre.s += this.slide.bre.incr1;
		this.slide.bre.mass[this.slide.bre.npos] = {
			x : this.slide.bre.xn,
			y : this.slide.bre.yn
		}
		this.slide.bre.npos++;
	}
	this.slide.bre.npos = 0;
	this.slide.bre.diff = 0;
	this.slide.bre.speedup = 4;

	this.slide.newarr = [];
	this.slide.slist = [Math.round(this.slide.bre.mass.length/5), 0, Math.round(this.slide.bre.mass.length/5)];
	this.slide.slist[1] = this.slide.bre.mass.length-(this.slide.slist[0]+this.slide.slist[2]);
	for(i=0;i<this.slide.bre.mass.length;i++){
		if (i < this.slide.slist[0]) {
			this.slide.newarr.push(this.slide.bre.mass[i]);
			i += this.slide.bre.diff;
			this.slide.bre.diff += this.slide.bre.speedup;
		}
		if (i>= this.slide.slist[0] && i < this.slide.slist[0]+this.slide.slist[1]) {
			this.slide.newarr.push(this.slide.bre.mass[i]);
			i += this.slide.bre.diff;
		}
		if (i>= this.slide.slist[0]+this.slide.slist[1] && i < this.slide.slist[0]+this.slide.slist[1]+this.slide.slist[2]) {
			this.slide.newarr.push(this.slide.bre.mass[i]);
			i += this.slide.bre.diff;
			this.slide.bre.diff -= this.slide.bre.speedup;
			if (i < 1) i = 1;
		}
	}
	if (this.slide.newarr[this.slide.newarr.length-1] != this.slide.bre.mass[this.slide.bre.mass.length-1]) {
		this.slide.newarr.push(this.slide.bre.mass[this.slide.bre.mass.length-1]);
	}
	this.slide.bre.mass = this.slide.newarr;
}
Matrix.prototype.doSlideMoving = function() {
	var to;
	if (!this.moving) {
		return false;
	}
	if (!this.tiles[this.slide.worktileid]) {
		this.stopnow = true;
	}
	if (this.stopnow) {
		return;
	}
	this.slide.bre.xn = this.slide.bre.mass[this.slide.bre.npos].x;
	this.slide.bre.yn = this.slide.bre.mass[this.slide.bre.npos].y;
	for(var i in this.tiles) {
		to = {
			x: (this.slide.bre.xn+((this.tiles[i].x-this.tiles[this.slide.worktileid].x)*TILE_SIZE)),
			y: (this.slide.bre.yn+((this.tiles[i].y-this.tiles[this.slide.worktileid].y)*TILE_SIZE))
		}
		this.tiles[i].SetPosition(to);
	}
}
Matrix.prototype.checkEndSlideMoving = function() {
	if (!this.moving) {
		return false;
	}
	if (this.slide.bre.npos >= (this.slide.bre.mass.length-1)) {
		return true;
	}
	if (this.stopnow) {
		return true;
	}
	this.slide.bre.npos++;
	return false;
}
Matrix.prototype.EndSlideMoving = function() {
	var to;
	if (!this.moving) {
		return false;
	}
	if (!this.tiles[this.slide.worktileid]) {
		this.stopnow = true;
	} else {
		for(var i in this.tiles) {
			to = {
				x: (this.slide.bre.xk+((this.tiles[i].x-this.tiles[this.slide.worktileid].x)*TILE_SIZE)),
				y: (this.slide.bre.yk+((this.tiles[i].y-this.tiles[this.slide.worktileid].y)*TILE_SIZE))
			}
			this.tiles[i].SetPosition(to);
		}
	}
	this.needupdate = true;
	this.moving = false;
	this.disablehandmove = false;
}
Matrix.prototype.CheckKeyboard = function() {
	var shiftx, shifty;
	if (control.stopmatrix) return;
	if (this.keyboardflags.esc) {
		control.Finder.Abort();
		return;
	}
	if (this.keyboardflags.plus) {
		control.ChangeZoom(-1);
		this.keyboardflags.plus = false;
		return;
	}
	if (this.keyboardflags.minus) {
		control.ChangeZoom(1);
		this.keyboardflags.minus = false;
		return;
	}
	if (!this.keyboardflags.left && !this.keyboardflags.up && !this.keyboardflags.right && !this.keyboardflags.down) {
		this.keyboardmovingstep = 1;
		this.stopnow = false;
		return;
	}
	this.stopnow = true;
	if (this.keyboardmovingstep <= MAP_MAX_STEP) {
		this.keyboardmovingstep += MAP_INC_STEP;
	}
	shiftx = 0;
	shifty = 0;
	if (this.keyboardflags.left) {
		shiftx = this.keyboardmovingstep;
	}
	if (this.keyboardflags.up) {
		shifty = this.keyboardmovingstep;
	}
	if (this.keyboardflags.right) {
		shiftx = -this.keyboardmovingstep;
	}
	if (this.keyboardflags.down) {
		shifty = -this.keyboardmovingstep;
	}
	for(var i in this.tiles) {
		this.tiles[i].SetPosition({x: this.tiles[i].image.offsetLeft+shiftx, y: this.tiles[i].image.offsetTop+shifty});
	}
	//----------------------------------------------------------(from Editor)
	if (surf) {
		Editor_onZoom({x: shiftx, y: shifty});
	};
	//----------------------------------------------------------

	this.needupdate = true;
	control.UpdateLocation();
}

Matrix.prototype.PressKeyboard = function(e) {
	keycode = GetKeyboardCode(e);
	switch (keycode) {
		case 27: // ESC
		if (control.rWindow.state) {
			control.rWindow.Show(false);
		}
		this.keyboardflags.esc = true;
		break;
		case 37: // LEFT ARROW
		//		case 72: // H
		this.keyboardflags.left = true;
		break;
		case 38: // UP ARROW
		//		case 75: // K
		this.keyboardflags.up = true;
		break;
		case 39: // RIGHT ARROW
		//		case 76: // L
		this.keyboardflags.right = true; break;
		case 40: // DOWN ARROW
		//		case 74: // J
		this.keyboardflags.down = true; break;
		case 187 : // =
		case 61  : // = for FireFox ?
		this.keyboardflags.plus = true;
		break;
		case 189 : // -
		case 109 : // - for FireFox ?
		this.keyboardflags.minus = true;
		break;
	}
}
Matrix.prototype.UnPressKeyboard = function(e) {
	keycode = GetKeyboardCode(e);
	switch (keycode) {
		case 90: // Z
		if (GetAltKey(e)) {
			this.RemoveAllMarkers();
		}
		break;
		case 71: // G
		if (GetAltKey(e)) {
			this.SwitchGrid();
		}
		break;
		case 76: // L
		if (GetAltKey(e)) {
			currentcentertile = control.matrix.GetTileAtPix({
				left: control.matrix.box.center.x,
				top: control.matrix.box.center.y
			});
			alert('bin/rasterizer --verbose=debug1 --map='+control.vars.mapid+' --outpath=/spool/atlas/tiles/ --scale='+(control.maxscalenum-control.currentscalenum)+' --left='+(currentcentertile.x-5)+' --top='+(currentcentertile.y-5)+' --right='+(currentcentertile.x+5)+' --bottom='+(currentcentertile.y+5)+' etc/build.iac');
		}
		break;
		case 27: this.keyboardflags.esc = false; break;
		case 37:
		//		case 72:
		this.keyboardflags.left = false; break;
		case 38:
		//		case 75:
		this.keyboardflags.up = false; break;
		case 39:
		//		case 76:
		this.keyboardflags.right = false; break;
		case 40:
		//		case 74:
		this.keyboardflags.down = false; break;
		case 187 : this.keyboardflags.plus = false; break;
		case 189 : this.keyboardflags.minus = false; break;
	}
}
Matrix.prototype.AddTiles = function() {
	var end, result;
	if (!this.needupdate) return;
	end = false;
	while(!end) {
		result = false;
		for(var i in this.tiles) {
			result |= this.AddNear(this.tiles[i]);
		}
		end = !result;
	}
	this.needupdate = true;
}

Matrix.prototype.RemoveTiles = function() {
	if (!this.needupdate) return;
	for(var i in this.tiles) {
		if (this.moving) {
			return;
		}
		this.ConditionRemove(this.tiles[i]);
	}
	this.needupdate = false;
}

Matrix.prototype.ConditionRemove = function(tile) {
	var tilebox;
	tilebox = {
		x1: tile.image.offsetLeft,
		y1: tile.image.offsetTop,
		x2: tile.image.offsetLeft+TILE_SIZE,
		y2: tile.image.offsetTop+TILE_SIZE
	}
	if (!this.isVisible(tilebox)) {
		this.RemoveTile(tile)
	}
}
Matrix.prototype.AddNear = function (tile) {
	var tilebox, r, newtilebox;
	tilebox = {
		x1 : tile.image.offsetLeft,
		y1 : tile.image.offsetTop,
		x2 : (tile.image.offsetLeft+TILE_SIZE),
		y2 : (tile.image.offsetTop+TILE_SIZE)
	}
	r = false;
	newtilebox = {x1: tilebox.x1-TILE_SIZE, y1: tilebox.y1, x2: tilebox.x1, y2: tilebox.y2}
	if (!this.tiles[(tile.x-1)+'x'+(tile.y)] && this.isVisible(newtilebox)) {
		newtile = new Tile({x: (tile.x-1), y: tile.y, left: newtilebox.x1, top: newtilebox.y1}, this.params.tileborders);
		this.AppendTile(newtile);
		r = true;
	}
	newtilebox = {x1: tilebox.x1, y1: tilebox.y1-TILE_SIZE, x2: tilebox.x2, y2: tilebox.y1}
	if (!this.tiles[(tile.x)+'x'+(tile.y-1)] && this.isVisible(newtilebox)) {
		newtile = new Tile({x: (tile.x), y: (tile.y-1), left: newtilebox.x1, top: newtilebox.y1}, this.params.tileborders);
		this.AppendTile(newtile);
		r = true;
	}
	newtilebox = {x1:tilebox.x2, y1: tilebox.y1, x2: tilebox.x2+TILE_SIZE, y2: tilebox.y2}
	if (!this.tiles[(tile.x+1)+'x'+(tile.y)] && this.isVisible(newtilebox)) {
		newtile = new Tile({x: (tile.x+1), y: (tile.y), left: newtilebox.x1, top: newtilebox.y1}, this.params.tileborders);
		this.AppendTile(newtile);
		r = true;
	}
	newtilebox = {x1: tilebox.x1, y1: tilebox.y2, x2: tilebox.x2, y2: tilebox.y2+TILE_SIZE}
	if (!this.tiles[(tile.x)+'x'+(tile.y+1)] && this.isVisible(newtilebox)) {
		newtile = new Tile({x: (tile.x), y: (tile.y+1), left: newtilebox.x1, top: newtilebox.y1}, this.params.tileborders);
		this.AppendTile(newtile);
		r = true;
	}
	return r;
}
Matrix.prototype.isVisible = function(tile) {
	if ((tile.x2 < this.bigbox.x1) || (tile.x1 > this.bigbox.x2) || (tile.y2 < this.bigbox.y1) || (tile.y1 > this.bigbox.y2)) {
		return false;
	}
	return true;
}
Matrix.prototype.GetTileAtPix = function(pix) {
	var tile, tilebox;
	for(var i in this.tiles) {
		tile = this.tiles[i];
		tilebox = {
			x1: tile.image.offsetLeft,
			y1: tile.image.offsetTop,
			x2: tile.image.offsetLeft+TILE_SIZE,
			y2: tile.image.offsetTop+TILE_SIZE
		}
		if (pix.left >= tilebox.x1 && pix.left <= tilebox.x2 && pix.top >= tilebox.y1 && pix.top <= tilebox.y2) {
			return {
				x: tile.x,
				y: tile.y,
				left: pix.left-tile.image.offsetLeft,
				top: pix.top-tile.image.offsetTop
			}
		}
	}
	return false;
}
Matrix.prototype.GetTileMinMax = function() {
	minX = Infinity;
	maxX = -Infinity;
	minY = Infinity;
	maxY = -Infinity;
	for(var i in this.tiles) {
		if (this.tiles[i].x < minX) {
			minX = this.tiles[i].x;
		}
		if (this.tiles[i].x >= maxX) {
			maxX = this.tiles[i].x;
		}
		if (this.tiles[i].y < minY) {
			minY = this.tiles[i].y;
		}
		if (this.tiles[i].y >= maxY) {
			maxY = this.tiles[i].y;
		}
	}
	return {minx: minX, miny: minY, maxx: maxX, maxy: maxY};
}
Matrix.prototype.HideAllMarkers = function() {
	for(var i in this.markers) {
		this.markers[i].Show(false);
	}
}
Matrix.prototype.RemoveAllMarkers = function() {
	for(var i in this.markers) {
		this.RemoveMarker(i);
	}
}
Matrix.prototype.RemoveMarker = function(markerid) {
	for (var i in this.markers[markerid].tiles) {
		tileid = this.markers[markerid].tiles[i].x+'x'+this.markers[markerid].tiles[i].y;
		if (this.tiles[tileid] && this.tiles[tileid].markers[markerid]) {
			delete this.tiles[tileid].markers[markerid];
		}
	}
	this.div.removeChild(this.markers[markerid].div);
	delete this.markers[markerid];
}
Matrix.prototype.SetMarker = function(marker) {
	this.RemoveAllMarkers();
	this.AddMarker(marker);
}
Matrix.prototype.AddMarker = function(marker) {
	if (!this.markers[marker.id]) {
		this.markers[marker.id] = marker;
		this.div.appendChild(marker.div);
	}
}

function MarkerTemplate(data) {
	if (!data.Y || !data.Y) {
		return false;
	}
	this.currentstate = false;
	this.tiles = {};

	this.x = data.X;
	this.y = data.Y;

	if (data.STYLE) {
		addStyleSheet(data.STYLE);
	}

	this.div = document.createElement('DIV');
	this.div.style.position = 'absolute';
	this.div.style.zIndex = '10001';
	this.div.style.visibility = 'hidden';

	if (data.ICON) {
		this.icon = document.createElement('IMG');
		this.icon.style.position = 'absolute';
		this.icon.style.left = '-10px';
		this.icon.style.top = '-10px';
		this.icon.src = data.ICON; // icon is 20x20
		this.div.appendChild(this.icon);
	}

	if (data.HTML) {
		this.hintdiv = document.createElement('DIV');
		this.hintdiv.style.position = 'absolute';
		this.hintdiv.innerHTML = data.HTML;
		this.hintdiv.style.zIndex = '10002';
		this.hintdiv.style.visibility = 'hidden';

		this.div.appendChild(this.hintdiv);
	}
	for(var i in control.map.scalelist) {
		this.tiles[i] = Geo2Pix({x:this.x, y:this.y}, control.map.extent, control.map.scalelist[i], control.map.datum);
	}

	this.ok = true;

	this.FixPosition = function() {
		if (this.hintdiv) {
			this.hintdiv.style.left = -document.getElementById('hint').offsetWidth+25;
			this.hintdiv.style.top = -document.getElementById('hint').offsetHeight;
		}
	}
	this.SetPosition = function(to) {
		this.div.style.left = to.x;
		this.div.style.top = to.y;
	}
	this.Show = function(state) {
		if (state) {
			if (this.tiles[control.currentscalenum] == undefined) {
				this.tiles[control.currentscalenum] = Geo2Pix({x:this.x, y:this.y}, control.map.extent, control.currentscale, control.map.datum);
			}
			var tileid = this.tiles[control.currentscalenum].x+'x'+this.tiles[control.currentscalenum].y;
			if (control.matrix.tiles[tileid] != undefined) {
				this.SetPosition({x: control.matrix.tiles[tileid].image.offsetLeft+this.tiles[control.currentscalenum].left, y: control.matrix.tiles[tileid].image.offsetTop+this.tiles[control.currentscalenum].top});
				if (!control.matrix.tiles[tileid].markers[this.id]) {
					control.matrix.tiles[tileid].markers[this.id] = this;
				}
			}
		}
		this.div.style.visibility = (state) ? 'visible' : 'hidden';
		if (this.hintdiv) this.hintdiv.style.visibility = (state) ? 'visible' : 'hidden';
		this.currentstate = state;
	}
}

function Marker(id, x, y, customimage) {
	this.id = id;
	this.x = x;
	this.y = y;
	this.text = '';
	this.customimage = customimage;
	this.tiles = {};
	this.currentstate = false;
	this.labelcurrentstate = false;
	this.havecontent = false;

	this.div = document.createElement('DIV');
	this.div.style.position = 'absolute';
	this.div.style.zIndex = '1000';
	this.image = document.createElement('IMG');
	if (customimage) {
		this.image.src = customimage;
		this.image.style.left = 0;
		this.image.style.bottom = 0;
	} else {
		this.image.src = 'i/bluepoint.gif';
		this.image.style.left = -12;
		this.image.style.bottom = 0;
	}
	this.image.style.position = 'absolute';
	this.image.style.cursor = 'pointer';
	this.image.style.zIndex = '1000';
	this.div.appendChild(this.image);

	this.label = document.createElement('DIV');
	this.label.style.position = 'absolute';
	this.label.style.left = 0;
	this.label.style.bottom = 30;
	this.label.style.width = 'auto';
	this.label.style.height = 'auto';
	this.label.style.zIndex = '999';
	this.label.style.background = '#FFFFFF';
	this.label.style.border = '1px solid #639ADC';
	this.label.style.padding = '20px';
	this.label.style.display = 'none';
	this.div.appendChild(this.label);

	this.closeimage = document.createElement('IMG');
	this.closeimage.src = 'i/close.gif';
	this.closeimage.style.position = 'absolute';
	this.closeimage.style.cursor = 'pointer';
	this.closeimage.style.right = 2;
	this.closeimage.style.top = 2;
	this.closeimage.style.zIndex = '1000';
	this.label.appendChild(this.closeimage);

	var self = this;
	addhandler(this.image, 'click', function(e) {self.ShowLabel(!self.labelcurrentstate)});
	addhandler(this.closeimage, 'click', function(e) {control.matrix.RemoveMarker(self.id)});

	for(var i in control.map.scalelist) {
		this.tiles[i] = Geo2Pix({x:this.x, y:this.y}, control.map.extent, control.map.scalelist[i], control.map.datum);
	}
}
Marker.prototype.Show = function(state) {
	if (state) {
		if (this.tiles[control.currentscalenum] == undefined) {
			this.tiles[control.currentscalenum] = Geo2Pix({x:this.x, y:this.y}, control.map.extent, control.currentscale, control.map.datum);
		}
		tileid = this.tiles[control.currentscalenum].x+'x'+this.tiles[control.currentscalenum].y;
		if (control.matrix.tiles[tileid] != undefined) {
			this.SetPosition({x: control.matrix.tiles[tileid].image.offsetLeft+this.tiles[control.currentscalenum].left, y: control.matrix.tiles[tileid].image.offsetTop+this.tiles[control.currentscalenum].top});
			if (!control.matrix.tiles[tileid].markers[this.id]) {
				control.matrix.tiles[tileid].markers[this.id] = this;
			}
		}
	}
	this.div.style.display = (state) ? 'block' : 'none';
	this.currentstate = state;
}
Marker.prototype.FixPosition = function(x, y) {
	x = x*1;y = y*1;
	var labelH = this.label.offsetHeight + this.image.offsetHeight;
	var labelW = this.label.offsetWidth + this.image.offsetWidth;
	return {x:x+Math.round(labelW/2), y:y+Math.round(labelH/2)};
}
Marker.prototype.ShowLabel = function(state) {
	if (!this.havecontent) return;
	this.label.style.display = (state) ? 'block' : 'none';
	this.labelcurrentstate = state;
}
Marker.prototype.SetPosition = function(to) {
	this.div.style.left = to.x;
	this.div.style.top = to.y;
}
Marker.prototype.AddURL = function(url, content, prefix) {
	if (url == undefined || url == '') {
		return false;
	}
	if (content == undefined) {
		content = url;
	}
	D = document.createElement('DIV');
	D.className = 'markerlabel';
	Anode = document.createElement('A');
	url=url.replace('http://', '', 'gi');
	Anode.setAttribute('href', 'http://'+url);
	Anode.setAttribute('target', '_blank');

	textnode = document.createTextNode(content);
	Anode.appendChild(textnode);
	Anode.className = 'markerlabelsmall';
	D.appendChild(Anode);
	this.label.appendChild(D);
	this.havecontent = true;
}

Marker.prototype.AddToLabel = function(content, small, gray, wrap) {
	this.text += content;
	labeldiv = document.createElement('DIV');
	labeldiv.className = 'markerlabel';
	if (small) {
		labeldiv.className = 'markerlabelsmall';
	}
	if (gray) {
		labeldiv.className = 'markerlabelgray';
	}
	if (!wrap) {
		labeldiv.style.whiteSpace  = 'nowrap';
	}
	node = document.createTextNode(content);
	labeldiv.appendChild(node);
	this.label.appendChild(labeldiv);
	this.havecontent = true;
}

function Zoomer(zoomcount, initzoom) {
	var temp, slider;
	this.initzoom = initzoom;
	this.zoomcount = zoomcount;
	this.div = document.createElement('DIV');
	this.div.style.position = 'absolute';
	this.div.style.overflow = 'hidden';
	this.div.style.zIndex = '1000';
	this.div.style.height = 25*2+13*zoomcount;
	this.div.style.width = 28;
	this.div.style.right = '2px';
	this.div.style.top = document.getElementById('head').offsetHeight+2;
	this.div.id = 'zoomer';

	temp = document.createElement('IMG');
	temp.src = 'i/slider_top.png';
	temp.className='fixpng';
	temp.style.position = 'absolute';
	temp.style.left = 0;
	temp.style.top = 0;
	temp.width = 28;
	temp.height = 25;
	temp.id = 'zoomin';
	temp.style.cursor = 'pointer';
	this.div.appendChild(temp);

	for(var i=0;i<zoomcount;i++){
		temp = document.createElement('IMG');
		temp.src = 'i/slider_step.png';
		temp.style.position = 'absolute';
		temp.style.left = 0;
		temp.style.top = 25+i*13;
		temp.width = 28;
		temp.height = 13;
		temp.style.cursor = 'pointer';
		temp.id = "zoom_step_"+i;
		temp.cnt = i;
		temp.title = control.map.scalelist[i];
		this.div.appendChild(temp);
		addhandler(temp, 'click', function(e) {
			control.ChangeZoom(GetTarget(e).cnt-control.currentscalenum);
			control.zoomer.initzoom = GetTarget(e).cnt
		});
	}

	temp = document.createElement('IMG');
	temp.src = 'i/slider_bottom.png';
	temp.className='fixpng';
	temp.style.position = 'absolute';
	temp.style.left = 0;
	temp.style.bottom = 0;
	temp.width = 28;
	temp.height = 25;
	temp.id = 'zoomout';
	temp.style.cursor = 'pointer';
	this.div.appendChild(temp);

	this.slider = document.createElement('IMG');
	this.slider.src = 'i/slider_slider.png';
	this.slider.style.position = 'absolute';
	this.slider.style.left = 5;
	this.slider.style.top = initzoom*13+25+3;
	this.slider.width = 18;
	this.slider.height = 5;
	this.slider.style.cursor = 'pointer';
	this.slider.id = 'slider';
	this.div.appendChild(this.slider);

	slider = new Object();
	slider.control = this;
	slider.moving = false;
	slider.obj = this.slider;
	slider.dy = 0;
	slider.obj.miny = 22;
	slider.obj.maxy = (zoomcount-1)*13+25+10;
	slider.obj.onmousedown = function(e) {cancelevent(e); return slider.control.StartDrag(e)}
	addhandler(document, 'mousemove', function(e) { return slider.control.Drag(e) });
	addhandler(document, 'mouseup', function(e) { slider.control.EndDrag(e) });

}
Zoomer.prototype.ShiftToZoom = function(zoom) {
	this.slider.style.top = zoom*13+25+3;
	//----------------------------------------------------------(from Editor)
	if (surf) {
		Editor_onZoom();
	};
	//----------------------------------------------------------
}
Zoomer.prototype.StartDrag = function(e) {
	this.moving = true;
	this.dy = GetMouse(e).y-this.slider.offsetTop;
	return false;
}
Zoomer.prototype.EndDrag = function(e) {
	var newzoom;
	if (!this.moving) return false;
	this.moving = false;
	newzoom = Math.round((this.slider.offsetTop-28)/13);
	if (newzoom < 0) newzoom = 0;
	if (newzoom > this.zoomcount-1) newzoom = this.zoomcount-1;
	this.slider.style.top = newzoom*13+25+3;
	control.ChangeZoom(newzoom-this.initzoom);
	this.initzoom = newzoom;
}
Zoomer.prototype.Drag = function(e) {
	var newy;
	if (!this.moving) return true;
	newy = e.clientY-this.dy;
	if (newy >= this.slider.miny && newy <= this.slider.maxy) this.slider.style.top = newy;
	return false;
}
Zoomer.prototype.Show = function(state) {
	this.div.style.visibility = (state) ? 'visible' : 'hidden';
}
function Finder(mapid) {
	this.base = FINDER_SERVER;
	this.offset = 0;
	this.limit = 0;
	this.mapid = mapid;
	this.types = false;
	this.callback = false;
}
Finder.prototype.SelectBy = function(to, where, what, parent, context) {
	if (where == 'buildings') {
		this.url = this.base + 'finder/?sub=1&rnd='+control.rnd+'&mapid='+this.mapid+'&layer='+where+'&expr="!'+what+'"&sortby=ADRES%2BM&crutch=апож';
	} else {
		this.url = this.base + 'finder/?sub=1&rnd='+control.rnd+'&mapid='+this.mapid+'&layer='+where+'&expr="!'+what+'"&sortby=TEXT%2BM&crutch=апож';
	}
	replyfunc = function () {
		var search_objects=[];
		eval(this.request.responseText);
		if (search_objects[0].params.error != undefined) {
			control.SearchResults.ClearSubResults();
			control.SearchResults.JumpToObject(context);
		} else {
			control.SearchResults.ClearSubResults();
			control.SearchResults.AppendSubResults(parent, search_objects);
		}
	};
	document.getElementById('searchbutton').src = 'i/progress.gif';
	this.MakeRequest(function () {replyfunc() });
}
Finder.prototype.SearchByAgent = function(agent, oid, z) {
	//!   oids => list
	this.url = this.base + 'finder/?sub=0&rnd='+control.rnd+'&mapid='+this.mapid+'&layer='+agent+'&expr="!'+oid+'"&sortby=NAME%2BM,TEXT%2BM,STREETADR%2BM&crutch=апож';
	replyfunc = function () {
		var search_objects=[];
		eval(control.Finder.request.responseText);
		if (search_objects[0].params.error != undefined) {
		} else {
			//! loop for all
			//! extent extent
			control.SearchResults.JumpToObject(search_objects[0].params, z);
		}
	}
	document.getElementById('searchbutton').src = 'i/progress.gif';
	this.MakeRequest(function () {replyfunc() });
}
Finder.prototype.SearchByKeyword = function(keyword) {
	if (keyword == '' || keyword == undefined) {
		return;
	}
	keyword = keyword.replace(/\"/g, '\\"');
	this.url = this.base + 'finder/?sub=0&rnd='+control.rnd+'&mapid='+this.mapid+'&layer=*,-metro&expr="'+keyword+'"&sortby=TEXT%2BM,STREETADR%2BM&crutch=апож';
	subrequestfunc = function(parent) {
		if (this.typeid == 'metrostat') {
			where = 'metro';
		}
		if (this.typeid == 'roads') {
			where = 'buildings';
		}
		what = this.obj_cod;
		control.Finder.SelectBy(this.id, where, what, parent, this);
	}
	replyfunc = function () {
		var search_objects=[];
		eval(control.Finder.request.responseText);
		if (search_objects && search_objects[0] && search_objects[0].params && search_objects[0].params.error != undefined) {
			keyword = keyword.replace(/\\"/g, '"');
			control.rWindow.Generate('', 'Ничего не найдено по запросу <B>'+keyword+'</B>');
			control.rWindow.Show(true);
		} else {
			control.SearchResults.ClearSubResults();
			control.SearchResults.Clear(true);
			for(i in search_objects) {
				search_objects[i].params.subrequest = subrequestfunc;
				control.SearchResults.AddObject(search_objects[i].params);
			}
			control.SearchResults.Show(true);
		}
	};
	document.getElementById('searchbutton').src = 'i/progress.gif';
	this.MakeRequest(function () {replyfunc() });
}
function SimpleObject(params) {this.params = params;}
Finder.prototype.MakeRequest = function(callback) {
	try {
		request = new XMLHttpRequest();
	} catch (e) {
		request = new ActiveXObject("Microsoft.XMLHTTP");
	}
	request.onreadystatechange = function() {
		if (request.readyState == 4) {
			if (request.status == 200) {
				callback();
				document.getElementById('searchbutton').src = 'i/search.gif';
			} else if (request.status == undefined) {
			} else {
				document.getElementById('searchbutton').src = 'i/search.gif';
				control.rWindow.Generate('Ошибка '+request.status, 'Проблема с поиском!');
				control.rWindow.Show(true);
			}
		}
	}
	this.request = request;
	request.open("GET", this.url);
	request.send(null);
	//	request.setRequestHeader('Content-Type', 'text/javascript; charset=windows-1251');
	//	request.overrideMimeType('text/plain;charset=windows-1251');
}
Finder.prototype.Abort = function() {
	if (this.request != undefined) {
		this.request.abort();
	}
	document.getElementById('searchbutton').src = 'i/search.gif';
}

function ControlPanel() {
	var temp, temp2;
	this.div = document.createElement('DIV');
	this.div.style.position = 'absolute';
	this.div.style.overflow = 'hidden';
	this.div.style.right = 33;
	this.div.style.top = document.getElementById('head').offsetHeight+2;

	this.div.style.width = 102;
	this.div.style.height = 25;
	this.div.style.zIndex = '1000';
	this.div.id = 'controlpanel';

	temp = document.createElement('IMG');
	temp.src = 'i/hs-1.gif';
	temp.style.position = 'absolute';
	temp.style.left = 0;
	temp.style.top = 0;
	temp.width = 7;
	temp.height = 25;
	this.div.appendChild(temp);

	temp = document.createElement('DIV');
	temp.style.backgroundImage = "url(i/hs-2.gif)";
	temp.style.backgroundPosition = 'center center';
	temp.style.backgroundRepeat = 'repeat-x';
	temp.style.position = 'absolute';
	temp.style.left = 7;
	temp.style.top = 0;
	temp.style.width = 90;
	temp.style.height = 25;
	this.div.appendChild(temp);

	temp2 = document.createElement('IMG');
	temp2.src = 'i/hs-star.gif';
	temp2.style.position = 'absolute';
	temp2.style.left = 0;
	temp2.style.top = 2;
	temp2.width = 26;
	temp2.height = 19;
	temp2.id = "favorite";
	temp2.style.cursor = "pointer";
	temp.appendChild(temp2);

	temp2 = document.createElement('IMG');
	temp2.src = 'i/hs-url.gif';
	temp2.style.position = 'absolute';
	temp2.style.left = 30;
	temp2.style.top = 2;
	temp2.width = 26;
	temp2.height = 19;
	temp2.id = "geturl";
	temp2.style.cursor = "pointer";
	temp.appendChild(temp2);

	temp2 = document.createElement('IMG');
	temp2.src = 'i/hs-print.gif';
	temp2.style.position = 'absolute';
	temp2.style.left = 60;
	temp2.style.top = 2;
	temp2.width = 26;
	temp2.height = 19;
	temp2.id = "print";
	temp2.style.cursor = "pointer";
	temp.appendChild(temp2);

	temp = document.createElement('IMG');
	temp.src = 'i/hs-3.gif';
	temp.style.position = 'absolute';
	temp.style.right = 0;
	temp.style.top = 0;
	temp.width = 7;
	temp.height = 25;
	this.div.appendChild(temp);
}
ControlPanel.prototype.Show = function(state) {
	this.div.style.visibility = (state) ? 'visible' : 'hidden';
}

function MapSelector() {
	this.div = document.createElement('DIV');
	this.div.style.position = 'absolute';
	this.div.style.overflow = 'hidden';
	this.div.id = 'mapselector';
	this.div.style.left = 0;
	this.div.style.top = document.getElementById('head').offsetHeight;

	this.div.style.width = 'auto';
	this.div.style.height = 'auto';
	this.div.style.zIndex = '1000';
	this.div.style.padding = '20px';
	this.div.style.backgroundImage = "url(i/box2.png)";
	this.div.style.background = "#FFFFFF";
	this.div.style.border = "#FF0000";
	this.div.style.visibility = 'hidden';

	var dumplist = [];
	for(mapid in control.maps) {
		firstletter = control.maps[mapid].description.charAt(0);
		dumplist.push({
			firstletter : firstletter,
			id : mapid,
			vid: mapid,
			status: control.maps[mapid].status,
			description : control.maps[mapid].description,
			path: control.maps[mapid].path,
			type : 'real'
		});
	}
	for(mapid in control.virtualmaps) {
		firstletter = control.virtualmaps[mapid].description.charAt(0);
		dumplist.push({
			firstletter : firstletter,
			id : control.virtualmaps[mapid].linkto,
			vid: mapid,
			x : control.virtualmaps[mapid].defaultcenter.x,
			y : control.virtualmaps[mapid].defaultcenter.y,
			z : control.virtualmaps[mapid].defaultcenter.z,
			description : control.virtualmaps[mapid].description,
			status: control.virtualmaps[mapid].status,
			path: control.virtualmaps[mapid].path,
			type : 'virtual'
		});
	}
	dumplist.sort(this.compare);
	this.html = '<TABLE cellpadding="10" cellspacing="0" border="0"><TR valign="top">';
	var lfl,cur=0;
	for(var column=0;column<3;column++) {
		this.html += '<TD width="33%">';
		this.html += '<TABLE cellpadding="0" cellspacing="0" border="0">';
		lfl = dumplist[cur].firstletter;
		this.html += '<TR><TD align="center" width="20" class="mapselector_firstletter">'+dumplist[cur].firstletter+'</TD><TD></TD></TR>';
		for(elem=0;elem<Math.round(dumplist.length/3);elem++){
			if (lfl != dumplist[cur].firstletter) {
				this.html += '<TR><TD height="10" colspan="2"></TD></TR>';
				this.html += '<TR><TD align="center" width="20" class="mapselector_firstletter">'+dumplist[cur].firstletter+'</TD><TD></TD></TR>';
			}
			if (dumplist[cur].status) {
				this.html += '<TR><TD colspan="2" nowrap><A href="'+window.location.protocol+'//'+window.location.host+'/'+dumplist[cur].path+'/';
				if (dumplist[cur].x != undefined && dumplist[cur].y != undefined && dumplist[cur].z != undefined) {
					this.html += '#x='+dumplist[cur].x+'&y='+dumplist[cur].y+'&z='+dumplist[cur].z;
				}
				this.html += '">';
			} else {
				this.html += '<TR><TD colspan="2" nowrap><A href="#" onclick="return false" class="disabled">';
			}
			this.html += dumplist[cur].description;
			this.html += '</A></TD></TR>';
			lfl = dumplist[cur].firstletter;
			cur++;
			if (cur>=dumplist.length) {
				break;
			}
		}
		this.html += '</TABLE>';
		this.html += '</TD>';
	}
	this.html += '</TR></TABLE>';
}

MapSelector.prototype.compare = function(a, b) {
	if (a.description < b.description) {
		return -1;
	}
	if (a.description > b.description) {
		return 1;
	}
	return 0;
}
MapSelector.prototype.PopUp = function() {
	control.rWindow.Generate('Выберите карту', this.html);
	control.rWindow.Show(true);
}
MapSelector.prototype.Show = function(state) {
	control.rWindow.Show(state);
}

function rWindow() {
	this.div = document.createElement('DIV');
	this.div.style.position = 'absolute';
	this.div.style.zIndex = '30000';
	this.div.style.borderRight = '3px solid #999999';
	this.div.style.borderBottom = '3px solid #999999';
	this.div.style.width = 'auto';
	this.div.style.height = 'auto';
	this.contentdiv = document.createElement('DIV');
	this.contentdiv.style.margin = '30px';
	this.contentdiv.style.paddingBottom = '20px';
	this.div.style.background = "url(i/box2.png)";
	this.state = false;
	this.div.appendChild(this.contentdiv);

}
rWindow.prototype.Generate = function(header, content) {
	if (this.headernode) {
		this.contentdiv.removeChild(this.headernode);
	}
	if (this.contentnode) {
		this.contentdiv.removeChild(this.contentnode);
	}
	this.headernode = document.createTextNode(header);
	this.contentdiv.appendChild(this.headernode);

	this.contentnode = document.createElement('DIV');
	this.contentnode.innerHTML = content;
	this.contentdiv.appendChild(this.contentnode);

	this.closebutton = document.createElement('IMG');
	this.closebutton.src = 'i/close.png';
	this.closebutton.style.position = 'absolute';
	this.closebutton.style.bottom = 2;
	this.closebutton.style.right = 2;
	this.closebutton.width = 61;
	this.closebutton.height = 17;
	this.closebutton.style.cursor = "pointer";
	var self = this;
	addhandler(this.closebutton, 'click', function(e) {self.Show(false)});
	this.div.appendChild(this.closebutton);

	this.div.style.top = control.matrix.box.center.y - Math.round(this.div.offsetHeight / 2);
	this.div.style.left = control.matrix.box.center.x - Math.round(this.div.offsetWidth / 2);
}
rWindow.prototype.Show = function(state) {
	var prevstate = (this.div.style.visibility == 'visible');
	this.div.style.visibility = (state) ? 'visible' : 'hidden';
	this.state = state;
	return prevstate;
}

Show = function(state) {
	var prevstate = (this.div.style.display == 'block');
	this.div.style.display = (state) ? 'block' : 'none';
	return prevstate;
}
function SearchSubResults(left, top) {
	this.div = document.createElement('DIV');
	this.div.style.top =  document.getElementById('head').offsetHeight+2;

	this.div.style.backgroundImage = 'url("i/box2.png")';
	this.div.style.border = '1px solid #639ADC';
	this.div.style.position = 'absolute';
	this.div.style.font = 'normal 12px arial,sans-serif';
	this.div.style.overflow = 'scroll';
	this.div.style.zIndex = '300000';
	this.div.style.width = '300px';
	this.div.style.padding = '5px';

	this.div.style.height = '300px';
}
SearchSubResults.prototype.Show = function(state) {
	var prevstate = (this.div.style.display == 'block');
	if (!state) {
		this.div.style.display = 'none';
	} else {
		this.div.style.left = control.SearchResults.div.offsetWidth+4;
		this.div.style.display = 'block';
	}
	return prevstate;
}

function SearchResults() {
	this.div = document.createElement('DIV');
	this.div.style.left = '2px';
	this.div.className = "clientfix";
	this.div.style.top = document.getElementById('head').offsetHeight+2;
	this.div.style.backgroundImage = 'url("i/box2.png")';
	this.div.style.border = '1px solid #639ADC';
	this.div.style.position = 'absolute';
	this.div.style.font = 'normal 12px arial,sans-serif';
	this.div.style.overflow = 'scroll';
	this.div.style.zIndex = '300000';
	this.div.style.width = '300px';

	this.div.style.height = '300px';

	this.groups = {};
	closebutton = document.createElement('IMG');
	closebutton.src = 'i/close.png';
	closebutton.width = '61';
	closebutton.height = '17';
	closebutton.align = 'right';
	closebutton.style.cursor = "pointer";
	addhandler(closebutton, 'click', function(e) {
		control.SearchSubResults.Show(false);
		control.SearchResults.Show(false);
	});
	this.div.appendChild(closebutton);
}

SearchResults.prototype.ClearSubResults = function() {
	control.SearchSubResults.Show(false);
	while(control.SearchSubResults.div.firstChild) {
		control.SearchSubResults.div.removeChild(control.SearchSubResults.div.firstChild);
	}
}
SearchResults.prototype.AppendSubResults = function(fortype, objects) {
	var objdiv;
	var textnode;
	var object;
	closebutton = document.createElement('IMG');
	closebutton.src = 'i/close.png';
	closebutton.width = '61';
	closebutton.height = '17';
	closebutton.align = 'right';
	closebutton.style.cursor = "pointer";
	addhandler(closebutton, 'click', function(e) {
		control.SearchSubResults.Show(false);
	});
	control.SearchSubResults.div.appendChild(closebutton);

	if (fortype.typeid == 'roads') {
		objdiv = document.createElement('DIV');
		objdiv.className = 'searchsubresultsitem';
		objdiv.data = fortype;
		textnode = document.createTextNode(fortype.text+': ');
		objdiv.appendChild(textnode);
		control.SearchSubResults.div.appendChild(objdiv);
		addhandler(objdiv, 'click', function(e) {
			target = GetTarget(e);
			control.SearchResults.JumpToObject(target.data);
			control.SearchSubResults.Show(false);
			control.SearchResults.Show(false);
		});
	}
	for(var i in objects) {
		object = objects[i].params;
		objdiv = document.createElement('DIV');
		if (object.adres) {
			text = object.adres;
		} else if (object.name) {
			text = object.name;
		} else {
			text = object.text;
		}
		textnode = document.createTextNode(text);
		objdiv.appendChild(textnode);
		objdiv.className = 'searchsubresultsitem';
		objdiv.style.cursor = 'pointer';
		objdiv.data = object;
		addhandler(objdiv, 'click', function(e) {
			target = GetTarget(e);
			control.SearchSubResults.Show(false);
			control.SearchResults.Show(false);
			control.SearchResults.JumpToObject(target.data);
		});

		control.SearchSubResults.div.appendChild(objdiv);
		if (object.exit) {
			subobjdiv = document.createElement('DIV');
			subobjdiv.className = 'search_results_object_subinfo';
			textnode = document.createTextNode(object.exit);
			subobjdiv.appendChild(textnode);
			control.SearchSubResults.div.appendChild(subobjdiv);
		}
	}
	control.SearchSubResults.Show(true);
}

SearchResults.prototype.AddObject = function(object) {
	if (!this.groups[object.typeid]) {
		this.groups[object.typeid] = new SearchResultGroup(object.typeid, (object.typename != '' ? object.typename : control.object_types[object.typeid]));
		this.div.appendChild(this.groups[object.typeid].div);
	}
	this.groups[object.typeid].AddItem(object);
}
SearchResults.prototype.Clear = function(removegroups) {
	for(var i in this.groups) {
		this.groups[i].Clear();
		if (removegroups) {
			this.div.removeChild(this.groups[i].div);
			delete this.groups[i];
		}
	}
}
SearchResults.prototype.Generate = function() {

}
SearchResults.prototype.Show = function(state) {
	var prevstate = (this.div.style.display == 'block');
	this.div.style.display = (state) ? 'block' : 'none';
	if (state) {
		if (Count(this.groups) == 1) {
			var firstgroup = GetFirst(this.groups);
			this.groups[firstgroup.id].ShowContent(true);

			/*			if (Count(firstgroup.items) == 1) {
			this.JumpToObject(GetFirst(firstgroup.items).textdiv.data);
			control.SearchSubResults.Show(false);
			control.SearchResults.Show(false);
			}
			*/
		}
	}
	return prevstate;
}

SearchResults.prototype.JumpToObject = function(object, z) {
	var s1 = ComprehensiveScale({x1:object.min_x, y1:object.min_y, x2:object.max_x, y2:object.max_y}, {width: control.matrix.box.width, height: control.matrix.box.height}, control.map.datum);
	var obj;
	if (object.text == undefined) {
		object.text = object.streetadr;
	}
	if (object.text == undefined) {
		object.text = object.name;
	}
	var workid = object.rowid||object.id;
	if (!object.x) {
		object.x = object.min_x;
		object.y = object.min_y;
	}
	if (!control.matrix.markers[workid]) {
		obj = new Marker(object.rowid||object.id, object.x, object.y);
		obj.AddToLabel(object.text);
		if (object.exit) {
			obj.AddToLabel(object.line1, true, false);
			obj.AddToLabel(object.exit, true, true, true);
		}
		if (object.groupname) { obj.AddToLabel(object.groupname, true, true); }
		if (object.address) { obj.AddToLabel(object.address, true, false); }
		if (object.adm) { obj.AddToLabel(object.adm, true, true); }
		if (object.adm1) { obj.AddToLabel(object.adm1, true, true); }
		if (object.adm2) { obj.AddToLabel(object.adm2, true, true); }
		if (object.phone) { obj.AddToLabel(object.phone, true, true); }
		if (object.fax) { obj.AddToLabel(object.fax, true, true); }
		if (object.website) { obj.AddURL(object.website); }
		if (control.vars.makeobjurl) { obj.AddURL(control.vars.makeobjurl(object.id, object.typeid), 'Подробнее...'); }
		control.matrix.AddMarker(obj);
		obj.Show(true);
		obj.ShowLabel(true);
		scale = z || NearestScale(s1+1);
		var newpos = obj.FixPosition(object.x, object.y);
		control.Goto(newpos.x, newpos.y, scale);
	} else {
		newpos = {x:object.x, y:object.y};
		control.Goto(newpos.x, newpos.y, scale);
	}
}

SearchResults.prototype.HighlightItem = function(id) {
	for(var i in this.groups) {
		for(var j in this.groups[i].items) {
			if (this.groups[i].items[j].data.id == id) {
				this.groups[i].items[j].textdiv.style.backgroundColor = '#3370CE';
				this.groups[i].items[j].textdiv.style.color = '#FFFFFF';
			} else {
				this.groups[i].items[j].textdiv.style.backgroundColor = 'transparent';
				this.groups[i].items[j].textdiv.style.color = '#000000';
			}
		}
	}
}

function SearchResultGroup(id, name) {
	this.id = id;
	this.name = name;
	this.items = {};
	this.contentstate = false;
	this.div = document.createElement('DIV');
	this.headerdiv = document.createElement('DIV');
	this.headerdiv.className = 'searchresultsgroup';
	this.headerdiv.containdivid = id;

	this.contentdiv = document.createElement('DIV');
	this.contentdiv.style.paddingLeft = '10px';
	this.contentdiv.style.display = 'none';
	this.contentdiv.id = this.headerdiv.containdivid;

	this.headerdiv.appendChild(document.createTextNode(name));
	this.div.appendChild(this.headerdiv);
	this.div.appendChild(this.contentdiv);
	addhandler(this.headerdiv, 'click', function(e) {
		var target = GetTarget(e);
		control.SearchResults.ClearSubResults();
		var prevstate = control.SearchResults.groups[target.containdivid].contentstate;
		for(var i in control.SearchResults.groups) {
			control.SearchResults.groups[i].ShowContent(false);
		}
		control.SearchResults.groups[target.containdivid].ShowContent(!prevstate);
	});
}
SearchResultGroup.prototype.FindExistObjCod = function(obj_cod) {
	for(var i in this.items) {
		if (this.items[i].data.obj_cod == obj_cod) {
			return true;
		}
	}
	return false;
}
SearchResultGroup.prototype.AddItem = function(object) {
	if (!this.items[object.id]) {
		this.items[object.id] = new SearchResultsItem(object);
		this.contentdiv.appendChild(this.items[object.id].div);
	}
}
SearchResultGroup.prototype.Clear = function() {
	for(var i in this.items) {
		delete this.items[i];
	}
}
SearchResultGroup.prototype.Show = Show;
SearchResultGroup.prototype.ShowContent = function(state) {
	this.contentstate = state;
	var prevstate = (this.contentdiv.style.display == 'block');
	this.contentdiv.style.display = (state) ? 'block' : 'none';
	return prevstate;
}

function SearchResultsItem(object) {
	this.data = object;
	this.div = document.createElement('DIV');

	this.textdiv = document.createElement('DIV');
	this.textdiv.className = 'searchresultsitem';

	var text;
	if (object.streetadr) {
		text = object.streetadr;
	} else if (object.text) {
		text = object.text;
	} else if (object.name) {
		text = object.name;
	} else {
		text = 'Неизвестный объект';
	}
	if (object.typeid == 'roads' || (object.typeid == 'metrostat' && object.leg_num == '1')) {
		this.textdiv.havesub = true;
	} else {
		this.textdiv.havesub = false;
	}
	text = cleanUpText(text);
	this.textdiv.appendChild(document.createTextNode(text));

	this.textdiv.data = object;
	this.textdiv.id = object.id;
	this.div.appendChild(this.textdiv);
	if (object.adm1 || object.adm || object.line1) {
		var subinfo = object.adm1 || object.adm || object.line1;
		if (object.adm2) {
			subinfo = subinfo + ', '+object.adm2;
		}
		subobjdiv = document.createElement('DIV');
		subobjdiv.className = 'search_results_object_subinfo_main';
		textnode = document.createTextNode('('+subinfo+')');
		subobjdiv.appendChild(textnode);
		this.div.appendChild(subobjdiv);
	}
	addhandler(this.textdiv, 'click', function(e) {
		target = GetTarget(e);
		control.SearchResults.HighlightItem(target.id);
		if (!target.havesub) {
			control.SearchResults.JumpToObject(target.data);
			control.SearchSubResults.Show(false);
			control.SearchResults.Show(false);
		} else {
			object.subrequest(target.data);
		}
	});
}
function rMap(vars) {
	this.LoadTop100 = function() {
		var top100image = new Image();
		top100image.src = 'http://counter.rambler.ru/top100.cnt?175265&rn='+Math.random()+'&rf='+escape(document.referrer);
	}

	this.Goto = function(x, y, z) {
		var centertile;
		this.currentcenter = {
			x: x,
			y: y
		};
		z = z*1;
		oldcenter = this.matrix.GetTileAtPix({left: this.matrix.box.center.x, top: this.matrix.box.center.y});
		newcenter = Geo2Pix(this.currentcenter, this.map.extent, this.currentscale, this.map.datum);
		distance = this.CalcPixDistance(oldcenter, newcenter);
		if (z == this.currentscalenum && distance.distance < 1000) { // near?
			oldcenter = control.matrix.box.center;
			newcenter = {x: oldcenter.x+distance.xdiff, y: oldcenter.y+distance.ydiff};
			control.matrix.SlideFromTo(
			oldcenter,
			newcenter
			);
		} else {
			this.currentscale = this.map.scalelist[z];
			this.currentscalenum = z;
			centertile = Geo2Pix(this.currentcenter, this.map.extent, this.currentscale, this.map.datum);
			this.recalcMostTile();
			this.matrix.HideAllMarkers();
			this.matrix.RemoveAllTiles();
			this.matrix.currentscale = this.currentscale;
			this.matrix.CreateMatrix(centertile);
			this.zoomer.ShiftToZoom(z);
		}
		this.UpdateLocation();
	}
	this.CalcPixDistance = function(from, to) {
		from_pix_x = from.x*TILE_SIZE+from.left;
		from_pix_y = from.y*TILE_SIZE+from.top;
		to_pix_x = to.x*TILE_SIZE+to.left;
		to_pix_y = to.y*TILE_SIZE+to.top;
		distance = Math.round(Math.sqrt((from_pix_x-to_pix_x)*(from_pix_x-to_pix_x) + (from_pix_y-to_pix_y)*(from_pix_y-to_pix_y)));
		return {distance: distance, xdiff: (from_pix_x-to_pix_x), ydiff: (from_pix_y-to_pix_y)};
	}
	this.ChangeZoom = function(shift) {
		var currentcentertile, currentcenter;
		if ((shift == 0 ) || (this.currentscalenum+shift < 0) || (this.currentscalenum+shift > this.maxscalenum)) {
			return;
		}
		currentcentertile = control.matrix.GetTileAtPix({
			left: control.matrix.box.center.x,
			top: control.matrix.box.center.y
		});
		currentcenter = Pix2Geo(currentcentertile, control.map.extent, control.currentscale, control.map.datum);

		changezoomprocess = function() {
			control.currentscalenum += shift;
			control.currentscale = control.map.scalelist[control.currentscalenum];
			control.recalcMostTile();
			control.matrix.RemoveAllTiles();
			control.matrix.currentscale = control.currentscale;
			centertile = Geo2Pix(currentcenter, control.map.extent, control.currentscale, control.map.datum);
			control.matrix.CreateMatrix(centertile);
			control.zoomer.ShiftToZoom(control.currentscalenum);
			control.UpdateLocation();
		}
		control.matrix.HideAllMarkers();
		if (Math.abs(shift) != 1) {
			changezoomprocess();
		} else {
			control.SmoothExec(
			function() {
				control.smoothresize = {};
				control.matrix.needupdate = false;
				control.smoothresize.image_size_from = TILE_SIZE;
				if (shift < 0) {
					control.smoothresize.image_size_to = TILE_SIZE*(-shift*2);
				} else {
					control.smoothresize.image_size_to = TILE_SIZE/(shift*2);
				}
				control.smoothresize.imagechanger = -Math.ceil((control.smoothresize.image_size_from - control.smoothresize.image_size_to) / 5);
				control.smoothresize.iterator = 0;
				control.smoothresize.centertile = control.matrix.GetTileAtPix({left: control.matrix.box.center.x, top: control.matrix.box.center.y});
				control.smoothresize.minmax = control.matrix.GetTileMinMax();
				control.smoothresize.tiles = {};
				for(var i in control.matrix.tiles) {
					control.smoothresize.tiles[i] = document.createElement('IMG');
					control.smoothresize.tiles[i].src = control.matrix.tiles[i].image.src;
					control.smoothresize.tiles[i].style.position = 'absolute';
					control.smoothresize.tiles[i].style.zIndex = '600';
					control.smoothresize.tiles[i].width = TILE_SIZE;
					control.smoothresize.tiles[i].height = TILE_SIZE;
					control.smoothresize.tiles[i].style.left = control.matrix.tiles[i].image.offsetLeft;
					control.smoothresize.tiles[i].style.top = control.matrix.tiles[i].image.offsetTop;
					control.matrix.div.appendChild(control.smoothresize.tiles[i]);
				}
			},
			function() {
				for(x=control.smoothresize.minmax.minx;x<=control.smoothresize.minmax.maxx;x++) {
					for(y=control.smoothresize.minmax.miny;y<=control.smoothresize.minmax.maxy;y++) {
						tileid = x+'x'+y;
						xdiff = control.smoothresize.centertile.x-x;
						ydiff = control.smoothresize.centertile.y-y;
						if (control.smoothresize.tiles[tileid]) {
							control.smoothresize.tiles[tileid].width += control.smoothresize.imagechanger;
							control.smoothresize.tiles[tileid].height += control.smoothresize.imagechanger;
							control.smoothresize.tiles[tileid].style.left = control.smoothresize.tiles[tileid].offsetLeft-(control.smoothresize.imagechanger/2)-xdiff*control.smoothresize.imagechanger;
							control.smoothresize.tiles[tileid].style.top = control.smoothresize.tiles[tileid].offsetTop-(control.smoothresize.imagechanger/2)-ydiff*control.smoothresize.imagechanger;
						}
					}
				}
			},
			function() {
				control.smoothresize.iterator++;
				return (control.smoothresize.iterator == 5);
			},
			function() {
				for(var i in control.smoothresize.tiles) {
					control.smoothresize.tiles[i].style.zIndex = '400';
				}
				changezoomprocess();
				if (control.smoothresize && control.smoothresize.tiles) {
					for(var i in control.smoothresize.tiles) {
						control.matrix.div.removeChild(control.smoothresize.tiles[i]);
						delete control.smoothresize.tiles[i];
					}
					control.smoothresize.tiles = {};
				}
			},
			1
			);
		}
	}
	this.wheel = function(event) {
		var delta;
		if (!GetTarget(event).drag) return true;
		delta = 0;
		if (!event) {
			event = window.event;
		}
		if (event.wheelDelta) {
			delta = event.wheelDelta/120;
			if (window.opera) {
				delta = -delta;
			}
		} else if (event.detail) {
			delta = -event.detail/3;
		}
		if (delta > 0) {
			delta = -1;
		} else {
			delta = 1;
		}
		if ((delta == -1 &&  (control.currentscalenum == 0)) || (delta == 1 &&  (control.currentscalenum == control.maxscalenum))) {
			return;
		}

		from = GetMouseWheel(event);
		half_x = Math.round((control.matrix.box.center.x-from.x)/2);
		half_y = Math.round((control.matrix.box.center.y-from.y)/2);
		to = {x:control.matrix.box.center.x-half_x, y:control.matrix.box.center.y-half_y};
		//		control.matrix.SlideFromTo(from, to, function() {control.ChangeZoom(delta);});
		control.ChangeZoom(delta);
		cancelevent(event);
		return false;
	}
	this.SmoothExec = function(startfunc, periodicalfunc, checkendfunc, endfunc, speed) {
		this.smoothstartfunc = startfunc;
		this.smoothperiodicalfunc = periodicalfunc;
		this.smoothcheckendfunc = checkendfunc;
		this.smoothendfunc = endfunc;
		startfunc();
		this.smoothinterval = window.setInterval("control.SmoothExecDo()", speed);
	}
	this.SmoothExecDo = function() {
		if (this.smoothcheckendfunc()) {
			window.clearInterval(this.smoothinterval);
			this.smoothendfunc();
		} else {
			this.smoothperiodicalfunc();
		}
	}

	this.State2Url = function(fullpath) {
		var currentcentertile, currentcenter, result = '', str, query, d;
		currentcentertile = control.matrix.GetTileAtPix({
			left: control.matrix.box.center.x,
			top: control.matrix.box.center.y
		});
		currentcenter = Pix2Geo(currentcentertile, this.map.extent, this.currentscale, this.map.datum);
		if (fullpath) {
			result = window.location.protocol+'//'+window.location.host+window.location.pathname;
		}
		if (this.map.isgeo) {
			var cr = ToLonLat(currentcenter.x, currentcenter.y, this.map.datum.base)
			cr.lon = Math.round(cr.lon*10000)/10000;
			cr.lat = Math.round(cr.lat*10000)/10000;
			result += '#gx='+cr.lon+'&gy='+cr.lat+'&z='+this.currentscalenum;
		} else {
			currentcenter.x = Math.round(currentcenter.x*10000)/10000;
			currentcenter.y = Math.round(currentcenter.y*10000)/10000;
			result += '#x='+currentcenter.x+'&y='+currentcenter.y+'&z='+this.currentscalenum;
		}

		if (this.matrix.markers['user'] != undefined) {
			result += '&utext='+this.matrix.markers['user'].text+'&ux='+this.matrix.markers['user'].x+'&uy='+this.matrix.markers['user'].y;
		}
		if (this.matrix.markers['usericon'] != undefined) {
			result += '&uicon='+this.matrix.markers['usericon'].customimage+'&ux='+this.matrix.markers['usericon'].x+'&uy='+this.matrix.markers['usericon'].y;
		}
		if (this.userurl != undefined) {
			result += '&userurl='+this.userurl;
		}
		if (this.xml != undefined) {
			result += '&xml='+escape(this.xml);
		}
		if (this.userdata != undefined) {
			for(var i in this.userdata) {
				result += '&data.'+i+'='+this.userdata[i];
			}
		}
		return result;
	}
	this.recalcMostTile = function() {
		this.mosttile = Geo2Pix({x:this.map.extent.x2, y:this.map.extent.y1}, this.map.extent, this.currentscale, this.map.datum);
		if (this.mosttile.left > 0) {
			this.mosttile.x++;
		}
		if (this.mosttile.top > 0) {
			this.mosttile.y++;
		}
	}
	this.calcCoords = function() {
		var tile1, tile2;
		tile1 = Pix2Geo(control.matrix.GetTileAtPix({left: this.matrix.box.x1, top: this.matrix.box.y1}),  this.map.extent, this.currentscale, this.map.datum);
		tile2 = Pix2Geo(control.matrix.GetTileAtPix({left: this.matrix.box.x2, top: this.matrix.box.y2}),  this.map.extent, this.currentscale, this.map.datum);
		this.coords.x1 = tile1.x;
		this.coords.y1 = tile1.y;
		this.coords.x2 = tile2.x;
		this.coords.y2 = tile2.y;
	}
	this.UpdateLocation = function() {
		state = this.State2Url(false);
		if (this.embed) {
			state = state + '&embed=yes';
		}
		location.href = window.location.protocol+'//'+window.location.host+window.location.pathname + state;
	}
	this.DoExternalXML = function(xml) {
		var o = {};
		if (typeof xml != 'object') {
			return false;
		}
		if (xml.nodeType==9) { // document.node
			xml = xml.documentElement;
		}
		if (xml.nodeType==1) {   // element node ..
			if (xml.firstChild) {
				for (var n=xml.firstChild; n; n=n.nextSibling) {
					var tName =  false;
					var tVal = false;
					if (n.firstChild) {
						tName = n.nodeName;
						if (n.firstChild.nextSibling) { // cdata
							tVal = n.firstChild.nextSibling.nodeValue;
						} else {
							tVal = n.firstChild.nodeValue;
						}
					}
					if (tName && tVal) {
						switch (tName) {
							case 'X' :
							case 'Y' :
							case 'ICON' :
							case 'STYLE' :
							case 'HTML' :
								o[tName] = tVal;
							break;
						}
					}
				}
			}
		}
		return o;
	}
	this.SelectMapid = function(pathname) {
		if (pathname == undefined) {
			return false;
		}
		for(var i in this.virtualmaps) {
			if (pathname.indexOf(this.virtualmaps[i].path) != -1) {
				return {mapid: this.virtualmaps[i].linkto, vmapid: i};
			}
		}
		for(var i in this.maps) {
			if (pathname.indexOf(this.maps[i].path) != -1) {
				return {mapid: i};
			}
		}
		return false;
	}
	var urlvalues, currentcenter, d, centertile;

	this.maps = globalsettings.maps;
	this.virtualmaps = globalsettings.virtualmaps;
	this.object_types = globalsettings.object_types;
	this.defaultdocumenttitle = document.title;
	this.vars = vars;
	this.coords = {};
	urlvalues = URL2Array();
	if (urlvalues.embed == 'yes' || urlvalues.header == 'no') {
		this.embed = true;
	}
	if (this.vars.staticmap == undefined) {
		var rvalue = this.SelectMapid(window.location.pathname);
	} else {
		if (vars.vmapid != undefined) {
			var rvalue = {mapid: this.virtualmaps[vars.vmapid].linkto, vmapid: vars.vmapid};
		} else if (vars.mapid != undefined) {
			var rvalue = {mapid: vars.mapid};
		}
	}
	this.vars.mapid = rvalue.mapid;
	if (rvalue.vmapid != undefined) { // is virtual
		this.map = this.maps[rvalue.mapid];
		this.vars.search_mapid = this.virtualmaps[rvalue.vmapid].search_mapid;
		this.vars.makeobjurl = this.virtualmaps[rvalue.vmapid].makeobjurl;
		this.map.defaultcenter = this.virtualmaps[rvalue.vmapid].defaultcenter;
		this.currentscalenum = this.virtualmaps[rvalue.vmapid].defaultcenter.z;
	} else { // real
		this.map = this.maps[rvalue.mapid];
		this.vars.makeobjurl = this.maps[rvalue.mapid].makeobjurl;
		this.vars.search_mapid = rvalue.mapid;
		this.map.defaultcenter = this.maps[rvalue.mapid].defaultcenter;
		this.currentscalenum = this.maps[rvalue.mapid].defaultscalenum;
	}
	this.map.datum = globalsettings.datums[this.maps[this.vars.mapid].datum];
	this.map.isgeo = this.maps[this.vars.mapid].isgeo;
	this.maxscalenum = this.map.scalelist.length-1;
	currentcenter = this.map.defaultcenter;
	document.title =  this.map.description + ' ' + this.defaultdocumenttitle;
	if (document.getElementById('mapname') != null) {
		document.getElementById('mapname').innerHTML = this.map.description;
	}
	control = this;
	control.rWindow = new rWindow();

	if (urlvalues.gx != undefined && urlvalues.gy != undefined && urlvalues.z != undefined && this.map.isgeo) {
		this.currentscalenum = (urlvalues.z*1);
		var tmp = FromLonLat(urlvalues.gx, urlvalues.gy, this.map.datum.base);
		currentcenter = {x: tmp.x, y:tmp.y};
	}

	if (urlvalues.x != undefined && urlvalues.y != undefined && urlvalues.z != undefined) {
		this.currentscalenum = (urlvalues.z*1);
		currentcenter = {x: urlvalues.x*1, y:urlvalues.y*1};
	}
	control.rnd = (Math.round(Math.random()*1000000000));
	this.currentscale = this.map.scalelist[this.currentscalenum];
	this.recalcMostTile();

	centertile = Geo2Pix(currentcenter, this.map.extent, this.currentscale, this.map.datum);
	control.matrix = new Matrix(this.vars.maindivid, this.currentscale, this.vars.mapid, {showcenter:false, tileborders: false});
	control.matrix.CreateMatrix(centertile);

	control.zoomer = new Zoomer(this.maxscalenum+1, this.currentscalenum);
	control.MapSelector = new MapSelector();
	control.SearchResults = new SearchResults();
	control.Finder = new Finder(this.vars.search_mapid);

	control.matrix.AddInterface(control.zoomer);
	control.matrix.AddInterface(control.rWindow);
	control.rWindow.Show(false);
	control.matrix.AddInterface(control.SearchResults, false);

	control.SearchSubResults = new SearchSubResults();
	control.matrix.AddInterface(control.SearchSubResults, false);

	if (urlvalues.q) {
		d = document.getElementById('query');
		d.value = unescape(urlvalues.q);
		control.Finder.SearchByKeyword(document.getElementById('query').value);
	}
	if (urlvalues.utext) {
		urlvalues.utext = decode_utf8(urlvalues.utext);
		if (urlvalues.ugx) {
			var tmp = FromLonLat(urlvalues.ugx, urlvalues.ugy, this.map.datum.base);
			urlvalues.ux = tmp.x;
			urlvalues.uy = tmp.y;
		}
		userpoint = new Marker('user', urlvalues.ux, urlvalues.uy);
		this.matrix.AddMarker(userpoint);
		userpoint.AddToLabel(unescape(urlvalues.utext));
		userpoint.Show(true);
		userpoint.ShowLabel(true);
	}
	if (urlvalues.uicon) {
		userpoint = new Marker('usericon', urlvalues.ux, urlvalues.uy, urlvalues.uicon); // replace pointer
		this.matrix.AddMarker(userpoint);
		userpoint.Show(true);
	}
	if (urlvalues.xml) {
		this.xml = urlvalues.xml;
		extrnalxml_requester = new Finder(this.vars.mapid);
		extrnalxml_requester.url = '/showrml/'+this.xml;
		extrnalxml_requester.MakeRequest(function() {
			var v = extrnalxml_requester.request.responseXML;
			var o = control.DoExternalXML(v);
			if (o) {
				var point = new MarkerTemplate(o);
				if (point.ok)  {
					control.matrix.AddMarker(point);
					point.FixPosition();
					point.Show(true);
					if (!urlvalues.x || !urlvalues.y && urlvalues.z) {
						control.Goto(o.X, o.Y, urlvalues.z);
					}
				}
			}
		});
	}
	if (urlvalues.agent && urlvalues.oid) {
		var z = false;
		if (urlvalues.z != undefined) {
			z=urlvalues.z;
		}
		control.Finder.SearchByAgent(urlvalues.agent, urlvalues.oid, z);
	}
	addhandler(document.getElementById('searchform'), 'submit', function(e) {
		control.Finder.SearchByKeyword(document.getElementById('query').value);
	});
	if (document.getElementById('selector_allmaps') != null) {
		addhandler(document.getElementById('selector_allmaps'), 'click', function(e) {
			control.SearchSubResults.Show(false);
			control.SearchResults.Show(false);
			control.MapSelector.PopUp();
		});
	}
	addhandler(document.getElementById('zoomin'), 'click', function(e) { control.ChangeZoom(-1) });
	addhandler(document.getElementById('zoomout'), 'click', function(e) { control.ChangeZoom(1) });

	addhandler(control.matrix.div, 'mousedown', function(e) {
		var v;
		if (GetShiftKey(e)) {
			v = control.matrix.StartSelection(e);
		} else {
			v = control.matrix.StartDrag(e);
		}
		if (!v) {
			cancelevent(e);
		}
		return v;
	});

	addhandler(document, 'mouseup', function(e) {
		var v;
		if (GetShiftKey(e)) {
			v = control.matrix.EndSelection(e);
		} else {
			v = control.matrix.EndDrag(e);
		}
		if (!v) {
			cancelevent(e);
		}
		return v;
	});
	addhandler(control.matrix.div, 'mousemove', function(e) {
		var v;
		if (GetShiftKey(e)) {
			v = control.matrix.DoSelection(e);
		} else {
			v = control.matrix.Drag(e);
		}
		if (!v) {
			cancelevent(e);
		}
		return v;
	});

	addhandler(document, 'keydown', function(e) { control.matrix.PressKeyboard(e) });
	addhandler(document, 'keyup', function(e) { control.matrix.UnPressKeyboard(e) });
	addhandler(control.matrix.div, 'dblclick', function(e) {
		control.e = e;
		if (GetTarget(control.e).drag == undefined) {
			return false;
		}
		control.matrix.SlideFromTo(
		{x: GetMouse(control.e).x, y: GetMouse(control.e).y},
		{x: control.matrix.box.center.x, y: control.matrix.box.center.y},
		function() {control.ChangeZoom(-1)}
		);
	});
	this.hsize = control.matrix.box.width;
	this.vsize = control.matrix.box.height;
	this.underresize = false;
	this.CheckChangeSize = function() {
		if (this.underresize) {
			return false;
		}
		if (control.matrix.div.offsetWidth != this.hsize || control.matrix.div.offsetHeight != this.vsize) {
			this.underresize = true;
			oldcenter = control.matrix.box.center;
			control.matrix.MakeBox();
			control.matrix.needupdate = true;
			control.matrix.SlideFromTo(
			oldcenter,
			control.matrix.box.center,
			function() {
				control.underresize = false
			//----------------editor--------------------
				if (surf) {
					Editor_onResize();
				};
			//------------------------------------------
			}
			);
			this.hsize = control.matrix.box.width;
			this.vsize = control.matrix.box.height;
		}
	}

	window.setInterval("control.CheckChangeSize()", 1*1000);

	window.setInterval("control.matrix.CheckKeyboard()", .01*1000);

	window.setInterval("control.matrix.AddTiles()", .01*1000);
	window.setInterval("control.matrix.RemoveTiles()", 3*1000);

	buttons_div = document.getElementById('buttons');

	temp = document.createElement('IMG');
	temp.id = 'iconprint';
	temp.src = 'i/icon_print.png';
	temp.className='fixpng';
	temp.width = 28;
	temp.height = 25;
	temp.style.cursor = 'pointer';
	temp.style.margin = '15px';
	temp.style.zIndex = 1000;
	buttons_div.appendChild(temp);
	addhandler(document.getElementById('iconprint'), 'mouseover', function(e) {
		document.getElementById('iconprint').src = 'i/icon_print_active.png';
	});
	addhandler(document.getElementById('iconprint'), 'mouseout', function(e) {
		document.getElementById('iconprint').src = 'i/icon_print.png';
	});
	addhandler(document.getElementById('iconprint'), 'click', function(e) {
		document.getElementById('head').style.visibility = 'hidden';
		document.getElementById('zoomer').style.visibility = 'hidden';
		control.zoomer.Show(false);
		var sr_state = control.SearchResults.Show(false);
		var sur_state = control.SearchSubResults.Show(false);
		if (confirm('Вывести на печать?')) {
			window.print();
		}
		control.SearchResults.Show(sr_state);
		control.SearchSubResults.Show(sur_state);
		control.zoomer.Show(true);
		document.getElementById('zoomer').style.visibility = 'visible';
		document.getElementById('head').style.visibility = 'visible';
	});

	temp = document.createElement('IMG');
	temp.id = 'iconurl';
	temp.src = 'i/icon_url.png';
	temp.className='fixpng';
	temp.width = 28;
	temp.height = 25;
	temp.style.cursor = 'pointer';
	temp.style.margin = '15px';
	temp.style.zIndex = 1000;
	buttons_div.appendChild(temp);
	addhandler(document.getElementById('iconurl'), 'mouseover', function(e) {
		document.getElementById('iconurl').src = 'i/icon_url_active.png';
	});
	addhandler(document.getElementById('iconurl'), 'mouseout', function(e) {
		document.getElementById('iconurl').src = 'i/icon_url.png';
	});
	addhandler(document.getElementById('iconurl'), 'click', function(e) {
		var url = control.State2Url(true);
		control.SearchSubResults.Show(false);
		control.SearchResults.Show(false);
		control.rWindow.Generate('Ссылка на этот фрагмент карты', '<A target="_blank" href="'+url+'">'+url+'</A>');
		control.rWindow.Show(true);
	});

	if (!this.embed && window.addEventListener) {
		window.addEventListener('DOMMouseScroll', control.wheel, false);
	}
	if (!this.embed) {
		window.onmousewheel = document.onmousewheel = control.wheel;
	}
	addhandlerCont(document.getElementById('query'), 'focus', function(e) {control.stopmatrix = true;});
	addhandlerCont(document.getElementById('query'), 'blur', function(e) {control.stopmatrix = false});
	addhandlerCont(document.getElementById('searchform'), 'submit', function(e) {
		control.SearchSubResults.Show(false);
		control.SearchResults.Show(false);
		control.rWindow.Show(false);
		document.getElementById('query').blur();
		control.UpdateLocation();
	});
	if (!this.embed) {
		var lastupdate = this.maps[this.vars.mapid]['lastupdate'];
		if (lastupdate) {
			document.getElementById('version').innerHTML = 'Обновление от: '+lastupdate + ' / '+RMAP_VERSION;
		}
		if (this.maps[this.vars.mapid]['author2date']) {
			document.getElementById('version').innerHTML += ' [DB: '+this.maps[this.vars.mapid]['author2date']+']';
		}
		var author = this.maps[this.vars.mapid]['author'];
		var authortitle;
		if (author) {
			document.getElementById('copyright').innerHTML += ', ';
			if (this.maps[this.vars.mapid]['authorhref']) {
				if (this.maps[this.vars.mapid]['authortitle']) {
					authortitle = 'title="'+this.maps[this.vars.mapid]['authortitle']+'"';
				}
				document.getElementById('copyright').innerHTML += '<a href="'+this.maps[this.vars.mapid]['authorhref']+'" class="miniblue" target="_blank" '+authortitle+'>'+author+'</a>';
			} else {
				document.getElementById('copyright').innerHTML += author;
			}
			if (this.maps[this.vars.mapid]['author2'] != undefined) {
				document.getElementById('copyright').innerHTML += ', ';
				var author2 = this.maps[this.vars.mapid]['author2'];
				if (this.maps[this.vars.mapid]['author2href']) {
					document.getElementById('copyright').innerHTML += '<a href="'+this.maps[this.vars.mapid]['author2href']+'" class="miniblue" target="_blank">'+author2+'</a>';
				} else {
					document.getElementById('copyright').innerHTML += author2;
				}
			}
		}
	} else {
		document.getElementById('version').innerHTML = '';
		document.getElementById('copyright').innerHTML = '';
	}
	this.LoadTop100();
	if (!this.embed) {
		document.getElementById('head').style.display = 'block';
	} else {
		document.getElementById('head').style.visibility = 'hidden';
		document.getElementById('zoomer').style.top = '2px';

	}
	surf = Init(this, {object: this.matrix, metodname: 'GetTileAtPix'}, 'Pix2Geo', 'Geo2Pix', TILE_SIZE);
}