/* Minification failed. Returning unminified contents.
(5938,48-56): run-time error JS1193: Expected ',' or ')': function
(5938,58-59): run-time error JS1195: Expected expression: )
(5938,60-61): run-time error JS1004: Expected ';': {
(5945,14-15): run-time error JS1195: Expected expression: )
(5954,15-16): run-time error JS1004: Expected ';': {
(6006,2-3): run-time error JS1195: Expected expression: )
(7654,26-27): run-time error JS1003: Expected ':': ,
(7656,13-14): run-time error JS1003: Expected ':': }
 */
function isset(v) {
	return (typeof v!='undefined');
}
function is_function(v) {
	return (typeof v==='function');
}
function is_array(v) {
	return (typeof v==='object'&&v instanceof Array&&isset(v.length));
}
function is_object(v) {
	return (typeof v==='object'&&v instanceof Object&&!(v instanceof Array));
}
function is_numeric(v) {
	return !isNaN(v);
}
function is_NodeList(v) {
	return typeof v==='object'&&v instanceof Object&&v instanceof NodeList;
}
function is_string(i) {
	return (typeof i==='string');
}
function is_iOS() {
	return (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream);
}
function is_bool(i) {
	return (typeof i==='boolean');
}
function is_empty(V) {
	return (V==='');
}
function is_not_empty(V) {
	return !is_empty(V);
}

function is_mobile() {
	if (!isset(window.deviceConfig.is_mobile)) window.deviceConfig.is_mobile = (window.deviceConfig.type == 'Mobile');
	return window.deviceConfig.is_mobile;
}
function is_desktop() {
	return !is_mobile();
}

function prTourId(id) {
	id = parseInt(id);
	switch (id) {
		case 0: case 85:
			id = 0;
		break;
		case 1: case 34:
			id = 1;
		break;
		case 3: case 109:
			id = 3;
		break;
		case 4: case 84: case 118:
			id = 4;
		break;
		case 6: case 62: case 86: case 110:
			id = 6;
		break;
		case 8: case 92:
			id = 8;
		break;
		case 9: case 66: case 80:
			id = 9;
		break;
		case 11: case 60:
			id = 11;
		break;
		case 13: case 14:
			id = 13;
		break;
		case 24: case 59:
			id = 24;
		break;
		case 67: case 111:
			id = 67;
		break;
		case 61: case 82:
			id = 61;
		break;
		case 81: case 83: case 103:
			id = 81;
		break;
		case 102:
			id = 102;
		break;
	}
	return id;
}

function formatShortDateString(value) {
	//2019-11-28T00:00:00+02:00
	var y = parseInt(value.substr(0, 4)),
		m = parseInt(value.substr(5, 2)),
		d = parseInt(value.substr(8, 2));
	return [y, '-', this.format00(m), '-', this.format00(d)].join('');
};
function format00(v) {
	return ('0' + v.toString()).slice(-2);
};

function emptyFunc() {}
function VtoString(V) {return V.toString();}
function simpleParseInt(V) {return parseInt(V);}
function encode64(input) {
	input = escape(input); var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0; do { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + base64keyStr.charAt(enc1) + base64keyStr.charAt(enc2) + base64keyStr.charAt(enc3) + base64keyStr.charAt(enc4); chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length); return output;
}
function decode64(input) {
	var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0; var base64test = /[^A-Za-z0-9\+\/\=]/g; if (base64test.exec(input)) { return "There were invalid base64 characters in the input text"; } input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); do { enc1 = base64keyStr.indexOf(input.charAt(i++)); enc2 = base64keyStr.indexOf(input.charAt(i++)); enc3 = base64keyStr.indexOf(input.charAt(i++)); enc4 = base64keyStr.indexOf(input.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length); return unescape(output);
}
var base64keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function stringSeparations(string){
	return string.stringSeparations();
}

function createRandName() {
	return ''.randName();
}
function ratingToText(r) {
	var i = parseInt(r), s = '';
	switch (i) {
		case 10:
			s = localizationValues.Great;
			break;
		case 9:
			s = localizationValues.Great;
			break;
		case 8:
			s = localizationValues.Excellent;
			break;
		case 7:
			s = localizationValues.VeryGood;
			break;
		case 6:
			s = localizationValues.Good;
			break;
		default:
			break;
	}
	return s;
}
function unsetClick(e){
	e.preventDefault();
	e.stopPropagation();
	return false;
}

function removeChilds(element) {
	while (element.firstChild) {
		element.removeChild(element.firstChild);
	}
}

function cloneElement(element) {
	return removeIds(element.cloneNode(true));
}

function removeIds(element) {
	element.removeAttribute('id');
	var childs = element.children;
	for (var i=childs.length-1;i>=0;i--) removeIds(childs[i]);
	return element;
}

function createElement(model) {
	var element, i, objectName, style, attribute, event, modelItem;
	if (is_object(model)) {
		element = document.createElement(isset(model.tag)?model.tag:'div');
		if (isset(model.id)) element.id = model.id;
		if (isset(model.className)) element.className = model.className;
		if (isset(model.innerHTML)) element.innerHTML = model.innerHTML;
		if (isset(model.innerText)) element.innerText = model.innerText;
		if (isset(model.hidden)) element.hidden = model.hidden;
		if (isset(model.model)) {
			for (objectName in model.model) {
				element[objectName] = model.model[objectName];
			}
		}
		if (isset(model.style)) {
			for (style in model.style) {
				element.style[style] = model.style[style];
			}
		}
		if (isset(model.attributes)) {
			for (attribute in model.attributes) {
				element.setAttribute(attribute, model.attributes[attribute]);
			}
		}
		if (isset(model.model)) {
			for (modelItem in model.model) {
				element[modelItem] = model.model[modelItem];
			}
		}
		if (isset(model.events)) {
			for (event in model.events) {
				element.addEventListener(event, model.events[event]);
			}
		}
		if (isset(model.appends)) model.childs = (isset(model.childs)?model.childs.concat(model.appends):model.appends);
		if (isset(model.childs)) {
			for (i=0;i<model.childs.length;i++) {
				if (model.childs[i]) element.appendChild(model.childs[i]);
			}
		}
		if (isset(model.prepends)) {
			for (i=(model.prepends.length - 1);i>=0;i--) {
				if (isset(element.firstChild)&&element.firstChild) {
					element.insertBefore(model.prepends[i], element.firstChild);
				} else {
					element.appendChild(model.childs[i]);
				}
			}
		}
		if (isset(model.onCreate)) {
			model.onCreate(element);
		}
	} else {
		element = document.createElement(model);
	}
	return element;
}
function summHumanize(n) {
	var i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(2))),
		j = (j = i.length) > 3 ? j % 3 : 0;
	return (j ? i.substr(0, j) + " " : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + " ");
}
function createElementFromHTML(htmlString) {
	if (!htmlString.length) return null;
	var template = document.createElement('template');
	template.innerHTML = htmlString.trim();
	return template.content.firstChild;
}
window.Far.eventsNaming = {
	touchstart: function() {
		return (window.Far.Device=='Desktop'?"mousedown":"touchstart");
	},
	touchmove: function() {
		return (window.Far.Device=='Desktop'?"mousemove":"touchmove");
	},
	touchend: function() {
		return (window.Far.Device=='Desktop'?"mouseup":"touchend");
	}
};

window.Far.Services = {};
farDocument.onReady(function(){
	setTimeout(function(){
		window.Far.Script({
			src: '/NewDesign/Scripts/Services/Favorites.js',
			addBuildNumber: true
		});
	}, 500);
});
window.Far.require = {};

window.Far.require.Catalog__done = false;
window.Far.require.Catalog = function(callback) {
	if (window.Far.require.Catalog__done) {
		if (isset(callback)) callback();
		return;
	}
	window.Far.require.Catalog__done = true;
	var done = 0;
	window.Far.Script({
		src: '/Scripts/V4/Catalog.js',
		addBuildNumber: true,
		callback: function() {done++;}
	});
	window.Far.Script({
		src: '/Scripts/V4/UrlController.js',
		addBuildNumber: true,
		callback: function() {done++;}
	});
	var f;
	if (isset(callback)) {
		f = function() {
			if (done<2) {
				setTimeout(f, 50);
				return;
			}
			callback();
		};
		f();
	} else {
		f = function() {};
	}
	window.Far.require.Hotel(f);
};
window.Far.require.FormControl__done = false;
window.Far.require.FormControl = function(callback) {
	if (window.Far.require.FormControl__done) {
		if (isset(callback)) callback();
		return;
	}
	window.Far.require.FormControl__done = true;
	window.Far.Script({
		src: '/NewDesign/Scripts/Components/FormControl.js',
		addBuildNumber: true,
		callback: callback
	});
	window.Far.Style({
		href: '/NewDesign/Styles/Common/FormControl.css',
		addBuildNumber: true
	});
};
window.Far.require.Hotel__done = false;
window.Far.require.Hotel = function(callback) {
	if (window.Far.require.Hotel__done) {
		if (isset(callback)) callback();
		return;
	}
	window.Far.require.Hotel__done = true;
	window.Far.Style({
		href: ['/css/V4/',window.Far.Device,'/components/tourCard.css'].join(''),
		addBuildNumber: true
	});
	if (isset(callback)) {
		setTimeout(callback, 50);
	}
};

window.Far.validators = {
	phone: function(str) {
		var digits = str.replace(/\D/g, ''); if (digits.length != 12) return false; var pattern = new RegExp(/380(39|50|63|73|66|67|68|91|92|93|94|95|96|97|98|99)\d{7}$/i); return pattern.test(digits);
	},
	email: function(str) {
		var pattern = new RegExp(/^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i); return pattern.test(str);
	},
};

function getCurrencySymbol(s) {
	var r;
	switch (s.toLowerCase()) {
		case 'usd':
			r = '$';
		break;
		case 'eur':
			r = '€';
		break;
		case 'uah':
			r = '₴';
		break;
		default:
			r = s;
		break;
	}
	return r;
}

function intHumanize(n) {
	return parseInt(n).humanize();
}

function rendomId() {
	var f = function(){
			return String.fromCharCode(65 + Math.floor(Math.random() * 26)) + Date.now();
		},
	a = f();
	while (document.getElementById(a)) a = f();
	return a;
}
function multipleCheckboxClickHelper(target, value, model, maxCheked, allCheckedModel) {
	if (value.id == -1) {
		if (target.is_checked) return;
		var nextModel = [value];
		return nextModel;
	} else {
		var prevModel = model,
			nextModel = [];
		for (var i = 0; i < prevModel.length; i++) {
			if (prevModel[i].id == -1) {
				prevModel.splice(prevModel[i], 1);
			}
		}
		if (target.is_checked) {
			if (prevModel.length == 1) {
				nextModel = allCheckedModel;
			} else {
				for (var i = 0 ; i < prevModel.length; i++) {
					if (prevModel[i].id != value.id) {
						nextModel.push(prevModel[i]);
					}
				}
			}
		} else {
			if (prevModel.length == maxCheked) {
				nextModel = allCheckedModel;
			} else {
				nextModel = Object.assign([], prevModel);
				nextModel.push(value);
			}
		}
		return nextModel;
	}
}

function multipleCheckboxClickInverseHelper(target, value, model, maxCheked, allCheckedModel) {
	if (value.id == -1) {
		if (target.is_checked) return [];
		var nextModel = allCheckedModel;
		return nextModel;
	} else {
		var prevModel = Object.assign([], model),
			nextModel = [];
		for (var i = 0; i < prevModel.length; i++) {
			if (prevModel[i].id == -1) {
				prevModel.splice(prevModel[i], 1);
			}
		}
		if (target.is_checked) {
			if (prevModel.length == 1) {
				nextModel = allCheckedModel;
			} else {
				if (prevModel.length - 1 == maxCheked) {
					for (var i = 0 ; i < prevModel.length; i++) {
						if (prevModel[i].id == value.id) {
							nextModel.push(prevModel[i]);
						}
					}
				} else {
					if (model.length - 1 < maxCheked) {
						for (var i = 0 ; i < prevModel.length; i++) {
							if (prevModel[i].id != value.id) {
								nextModel.push(prevModel[i]);
							}
						}
					} else {
						for (var i = 0 ; i < prevModel.length; i++) {
							if (prevModel[i].id == value.id) {
								nextModel.push(prevModel[i]);
							}
						}
					}
				}

			}
		} else {
			if (prevModel.length == maxCheked) {
				nextModel = prevModel;
			} else {
				nextModel = Object.assign([], prevModel);
				nextModel.push(value);
			}
		}
		return nextModel;
	}
}


if (!String.prototype.format) {
	String.prototype.format = function () {
		var args = arguments;
		return this.replace(/{(\d+)}/g, function (match, number) {
			return isset(args[number])
			  ? args[number]
			  : match
			;
		});
	};
}
Object.defineProperty(String.prototype, 'stringSeparations', {
	value: function() {
		return this.replace(/(\d)(?=(\d{3})+(\D|$))/g, '$1&nbsp;');
	},
	enumerable: false
});
Object.defineProperty(String.prototype, 'toJsDate', {
	value: function() {
		return new Date(this.replace(/(\d{2})\.(\d{2})\.(\d{4})/,'$3-$2-$1'));
	},
	enumerable: false
});
Object.defineProperty(String.prototype, 'hashCode', {
	value: function() {
		var hash = 0, i, chr;
		if (this.length === 0) return hash;
		for (i = 0; i < this.length; i++) {
			chr   = this.charCodeAt(i);
			hash  = ((hash << 5) - hash) + chr;
			hash |= 0;
		}
		return hash;
	},
	enumerable: false
});

Object.defineProperty(Object.prototype, 'randName', {
	value: function() {
		var name = ''.random();
		while (isset(this[name])) name = ''.random();
		return name;
	},
	enumerable: false
});
//Object.defineProperty(Object.prototype, 'compare', {
//	value: function(obj) {
//		var a = JSON.stringify(this.sortKeys()),
//			b = JSON.stringify(obj.sortKeys());
//		return a.length==b.length&&a==b;
//	},
//	enumerable: false
//});
Object.defineProperty(Object.prototype, 'sortKeys', {
	value: function() {
		var keys = Object.keys(this).sort(),
			obj = {};
		for (var i=keys.length-1;i>=0;i--) {
			if (is_object(this[keys[i]])) {
				obj[keys[i]] = this[keys[i]].sortKeys();
			} else {
				obj[keys[i]] = this[keys[i]];
			}
		}
		return obj;
	},
	enumerable: false
});

Object.defineProperty(String.prototype, 'random', {
	value: function() {
		return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
	},
	enumerable: false
});
Object.defineProperty(String.prototype, 'toInt', {
	value: function() {
		var int = this.match(/\d+/g).join('');
		return (int==''?0:parseInt(int));
	},
	enumerable: false
});

Object.defineProperty(Number.prototype, 'humanize', {
	value: function() {
		var n = this,
			i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(2))),
			j = (j = i.length) > 3 ? j % 3 : 0;
		return (j ? i.substr(0, j) + " " : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + " ");
	},
	enumerable: false
});

Object.defineProperty(Number.prototype, 'fileSizeHumanize', {
	value: function() {
		var bytes 	= this,
			thresh 	= 1024;
		if(Math.abs(bytes) < thresh) {
			return bytes + ' B';
		}
		var units = ['KB','MB','GB','TB','PB','EB','ZB','YB'];
		var u = -1;
		do {
			bytes /= thresh;
			++u;
		} while(Math.abs(bytes) >= thresh && u < units.length - 1);
		var b = bytes.toFixed(1);
		if (b.split('.')[1]=='0') b=b.split('.')[0];
		return b+units[u];
	},
	enumerable: false
});

Object.defineProperty(Date.prototype, 'addDays', {
	value: function(days) {
		var date = new Date(this.valueOf());
		date.setDate(date.getDate() + days);
		return date;
	},
	enumerable: false
});
Object.defineProperty(Date.prototype, 'clone', {
	value: function() {
		return new Date(this.getTime());
	},
	enumerable: false
});
Object.defineProperty(Date.prototype, 'toDateStr', {
	value: function(format, joiner) {
		joiner = (isset(joiner)?joiner:'.');
		var str = [],
			i,
			d = this.getDate(),
			m = (this.getMonth()+1),
			y = this.getFullYear();
		d = (d<10?'0'+d:d);
		m = (m<10?'0'+m:m);
		format = format.split('.');
		for (i=0;i<format.length;i++) {
			switch (format[i]) {
				case 'DD':
					str.push(d);
				break;
				case 'MM':
					str.push(m);
				break;
				case 'YYYY':
					str.push(y);
				break;
			}
		}
		return str.join(joiner);
	},
	enumerable: false
});
Object.defineProperty(Date.prototype, 'toTimeStr', {
	value: function(format, joiner) {
		joiner = (isset(joiner)?joiner:':');
		var str = [],
			i,
			h = this.getHours(),
			m = this.getMinutes(),
			s = this.getSeconds();
		h = (h<10?'0'+h:h);
		m = (m<10?'0'+m:m);
		s = (s<10?'0'+s:s);
		format = format.split(':');
		for (i=0;i<format.length;i++) {
			switch (format[i]) {
				case 'hh':
					str.push(h);
				break;
				case 'ii':
					str.push(m);
				break;
				case 'ss':
					str.push(s);
				break;
			}
		}
		return str.join(joiner);
	},
	enumerable: false
});
Object.defineProperty(Date.prototype, 'diff', {
	value: function(that, points) {
		var diffTime 	= Math.abs(this.getTime() - that.getTime()),
			diff 		= 0;
		switch (points) {
			case 'days':
				diff = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
			break;
			case 'hours':
				diff = Math.ceil(diffTime / (1000 * 60 * 60));
			break;
			case 'minutes':
				diff = Math.ceil(diffTime / (1000 * 60));
			break;
			case 'seconds':
				diff = Math.ceil(diffTime / 1000);
			break;
			default:
				diff = diffTime;
			break;
		}
		return diff;
	},
	enumerable: false
});

Object.defineProperty(Array.prototype, 'max', {
	value: function() {
		return Math.max.apply(null, this);
	},
	enumerable: false
});
Object.defineProperty(Array.prototype, 'min', {
	value: function() {
		return Math.min.apply(null, this);
	},
	enumerable: false
});
Object.defineProperty(Array.prototype, 'clone', {
	value: function() {
		return this.slice(0);
	},
	enumerable: false
});
Object.defineProperty(Array.prototype, 'diff', {
	value: function(that) {
		return this.length === that.length&&this.join('.')===that.join('.');
	},
	enumerable: false
});
Object.defineProperty(Array.prototype, 'sortObjects', {
	value: function(field, order) {
		var compare;
		if (order=='DESC') {
			compare = function( a, b ) {
				var x = is_numeric(a[field])?parseFloat(a[field]):a[field],
					y = is_numeric(b[field])?parseFloat(b[field]):b[field];
				if ( x < y ) return -1;
				if ( x > y ) return 1;
				return 0;
			};
		} else {
			compare = function( a, b ) {
				var x = is_numeric(a[field])?parseFloat(a[field]):a[field],
					y = is_numeric(b[field])?parseFloat(b[field]):b[field];
				if ( x > y ) return -1;
				if ( x < y ) return 1;
				return 0;
			};
		}
		return this.clone().sort(compare);
	},
	enumerable: false
});
Object.defineProperty(Array.prototype, 'objectUnique', {
	value: function(field, ret) {
		ret = (isset(ret)?ret:false);
		var arr = this.clone(),
			values = [],
			unique = [];
		for (var i=(arr.length-1);i>=0;i--) {
			if (values.indexOf(arr[i][field])==-1) {
				values.push(arr[i][field]);
				unique.push(arr[i]);
			}
		}
		return (ret?values:unique);
	},
	enumerable: false
});

var appendScript = function () {
	for (var i = 0; i < arguments.length; i++) {
		var data = arguments[i],
			url, callback, predicate, context;
		if (typeof data != 'string') {
			url = data.url;
			callback = data.callback;
			predicate = data.predicate;
			context = data.context;
		}
		else {
			url = data;
		}
		console.log(url);
		(function (w, d, s, p, u, c, cp, ct) {
			w[p] = w[p] || [];
			w[p].push({
				url: u,
				date: new Date().getTime(),
				callback: c,
				predicate: cp,
				context: ct,
				counter: 100,
				waiter: function () {
					var scope = this;
					setTimeout(function () {
						scope.counter--;
						if (scope.predicate()) {
							scope.callback.call(scope.context);
						}
						else if (scope.counter > 0) {
							scope.waiter();
						}
						else {
							//failed load
						}
					}, 50);
				}
			});
			var f = d.getElementsByTagName(s)[0],
				j = d.createElement(s);
			j.async = true;
			j.src = u;
			f.parentNode.insertBefore(j, f);
			if (isset(c)) {
				w[p][w[p].length - 1].waiter();
			}
		})(window, document, 'script', 'appendedScript', url, callback, predicate, context);
	}
};

function fileSizeHumanize(bytes) {
	var thresh = 1024;
	if (Math.abs(bytes) < thresh) {
		return bytes + ' B';
	}
	var units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	var u = -1;
	do {
		bytes /= thresh;
		++u;
	} while (Math.abs(bytes) >= thresh && u < units.length - 1);
	var b = bytes.toFixed(1);
	if (b.split('.')[1] == '0') b = b.split('.')[0];
	return b + units[u];
}


function decodeHTMLEntities(text) {
	var entities = [
		['amp', '&'],
		['apos', '\''],
		['#x27', '\''],
		['#x2F', '/'],
		['#39', '\''],
		['#47', '/'],
		['lt', '<'],
		['gt', '>'],
		['nbsp', ' '],
		['quot', '"']
	];
	for (var i = 0, max = entities.length; i < max; ++i) {
		if (text.indexOf(entities[i][0])!=-1) {
			text = text.replace(new RegExp('&'+entities[i][0]+';', 'g'), entities[i][1]);
		}
	}
	return text;
}

function ratingToText(r) {
	var i = parseInt(r),
		s = '';
	switch (i) {
		case 9:
			s = localizationValues.Great;
			break;
		case 10:
			s = localizationValues.Great;
			break;
		case 8:
			s = localizationValues.Excellent;
			break;
		case 7:
			s = localizationValues.VeryGood;
			break;
		case 6:
			s = localizationValues.Good;
			break;
		default:
			s = localizationValues.Rating;
	}
	return s;
}

function WebWorker(model){
	/*
		Worker Method
		var model = {a: 1};
		console.warn(model.a);
		console.time('WorkerExample1');
		WebWorker({
			name: '_WorkerExample1',
			model: model,
			callback: function(model) {
				console.warn('done::'+model.a);
				console.timeEnd('WorkerExample1');
			}
		});
		Look file /NewDesign/Scripts/Workers/SomeLongScript.js to view full example
	*/
	var result = null,
		time = performance.now(),
		worker = new Worker(['/NewDesign/Scripts/Workers/',model.name,'.js'].join(''));
	worker.onmessage = function(e) {
		result = e.data;
	}
	worker.postMessage(model.model);
	var f = function() {
		console.log(1);
		if (!result) {
			setTimeout(f, 1);
		} else {
			model.callback(result);
			worker.terminate();
		}
	}
	f();
};
window.Far.Events = {};

window.Far.Events.onScroll = {};
window.Far.Events.onScroll.events = {};
window.Far.Events.onScroll.add = function(name, callback) {
	if (isset(window.Far.Events.onScroll.events[name])) return;
	window.Far.Events.onScroll.events[name] = callback;
};
window.Far.Events.onScroll.remove = function(name) {
	if (!isset(window.Far.Events.onScroll.events[name])) return;
	delete window.Far.Events.onScroll.events[name];
};
var supportPageOffset = window.pageXOffset !== undefined;
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
window.Far.Events.onScroll.get = function() {
	return supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
};
window.onscroll = function() {
	var scrolled = window.Far.Events.onScroll.get();
	window.Far.Events.onScroll.previous = window.Far.Events.onScroll.current;
	window.Far.Events.onScroll.current = scrolled;
	for (var i in window.Far.Events.onScroll.events) window.Far.Events.onScroll.events[i](scrolled);
};
window.Far.Events.onScroll.current = window.Far.Events.onScroll.get();
window.Far.Events.onScroll.previous = window.Far.Events.onScroll.current;

window.Far.Events.onResize = {};
window.Far.Events.onResize.events = {};
window.Far.Events.onResize.add = function(name, callback) {
	if (isset(window.Far.Events.onResize.events[name])) return;
	window.Far.Events.onResize.events[name] = callback;
};
window.Far.Events.onResize.remove = function(name) {
	if (!isset(window.Far.Events.onResize.events[name])) return;
	delete window.Far.Events.onResize.events[name];
};
window.Far.Events.onResize.get = function() {
	return {
		width: window.innerWidth,
		height: window.innerHeight
	};
};
window.onresize = function() {
	var size = window.Far.Events.onResize.get();
	window.Far.Events.onResize.current = size;
	for (var i in window.Far.Events.onResize.events) window.Far.Events.onResize.events[i](size);
};
window.Far.Events.onResize.current = window.Far.Events.onResize.get();

window.Far.Events.onAfterResize = {};
window.Far.Events.onAfterResize.events = {};
window.Far.Events.onAfterResize.add = function(name, callback) {
	if (isset(window.Far.Events.onAfterResize.events[name])) return;
	window.Far.Events.onAfterResize.events[name] = callback;
};
window.Far.Events.onAfterResize.remove = function(name) {
	if (!isset(window.Far.Events.onAfterResize.events[name])) return;
	delete window.Far.Events.onAfterResize.events[name];
};
window.Far.Events.onAfterResize.get = window.Far.Events.onResize.get;
window.Far.Events.onAfterResize.timeout = null;
window.Far.Events.onResize.add('onAfterResize', function() {
	if (window.Far.Events.onAfterResize.timeout) clearTimeout(window.Far.Events.onAfterResize.timeout);
	window.Far.Events.onAfterResize.timeout = setTimeout(function(){
		var size = window.Far.Events.onAfterResize.get();
		window.Far.Events.onAfterResize.current = size;
		for (var i in window.Far.Events.onAfterResize.events) window.Far.Events.onAfterResize.events[i](size);
	}, 500);
});
window.Far.Events.onAfterResize.current = window.Far.Events.onAfterResize.get();

window.Far.Events.onUnload = {};
window.Far.Events.onUnload.events = {};
window.Far.Events.onUnload.add = function(name, callback) {
	if (isset(window.Far.Events.onUnload.events[name])) return;
	window.Far.Events.onUnload.events[name] = callback;
};
window.Far.Events.onUnload.remove = function(name) {
	if (!isset(window.Far.Events.onUnload.events[name])) return;
	delete window.Far.Events.onUnload.events[name];
};
window.onunload = function() {
	for (var i in window.Far.Events.onUnload.events) window.Far.Events.onUnload.events[i]();
};

window.Far.Events.onBeforeUnload = {};
window.Far.Events.onBeforeUnload.events = {};
window.Far.Events.onBeforeUnload.add = function(name, callback) {
	if (isset(window.Far.Events.onBeforeUnload.events[name])) return;
	window.Far.Events.onBeforeUnload.events[name] = callback;
};
window.Far.Events.onBeforeUnload.remove = function(name) {
	if (!isset(window.Far.Events.onBeforeUnload.events[name])) return;
	delete window.Far.Events.onBeforeUnload.events[name];
};
window.onbeforeunload = function() {
	for (var i in window.Far.Events.onBeforeUnload.events) window.Far.Events.onBeforeUnload.events[i]();
};

window.Far.Events.bodyClick = {};
window.Far.Events.bodyClick.events = {};
window.Far.Events.bodyClick.checkNodeClassMultiple = function(classesAndCallbacks, e) {
	var parent = e.target;
	while (parent) {
		for (var className in classesAndCallbacks) {
			if (parent.classList.contains(className)) {
				classesAndCallbacks[className](parent);
			}
		}
		parent = (isset(parent.parentNode)&&parent.parentNode !== null&&isset(parent.parentNode.classList)?parent.parentNode:false);
	}
};
window.Far.Events.bodyClick.checkNodeClass = function(className, e) {
	var parent = e.target;
	while (parent) {
		if (parent.classList.contains(className)) return parent;
		parent = (isset(parent.parentNode)&&isset(parent.parentNode.classList)?parent.parentNode:false);
	}
	return false;
};
window.Far.Events.bodyClick.add = function(name, context, callback) {
	if (isset(window.Far.Events.bodyClick.events[name])) return;
	window.Far.Events.bodyClick.events[name] = {name: name, context: context, callback: callback};
};
window.Far.Events.bodyClick.remove = function(name) {
	if (!isset(window.Far.Events.bodyClick.events[name])) return;
	delete window.Far.Events.bodyClick.events[name];
};
document.body.addEventListener('click', function(e) {
	for (var i in window.Far.Events.bodyClick.events) window.Far.Events.bodyClick.events[i].callback(e, window.Far.Events.bodyClick.events[i].context);
});

window.Far.Events.onMouseDown = {};
window.Far.Events.onMouseDown.events = {};
window.Far.Events.onMouseDown.add = function(name, context, callback) {
	if (isset(window.Far.Events.onMouseDown.events[name])) return;
	window.Far.Events.onMouseDown.events[name] = {name: name, context: context, callback: callback};
};
window.Far.Events.onMouseDown.remove = function(name) {
	if (!isset(window.Far.Events.onMouseDown.events[name])) return;
	delete window.Far.Events.onMouseDown.events[name];
};
document.body.addEventListener('mousedown', function(e) {
	for (var i in window.Far.Events.onMouseDown.events) window.Far.Events.onMouseDown.events[i].callback(e, window.Far.Events.onMouseDown.events[i].context);
});

window.Far.Events.onKeyDown = {};
window.Far.Events.onKeyDown.events = {};
window.Far.Events.onKeyDown.add = function(name, context, callback) {
	if (isset(window.Far.Events.onKeyDown.events[name])) return;
	window.Far.Events.onKeyDown.events[name] = {name: name, context: context, callback: callback};
};
window.Far.Events.onKeyDown.remove = function(name) {
	if (!isset(window.Far.Events.onKeyDown.events[name])) return;
	delete window.Far.Events.onKeyDown.events[name];
};
document.body.addEventListener('keydown', function(e) {
	for (var i in window.Far.Events.onKeyDown.events) window.Far.Events.onKeyDown.events[i].callback(e, window.Far.Events.onKeyDown.events[i].context);
});

window.Far.Events.onLoad = {};
window.Far.Events.onLoad.events = {};
window.Far.Events.onLoad.add = function(name, callback) {
	if (is_function(name)) {
		callback = name;
		name = window.Far.Events.onLoad.events.randName();
	}
	if (isset(window.Far.Events.onLoad.events[name])) return;
	window.Far.Events.onLoad.events[name] = callback;
};
window.Far.Events.onLoad.remove = function(name) {
	if (!isset(window.Far.Events.onLoad.events[name])) return;
	delete window.Far.Events.onLoad.events[name];
};
window.onLoad = function() {
	for (var i in window.Far.Events.onLoad.events) {
		window.Far.Events.onLoad.events[i]();
	}
};
document.addEventListener('DOMContentLoaded', window.onLoad);

window.onscroll__add = window.Far.Events.onScroll.add;
window.onscroll__remove = window.Far.Events.onScroll.remove;
window.onscroll__get = window.Far.Events.onScroll.get;

window.onresize__add = window.Far.Events.onResize.add;
window.onresize__remove = window.Far.Events.onResize.remove;
window.onresize__get = window.Far.Events.onResize.get;

window.onload__add = window.Far.Events.onLoad.add;
window.onload__remove = window.Far.Events.onLoad.remove;

window.onunload__add = window.Far.Events.onUnload.add;
window.onunload__remove = window.Far.Events.onUnload.remove;

window.onbeforeunload__add = window.Far.Events.onBeforeUnload.add;
window.onbeforeunload__remove = window.Far.Events.onBeforeUnload.remove;

window.clickEventsList = {
	add: window.Far.Events.bodyClick.add,
	remove: window.Far.Events.bodyClick.remove
};

window.mouseDownEventsList = {
    add: window.Far.Events.onMouseDown.add,
    remove: window.Far.Events.onMouseDown.remove
};
window.keydownEventsList = {
    add: window.Far.Events.onKeyDown.add,
	remove: window.Far.Events.onKeyDown.remove
};

window.Far.Events.bodyClick.add('scrollTo', {}, function(e, context){
	var target = e.target.getAttribute('scrollTo');
	if (target) {
		target = document.querySelector(target);
		if (target) {
			var header 	= document.getElementById('header'),
				must 	= (target.offsetTop-header.offsetHeight),
				n 		= 0;
			while (n<200) {
				setTimeout(function(){
                    must = (target.offsetTop - header.offsetHeight);
					window.scrollTo({top:must});
				}, (10*n));
				n++;
			}
		}
	}
});

// (function(m){if(!(/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1)){return}var l=m.document;if(!l.querySelector){return}var n=l.querySelector("meta[name=viewport]"),a=n&&n.getAttribute("content"),k=a+",maximum-scale=1",d=a+",maximum-scale=10",g=true,j,i,h,c;if(!n){return}function f(){n.setAttribute("content",d);g=true}function b(){n.setAttribute("content",k);g=false}function e(o){c=o.accelerationIncludingGravity;j=Math.abs(c.x);i=Math.abs(c.y);h=Math.abs(c.z);if(!m.orientation&&(j>7||((h>6&&i<8||h<8&&i>6)&&j>5))){if(g){b()}}else{if(!g){f()}}}m.addEventListener("orientationchange",f,false);m.addEventListener("devicemotion",e,false)})(this);
;
/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
 *
 *  https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
 *
 */
(function() {
'use strict';

// Exit early if we're not running in a browser.
if (typeof window !== 'object') {
  return;
}

// Exit early if all IntersectionObserver and IntersectionObserverEntry
// features are natively supported.
if ('IntersectionObserver' in window &&
    'IntersectionObserverEntry' in window &&
    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {

  // Minimal polyfill for Edge 15's lack of `isIntersecting`
  // See: https://github.com/w3c/IntersectionObserver/issues/211
  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
    Object.defineProperty(window.IntersectionObserverEntry.prototype,
      'isIntersecting', {
      get: function () {
        return this.intersectionRatio > 0;
      }
    });
  }
  return;
}


/**
 * A local reference to the document.
 */
var document = window.document;


/**
 * An IntersectionObserver registry. This registry exists to hold a strong
 * reference to IntersectionObserver instances currently observing a target
 * element. Without this registry, instances without another reference may be
 * garbage collected.
 */
var registry = [];


/**
 * Creates the global IntersectionObserverEntry constructor.
 * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
 * @param {Object} entry A dictionary of instance properties.
 * @constructor
 */
function IntersectionObserverEntry(entry) {
  this.time = entry.time;
  this.target = entry.target;
  this.rootBounds = entry.rootBounds;
  this.boundingClientRect = entry.boundingClientRect;
  this.intersectionRect = entry.intersectionRect || getEmptyRect();
  this.isIntersecting = !!entry.intersectionRect;

  // Calculates the intersection ratio.
  var targetRect = this.boundingClientRect;
  var targetArea = targetRect.width * targetRect.height;
  var intersectionRect = this.intersectionRect;
  var intersectionArea = intersectionRect.width * intersectionRect.height;

  // Sets intersection ratio.
  if (targetArea) {
    // Round the intersection ratio to avoid floating point math issues:
    // https://github.com/w3c/IntersectionObserver/issues/324
    this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4));
  } else {
    // If area is zero and is intersecting, sets to 1, otherwise to 0
    this.intersectionRatio = this.isIntersecting ? 1 : 0;
  }
}


/**
 * Creates the global IntersectionObserver constructor.
 * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
 * @param {Function} callback The function to be invoked after intersection
 *     changes have queued. The function is not invoked if the queue has
 *     been emptied by calling the `takeRecords` method.
 * @param {Object=} opt_options Optional configuration options.
 * @constructor
 */
function IntersectionObserver(callback, opt_options) {

  var options = opt_options || {};

  if (typeof callback != 'function') {
    throw new Error('callback must be a function');
  }

  if (options.root && options.root.nodeType != 1) {
    throw new Error('root must be an Element');
  }

  // Binds and throttles `this._checkForIntersections`.
  this._checkForIntersections = throttle(
      this._checkForIntersections.bind(this), this.THROTTLE_TIMEOUT);

  // Private properties.
  this._callback = callback;
  this._observationTargets = [];
  this._queuedEntries = [];
  this._rootMarginValues = this._parseRootMargin(options.rootMargin);

  // Public properties.
  this.thresholds = this._initThresholds(options.threshold);
  this.root = options.root || null;
  this.rootMargin = this._rootMarginValues.map(function(margin) {
    return margin.value + margin.unit;
  }).join(' ');
}


/**
 * The minimum interval within which the document will be checked for
 * intersection changes.
 */
IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100;


/**
 * The frequency in which the polyfill polls for intersection changes.
 * this can be updated on a per instance basis and must be set prior to
 * calling `observe` on the first target.
 */
IntersectionObserver.prototype.POLL_INTERVAL = null;

/**
 * Use a mutation observer on the root element
 * to detect intersection changes.
 */
IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true;


/**
 * Starts observing a target element for intersection changes based on
 * the thresholds values.
 * @param {Element} target The DOM element to observe.
 */
IntersectionObserver.prototype.observe = function(target) {
  var isTargetAlreadyObserved = this._observationTargets.some(function(item) {
    return item.element == target;
  });

  if (isTargetAlreadyObserved) {
    return;
  }

  if (!(target && target.nodeType == 1)) {
    throw new Error('target must be an Element');
  }

  this._registerInstance();
  this._observationTargets.push({element: target, entry: null});
  this._monitorIntersections();
  this._checkForIntersections();
};


/**
 * Stops observing a target element for intersection changes.
 * @param {Element} target The DOM element to observe.
 */
IntersectionObserver.prototype.unobserve = function(target) {
  this._observationTargets =
      this._observationTargets.filter(function(item) {

    return item.element != target;
  });
  if (!this._observationTargets.length) {
    this._unmonitorIntersections();
    this._unregisterInstance();
  }
};


/**
 * Stops observing all target elements for intersection changes.
 */
IntersectionObserver.prototype.disconnect = function() {
  this._observationTargets = [];
  this._unmonitorIntersections();
  this._unregisterInstance();
};


/**
 * Returns any queue entries that have not yet been reported to the
 * callback and clears the queue. This can be used in conjunction with the
 * callback to obtain the absolute most up-to-date intersection information.
 * @return {Array} The currently queued entries.
 */
IntersectionObserver.prototype.takeRecords = function() {
  var records = this._queuedEntries.slice();
  this._queuedEntries = [];
  return records;
};


/**
 * Accepts the threshold value from the user configuration object and
 * returns a sorted array of unique threshold values. If a value is not
 * between 0 and 1 and error is thrown.
 * @private
 * @param {Array|number=} opt_threshold An optional threshold value or
 *     a list of threshold values, defaulting to [0].
 * @return {Array} A sorted list of unique and valid threshold values.
 */
IntersectionObserver.prototype._initThresholds = function(opt_threshold) {
  var threshold = opt_threshold || [0];
  if (!Array.isArray(threshold)) threshold = [threshold];

  return threshold.sort().filter(function(t, i, a) {
    if (typeof t != 'number' || isNaN(t) || t < 0 || t > 1) {
      throw new Error('threshold must be a number between 0 and 1 inclusively');
    }
    return t !== a[i - 1];
  });
};


/**
 * Accepts the rootMargin value from the user configuration object
 * and returns an array of the four margin values as an object containing
 * the value and unit properties. If any of the values are not properly
 * formatted or use a unit other than px or %, and error is thrown.
 * @private
 * @param {string=} opt_rootMargin An optional rootMargin value,
 *     defaulting to '0px'.
 * @return {Array<Object>} An array of margin objects with the keys
 *     value and unit.
 */
IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) {
  var marginString = opt_rootMargin || '0px';
  var margins = marginString.split(/\s+/).map(function(margin) {
    var parts = /^(-?\d*\.?\d+)(px|%)$/.exec(margin);
    if (!parts) {
      throw new Error('rootMargin must be specified in pixels or percent');
    }
    return {value: parseFloat(parts[1]), unit: parts[2]};
  });

  // Handles shorthand.
  margins[1] = margins[1] || margins[0];
  margins[2] = margins[2] || margins[0];
  margins[3] = margins[3] || margins[1];

  return margins;
};


/**
 * Starts polling for intersection changes if the polling is not already
 * happening, and if the page's visibility state is visible.
 * @private
 */
IntersectionObserver.prototype._monitorIntersections = function() {
  if (!this._monitoringIntersections) {
    this._monitoringIntersections = true;

    // If a poll interval is set, use polling instead of listening to
    // resize and scroll events or DOM mutations.
    if (this.POLL_INTERVAL) {
      this._monitoringInterval = setInterval(
          this._checkForIntersections, this.POLL_INTERVAL);
    }
    else {
      addEvent(window, 'resize', this._checkForIntersections, true);
      addEvent(document, 'scroll', this._checkForIntersections, true);

      if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) {
        this._domObserver = new MutationObserver(this._checkForIntersections);
        this._domObserver.observe(document, {
          attributes: true,
          childList: true,
          characterData: true,
          subtree: true
        });
      }
    }
  }
};


/**
 * Stops polling for intersection changes.
 * @private
 */
IntersectionObserver.prototype._unmonitorIntersections = function() {
  if (this._monitoringIntersections) {
    this._monitoringIntersections = false;

    clearInterval(this._monitoringInterval);
    this._monitoringInterval = null;

    removeEvent(window, 'resize', this._checkForIntersections, true);
    removeEvent(document, 'scroll', this._checkForIntersections, true);

    if (this._domObserver) {
      this._domObserver.disconnect();
      this._domObserver = null;
    }
  }
};


/**
 * Scans each observation target for intersection changes and adds them
 * to the internal entries queue. If new entries are found, it
 * schedules the callback to be invoked.
 * @private
 */
IntersectionObserver.prototype._checkForIntersections = function() {
  var rootIsInDom = this._rootIsInDom();
  var rootRect = rootIsInDom ? this._getRootRect() : getEmptyRect();

  this._observationTargets.forEach(function(item) {
    var target = item.element;
    var targetRect = getBoundingClientRect(target);
    var rootContainsTarget = this._rootContainsTarget(target);
    var oldEntry = item.entry;
    var intersectionRect = rootIsInDom && rootContainsTarget &&
        this._computeTargetAndRootIntersection(target, rootRect);

    var newEntry = item.entry = new IntersectionObserverEntry({
      time: now(),
      target: target,
      boundingClientRect: targetRect,
      rootBounds: rootRect,
      intersectionRect: intersectionRect
    });

    if (!oldEntry) {
      this._queuedEntries.push(newEntry);
    } else if (rootIsInDom && rootContainsTarget) {
      // If the new entry intersection ratio has crossed any of the
      // thresholds, add a new entry.
      if (this._hasCrossedThreshold(oldEntry, newEntry)) {
        this._queuedEntries.push(newEntry);
      }
    } else {
      // If the root is not in the DOM or target is not contained within
      // root but the previous entry for this target had an intersection,
      // add a new record indicating removal.
      if (oldEntry && oldEntry.isIntersecting) {
        this._queuedEntries.push(newEntry);
      }
    }
  }, this);

  if (this._queuedEntries.length) {
    this._callback(this.takeRecords(), this);
  }
};


/**
 * Accepts a target and root rect computes the intersection between then
 * following the algorithm in the spec.
 * TODO(philipwalton): at this time clip-path is not considered.
 * https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo
 * @param {Element} target The target DOM element
 * @param {Object} rootRect The bounding rect of the root after being
 *     expanded by the rootMargin value.
 * @return {?Object} The final intersection rect object or undefined if no
 *     intersection is found.
 * @private
 */
IntersectionObserver.prototype._computeTargetAndRootIntersection =
    function(target, rootRect) {

  // If the element isn't displayed, an intersection can't happen.
  if (window.getComputedStyle(target).display == 'none') return;

  var targetRect = getBoundingClientRect(target);
  var intersectionRect = targetRect;
  var parent = getParentNode(target);
  var atRoot = false;

  while (!atRoot) {
    var parentRect = null;
    var parentComputedStyle = parent.nodeType == 1 ?
        window.getComputedStyle(parent) : {};

    // If the parent isn't displayed, an intersection can't happen.
    if (parentComputedStyle.display == 'none') return;

    if (parent == this.root || parent == document) {
      atRoot = true;
      parentRect = rootRect;
    } else {
      // If the element has a non-visible overflow, and it's not the <body>
      // or <html> element, update the intersection rect.
      // Note: <body> and <html> cannot be clipped to a rect that's not also
      // the document rect, so no need to compute a new intersection.
      if (parent != document.body &&
          parent != document.documentElement &&
          parentComputedStyle.overflow != 'visible') {
        parentRect = getBoundingClientRect(parent);
      }
    }

    // If either of the above conditionals set a new parentRect,
    // calculate new intersection data.
    if (parentRect) {
      intersectionRect = computeRectIntersection(parentRect, intersectionRect);

      if (!intersectionRect) break;
    }
    parent = getParentNode(parent);
  }
  return intersectionRect;
};


/**
 * Returns the root rect after being expanded by the rootMargin value.
 * @return {Object} The expanded root rect.
 * @private
 */
IntersectionObserver.prototype._getRootRect = function() {
  var rootRect;
  if (this.root) {
    rootRect = getBoundingClientRect(this.root);
  } else {
    // Use <html>/<body> instead of window since scroll bars affect size.
    var html = document.documentElement;
    var body = document.body;
    rootRect = {
      top: 0,
      left: 0,
      right: html.clientWidth || body.clientWidth,
      width: html.clientWidth || body.clientWidth,
      bottom: html.clientHeight || body.clientHeight,
      height: html.clientHeight || body.clientHeight
    };
  }
  return this._expandRectByRootMargin(rootRect);
};


/**
 * Accepts a rect and expands it by the rootMargin value.
 * @param {Object} rect The rect object to expand.
 * @return {Object} The expanded rect.
 * @private
 */
IntersectionObserver.prototype._expandRectByRootMargin = function(rect) {
  var margins = this._rootMarginValues.map(function(margin, i) {
    return margin.unit == 'px' ? margin.value :
        margin.value * (i % 2 ? rect.width : rect.height) / 100;
  });
  var newRect = {
    top: rect.top - margins[0],
    right: rect.right + margins[1],
    bottom: rect.bottom + margins[2],
    left: rect.left - margins[3]
  };
  newRect.width = newRect.right - newRect.left;
  newRect.height = newRect.bottom - newRect.top;

  return newRect;
};


/**
 * Accepts an old and new entry and returns true if at least one of the
 * threshold values has been crossed.
 * @param {?IntersectionObserverEntry} oldEntry The previous entry for a
 *    particular target element or null if no previous entry exists.
 * @param {IntersectionObserverEntry} newEntry The current entry for a
 *    particular target element.
 * @return {boolean} Returns true if a any threshold has been crossed.
 * @private
 */
IntersectionObserver.prototype._hasCrossedThreshold =
    function(oldEntry, newEntry) {

  // To make comparing easier, an entry that has a ratio of 0
  // but does not actually intersect is given a value of -1
  var oldRatio = oldEntry && oldEntry.isIntersecting ?
      oldEntry.intersectionRatio || 0 : -1;
  var newRatio = newEntry.isIntersecting ?
      newEntry.intersectionRatio || 0 : -1;

  // Ignore unchanged ratios
  if (oldRatio === newRatio) return;

  for (var i = 0; i < this.thresholds.length; i++) {
    var threshold = this.thresholds[i];

    // Return true if an entry matches a threshold or if the new ratio
    // and the old ratio are on the opposite sides of a threshold.
    if (threshold == oldRatio || threshold == newRatio ||
        threshold < oldRatio !== threshold < newRatio) {
      return true;
    }
  }
};


/**
 * Returns whether or not the root element is an element and is in the DOM.
 * @return {boolean} True if the root element is an element and is in the DOM.
 * @private
 */
IntersectionObserver.prototype._rootIsInDom = function() {
  return !this.root || containsDeep(document, this.root);
};


/**
 * Returns whether or not the target element is a child of root.
 * @param {Element} target The target element to check.
 * @return {boolean} True if the target element is a child of root.
 * @private
 */
IntersectionObserver.prototype._rootContainsTarget = function(target) {
  return containsDeep(this.root || document, target);
};


/**
 * Adds the instance to the global IntersectionObserver registry if it isn't
 * already present.
 * @private
 */
IntersectionObserver.prototype._registerInstance = function() {
  if (registry.indexOf(this) < 0) {
    registry.push(this);
  }
};


/**
 * Removes the instance from the global IntersectionObserver registry.
 * @private
 */
IntersectionObserver.prototype._unregisterInstance = function() {
  var index = registry.indexOf(this);
  if (index != -1) registry.splice(index, 1);
};


/**
 * Returns the result of the performance.now() method or null in browsers
 * that don't support the API.
 * @return {number} The elapsed time since the page was requested.
 */
function now() {
  return window.performance && performance.now && performance.now();
}


/**
 * Throttles a function and delays its execution, so it's only called at most
 * once within a given time period.
 * @param {Function} fn The function to throttle.
 * @param {number} timeout The amount of time that must pass before the
 *     function can be called again.
 * @return {Function} The throttled function.
 */
function throttle(fn, timeout) {
  var timer = null;
  return function () {
    if (!timer) {
      timer = setTimeout(function() {
        fn();
        timer = null;
      }, timeout);
    }
  };
}


/**
 * Adds an event handler to a DOM node ensuring cross-browser compatibility.
 * @param {Node} node The DOM node to add the event handler to.
 * @param {string} event The event name.
 * @param {Function} fn The event handler to add.
 * @param {boolean} opt_useCapture Optionally adds the even to the capture
 *     phase. Note: this only works in modern browsers.
 */
function addEvent(node, event, fn, opt_useCapture) {
  if (typeof node.addEventListener == 'function') {
    node.addEventListener(event, fn, opt_useCapture || false);
  }
  else if (typeof node.attachEvent == 'function') {
    node.attachEvent('on' + event, fn);
  }
}


/**
 * Removes a previously added event handler from a DOM node.
 * @param {Node} node The DOM node to remove the event handler from.
 * @param {string} event The event name.
 * @param {Function} fn The event handler to remove.
 * @param {boolean} opt_useCapture If the event handler was added with this
 *     flag set to true, it should be set to true here in order to remove it.
 */
function removeEvent(node, event, fn, opt_useCapture) {
  if (typeof node.removeEventListener == 'function') {
    node.removeEventListener(event, fn, opt_useCapture || false);
  }
  else if (typeof node.detatchEvent == 'function') {
    node.detatchEvent('on' + event, fn);
  }
}


/**
 * Returns the intersection between two rect objects.
 * @param {Object} rect1 The first rect.
 * @param {Object} rect2 The second rect.
 * @return {?Object} The intersection rect or undefined if no intersection
 *     is found.
 */
function computeRectIntersection(rect1, rect2) {
  var top = Math.max(rect1.top, rect2.top);
  var bottom = Math.min(rect1.bottom, rect2.bottom);
  var left = Math.max(rect1.left, rect2.left);
  var right = Math.min(rect1.right, rect2.right);
  var width = right - left;
  var height = bottom - top;

  return (width >= 0 && height >= 0) && {
    top: top,
    bottom: bottom,
    left: left,
    right: right,
    width: width,
    height: height
  };
}


/**
 * Shims the native getBoundingClientRect for compatibility with older IE.
 * @param {Element} el The element whose bounding rect to get.
 * @return {Object} The (possibly shimmed) rect of the element.
 */
function getBoundingClientRect(el) {
  var rect;

  try {
    rect = el.getBoundingClientRect();
  } catch (err) {
    // Ignore Windows 7 IE11 "Unspecified error"
    // https://github.com/w3c/IntersectionObserver/pull/205
  }

  if (!rect) return getEmptyRect();

  // Older IE
  if (!(rect.width && rect.height)) {
    rect = {
      top: rect.top,
      right: rect.right,
      bottom: rect.bottom,
      left: rect.left,
      width: rect.right - rect.left,
      height: rect.bottom - rect.top
    };
  }
  return rect;
}


/**
 * Returns an empty rect object. An empty rect is returned when an element
 * is not in the DOM.
 * @return {Object} The empty rect.
 */
function getEmptyRect() {
  return {
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    width: 0,
    height: 0
  };
}

/**
 * Checks to see if a parent element contains a child element (including inside
 * shadow DOM).
 * @param {Node} parent The parent element.
 * @param {Node} child The child element.
 * @return {boolean} True if the parent node contains the child node.
 */
function containsDeep(parent, child) {
  var node = child;
  while (node) {
    if (node == parent) return true;

    node = getParentNode(node);
  }
  return false;
}


/**
 * Gets the parent node of an element or its host element if the parent node
 * is a shadow root.
 * @param {Node} node The node whose parent to get.
 * @return {Node|null} The parent node or null if no parent exists.
 */
function getParentNode(node) {
  var parent = node.parentNode;

  if (parent && parent.nodeType == 11 && parent.host) {
    // If the parent is a shadow root, return the host element.
    return parent.host;
  }

  if (parent && parent.assignedSlot) {
    // If the parent is distributed in a <slot>, return the parent of a slot.
    return parent.assignedSlot.parentNode;
  }

  return parent;
}


// Exposes the constructors globally.
window.IntersectionObserver = IntersectionObserver;
window.IntersectionObserverEntry = IntersectionObserverEntry;

}());
;
function LazyBox(element, context, callbacks, model) {
	var self = this;
	this.current = 0;
	this.checkAndSet = function(entries) {
		if (entries[0].intersectionRatio > 0) {
			if (self.current==2) return;
			self.current = 2;
			self.callbacks.on(self.context);
		} else {
			if (self.current==1) return;
			self.current = 1;
			self.callbacks.off(self.context);
		}
	};
	this.precheck = function() {
		self.observer.observe(self.element);
	};
	this.initObserver = function() {
		self.observer = new IntersectionObserver(self.checkAndSet, self.model);
		self.precheck();
	};
	this.init = function(element, context, callbacks, model) {
		self.element = element;
		self.element.LazyBox = self;
		self.context = context;
		self.model = (isset(model)?model:{
			rootMargin: '50px 0px',
			threshold: 0.01
		});
		self.callbacks = (isset(callbacks)?callbacks:{});
		if (!isset(self.callbacks.on)) self.callbacks.on = emptyFunc;
		if (!isset(self.callbacks.off)) self.callbacks.off = emptyFunc;
		self.initObserver();
		setTimeout(self.initObserver, 100);
	};
	this.init(element, context, callbacks, model);
}

function LazyElement(element, context, callback, model) {
	var self = this;
	this.done = false;
	this.checkAndSet = function (entries) {
		
		if (entries[0].intersectionRatio > 0) {
			if (!self.multipli) {
				if (self.done) return;
				self.done = true; self.observer.unobserve(entries[0].target);
			}

			self.callback(self.context);
		} else {
			self.out();
		}
	};
	this.precheck = function() {
		self.observer.observe(self.element);
	};
	this.initObserver = function() {
		self.observer = new IntersectionObserver(self.checkAndSet, self.model);
		self.precheck();
	};
	this.init = function(element, context, callback, model) {
		self.element = element;
		self.element.LazyElement = self;
		self.context = context;
		self.multipli = isset(model) && isset(model.multipli) ? model.multipli : false;
		self.out = isset(model) && isset(model.out) ? model.out : function () { };
		self.model = (isset(model)?model:{
			rootMargin: '50px 0px',
			threshold: 0.01
		});
		self.callback = (isset(callback)&&is_function(callback)?callback:emptyFunc);
		self.initObserver();
		setTimeout(self.initObserver, 100);
	};
	this.init(element, context, callback, model);
}

function Lazy(image, onLazy, parent) {
	var self = this;
	this.parent = parent;
	this.precheck = function() {
		self.observer.observe(self.image);
	};
	this.Check = function(){
		self.precheck();
	};
	this.done = false;
	this.checkAndSet = function(entries) {
		if (entries[0].intersectionRatio > 0) {
			self.setSrcCheck();
		}
	};
	this.afterLoad = function() {
		self.image.onerror = function(){
			self.image.hidden = true;
		};
	};
	this.setSrcCheck = function() {
		if (self.done) return;
		self.done = true;
		self.setSrc();
	};
	this.setSrc = function() {
		switch (self.image.tagName) {
			case 'source':
			case 'SOURCE':
				self.image.setAttribute('srcset', self.image.imgSRC);
				self.afterLoad();
			break;
			case 'img':
			case 'IMG':
				self.image.setAttribute('src', self.image.imgSRC);
				self.image.classList.remove('loader');
				self.image.style.minWidth = '';
				self.image.style.minHeight = '';
				self.afterLoad();
			break;
		}

		self.observer.unobserve(self.image);
		self.onLazy();
	};
	this.transparentPixel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
	this.init = function(image, onLazy) {
		self.image = image;
		if (isset(self.image.Lazy)) {
			return;
		}
		self.image.Lazy = self;
		self.onLazy = (typeof onLazy=='function'?onLazy:emptyFunc);
		self.image.imgSRC = self.image.getAttribute('data-src')||self.image.getAttribute('data-srcset');
		if (self.image.imgSRC) {
			self.image.setAttribute('backup-src', self.image.imgSRC);
			self.image.removeAttribute('data-src');
			self.image.removeAttribute('data-srcset');
			switch (self.image.tagName) {
				case 'source':
				case 'SOURCE':
					self.image.setAttribute('srcset', self.transparentPixel);
				break;
				case 'img':
				case 'IMG':
					self.image.setAttribute('src', self.transparentPixel);
					self.image.classList.add('loader');
					self.image.style.minWidth = '100px';
					self.image.style.minHeight = '100px';
				break;
			}
			var config = (isset(image.lazyConfig)?image.lazyConfig:{
				rootMargin: '50px 0px',
				threshold: 0.01
			});
			self.observer = new IntersectionObserver(self.checkAndSet, config);
			setTimeout(self.precheck, 100);
		} else {
			self.onLazy();
		}
	};
	this.init(image, onLazy);
}

function LazyPicture(picture, onLazy) {
	var self = this;
	this.init = function(picture, onLazy) {
		self.picture = picture;
		if (isset(self.picture.Lazy)) {
			console.error('allready LazyPicture');
			return;
		}
		self.picture.Lazy = self;
		self.onLazy = (typeof onLazy=='function'?onLazy:emptyFunc);
		self.lazyes = [];
		self.imgs = self.picture.querySelectorAll('source, img');
		for (var i=(self.imgs.length-1);i>=0;i--) self.lazyes.push(new Lazy(self.imgs[i], self.onLazy, self));
	};
	this.init(picture, onLazy);
}

var imgs = document.querySelectorAll('img.lazy');
if (imgs&&imgs.length) {
	for (var i=imgs.length-1;i>=0;i--) {
		new Lazy(imgs[i]);
	}
};
/// <reference path="../../../Scripts/_references.js" />

Far.Script = function (model) {
	var script, hash, loaded;
	if (isset(model.src)) {
		
		var src = (isset(model.outside)?model.src:[model.src,(model.addBuildNumber?['?',window.Far.Version].join(''):'')].join(''));
		hash 	= ['script',src.hashCode()].join('__');
		loaded 	= document.getElementById(hash)?true:false;
		if (loaded) {
			if (isset(model.callback)) {
				if (isset(model.context)) {
					model.callback.call(model.context);
				}
				else {
					model.callback();
				}
			}
			return;
		}
		script = document.createElement('script');
		script.id = hash;
		script.setAttribute('type', 'text/javascript');
		script.setAttribute('src', src);
		document.body.appendChild(script);
		script.onload = function() {
			loaded = true;
			if (isset(model.callback)) {
				setTimeout(function(){window.Far.Script(model);}, 50);
			}
		};
	}
	else if (isset(model.inner)) {
		hash = ['script',model.inner.hashCode()].join('__');
		loaded 	= document.getElementById(hash)?true:false;
		if (loaded) {
			if (isset(model.callback)) model.callback();
		} else {
			script = createElement({tag: 'script', innerText: model.inner});
			document.body.appendChild(script);
			if (isset(model.callback)) setTimeout(function(){window.Far.Script(model);}, 50);
		}
	}
};

function createScriptCallback(callback) {
	
};

Far.Scripts = {
	getOrAdd: function (src, callback, async) {
		var hash = ['script', src.hashCode()].join('__');
		if (!this.storage.hasOwnProperty(hash)) {
			this.storage[hash] = {
				count: 1,
				loaded: false,
				callbacks: [callback],
				addCallback: function (c) {
					this.count++;
					if (this.loaded) {
						c();
					}
					else {
						this.callbacks.push(c);
					}
				},
				onLoad: function () {
					this.loaded = true;
					this.callbacks.forEach(function (c) {
						c();
					});
					this.callbacks = [];
				}
			};
			var script = document.createElement('script');
			script.id = hash;
			script.setAttribute('type', 'text/javascript');
			script.setAttribute('src', src);
			if (async) {
				script.async = true;
			}
			document.body.appendChild(script);
			script.onload = function () {
				this.onLoad();
			}.bind(this.storage[hash]);
		}
		else {
			this.storage[hash].addCallback(callback);
		}
		return this.storage[hash];
	},
	storage: {
	}
};

Far.Script2 = function (model) {
	if (isset(model.src)) {
		var src = (isset(model.outside) ? model.src : [model.src, (model.addBuildNumber ? ['?', window.Far.Version].join('') : '')].join(''));
		window.Far.Scripts.getOrAdd(src, model.callback);
	}
};

/**
 * 
 * @param {{ src: string; outside: boolean; addBuildNumber: boolean; callback: function(): void }} model
 */
Far.Script2Async = function (model) {
	var src = isset(model.outside) && model.outside ? model.src : [model.src, (model.addBuildNumber ? ['?', Far.Version].join('') : '')].join('');
	Far.Scripts.getOrAdd(src, model.callback, true);
};
window.Far.Style = function(model) {
	var link, hash, loaded;
	if (isset(model.href)) {
		var href= [model.href,'?',(model.addBuildNumber?[window.Far.Version].join(''):'')].join('');
		hash 	= ['style',href.hashCode()].join('__');
		loaded 	= document.getElementById(hash)?true:false;
		if (loaded) {
			if (isset(model.callback)) model.callback();
			return;
		}
		var prelink = document.createElement('link');
		prelink.setAttribute('rel', 'preload');
		prelink.setAttribute('as', 'style');
		prelink.setAttribute('href', href);
		document.body.appendChild(prelink);
		link = document.createElement('link');
		link.id = hash;
		link.setAttribute('type', 'text/css');
		link.setAttribute('rel', 'stylesheet');
		link.setAttribute('media', 'All');
		link.setAttribute('href', href);
		document.body.appendChild(link);
		link.onreadystatechange = link.onload = function() {
			loaded = true;
			if (isset(model.callback)) setTimeout(function(){window.Far.Style(model);}, 50);
		};
	} else if (isset(model.inner)) {
		hash = ['style',model.inner.hashCode()].join('__');
		loaded 	= document.getElementById(hash)?true:false;
		if (loaded) {
			if (isset(model.callback)) model.callback();
		} else {
			link = createElement({tag: 'style', innerText: model.inner});
			document.body.appendChild(link);
			if (isset(model.callback)) setTimeout(function(){window.Far.Style(model);}, 50);
		}
	}
};;
window.Far.ZIndex = {
	relative: [0,1999,0],
	absolute: [2000,3999,2000],
	fixed: [4000,5999,4000],
	modal: [6000,7999,6000],
	advanced: [10000,15000,10000],
	get: function(pos) {
		return window.Far.ZIndex[pos][2];
	},
	set: function(pos) {
		window.Far.ZIndex[pos][2]++;
		return window.Far.ZIndex.get(pos);
	}
};;
window.Far.Layout = {
	minimalScroll: 100,
	scrolled: (window.Far.Events.onScroll.current>=this.minimalScroll),
	noScroll: {
		curr: 0,
		add: function() {
			window.Far.Layout.html.classList.add('noScroll');
			window.Far.Layout.noScroll.curr++;
		},
		remove: function() {
			window.Far.Layout.noScroll.curr--;
			if (window.Far.Layout.noScroll.curr<0) window.Far.Layout.noScroll.curr = 0;
			if (!window.Far.Layout.noScroll.curr) window.Far.Layout.html.classList.remove('noScroll');
		}
	},
	setScrollMoment: function(scrolled) {
		if (scrolled>=window.Far.Layout.minimalScroll) {
			if (!window.Far.Layout.scrolled) {
				document.body.classList.add('__scrolled');
				window.Far.Layout.scrolled = true;
			}
		} else {
			if (window.Far.Layout.scrolled) {
				document.body.classList.remove('__scrolled');
				window.Far.Layout.scrolled = false;
			}
		}
	},
	body: document.getElementById('body'),
	html: document.getElementById('html'),
	header: document.getElementById('header'),
	main: document.getElementById('main'),
	footer: document.getElementById('footer'),
	preloader: document.getElementById('preloader'),
	init: function() {
		window.Far.Events.onScroll.add('Layout', window.Far.Layout.setScrollMoment);
		farDocument.onReady(function(){
			if (window.Far.Layout.preloader) {
				setTimeout(function(){
					window.Far.Layout.preloader.style.opacity = 0;
					setTimeout(function(){
						window.Far.Layout.preloader.hidden = true;
					}, 250);
				}, 100);
			}
			window.SearchForm.onRendered(function () {
				document.getElementById('Search_form_container').style.minHeight = '';
			});
			window.Far.Script({
				src: '/NewDesign/Scripts/Components/pageScroller.js',
				addBuildNumber: true,
			});
		});
	}
};

window.Far.Layout.init();;
(function () {
	function Header() {
		var self = this;
		this.isMasterCardBlack = true;
		this.isMasterCardCurrent = false;
		this.isMasterCardClick = false;
		this.currentScroll = 0;
		this.minimalScroll = 10;
		this.i = 0;
		this.onScrollMoment = [];
		this.setScrollMoment = function (scroll) {
			if (scroll <= self.minimalScroll) {
				if (self.elements.parent.classList.contains('__fixed')) {
					self.elements.parent.classList.remove('__fixed');
					self.invert.on();
				}
			} else {
				if (!self.elements.parent.classList.contains('__fixed')) {
					self.elements.parent.classList.add('__fixed');
					self.invert.off();
				}
			}
			self.currentScroll = scroll;
			for (var i = 0; i < self.onScrollMoment.length; i++) self.onScrollMoment[i](scroll);
		};
		this.invert = {
			using: (document.getElementById('homePageViewPortSection') ? true : false),
			active: false,
			on: function () {
				if (!self.invert.using || !self.invert.active || window.Far.Device == 'Mobile') return;
				self.invert.active = false;
				self.elements.parent.classList.add('__invert');
			},
			off: function () {
				if (!self.invert.using || self.invert.active || window.Far.Device == 'Mobile') return;
				self.invert.active = true;
				self.elements.parent.classList.remove('__invert');
			}
		};
		this.Call = {
			show: function () {
				self.elements.MainCall.style.zIndex = window.Far.ZIndex.set('fixed');
				self.elements.MainCall.hidden = false;
				setTimeout(function () {
					window.Far.Events.bodyClick.add('MainCallOutsideClick', self, self.Call.hide);
				}, 50);
			},
			hide: function () {
				self.elements.MainCall.hidden = true;
				window.Far.Events.bodyClick.remove('MainCallOutsideClick');
			},
			toggle: function () {
				if (!self.elements.MainCall.hidden) {
					self.Call.hide();
				} else {
					window.Far.Style({
						href: ['/NewDesign/Styles/', window.Far.Device, '/MainCall.css'].join(''),
						addBuildNumber: true,
						callback: self.Call.show
					});
					self.elements.orderCallbackBtn.addEventListener('click', self.Call.orderCallbackOpenModal);
				}
			},
			orderCallbackOpenModal: function () {
				window.Far.Script({
					src: '/NewDesign/Scripts/Components/OrderCallback.js',
					addBuildNumber: true,
					callback: function () {
						window.Far.OrderCallback.showModal();
					}
				});
			},
			init: function (callOpener) {
				self.elements.MainCall = document.getElementById('MainCall');
				self.elements.MainCall.hidden = true;
				callOpener.addEventListener('click', self.Call.toggle);
				self.elements.orderCallbackBtn = document.getElementById('MainCall__orderCallback');
			}
		};
		this.Menu = {
			isOpen: false,
			show: function () {
				self.Menu.isOpen = true;
				self.elements.MainMenu.style.zIndex = window.Far.ZIndex.set('fixed');
				self.elements.MainMenu.hidden = false;
				self.elements.MainMenu.style.display = 'block';
				window.Far.Layout.noScroll.add();
			},
			hide: function () {
				self.Menu.isOpen = false;
				self.elements.MainMenu.hidden = true;
				self.elements.MainMenu.style.display = 'none';
				self.elements.MainMenu.style.zIndex = 'auto';
				window.Far.Layout.noScroll.remove();
			},
			toggle: function () {
				if (self.Menu.isOpen) {
					self.Menu.hide();
				}
				else {
					window.Far.Style({
						href: ['/NewDesign/Styles/', window.Far.Device, '/MainMenu.css'].join(''),
						addBuildNumber: true,
						callback: self.Menu.show
					});
				}
			},
			init: function (menuOpener) {
				self.elements.MainMenu = document.getElementById('MainMenu');
				self.elements.MainMenu.hidden = true;
				document.getElementById('MainMenu__opener').addEventListener('click', self.Menu.toggle);
				document.getElementById('MainMenu__closeBtn').addEventListener('click', self.Menu.toggle);
				document.getElementById('MainMenu__backDrop').addEventListener('click', self.Menu.toggle);
			}
		};
		this.Banner = {
			/**
			 * @param {Event} e
			 */
			close: function (e) {
				try {
					self.elements.banner.remove();
					e.preventDefault();
					e.stopPropagation();
					window.Far.Layout.html.style.paddingTop = '53px';
					window.Far.Layout.header.style.minHeight = '53px';
				}
				catch (ex) {
					console.error(ex);
				}
			},
			init: function (headerBanner) {
				self.elements.banner = headerBanner;
				var closer = document.getElementById('headerBanner__closer');
				if (closer) {
					closer.addEventListener('click', self.Banner.close);
				}
			}
		};
		this.originalSearchFormPosition = 0;
		this.getOffsetTop = function(el) {
			var y = 0;
			while (el && !isNaN(el.offsetTop)) {
				y += el.offsetTop - el.scrollTop;
				el = el.offsetParent;
			}
			return y;
		}
		this.appendSearchForm = function () {
			if (!SearchForm || !isset(SearchForm) || !isset(SearchForm.instance) || !SearchForm.instance || !isset(SearchForm.instance.settings) || !SearchForm.instance.settings || !isset(SearchForm.instance.settings.container) || !SearchForm.instance.settings.container) {
				setTimeout(self.appendSearchForm, 20);
				return;
			}
			self.SearchForm = SearchForm.instance.settings.container;
			self.originalSearchFormPosition = self.getOffsetTop(self.SearchForm) + self.SearchForm.offsetHeight - window.Far.Layout.header.offsetHeight;

			if (Far.Device == 'Desktop') {
				self.appendSearchForm_Desktop();
			}
			else {
				if (document.querySelector('body').classList.contains('page_Home_MastercardBilsheBlack')) {
					self.appendSearchFormMasterCardBlack_Mobile();

					farDocument.onReady(function () {

						var formOpener = document.getElementById('catalog_search_properties_form');

						new LazyElement(document.getElementById('search_forms'), {
						}, function () {
							formOpener.style.display = 'none';
							hiddenSearchForm = true;
						},
							{
								multipli: true,
								out: function () {
									formOpener.style.display = '';
									hiddenSearchForm = false;
								}
							}
						);
					});
				}
				else {
					self.appendSearchForm_Mobile();
					farDocument.onReady(function () {

						var formOpener = document.getElementById('catalog_search_properties_form');

						new LazyElement(document.getElementById('search_forms'), {},
							function () {
								if (formOpener.classList.contains('__cloned')) {
									formOpener.style.display = 'none';
								}
								hiddenSearchForm = true;
							}, {
								multipli: true
							}
						);
					})
				}
			}
		};
		this.appendSearchForm_Desktop = function () {
			var movedSearchForm = false,
				hiddenSearchForm = false;
			if (!isset(self.parentSearchForm)) self.parentSearchForm = self.SearchForm.parentNode;
			self.onScrollMoment.push(function (scroll) {
				if (scroll >= self.originalSearchFormPosition) {
					if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
						if (window.Far.Events.onScroll.previous > window.Far.Events.onScroll.current) {
							if (hiddenSearchForm) {
								self.SearchForm.style.display = '';
								hiddenSearchForm = false;
							}
						} else {
							if (!hiddenSearchForm) {
								self.SearchForm.style.display = 'none';
								hiddenSearchForm = true;
							}
						}
					}
					if (movedSearchForm) return;
					self.elements.parent.classList.add('__hasSearchForm');
					self.elements.parent.appendChild(self.SearchForm);
					movedSearchForm = true;
				} else {
					if (hiddenSearchForm) self.SearchForm.style.display = '';
					if (!movedSearchForm) return;
					self.elements.parent.classList.remove('__hasSearchForm');
					self.parentSearchForm.insertBefore(self.SearchForm, self.parentSearchForm.getElementsByClassName('sticky_clone')[0]);
					movedSearchForm = false;
				}
			});
		};
		this.appendSearchForm_Mobile = function () {
			var //fixedBtn 			= document.getElementById('SearchFormMobileFixedAnchor'),
				hiddenSearchForm = false,
				movedSearchForm = false,
				formOpener = document.getElementById('catalog_search_properties_form');
			if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.useClickHandler) {
				formOpener.addEventListener('click', function () {
					window.Far.Style({
						href: '/NewDesign/Styles/Common/fixedSearchForm.css',
						addBuildNumber: true
					});
					self.SearchForm.style.zIndex = window.Far.ZIndex.set('modal');
					window.SearchForm.instance.events.onAdnvancedClick.call(window.SearchForm.instance);
				});
			}
			/*if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
				self.originalSearchFormPosition = (formOpener.getBoundingClientRect().top + formOpener.offsetHeight)
			}*/
			if (self.search_forms.appendToHeader.hideOnTop) {
				formOpener.hidden = true;
			}
			self.originalSearchFormPosition = Math.max(100, self.originalSearchFormPosition);

			self.onScrollMoment.push(function (scroll) {
				if (scroll >= self.originalSearchFormPosition) {
					if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
						if (window.Far.Events.onScroll.previous > window.Far.Events.onScroll.current) {
							if (hiddenSearchForm) {
								formOpener.style.display = '';
								hiddenSearchForm = false;
							}
						} else {
							if (!hiddenSearchForm) {
								formOpener.style.display = 'none';
								hiddenSearchForm = true;
							}
						}
						if (movedSearchForm) return;
						self.elements.parent.classList.add('__hasSearchForm');
						console.log('movedSearchForm');
						self.elements.parent.appendChild(formOpener);
						self.elements.parent.querySelector('.catalog_propperties').classList.add('__cloned');
						movedSearchForm = true;
					}
					if (self.search_forms.appendToHeader.hideOnTop) {
						if (!formOpener.hidden) return;
						formOpener.hidden = false;
					}
				}
				else {
					if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
						if (hiddenSearchForm) {
							formOpener.style.display = '';
						}
						if (!movedSearchForm) return;
						self.elements.parent.classList.remove('__hasSearchForm');
						if (document.getElementById('catalog_search_properties') !== null) {
							document.getElementById('catalog_search_properties').insertBefore(formOpener, document.getElementById('catalog_search_properties').getElementsByClassName('sticky_clone')[0]);
							document.getElementById('catalog_search_properties_form').classList.remove('__cloned');
						}
						movedSearchForm = false;
					}
					if (self.search_forms.appendToHeader.hideOnTop) {
						if (formOpener.hidden) return;
						formOpener.hidden = true;
					}
				}
			});
		};
		this.appendSearchFormMasterCardBlack_Mobile = function () {
			var //fixedBtn 			= document.getElementById('SearchFormMobileFixedAnchor'),
				hiddenSearchForm = false,
				movedSearchForm = false,
				formOpener = document.getElementById('catalog_search_properties_form');
			if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.useClickHandler) {
				formOpener.addEventListener('click', function () {
					window.Far.Style({
						href: '/NewDesign/Styles/Common/fixedSearchForm.css',
						addBuildNumber: true
					});
					self.SearchForm.style.zIndex = window.Far.ZIndex.set('modal');
					window.SearchForm.instance.events.onAdnvancedClick.call(window.SearchForm.instance);
				});
			}
			if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
				self.originalSearchFormPosition = formOpener.offsetHeight;
			}
			if (self.search_forms.appendToHeader.hideOnTop) {
				formOpener.hidden = false;
			}
			self.onScrollMoment.push(function (scroll) {
				if (scroll >= self.originalSearchFormPosition) {
					if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
							if (hiddenSearchForm) {
								formOpener.style.display = '';
								hiddenSearchForm = false;
					}
						if (movedSearchForm) return;
						self.elements.parent.appendChild(formOpener);
						movedSearchForm = false;
					}
					if (self.search_forms.appendToHeader.hideOnTop) {
						formOpener.hidden = false;
					}

				} else {
					if (self.search_forms.appendToHeader && self.search_forms.appendToHeader.hideOnScrollBottom) {
						if (hiddenSearchForm) formOpener.style.display = '';
						if (!movedSearchForm) return;
						self.elements.parent.classList.remove('__hasSearchForm');
						if (document.getElementById('catalog_search_properties') !== null) {
							document.getElementById('catalog_search_properties').insertBefore(formOpener, document.getElementById('catalog_search_properties').getElementsByClassName('sticky_clone')[0]);
						}
						movedSearchForm = false;
					}
					if (self.search_forms.appendToHeader.hideOnTop) {
						if (!formOpener.hidden) return;
						formOpener.hidden = false;
					}

				}
			});
		};
		this.setPaddingForHeader = function () {
			//var top = window.Far.Device == 'Mobile' ? (window.SeoPage ? 72 : 86) : 76;
			//window.Far.Layout.html.style.paddingTop = top + 'px';

			//var top = window.Far.Device == 'Mobile' ? 72 : 76;
			//window.Far.Layout.html.style.paddingTop = [self.elements.parent.offsetHeight, 'px'].join('');
			//console.log('paddingTop', [self.elements.parent.offsetHeight, 'px'].join(''))
		};
		this.init = function () {
			self.elements = {};
			self.elements.parent = window.Far.Layout.header;
			self.elements.parent.style.zIndex = window.Far.ZIndex.set('fixed');
			window.Far.Events.onScroll.add('Header', self.setScrollMoment);

			var callOpener = document.getElementById('MainCall__opener');
			if (callOpener) self.Call.init(callOpener);

			var headerBanner = document.querySelector('.header_banner-container');
			if (headerBanner) {
				self.Banner.init(headerBanner);
			}

			var menuOpener = document.getElementById('MainMenu__opener');
			if (menuOpener) self.Menu.init(menuOpener);
			self.search_forms = document.getElementById('search_forms');
			if (self.search_forms && self.search_forms.classList.contains('__appendToHeader')) {
				self.search_forms.appendToHeader = self.search_forms.getAttribute('data-appendToHeader');
				if (self.search_forms.appendToHeader) self.search_forms.appendToHeader = JSON.parse(self.search_forms.appendToHeader);
				farDocument.onReady(function () {
					setTimeout(self.appendSearchForm, 500);
				});
			}
			self.setPaddingForHeader();
		};
		this.init();
	}

	window.Far.Layout.Header = new Header();
})();;
function Layout_Footer() {
	var self = this;
	this.inited = false;
	this.initStylesAndScript = function() {
		if (self.inited) return;
		self.inited = true;
		window.Far.Style({
			href: ['/NewDesign/Styles/',window.Far.Device,'/Layout_Footer.css'].join(''),
			addBuildNumber: true
		});
		if (window.Far.Device=='Mobile') {
			var boxes = self.elements.parent.querySelectorAll('.footer__box');
			for (var i = boxes.length - 1; i >= 0; i--) {
				if (boxes[i].querySelector('.footer__box__title')) {
					boxes[i].querySelector('.footer__box__title').addEventListener('click', self.box.toggle);
				}
			}
		}
	};
	this.box = {
		toggle: function() {
			if (!isset(this.opened)) this.opened = false;
			if (!this.opened) {
				self.box.open(this);
			} else {
				self.box.close(this);
			}
		},
		open: function(box) {
			box.opened = true;
			box.parentNode.classList.add('__active');
		},
		close: function(box) {
			box.opened = false;
			box.parentNode.classList.remove('__active');
		}
	};
	this.init = function() {
		self.elements = {};
		self.elements.parent = window.Far.Layout.footer;
		new LazyElement(self.elements.parent, self, self.initStylesAndScript, {
			rootMargin: '500px 0px',
			threshold: 0.01
		});
	};
	this.init();
}

farDocument.onReady(function(){
	window.Far.Layout.Footer = new Layout_Footer();
});;
var LL = {

    current: localization,
    langList: {
        ru: {titleRU:'Русский',titleUK:'Російська',titleEn:'Russian'},
        uk: {titleRU:'Украинский',titleUK:'Українська',titleEn:'Ukraine'},
        en: {titleRU:'Английский',titleUK:'Англійська',titleEn:'English'}
    },
    get: function (str) {
        return str;
    },
    getMethering: function (str, v) {

        var lastDigits = 0,
			metering = ""
        if (str == "price")
        {
            var type = v.toString();
            var len = type.length;
            var count = v;
            if (len > 2) {
                type = type.substring(len - 2, len);
                count = parseInt(type);
            }
            if (count == 11) {
                metering = localizationValues.uah_0
            } else {
                lastDigits = count % 10;
                if (lastDigits == 1) {
                    metering = localizationValues.uah_1
                } else {
                    metering = localizationValues.uah_0
                }
            }
            return metering;
        }
        lastDigits = v % 100;
		metering 	= "";
        lastDigits = (lastDigits >= 20) ? lastDigits % 10 : lastDigits;
        if (lastDigits === 0 ||
			lastDigits >= 5 && lastDigits <= 20) {
            switch (str) {
                case 'reviews':
                    metering = localizationValues.reviews;
                    break;
                case 'days':
                    metering = localizationValues.days_0;
                    break;
                case 'hotels':
                    metering = localizationValues.hotels_0.toLowerCase();
                    break;
                case 'tours':
                    metering = localizationValues.tour_0;
                    break;
                case 'nights':
                    metering = localizationValues.night_0;
                    break;
                case 'stars':
                    metering = localizationValues.star_0;
                    break;
                case 'tourists':
                    metering = localizationValues.tourist_0;
                    break;
                case 'kids':
                    metering = localizationValues.kid_0;
                    break;
                case 'adults':
                    metering = localizationValues.adult_0;
                    break;
                case 'years':
                    metering = localizationValues.years_0;
                    break;
                case 'trips':
                    metering = localizationValues.trips_0;
                    break;
                case 'balls':
                    metering = localizationValues.balls_0;
                    break;
            }
        } else {
            if (lastDigits == 1) {
                switch (str) {
                    case 'reviews':
                        metering = localizationValues.reviews_1;
                        break;
                    case 'days':
                        metering = localizationValues.days_1;
                        break;
                    case 'hotels':
                        metering = localizationValues.hotels_1.toLowerCase();
                        break;
                    case 'tours':
                        metering = localizationValues.tour_1;
                        break;
                    case 'nights':
                        metering = localizationValues.night_1;
                        break;
                    case 'stars':
                        metering = localizationValues.star_1;
                        break;
                    case 'tourists':
                        metering = localizationValues.tourist_1;
                        break;
                    case 'kids':
                        metering = localizationValues.kid_2;
                        break;
                    case 'adults':
                        metering = localizationValues.adult_1;
                        break;
                    case 'years':
                        metering = localizationValues.years_1;
                        break;
                    case 'trips':
                        metering = localizationValues.trips_1;
                        break;
                    case 'balls':
                        metering = localizationValues.balls_1;
                        break;
                }
            } else {
                switch (str) {
                    case 'reviews':
                        metering = localizationValues.reviews_2;
                        break;
                    case 'days':
                        metering = localizationValues.days_2;
                        break;
                    case 'hotels':
                        metering = localizationValues.hotels_2.toLowerCase();
                        break;
                    case 'tours':
                        metering = localizationValues.tour_2;
                        break;
                    case 'nights':
                        metering = localizationValues.night_2;
                        break;
                    case 'stars':
                        metering = localizationValues.star_2;
                        break;
                    case 'tourists':
                        metering = localizationValues.tourist_2;
                        break;
                    case 'kids':
                        metering = localizationValues.kid_1;
                        break;
                    case 'adults':
                        metering = localizationValues.adult_0;
                        break;
                    case 'years':
                        metering = localizationValues.years_2;
                        break;
                    case 'trips':
                        metering = localizationValues.trips_2;
                        break;
                    case 'balls':
                        metering = localizationValues.balls_2;
                        break;
                }
            }
        }
        return metering;
    },
};

;
function Loader_(model) {
	var self = this;
	this.parent = model.parent;
	this.outer = model.outer || null;
    this.type   = model.type || 'pulsing'; // pulsing, spinning
	this.parent.data = (isset(this.parent.data)?this.parent.data:{});
	this.parent.data.Loader_started = false;
	this.fullScreen = model.fullScreen;
	this.is_started = false;
	this.settings = {
		icon_size: (isset(model.icon_size)?model.icon_size:50),
		parent_min_height: (isset(model.parent_min_height) ? model.parent_min_height : 0),
		bgColor: model.bgColor,
		bgOpacity: model.bgOpacity
	};
	this.zik_loader = null;
	this.on_start = (isset(model.on_start)?model.on_start:[]);
	this.on_stop = (isset(model.on_stop)?model.on_stop:[]);
	this.start = function(desc) {
	    if (self.is_started || self.parent.data.Loader_started) return;
		desc = (typeof desc == 'string' ? desc : false);
	    switch (self.type) {
			case 'pulsing':
				self.parent.data.Loader_started = true;
				if (!isset(self.parent.originalPosition) || !isset(self.parent.prevPosition)) {
					self.parent.originalPosition = getComputedStyle(self.parent).position;
					self.parent.prevPosition = self.parent.style.position;
				}
				if (self.parent.originalPosition != 'absolute' && self.parent.originalPosition != 'fixed' && self.parent.originalPosition != 'relative') self.parent.style.position = 'relative';
				self.parent.style.minHeight = (self.settings.parent_min_height ? self.settings.parent_min_height : self.settings.icon_size + 15) + 'px';
				if (!self.zik_loader) {
					var zik_loader = document.createElement('div');
					zik_loader.className = 'ZIK__loader';
					zik_loader.style.position = (self.fullScreen ? 'fixed' : 'absolute');
					zik_loader.style.top = '0px';
					zik_loader.style.left = '0px';
					zik_loader.style.right = '0px';
					zik_loader.style.bottom = '0px';
					zik_loader.style.opacity = 0;
					zik_loader.style.transition = 'opacity ease 0.5s';
					zik_loader.style.zIndex = 5;
					var top = (self.parent.offsetHeight > window.innerHeight ? '200px' : '50%');
					//zik_loader.innerHTML = ['<svg width="200px" height="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-ripple" style="background:none;position:absolute;top:', top, ';left:50%;width:', self.settings.icon_size, 'px;height:', self.settings.icon_size, 'px;margin:-', (self.settings.icon_size / 2), 'px auto auto -', (self.settings.icon_size / 2), 'px"><circle cx="50" cy="50" r="28.407" fill="none" ng-attr-stroke="{{config.c1}}" ng-attr-stroke-width="{{config.width}}" stroke="',
					//	'#8cd0e5', '" stroke-width="2"><animate attributeName="r" calcMode="spline" values="0;40" keyTimes="0;1" dur="1" keySplines="0 0.2 0.8 1" begin="-0.5s" repeatCount="indefinite"></animate><animate attributeName="opacity" calcMode="spline" values="1;0" keyTimes="0;1" dur="1" keySplines="0.2 0 0.8 1" begin="-0.5s" repeatCount="indefinite"></animate></circle><circle cx="50" cy="50" r="6.15459" fill="none" ng-attr-stroke="{{config.c2}}" ng-attr-stroke-width="{{config.width}}" stroke="',
					//	'#376888', '" stroke-width="2"><animate attributeName="r" calcMode="spline" values="0;40" keyTimes="0;1" dur="1" keySplines="0 0.2 0.8 1" begin="0s" repeatCount="indefinite"></animate><animate attributeName="opacity" calcMode="spline" values="1;0" keyTimes="0;1" dur="1" keySplines="0.2 0 0.8 1" begin="0s" repeatCount="indefinite"></animate></circle></svg>'].join('');
					zik_loader.innerHTML = ['<svg width="200px" height="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-ripple" style="background:none;position:absolute;top:', top, ';left:50%;transform: translateX(-50%);width:', self.settings.icon_size, 'px;height:', self.settings.icon_size, 'px;margin:-', (self.settings.icon_size / 2), 'px auto -', (self.settings.icon_size / 2), 'px auto"><circle cx="50" cy="50" r="28.407" fill="none" ng-attr-stroke="{{config.c1}}" ng-attr-stroke-width="{{config.width}}" stroke="',
						'#000000', '" stroke-width="2"><animate attributeName="r" calcMode="spline" values="0;40" keyTimes="0;1" dur="1" keySplines="0 0.2 0.8 1" begin="-0.5s" repeatCount="indefinite"></animate><animate attributeName="opacity" calcMode="spline" values="1;0" keyTimes="0;1" dur="1" keySplines="0.2 0 0.8 1" begin="-0.5s" repeatCount="indefinite"></animate></circle><circle cx="50" cy="50" r="6.15459" fill="none" ng-attr-stroke="{{config.c2}}" ng-attr-stroke-width="{{config.width}}" stroke="',
						'#000000', '" stroke-width="2"><animate attributeName="r" calcMode="spline" values="0;40" keyTimes="0;1" dur="1" keySplines="0 0.2 0.8 1" begin="0s" repeatCount="indefinite"></animate><animate attributeName="opacity" calcMode="spline" values="1;0" keyTimes="0;1" dur="1" keySplines="0.2 0 0.8 1" begin="0s" repeatCount="indefinite"></animate></circle></svg>'].join('');

					self.zik_loader = zik_loader;
				}
				
				if (self.outer) {
					self.outer.appendChild(self.zik_loader);
					if (isset(self.settings.bgColor)) {
						self.parent.style.backgroundColor = self.settings.bgColor;
					}
					if (isset(self.settings.bgOpacity)) {
						self.parent.style.opacity = self.settings.bgOpacity;
					}
					self.zik_loader.style.opacity = 1;
				}
				else {
					if (isset(self.settings.bgColor)) {
						self.zik_loader.style.backgroundColor = self.settings.bgColor;
					}
					if (isset(self.settings.bgOpacity)) {
						self.zik_loader.style.opacity = self.settings.bgOpacity;
					}
					else {
						self.zik_loader.style.opacity = 1;
					}
					self.parent.appendChild(self.zik_loader);
				}
	    	break;
	    	case 'spinning':
	    		var zik_loader = document.createElement('div');
	    		self.parent.classList.add('new_loader_animation');
	    		zik_loader.className = 'new_loader_animation__loader __loader_color-black __loader_opacity-50';
	    		zik_loader.innerHTML = ['<span></span><i></i>'].join('');
	    		self.parent.appendChild(zik_loader);
	    		setTimeout(function () {
	    		    zik_loader.classList.add('__active');
	    		}, 100);
	    		self.zik_loader = zik_loader;
	    	break;
	    }
		self.is_started = true;
		if (desc) self.setDesc(desc);
		for (var i=0;i<self.on_start.length;i++) {
			if (typeof self.on_start[i]=='function') self.on_start[i]();
		}
	};
	this.setDesc = function(desc) {
		if (!self.is_started&&!self.parent.data.Loader_started) return;
		var descBox = self.zik_loader.querySelector('.ZIK__loader__desc');
		if (!descBox) {
			descBox = createElement('span');
			descBox.className = 'ZIK__loader__desc';
			var top = (self.parent.offsetHeight>window.innerHeight?'200px':'50%');
			descBox.setAttribute('style', ['position:absolute;top:',top,';left:50%;max-width:80%;margin:',(self.settings.icon_size/2),'px 0 0 0;transform:translateX(-50%)'].join(''));
			self.zik_loader.appendChild(descBox);
		}
		descBox.innerText = desc;
	};
	this.stop = function(callback) {
		if (!self.is_started&&!self.parent.data.Loader_started) return;
		var descBox = self.zik_loader.querySelector('.ZIK__loader__desc');
		self.is_started = false;
		switch (self.type) {
			case 'pulsing':
				self.zik_loader.style.opacity = 0;
				setTimeout(function () {
				    self.parent.data.Loader_started = false;
				    self.parent.style.position = self.parent.prevPosition;
					self.parent.style.minHeight = '';
					if (self.outer) {
						self.parent.style.opacity = 1;
					}
				    if (typeof callback == 'function') callback();
					if (self.zik_loader.parentNode == self.parent) self.parent.removeChild(self.zik_loader);
					if (self.outer) {
						try {
							self.zik_loader.remove();
						}
						catch (e) { }
					}
				    for (var i = 0; i < self.on_stop.length; i++) {
				        if (typeof self.on_stop[i] == 'function') self.on_stop[i]();
				    }
				}, 250);
			break;
			case 'spinning':
				setTimeout(function () {
				    self.parent.classList.remove('new_loader_animation');
				    if (typeof callback == 'function') callback();
				    if (self.zik_loader.parentNode==self.parent) self.parent.removeChild(self.zik_loader);
				    for (var i = 0; i < self.on_stop.length; i++) {
				        if (typeof self.on_stop[i] == 'function') self.on_stop[i]();
				    }
				}, 250);
			break;
		}
	};
}

function HorisontalLineLoader_(model) {
	var self = this;
	this.is_started = false;
	this.opacited = false;
	this.start = function() {
		if (self.is_started) return;
		self.is_started = true;
		self.opacited = false;
		self.element = createElement({tag:'div',className:'HorisontalLineLoader',innerHTML:'<span></span>'});
		window.Far.Style({
			href: '/NewDesign/Styles/Common/HorisontalLineLoader.css',
			addBuildNumber: true
		});
		var parentPosition = getComputedStyle(self.model.parent).position;
		if (parentPosition!='absolute'&&parentPosition!='fixed'&&parentPosition!='relative') {
			self.model.parent.style.position = 'relative';
		}
		self.model.parent.appendChild(self.element);
	};
	this.stop = function() {
		if (!self.is_started) return;
		self.is_started = false;
		self.model.parent.removeChild(self.element);
	};
	this.opacity = function() {
		if (!self.is_started||self.opacited) return;
		self.element.classList.add('__opacited');
	};
	this.init = function(model) {
		self.model = model;
		if (isset(self.model.parent.HorisontalLineLoader)) {
			self = self.model.parent.HorisontalLineLoader;
		}
		self.model.parent.HorisontalLineLoader = self;
	}
	this.init(model);
};
/*
	var MyLoader = new HorisontalLoader_({
		parent: document.getElementById('SearchForm')
	});
	MyLoader.start();
	MyLoader.stop();
*/
function HorisontalLoader_(model) {
	var self = this;
	this.element = null;
	this.start = function() {
		if (!self.model.parent) return;
		if (!self.element) {
			self.element = document.createElement('div');
			self.element.className = 'HorisontalLoader';
			self.element.innerHTML = '<i></i>';
			self.model.parent.classList.add('HorisontalLoader__parent');
			self.model.parent.appendChild(self.element);
		}
		self.element.hidden = false;
		if (self.model.windowWidth) {
			var margin = [((window.innerWidth - self.model.parent.offsetWidth) / 2 * -1),'px'].join('');
			self.element.style.marginLeft = margin;
			self.element.style.marginRight = margin;
		}
	};
	this.stop = function() {
		if (!self.model.parent) return;
		self.element.hidden = true;
		setTimeout(function(){
			self.element.style.marginLeft = '';
			self.element.style.marginRight = '';
		},100);
	};
	this.init = function(model) {
		self.model = model;
	};
	this.init(model);
}
;
/// <reference path="_references.js" />
//main fronend application namespace
window.Far = window.Far || {};

window.Far.Global = window.Far.Global || {
    /*
     {
         method: 'GET',
         url: '/url',
         headers: [{key, value}, ...],
         onSuccess: function(response),
         onError: function(),
         contentType: 'application/json',
         responseType: 'json',
         data: {},
         context: object
     }
     */
    jsonRequest: function(model) {
        if (typeof model.headers === 'undefined') {
            model.headers = [{ key: "FAR-Header", value: "REST" }];
        }
        //model.headers.push({ key: 'X-Referrer', value: document.URL });
        if (typeof model.onSuccess === 'undefined') {
            model.onSuccess = function() {};
        }
        if (typeof model.onError === 'undefined') {
            model.onError = function() {};
        }
        if (typeof model.contentType === 'undefined') {
            model.contentType = 'application/json; charset=utf-8';
        }
        if (model.contentType.indexOf('application/json') != -1) {
            model.responseType = 'json';
        }
        if (typeof localizationFn.localizeUrl === 'function') {
            model.url = localizationFn.localizeUrl(model.url, localizationFn.current);
        }
        var ajax = new XMLHttpRequest();
        ajax.open(model.method || 'GET', model.url, true);
        ajax.setRequestHeader('Content-Type', model.contentType);
        ajax.responseType = model.responseType;
        for (var i = 0; i < model.headers.length; i++) {
            ajax.setRequestHeader(model.headers[i].key, model.headers[i].value);
        }
        ajax.arguments = model;
        ajax.onload = function (e) {
            if (ajax.readyState === 4) {
                if (ajax.status === 200&&ajax.response) {
                    if (typeof this.arguments.context !== 'undefined') {
                        this.arguments.onSuccess.call(this.arguments.context, ajax.response);
                    }
                    else {
                        this.arguments.onSuccess(ajax.response);
                    }
                } else {
                    this.arguments.onError(ajax.response);
                }
            }
        };
        ajax.onerror = function (e) {
            console.error(ajax.statusText);
        };
        ajax.send(JSON.stringify(model.data));
        return ajax;
    },

    scripts: {
    	'urlCode': []
    },

	/*
	{
		url: 'url',
		urlCode: 'unique_script_name',
		callback: function,
		predicate: function indicate when script is loaded,
		context: object
	}
	*/
    appendScript: function () {
    	for (var i = 0; i < arguments.length; i++) {
    		var data = arguments[i],
                url, urlCode, callback, predicate, context;
    		if (typeof data === 'object') {
    			url = data.url;
    			urlCode = data.urlCode;
    			callback = data.callback;
    			predicate = data.predicate;
    			context = data.context;
    			if (predicate.call(context || window)) {
    				callback.call(context);
    				return;
    			}
    		}
    		else {
    			url = data;
    		}
    		if (typeof urlCode === 'undefined') {
    			urlCode = ['key', url.hashCode()].join('');
    		}
    		if (url.indexOf('build=') === -1) {
    			url = [url, window.Far.Version].join(url.indexOf('?') === -1 ? '?' : '&');
    		}
    		if (typeof window.Far.Global.scripts[urlCode] === 'undefined') {
    			window.Far.Global.scripts[urlCode] = [];
    		}
    		var len = window.Far.Global.scripts[urlCode].length,
				obj = {
					url: url,
					urlCode: urlCode,
					date: new Date().getTime(),
					callback: callback,
					predicate: predicate,
					context: context,
					counter: 100,
					waiter: function () {
						var scope = this;
						setTimeout(function () {
							scope.counter--;
							if (scope.predicate.call(scope.context || window)) {
								scope.callback.call(scope.context);
							}
							else
								if (scope.counter > 0) {
									scope.waiter();
								}
								else {
									//failed load
								}
						}, 50);
					}
				};

    		window.Far.Global.scripts[urlCode].push(obj);

    		if (len === 0) {
    			var f = document.getElementsByTagName('script')[0],
					j = document.createElement('script');
    			j.async = true;
    			j.src = url;
    			f.parentNode.insertBefore(j, f);
    		}
    		if (typeof callback !== 'undefined') {
    			obj.waiter();
    		}
    	}
    },

    appendStyle: function (href) {

        window.Far.Style({ href: href });
        return;
        console.error(1);
        var id = 'sss'+href.hashCode();
        if (document.getElementById(id)!=null) {
            alert(href);
            return;
        }
	    var doc = window.document;
	    var ss = doc.createElement("link");
        ss.id = id;
	    var refs = doc.getElementsByTagName("head")[0].childNodes;
	    var ref = refs[refs.length - 1];
	    var sheets = doc.styleSheets;
	    ss.rel = "stylesheet";
	    ss.href = href;
	    ss.media = "only x";
	    var l = sheets.length;
	    while (l--) {
	    	if (sheets[l].href === ss.href) {
		        console.log('href css exists ', href)
			    return;
		    }
	    }
		console.log('href css = ', href)
	    ref.parentNode.insertBefore(ss, ref.nextSibling);
	    var onloadcssdefined = function (cb) {
		    var resolvedHref = ss.href;
		    var i = sheets.length;
		    while (i--) {
			    if (sheets[i].href === resolvedHref) {
				    return cb();
			    }
		    }
		    setTimeout(function () {
			    onloadcssdefined(cb);
		    });
	    };
	    function loadCB() {
		    if (ss.addEventListener) {
			    ss.removeEventListener("load", loadCB);
		    }
		    ss.media = "all";
		    console.log('ss media load');
	    }
	    if (ss.addEventListener) {
		    ss.addEventListener("load", loadCB);
	    }
	    ss.onloadcssdefined = onloadcssdefined;
	    onloadcssdefined(loadCB);
	    return ss;
    }
};

;
/// <reference path="../../../../Scripts/_references.js" />

(function (impl) {

    impl.ControlHelpers = {
        enumerator: {
            id: 0,
            getId: function () {

                this.id++;
                return 'id' + this.id;
            }
        }
    };

    impl.Control = function (templateImpl, options, events, root) {

        this.containerId = options.containerId;  // ID - контейнера куда вставляем контролл
        this.name = options.name;                // Названия контролла
        this.childControlName = options.childControlName;

        this.templateImpl = templateImpl;
        this.template = new impl.Control.Templates.create(this, templateImpl);
        this.options = options;
        this.events = events;

        this.comparer = options.comparer;

        this.model = options.model || null;

        //контейнер
        this.dom = null;

        //контрол
        this.control = null;

        this.title = null;

        this.root = root || null;

        //елементы в контроле
        this.items = [];
        this.elements = {};

        //параметры аякс запроса
        this.ajaxOptions = options.ajax || null;

        this.initialized = false;
        this.rendered = false;
    };

    /// Добавляет новый контрол
    /// На этом этапе, контейнер под контрол должен быть уже в DOM-е
    impl.Control.prototype.addChild = function (control, id) {

        control.parent = this;

        if (typeof id !== 'undefined') {
            control.containerId = id;
        } else {
            control.containerId = [this.deepId(), '_', control.name, '_controlContainer'].join('');
        }
        control.init();
    };

    /// Добавляет новый контрол
    /// Создает контейнер под новый контрол, и добавляет его в конец
    impl.Control.prototype.appendChild = function (control) {
        var container = document.createElement('div');
        container.setAttribute('id', [this.deepId(), '_', control.name, '_controlContainer'].join(''));
        this.control.appendChild(container);
        this.addChild(control);
    };

    /// Id контрола, правила именование:
    ///
    impl.Control.prototype.deepId = function () {
        var id = this.name,
            p = this.parent;
        while (typeof p !== 'undefined') {
            id = p.name + '_' + id;
            p = p.parent;
        }
        return id;
    };

    impl.Control.prototype.addElement = function (item, field, n) {
        var context = this,
            name = n;
        item['get' + field] = function () {
            return document.getElementById([context.deepId(), '_', name].join(''));
        };
    };

    impl.Control.prototype.getItem = function (item) {

        if (typeof item === 'undefined') {

            return this.model[0];
        }
        for (var i = 0; i < this.model.length; i++) {

			if (Array.isArray(this.model[i])) {

				for (var j = 0; j < this.model[i].length; j++) {
					if (this.template.getId(this.model[i][j]) === this.template.getId(item)) {
						return this.model[i][j];
					}
				}
			}
			else if (this.template.getId(this.model[i]) === this.template.getId(item)) {
                return this.model[i];
            }
        }
        return item;
    };

    ///Инициализация контрола. Использовать надо на document.ready
    impl.Control.prototype.init = function () {

    	if (this.initialized) {

            return;
        }

        this.dom = document.getElementById(this.containerId);

        if (typeof this.options.classList !== 'undefined' && this.options.classList !== '') {
            var classList = this.options.classList.split(' ');
            for (var i = 0; i < classList.length; i++) {

                this.dom.classList.add(classList[i]);
            }
        }

        if (typeof this.options.title !== 'undefined') {
            this.title = document.createElement('h3');
            this.title.setAttribute('id', this.deepId() + '_controlTitle');
            this.title.classList = '';
            this.title.innerHTML = this.options.title;
        }

        this.control = document.createElement(this.template.tag);
        if (this.template.tag === 'table') {
            if (this.template.caption != null) {

                var thead = document.createElement('thead');
                var tr = document.createElement('tr');
                for (var i = 0; i < this.template.caption.length; i++) {
                    var td = document.createElement('th');
                    td.innerHTML = this.template.caption[i];
                    tr.appendChild(td);
                }
                thead.appendChild(tr);
                this.control.appendChild(thead);
            }
            var tbody = document.createElement('tbody');
            this.control.appendChild(tbody);
        }
        this.control.setAttribute('id', this.deepId());
        this.control.classList = [this.name || '', this.options.controlClassList || ''].join(' ');
        if (this.title != null) {
            this.dom.appendChild(this.title);
        }
        this.dom.appendChild(this.control);
        if (this.template.tag === 'table') {
            this.control = tbody;
        }

        this.initialized = true;
    };

    /// Ajax запрос на сервер
    impl.Control.prototype.jsonRequest = function () {

        if (this.ajaxOptions != null && typeof this.ajaxOptions.url !== 'undefined') {
            var ajax = new XMLHttpRequest();

            ajax.open(this.ajaxOptions.method || 'GET', this.ajaxOptions.url, true)
            ajax.setRequestHeader('Access-Token', '1F31C7D6-8E2C-4917-8FAD-36AA4F4690F0');
            ajax.setRequestHeader('Role-Token', '2FCB66F5-D533-4648-BB7A-BABBA23D6F03');
            ajax.arguments = this;
            ajax.onload = function (e) {
                if (ajax.readyState === 4) {
                    if (ajax.status === 200) {
                        var response = JSON.parse(this.responseText);
                        this.arguments.onAjaxSuccess(response);
                    } else {
                        console.error(ajax.statusText);
                    }
                }
            };
            ajax.onerror = function (e) {
                console.error(ajax.statusText);
            };

            ajax.send([this.ajaxOptions.data]);
        }
    };

    /// Обработчик получения данных Ajax запросом.
    impl.Control.prototype.onAjaxSuccess = function (response) {

        this.render(this.responseConverter(response));
    };

    ///Метод рендера контрола
    impl.Control.prototype.render = function (model) {
        if (this.rendered) {
            console.error('Control has been rendered',this);
            return;
        }
        if (typeof model === 'undefined') {
            this.jsonRequest();
            return;
        }

        //console.time('render-' + this.deepId() + '-' + this.name);
        this.model = model;
        for (var i = 0; i < model.length; i++) {
            var html = this.template.render(model[i], model),
                id = this.template.getId(model[i]);
            this.control.insertAdjacentHTML('beforeEnd', html);
            this.items.push(document.getElementById(id));
        }
        //console.timeEnd('render-' + this.deepId() + '-' + this.name);

        this.setModel(model);

        this.onRendered(this.items);

        this.rendered = true;
    };

    impl.Control.prototype.setModel = function(model) {

        this.model = model;
    };

    /// Ф-ция рендера контрола с указанием контейнера.
    /// <returns>Результатом работы будет срендереный контрол и возвращена ссылка на созданый обьект</returns>
    impl.Control.prototype.renderTo = function (id, model) {

        var options = this.options;
        options.containerId = id;
        var control = new impl.Control(this.templateImpl, options, this.events);
        control.init();
        control.render(model);
        return control;
    };

    ///
    impl.Control.prototype.appendTo = function(containerId, model) {

        this.containerId = containerId;
        this.init();
        this.dom = this.control;
        this.render(model || this.model);
        return this;
    };

    ///Добавляет элемент в коллекцию
    /// <param name="poistion">Позиция в которую необходимо вставить новый элемент. В начало - "afterbegin" или в конец - "beforeend"</param>
    ///метод всегда вызывает собитие onRendered, параметром в который передает новый нод
    impl.Control.prototype.add = function (position, item) {

        var html = this.template.render(item);
        this.control.insertAdjacentHTML(position, html);
        var newNode = document.getElementById(this.template.getId(item));
        this.items.push(newNode);

        this.onRendered([newNode]);
    };

    ///Удаляет элемент из коллекции
    /// <param name="item">Модель на удаление, обязательно должно быть указано поле, с которого строилось id. Например {id: 1}</param>
    impl.Control.prototype.remove = function (item) {

        var id = this.template.getId(item);
        document.getElementById(id).remove();

        for (var i = 0; i < this.items.length; i++) {

            if (this.items[i].id === id) {

                this.items.splice(i, 1);
                break;
            }
        }
    };

    ///Обновляет элемент коллекции
    /// <param name="item">Новая модель, которую надо обновит в DOM. В модели надо указывать все поля.</param>
    ///
    impl.Control.prototype.update = function (item) {

        var id = this.template.getId(item),
            oldNode = document.getElementById(id),
            html = this.template.render(item),
            newNode = document.createElement('div');
        newNode.innerHTML = html;
        this.control.replaceChild(newNode.childNodes[0], oldNode);
        var updatedNode = document.getElementById(id);
        for (var i = 0; i < this.items.length; i++) {
            if (this.items[i].id === id) {
                this.items[i] = updatedNode;
                break;
            }
        }
        this.onRendered([updatedNode]);
    };

    /// Обновляет весь элемент, очищает и заново перестраивает коллекцию
    impl.Control.prototype.refresh = function (model) {

    	if (this.compareModel(model)) {

            return;
        }
        this.clear();
        this.rendered = false;
        this.render(model);
    };

    ///Конвертация респонса в модель шаблона
    impl.Control.prototype.responseConverter = function (response) {
        if (this.ajaxOptions !== null && typeof this.ajaxOptions.responseConverter !== 'undefined') {
            return this.ajaxOptions.responseConverter(response);
        }
        return response;
    };

    ///Событие добаления/изменения/удаления строк
    impl.Control.prototype.onRendered = function (items) {
        if (typeof this.events.onRendered !== 'undefined') {
            this.events.onRendered.call(this, items);
        }
    };

    ///Очищает контрол, контейнер остается
    impl.Control.prototype.clear = function () {
        this.items = [];
        this.control.innerHTML = '';
    };

    ///Удаляет контрол, контейнер остается
    impl.Control.prototype.removeControl = function () {
        this.items = [];
        if (this.control !== null) {
            this.control.innerHTML = '';
            this.control.remove();
        }
        this.initialized = false;
        this.rendered = false;
    };

    ///Убивает контрол, возвращает в начальное состояние
    impl.Control.prototype.destroy = function () {
        this.clear();
        this.dom.remove();
        this.dom = null;
        this.control = null;
        this.initialized = false;
        this.rendered = false;
    };

    impl.Control.prototype.lock = function () {

        
    };

    impl.Control.prototype.unlock = function () {

    };

    impl.Control.prototype.compareModel = function(options) {
    	if (typeof this.comparer === 'undefined') {
		    return false;
	    }
		if (this.model === null) {
			return false;
		}
    	var len = this.model.length;
    	if (len !== options.length) {
		    return false;
	    }
        for (var i = 0; i < len; i++) {
	        if (!this.comparer(this.model[i], options[i])) {
		        return false;
	        }
        }
        return true;
    };
})(Far.Impl);



/*

var body = document.getElementById('body');
body.innerHTML = '';
var el = document.createElement('div');
el.id = 'townFromDd';
body.appendChild(el);

var o = new Far.impl.Control(
            Far.impl.ControlsType.liSimple,
            {
                //containerId: 'table',
                name: 'townFrom',
                classList: 'table table-bordered',
                ajax: {
                    url: 'https://testapi.farvater.travel/dic/cityFrom/',
                    method: 'GET',
                    data: {},
                    responseConverter: function(response) {

                        return response.data;
                    }
                }
            },
            {
                onRendered: function(items) {

                    for (var i = 0; i < items.length; i++) {

                        items[i].addEventListener('click',
                            function() {
                                alert(this.id);
                            },
                            false);
                    }
                }
            }
        );
        var buttons = new Far.impl.Control(
            Far.impl.ControlsType.searchFormDropdownButtons,
            {
                name: 'searchFormDropdownButtons',
                classList: ''
            },
            {
                onRendered: function(items) {

                    
                }
            }
        );

        var dd = new Far.impl.Control(
            Far.impl.ControlsType.searchFormDropdown,
            {
                containerId: 'townFromDd',
                name: 'townFrom',
                classList: ''
            },
            {
                onRendered: function(items) {

                    dd.addChild(o);
                    o.render();

                    dd.addChild(buttons);
                    buttons.render([{id:'apply', name:'Apply'},{id:'reset', name:'Reset'}])
                }
            }
        );
        dd.init();
        dd.render([{}]);

 */

;
/// <reference path="../../../../Scripts/_references.js" />

(function (impl) {
    /// Шаблоны
    impl.Templates = {

        getId: function (item) {
            return [this.control.deepId(), '_', item.id].join('');
        },
        getKey: function (item) {
            return item.id;
        },
        getValue: function (item) {
            return item.name;
        },

        searchFormControl: {
            tag: 'div',
            render: function (item) {
                var id = this.getId(item),
                    name = this.control.name,
                    placeholder = item.placeholder,
                    icon = item.icon,
                    arrow = item.arrow,
                    label = item.label,
                    childControlName = this.control.childControlName;

                this.control.addElement(item, 'Label', 'label');
                this.control.addElement(item, 'Placeholder', "label_placeholder");

                return [
                    '<div id="', id, '" class="SearchForm__control__label ', item.classList, '">',
                        (typeof icon !== 'undefined' && icon.length
                            ?
                            '<div id="'+ id+ '_icon" class="SearchForm__control__icon">' + (item.iconTitle || '') + icon + '</div>'
                            :
                            ''
                        ),
                        (typeof label !== 'undefined' && label.length  && item.mobile
                        ?
                        '<span id="'+ id+ '_name" class="SearchForm__control__span">'+ label+'</span>'
                        : ''), 
                        '<span id="', id, '_placeholder" class="SearchForm__control__placeholder">', placeholder,
                        '</span>',
                         '<div id="', id, '_arrow" class="SearchForm__control__arrow">', arrow,
                        '</div>',
                    '</div>'
                ].join('');
            }
        },
        dropdownControl: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId(),
                    placeholder = item.placeholder,
                    childControlName = this.control.childControlName;

                this.control.addElement(item, 'Button', 'btn');
                this.control.addElement(item, 'Placeholder', 'placeholder');

                return [
                        '<button id="', id, '_btn" class="b btn-default dropdown-toggle"><span id="', id, '_placeholder" class="placeholder"></span><span><svg width="10" height="5" viewBox="0 0 10 5" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.84615 0L5 3.07692L1.15385 0L0 1.15385L5 5.38462L10 1.15385L8.84615 0Z" fill="#9E9E9E"/></svg></span></button>',
                ].join('');
            },
            each: function(items) {
            }
        },
        simpleNights: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId(),
                    placeholder = item.placeholder,
                    childControlName = this.control.childControlName;

                this.control.addElement(item, 'SelectFrom', 'select_from');
                this.control.addElement(item, 'SelectTill', 'select_till');
                this.control.addElement(item, 'Options', 'options');
                this.control.addElement(item, 'OptionBtn', 'option_btn');

                this.control.addElement(item, 'Select6_8', 'select_6_8');
                this.control.addElement(item, 'Select9_11', 'select_9_11');
                this.control.addElement(item, 'Select12_14', 'select_12_14');

                function renderOptions(name) {
                    return '<option>' + name + '</option>';
                }

                var options = [];
                for (var i = 1 ; i < 16; i++) {
                    options.push(renderOptions(i));
                }
                return [
                        '<ul class="simple_nights_select">',
                            '<li  id="', id, '_select_6_8" model="6/8">6 - 8</li>',
                            '<li  id="', id, '_select_9_11"  model="9/11">9 - 11</li>',
                            '<li  id="', id, '_select_12_14"  model="12/14">12 - 14</li>',
                            '<li  id="', id, '_option_btn"><span><svg width="15" height="10" viewBox="0 0 10 5" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.84615 0L5 3.07692L1.15385 0L0 1.15385L5 5.38462L10 1.15385L8.84615 0Z" fill="#9E9E9E"></path></svg></span></li>',
                        '</ul>',
                        '<div  id="', id, '_options" class="simple_nights_options">',
                            '<div class="simple_nights_options_from">',
                                '<label> От </label>',
                                '<select id="', id, '_select_from"  id="from_select">',
                                   options.join(''),
                                '</select>',
                            '</div>',
                            '<div class="simple_nights_options_till">',
                                '<label>До </label>',
                                '<select id="', id, '_select_till">',
                                   options.join(''),
                                '</select>',
                            '</div>',
                        '</div>'
                ].join('');
            },
            each: function (items) {
            }
        },
        searchFormDropdown: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId(),
                    name = this.control.name,
                    label = item.label,
                    childControlName = this.control.childControlName,
                    options = item.options || {};

                //console.log(id, options);

                this.control.addElement(item, 'Dropdown', 'dropdown');
                this.control.addElement(item, 'Content', 'content');
                this.control.addElement(item, 'Input', 'input');
                this.control.addElement(item, 'HeaderRightSide', 'headerRightSide');
                this.control.addElement(item, 'Clear', 'clear');
                return [
                    '<div id="', this.getId(item), '" class="SearchForm__control__dropdown">',
                        '<div id="', id, '_header" class="SearchForm__control__dropdown__header">',
							(item.mobile ?
                            ['<div id="', id, '_header_closer" class="SearchForm__control__dropdown__header__closer">',
                                '<svg width="17" height="9" viewBox="0 0 17 9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.0687 3.6H3.32177L6.54419 1.548L6.55661 1.536C6.91673 1.188 6.91673 0.612 6.55661 0.264C6.38276 0.096 6.14682 0 5.89847 0C5.65632 0 5.42038 0.09 5.24653 0.258L0.291819 3.852L0.273192 3.864C0.0993426 4.032 0 4.26 0 4.5C0 4.74 0.0993426 4.968 0.273192 5.136L0.279401 5.142L5.24653 8.742C5.42038 8.91 5.65011 9 5.89847 9C6.14682 9 6.38276 8.904 6.55661 8.736C6.91673 8.388 6.91673 7.812 6.55661 7.464L6.54419 7.452L3.32177 5.4H16.0687C16.584 5.4 17 4.998 17 4.5C17 4.002 16.584 3.6 16.0687 3.6Z" fill="#333333"/></svg>',
                                '<span>', label, '</span>',
                                '<span id="', id, '_headerRightSide"></span>',
                            '</div>'].join('') : [
                                label ? ['<div class="SearchForm__control__dropdown__header__title"><span>', label, '</span></div>'].join('') : ''
                            ].join('')),
                        '</div>',
                        (options.enableInput ?
                        '<div class="SearchForm__control__dropdown__input_block">'
                            +
                                '<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18.5472 18.3927L13.217 12.8494C14.5765 11.4859 15.4188 9.60618 15.4188 7.53313C15.4188 3.37915 12.0397 0 7.88567 0C3.73169 0 0.352539 3.37915 0.352539 7.53313C0.352539 11.6871 3.73169 15.0663 7.88567 15.0663C9.70905 15.0663 11.3825 14.4145 12.6868 13.3329L18.0299 18.8899C18.1002 18.9634 18.1942 19 18.2886 19C18.3783 19 18.4676 18.9666 18.5372 18.8999C18.6799 18.7625 18.6842 18.5355 18.5472 18.3927ZM7.88567 14.3488C4.12736 14.3488 1.06998 11.2915 1.06998 7.53313C1.06998 3.77482 4.12736 0.717441 7.88567 0.717441C11.644 0.717441 14.7014 3.77482 14.7014 7.53313C14.7014 11.2915 11.6436 14.3488 7.88567 14.3488Z" fill="#A0A0A0"/></svg>'
                            +
                                '<input id="' + id + '_input" class="SearchForm__control__dropdown__input" type="text" placeholder="' + options.inputPlaceholder + '">'
                            +
                        '</div>'
                        :
                        ''),
                        '<div id="', id, '_content" class="SearchForm__control__dropdown__content">',
                            '<div id="', id, '_content_header" class="SearchForm__control__dropdown__content__header">',
                                (options.clear ? ['<div id="', id,'_clear" class="clear_form_v2"><a href="#">Очистити</a></div>'] : []).join(''),
                            '</div>',
                            '<div id="', id, '_', childControlName, '_controlContainer" class="SearchForm__control__dropdown__content__content">',
                            '</div>',
                            '<div id="', id, '_content_footer" class="SearchForm__control__dropdown__content__footer">',
                            '</div>',
                        '</div>',
                        '<div id="', id, '_buttons_controlContainer" class="SearchForm__control__dropdown__footer">',
                        '</div>',
                    '</div>',
                ].join('');
            }
        },
        searchFormDropdownButtons: {
            tag: 'div',
            render: function (item) {
                var id = this.getId(item);
                return [
                    '<button id="', id, '" class="btn ', item.classList, '">', item.name, '</button>',
                ].join('');
            }
        },
        searchFormTouristsDropdown: {
            tag:'div',
            render: function (item) {
                var id = this.control.deepId();


                this.control.addElement(item, 'KidsContainer', 'kids_container');

                return [
                    '<div class="tourist_control_item">',
                        '<div class="tourist_control_title">',
                            '<span>', item.adultTitle, '</span>',
                            '<span>', item.adultText, '</span>',
                        '</div>',
                        '<div id="', id, '_select_adult_controlContainer" class="tourist_control_select_adult" >',
                        '</div>',
                    '</div>',
                    '<div class="tourist_control_item">',
                        '<div class="tourist_control_title">',
                            '<span>', item.kidTitle, '</span>',
                            '<span>', item.kidText, '</span>',
                        '</div>',
                        '<div id="', id, '_select_kid_controlContainer" class="tourist_control_select_kid">',
                        '</div>',
                    '</div>',
                    '<div id="', id, '_kids_container" class="tourist_control_container">',
                        '<div class="tourists_kids_container_title">', localizationValues.enter_kids_ages, '</div>',
                        '<div class="tourists_kids_container_Ages">',
                            '<div id="', id, '_select_age_1_controlContainer" class="tourist_control_select_age ">',
                            '</div>',
                            '<div id="', id, '_select_age_2_controlContainer" class="tourist_control_select_age ">',
                            '</div>',
                            '<div id="', id, '_select_age_3_controlContainer" class="tourist_control_select_age ">',
                            '</div>',
                            '<div id="', id, '_select_age_4_controlContainer" class="tourist_control_select_age ">',
                            '</div>',
                        '</div>',
                    '</div>'
                ].join('');
            }
        },
        calendarBlock: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId();

                this.control.addElement(item, 'CalendarPlaceholder', 'calendarPlaceholder');
                this.control.addElement(item, 'PrevButton', 'prev_button');
                this.control.addElement(item, 'NextButton', 'next_button');
                this.control.addElement(item, 'Checkbox', 'checkbox');
                this.control.addElement(item, 'Range', 'range');
                this.control.addElement(item, 'FromRangeButton', 'from_range_button');
                this.control.addElement(item, 'TillRangeButton', 'till_range_button');
                function renderFooter() {
                    var footerHtml = [];
                    footerHtml.push('<div class="callendarPanel__footer">');
                        if (item.type === 'RangeCheckbox') {
                            footerHtml.push('<button id="', id, '_checkbox" class="btn"><span data-icon="radio-unchecked" class="callendarPanel__footer__icon ', (item.checkboxActive ? '__active' : ''), '"></span><span>+/-', item.checkboxDays, ' ', LL.getMethering('days', item.checkboxDays),'</span></button>');
                            footerHtml.push('<button id="', id, '_range" class="btn"><span data-icon="radio-unchecked" class="callendarPanel__footer__icon"></span><span>', localizationValues.range, '</span></button>');
                        } else if (item.allowCheckbox) {
                            footerHtml.push([
                                '<label id="', id, '_checkbox" class="formControl __checkbox ', (item.checkboxActive ? '__active' : ''), '">',
                                    '<span class="formControl__label">+/-', item.checkboxDays, ' ', LL.getMethering('days', item.checkboxDays), '</span>',
                                '</label>'].join('')
                                )
                        }
                        footerHtml.push('</div>');
                        return footerHtml.join('')
                }

                return [
                    '<div class="callendarPanel">',
                     '<header class="callendarPanel__header">',
                       '<a id="', id, '_prev_button" class="callendarPanel__nav __prev ', item.prevButtonDisable ? 'disable' : '', '"></a>',
                       '<b id="', id, '_calendarPlaceholder" >', item.monthName, ' ' , item.year, '</b>',
                       '<a  id="', id, '_next_button" class="callendarPanel__nav __next ', item.nextButtonDisable ? 'disable' : '', '"></a>',
                     '</header>',
                     '<div id="', id, '_calendarTable_controlContainer" class="callendarPanel__body">',
                     '<button id="', id, '_from_range_button" class="calendarSelector"><span></span></button>',
                     '<button id="', id, '_till_range_button" class="calendarSelector"><span></span></button>',
                     '</div>',
                        (renderFooter()),
                    '</div>'
                ].join('');
            }
        },
        calendarTable: {
            tag: 'table',
            caption: [localizationValues.week_day_short_1, localizationValues.week_day_short_2, localizationValues.week_day_short_3, localizationValues.week_day_short_4, localizationValues.week_day_short_5, localizationValues.week_day_short_6, localizationValues.week_day_short_7],
            render: function (item) {
                var self = this;
                function renderTd(td) {
                    var id = self.getId(td);
                    self.control.addElement(td, 'Cell', td.id);
                    return ['<td id="', id, '" value="', td.id, '" class="', (td.disabled === true ? '__disabled ' : ''), (td.hasStatistic === true ? ' __statistic' : ''), '"><span>', td.name, '<span></td>'].join('');
                }
                var slices = [];
                slices.push('<tr>');
                for (var i = 0; i < item.length; i++) {
                    slices.push(renderTd(item[i]));
                }
                slices.push('</tr>');
                return slices.join('');
            }
        },
        nightsRange: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId();
                var self = this;
                this.control.addElement(item, 'Placeholder', "placeholder");
                this.control.addElement(item, 'FirstRangeInput', "first_range_input");
                this.control.addElement(item, 'SecondRangeInput', "second_range_input");

                this.control.addElement(item, 'LeftRangeButton', "left_range_button");

                this.control.addElement(item, 'RightRangeButton', "right_range_button");

                this.control.addElement(item, 'SelectedRange', "selected_range");

                this.control.addElement(item, 'LeftRangeInverse', "left_range_inverse");

                this.control.addElement(item, 'RightRangeInverse', "right_range_inverse");

                function renderLabels(label) {
                    var id = self.getId(label);
                    self.control.addElement(label, 'Label', label.id);
                    return ['<li id="', id, '" value="', label.id, '"><span>', label.name, '</span></li>'].join('');
                }
                var slices = [];

                slices.push('<div class="dates_nights_label">');
                    slices.push('<span>' + localizationValues.count_of_night + ': </span>');
                    slices.push('<span id="', id, '_placeholder" class="dates_nights_placeholder"></span>');
                slices.push('</div>');
                slices.push('<div class="dates_nights_range">');
                    slices.push('<div>');
                        slices.push('<div  id="', id, '_left_range_inverse" class="inverse-left" ></div>');
                        slices.push('<div  id="', id, '_right_range_inverse" class="inverse-right" ></div>');
                        slices.push('<div  id="', id, '_selected_range" class="range" ></div>');
                        slices.push('<span  id="', id, '_left_range_button" class="thumb" ></span>');
                        slices.push('<span id="', id, '_right_range_button" class="thumb" ></span>');
                            slices.push('<ul class="ticks">');
                                for (var i = 0; i < item.labels.length; i++) {
                                    slices.push(renderLabels(item.labels[i]));
                                }
                            slices.push('</ul>');
                        slices.push('<input id="', id, '_first_range_input" type="range" class="dates_nights_range_input" tabindex="0"  max="15" min="1" step="1" >');
                        slices.push('<input id="', id, '_second_range_input" type="range" class="dates_nights_range_input" tabindex="0"  max="15" min="1" step="1" >');
                    slices.push('</div>');
                slices.push('</div>');
                return slices.join('');
            }
        },
        destinationSimpleBlock: {
            tag: 'div',
            render: function (item) {
                if (typeof item.model == 'undefined' || item.model.length == 0) return [];
                var label = item.label;
                var self  = this;
                function renderli(item) {
                    var id = self.getId(item);
                    self.control.addElement(item, 'ListItem', item.id);
                    self.control.addElement(item, 'StatisticItem', item.id + '_statistic');
                    return ['<li id="', id, '" value="', item.id, '">', (typeof item.alpha2 !== 'undefined' ? '<img src="/img/flags/' + item.alpha2 + '.png" alt="'+ item.name+ '" />' : ''), '<span>', item.name, '</span><span id="', self.control.deepId(), '_', item.id, '_statistic"  class="tours_statistic_item"><span></li>'].join('');
                }
                var html = [];
                for (var i = 0 ; i < item.model.length; i++) {
                    html.push(renderli(item.model[i]));
                }

                return [
                    //2023-03-30//'<div class="destination_block_title">', label, '</div>',
                    '<ul>',
                        html.join(''),
                    '</ul>'
                ].join('');
            }
        },
        destinationCheckboxBlock: {
            tag: 'div',
            render: function (item) {
                if (typeof item.model == 'undefined' || item.model.length == 0) return [];
                var self = this;
                function renderli(item) {
                    var id = self.getId(item);
                    self.control.addElement(item, 'ListItem', item.id);
                    self.control.addElement(item, 'Li', item.id + '_li');
                    self.control.addElement(item, 'StatisticItem', item.id + '_statistic');
                    return [
                        '<li id="', self.control.deepId(), '_', item.id, '_li">',
                            '<label id="', id, '"  class="formControl __checkbox " value="', item.id, '">',
                                '<span class="formControl__label">',
                                    (typeof item.alpha2 != 'undefined' ? '<img src="/img/flags/' + item.alpha2 + '.png" alt="' + item.name + '" />' : ''),
                                     '<span>', item.name, '</span>',
                                     '<span id="', self.control.deepId(), '_', item.id, '_statistic" class="tours_statistic_item"><span>',
                                '</span>',
                            '</label>',
                            (typeof item.helper != 'undefined' ? '<span class="li_helper">' + item.helper + '</span>' : ''),
                        '</li>'
                    ].join('');
                }
                var html = [];
                if (typeof item.model != 'undefined') {
                    for (var i = 0 ; i < item.model.length; i++) {
                        html.push(renderli(item.model[i]));
                    }
                }
                return [
                    '<div class="destination_block_title">',item.label,'</div>',
                    '<ul>',
                        html.join(''),
                    '</ul>'
                ].join('');
            }
        },
        emptyBlock: {
            tag: 'div',
            render: function (item) {
                return '';
            }
        },
        blockWithChild: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId(),
                   childControlName = this.control.childControlName,
                   label = item.label;
                this.control.addElement(item, 'Placeholder', "placeholder");
                return [
                    '<div id="', id, '_placeholder"  class="simple_label">', label, '</div>',
                    '<div id="', id, '_', childControlName, '_controlContainer"></div>'
                ].join('');
            }
        },
        blockWithInput: {
            tag: 'div',
            render: function (item) {
                var id = this.control.deepId(),
                   childControlName = this.control.childControlName,
                   label = item.label;
                this.control.addElement(item, 'Placeholder', "placeholder");
                this.control.addElement(item, 'Input', "input");
                return [
                    '<div id="', id, '_placeholder"  class="simple_label">', label, '</div>',
                    '<div class="simple_input">',
                        (item.enableIcon 
                        ?
                            '<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18.5472 18.3927L13.217 12.8494C14.5765 11.4859 15.4188 9.60618 15.4188 7.53313C15.4188 3.37915 12.0397 0 7.88567 0C3.73169 0 0.352539 3.37915 0.352539 7.53313C0.352539 11.6871 3.73169 15.0663 7.88567 15.0663C9.70905 15.0663 11.3825 14.4145 12.6868 13.3329L18.0299 18.8899C18.1002 18.9634 18.1942 19 18.2886 19C18.3783 19 18.4676 18.9666 18.5372 18.8999C18.6799 18.7625 18.6842 18.5355 18.5472 18.3927ZM7.88567 14.3488C4.12736 14.3488 1.06998 11.2915 1.06998 7.53313C1.06998 3.77482 4.12736 0.717441 7.88567 0.717441C11.644 0.717441 14.7014 3.77482 14.7014 7.53313C14.7014 11.2915 11.6436 14.3488 7.88567 14.3488Z" fill="#A0A0A0"/></svg>'
                        :
                            ''
                        ),
                        '<input id="', id, '_input" type="text" placeholder="', item.options.inputPlaceholder, '" />',
                    '</div>',
                    '<div id="', id, '_', childControlName, '_controlContainer"></div>'
                ].join('');
            }
        },
        contentBlock: {
            tag: 'div',
            render: function (item) {
                return (typeof item.content !== 'undefined' ? item.content : '');
            }
        },
        titleBlock: {
            tag: 'div',
            render: function (item) {
                return (typeof item.content !== 'undefined' ? ['<div class="destination_block_title">', item.content, '</div>'].join('') : '');
            }
        },
        liSimple: {
            tag: 'ul',
            render: function (item) {
                return [
                    '<li id="', this.getId(item), '" value="', this.getKey(item), '">', this.getValue(item), '</li>'
                ].join('');
            }
        },
        cityFrom: {
            tag: 'ul',
            /** @typedef {{
             *  id: number; 
             *  name: string; 
             *  code: string; 
             *  town: string; 
             *  countryId: number; 
             *  countryName: string; 
             *  countrySort: number;
             * }} CityFrom
             */
            /** @param {CityFrom} city
             *  @param {CityFrom[]} cities */
            render: function (city, cities) {
                var result = [];
                var prev = null;
                for (var i = 0; i < cities.length; i++) {
                    var item = cities[i];
                    if (item.id === city.id) {
                        if (prev !== item.countryId && item.countryId !== 255) {
                            result.push('<li class="MainForm_CityFrom_dropdown_list_countryName">', item.countryName, '</li>');
                        }
                        result.push('<li id="', this.getId(item), '" value="', this.getKey(item), '">', this.getValue(item), '</li>');
                        break;
                    }
                    prev = item.countryId;
                }
                return result.join('');
            }
        },
        cityFromSimpleBlock: {
            tag: 'div',
            render: function (item, items) {
                if (typeof item.model == 'undefined' || item.model.length == 0) return [];
                var label = item.label;
                var self = this;
                function renderli(item) {
                    var id = self.getId(item);
                    self.control.addElement(item, 'ListItem', item.id);
                    return [
                        '<li id="', id, '" data-value="', item.id, '">',
                        '<span data-value="', item.id, '">', item.name, '</span>',
                        '</li>'].join('');
                }
                var html = [];
                var prev = null;
                for (var i = 0; i < item.model.length; i++) {
                    if (prev !== item.model[i].countryId && item.model[i].countryId !== 255) {
                        html.push('<li class="MainForm_CityFrom_dropdown_list_countryName">', item.model[i].countryName, '</li>');
                    }
                    html.push(renderli(item.model[i]));
                    
                    prev = item.model[i].countryId;
                }

                return [
                    //2023-03-30//'<div class="destination_block_title">', label, '</div>',
                    '<ul>',
                    html.join(''),
                    '</ul>'
                ].join('');
            }
        },
        cityFromCheckedBlock: {
            tag: 'div',
            render: function (item, items) {
                if (typeof item.model == 'undefined' || item.model.length == 0) return [];
                var label = item.label;
                var self = this;
                function renderli(item) {
                    var id = self.getId(item);
                    self.control.addElement(item, 'ListItem', item.id);
                    return [
                        '<li id="', id, '" value="', item.id, '">',
                        '<label class="formControl __checkbox __active">',
                        '<span class="formControl__label"><span>', item.name, '</span></span>',
                        '</label>',
                        '</li>'].join('');
                }
                var html = [];
                for (var i = 0; i < item.model.length; i++) {
                    html.push(renderli(item.model[i]));
                }
                return [
                    '<div class="destination_block_title">', 'Вибрано', '</div>',
                    '<ul>',
                    html.join(''),
                    '</ul>'
                ].join('');
            }
        },
        checkboxSimple: {
            tag: 'ul',
            render: function (item) {
	            var id = this.control.deepId();
	            this.control.addElement(item, 'LabelCheckbox', item.id + '_checkbox');
	            this.control.addElement(item, 'LiCheckbox', item.id);
                return [
                     '<li id="', this.getId(item), '">',
                        '<label id="', id, '_', item.id, '_checkbox"  class="formControl __checkbox ', item.checked ? '__active' : '', '">',
                            '<span class="formControl__label">', this.getValue(item), '</span>',
                        '</label>',
                    '</li>'
                ].join('');
            }
        },
        checkboxTree: {
            tag: 'ul',
            render: function (item) {
                var id = this.control.deepId(),
                    self = this;
                function renderLi(itemInside) {
                    self.control.addElement(itemInside, 'ResortLiCheckbox', itemInside.id + '_resort_li');
                    self.control.addElement(itemInside, 'ResortLabelCheckbox', itemInside.id, '_resort_label');
                    return [
                    '<li id="', id, '_', itemInside.id, '_resort_li" >',
                       '<label id="', id, '_', itemInside.id, '_resort_lable"  class="formControl __checkbox">',
                           '<span class="formControl__label">', self.getValue(itemInside), '</span>',
                       '</label>',
                   '</li>'
                    ].join('');
                }
                this.control.addElement(item, 'LabelCheckbox', item.id + '_checkbox');
                this.control.addElement(item, 'LiCheckbox', item.id);
                var resortHtml = [];
                for (var i = 0 ; i < item.resorts.length; i++) {
                    resortHtml.push(renderLi(item.resorts[i]));
                }
                return [
                     '<li id="', this.getId(item), '">',
                        '<label id="', id, '_', item.id, '_checkbox"  class="formControl __checkbox">',
                            '<span class="formControl__label">', this.getValue(item), '</span>',
                        '</label>',
                    '</li>',
                    '<ul class="inserted_list">',
                           resortHtml.join(''),
                     '</ul>',
                ].join('');
            }
        },
        checkboxSimpleWithStatistic: {
            tag: 'ul',
            render: function (item) {
                var id = this.control.deepId();
                this.control.addElement(item, 'LabelCheckbox', item.id + '_checkbox');
                this.control.addElement(item, 'LiCheckbox', item.id);
                this.control.addElement(item, 'StatisticItem', item.id + '_statistic');
                return [
                     '<li id="', this.getId(item), '">',
                        '<label id="', id, '_', item.id, '_checkbox"  class="formControl __checkbox">',
                            '<span class="formControl__label"><span>', this.getValue(item), '</span>',
                            '<span id="', id, '_', item.id, '_statistic" class="tours_statistic_item"></span>',
                            '</span>',
                        '</label>',
                    '</li>'
                ].join('');
            }
        },
        optionSimple: {
            tag: 'select',
            render: function (item) {
                return [
                    '<option id="', this.getId(item), '" value="', this.getKey(item), '">', this.getValue(item), '</option>'
                ].join('');
            }
        },

        trSimple: {
            tag: 'table',
            render: function (item) {
                return [
                    '<tr id="', this.getId(item), '">',
                    '<td>', this.getKey(item), '</td>',
                    '<td>', this.getValue(item), '</td>',
                    '</tr>'
                ].join('');
            }
        },

        create: function (control, template) {

            this.control = control;
            this.name = template.name;


            this.tag = template.tag;
            this.caption = template.caption || null;
            this.title = template.title || null;

            this.render = template.render;
            this.getId = template.getId || impl.Templates.getId;
            this.getKey = template.getKey || impl.Templates.getKey;
            this.getValue = template.getValue || impl.Templates.getValue;
        }
    };
})(window.Far.Impl.Control);

;
/// <reference path="../../../../Scripts/_references.js" />
(function (impl) {
    impl.DropdownPanel = function (id, allowClickBehind) {
        var self = this;
        var state = {
            open: false
        };
        this.settings = {
            dropdownDom: (typeof id.id !== 'undefined' ? id : document.getElementById(id)),
            id: (id instanceof HTMLElement ? id.id : id),
            html: document.querySelector('html'),
            allowClickBehind: allowClickBehind || false // Если значения равно true, то клик за пределы дропдауна будет разрешен
        };
        this.onCloseCallback = null;
        this.onOpenCallback = null;
        this.toggle = function () {
            if (state.open) {
                self.close();
            }
            else {
                self.open();
            }
        };
        var ParentId = null;
        this.getParentId = function() {
            if (ParentId) return ParentId;
            ParentId = self.settings.id.split('_')[0];
            return self.getParentId();
        };
        this.open = function () {
            if (state.open) return;
            self.settings.dropdownDom.classList.add('__active');
            if (deviceConfig.type === 'Mobile') {
                window.Far.Layout.noScroll.add();
            }
            state.open = true;
            var Parent = document.getElementById(self.getParentId());
            if (!isset(Parent.hasOpenedControl)) Parent.hasOpenedControl = 0;
            Parent.hasOpenedControl++;
            Parent.classList.add('__hasOpenedControl');
            /*
                Events
                Добавляем событие асинхронно
            */
            window.requestAnimationFrame(function () {
                var header = self.settings.dropdownDom.querySelector('.SearchForm__control__dropdown__header__closer');

                window.clickEventsList.add(self.settings.id, self, function (e, context) {
                    var isClickInside = self.settings.dropdownDom.contains(e.target);
                    if (!isClickInside && !self.settings.allowClickBehind) {
                        self.close();
                    }

                });
                if (header !== null) {
                    header.addEventListener(farDocument.clickEventName(), function (e) {
                        if (e.stopImmediatePropagation) {
                            e.stopImmediatePropagation();
                        }
                        e.preventDefault();
                        e.stopPropagation();
                        self.close();
                    });
                }
                window.keydownEventsList.add(self.settings.id, self, function (e, context) {
                    if (e.keyCode == 27) {
                        self.close();
                    }
                });

            });

            if (this.onOpenCallback != null) {
                this.onOpenCallback();
            }
        };

        this.close = function () {
            if (!state.open) return;
            self.settings.dropdownDom.classList.remove('__active');
            if (deviceConfig.type === 'Mobile') {
                window.Far.Layout.noScroll.remove();
            }
            state.open = false;
            var Parent = document.getElementById(self.getParentId());
            Parent.hasOpenedControl--;
            if (!Parent.hasOpenedControl) {
                Parent.classList.remove('__hasOpenedControl');
            }
            /*Events*/


            window.clickEventsList.remove(self.settings.id);
            //window.clickEventsList.remove(header.id);

            window.keydownEventsList.remove(self.settings.id);

            if (this.onCloseCallback !== null) {
                this.onCloseCallback();
            }
        };
        this.getState = function () {
            return Object.assign({}, state);
        };
    };

})(window.Far.Impl.Control);

;
/// <reference path="../../../../Scripts/_references.js"/>

(function (impl) {

    impl.DropdownActive = null;

    impl.Dropdown = function(options, model) {

        this.options = options;
        this.model = model;

        var controlModel = null;

        this.set = function(model) {
            controlModel = model;
            this.setPlaceholder();
        };
        this.setPlaceholder = function () {

            this.view.placeholder.textContent = this.get().name;
        }
        this.get = function() {

            return Object.assign({}, controlModel);
        };
        this.render = function() {
            this.view.render();
        }

        this.view = new impl.Dropdown.View(this);
        this.events = new impl.Dropdown.Events(this);

        this.init = function () {

            
        };
    };
})(window.Far.Impl);

;
/// <reference path="../../../../Scripts/_references.js"/>

(function (impl) {
    impl.View = function (dropdown) {
        /** @type {window.Far.Impl.Dropdown} */
        var self = dropdown;

        this.placeholder = null;
        this.dropdown = null;
        this.list = null;
        this.toogleBtn = null;
        this.template = new Far.Impl.Control(
            Far.Impl.Control.Templates.dropdownControl,
            {
                containerId: self.options.containerId,
                name: self.options.name || 'dropdown',
                classList:'',
                controlClassList:'dropdown far_dropdown'
            },
            {
                onRendered: function (items) {
                    self.view.toggleBtn = this.getItem().getButton();
                    self.view.placeholder = this.getItem().getPlaceholder();

                    self.view.toggleBtn.addEventListener(farDocument.clickEventName(), self.events.toggle);

                    self.view.template.appendChild(self.view.list);
                    self.view.list.render(self.model);
                }
            }
        );
        this.render = function () {
            self.view.list = new Far.Impl.Control(
                Far.Impl.Control.Templates.liSimple,
                {
                    name: 'list',
                    classList: 'dropdown-menu'
                },
                {
                    onRendered: function(items) {
                        for (var i = 0; i < items.length; i++) {
                            items[i].addEventListener(self.options.clickEventName || farDocument.clickEventName(), self.events.onChange);
                        }
                    }
                }
            );
            if (typeof self.options.containerId !== 'undefined') {
                self.view.template.init();
            }
            self.view.template.render([{}]);
        };
    }
})(window.Far.Impl.Dropdown);

;
/// <reference path="../../../../Scripts/_references.js"/>

(function (impl) {

    impl.DocumentEvents = {
        click: null,
        once: function() {

            if (this.click === null) {

                this.click = window.onclick = function(event) {
                    if (Far.Impl.DropdownActive !== null) {
                        if (!Far.Impl.DropdownActive.view.template.dom.contains(event.target)) {

                            Far.Impl.DropdownActive.events.close();
                        }
                    }
                };
            }
        }
    };

    impl.Events = function(control) {

        var self = control;
        var isOpen = false;

        this.toggle = function (e) {
            if (e.stopImmediatePropagation) {
                e.stopImmediatePropagation();
            }
            e.preventDefault();
            e.stopPropagation();
            if (isOpen) {

                self.events.close();
            }
            else {

                self.events.open();
            }
        };

        this.open = function() {

            if (isOpen) {

                return;
            }

            isOpen = true;
            self.view.template.control.classList.add('open');

            if (window.Far.Impl.DropdownActive != null && window.Far.Impl.DropdownActive != self) {

                window.Far.Impl.DropdownActive.events.close();
            }
            window.Far.Impl.DropdownActive = self;
        };

        this.close = function() {

            if (!isOpen) {

                return;
            }

            isOpen = false;
            self.view.template.control.classList.remove('open');

            window.Far.Impl.DropdownActive = null;
        };

        this.onChange = function(e) {
            if (e.stopImmediatePropagation) {
                e.stopImmediatePropagation();
            }
            e.preventDefault();
            e.stopPropagation();

            var id = e.target.getAttribute('value');
            var item = self.view.list.getItem({ id: id });

            self.set(item);

            if (typeof self.options.onChange !== 'undefined') {

                self.options.onChange.call(self);
            }

            self.events.close();
        };

        impl.DocumentEvents.once();
    };
})(window.Far.Impl.Dropdown);

;
/// <reference path="../../../../Scripts/_references.js"/>

/*
 модуль модального окна

 options: {
     containerId: id dom элемента
     model: модель для рендера контрола
 }
 */

(function (impl) {

    impl.Modal = function (options, model) {

        this.options = options || {};

        this.model = model;

        // устанавливает контрол в модальное окно
        // control - Far.Impl.Control
        this.renderControl = function (control) {

            this.view.renderControl(control);
        };

        this.view = new impl.Modal.View(this);
        this.events = new impl.Modal.Events(this);

        var initialized = false;

        this.init = function() {

            if (initialized) {

                return;
            }
            this.view.render();

            initialized = true;
        };

        this.show = function() {

            this.init();
            this.events.show();
        };

        this.hide = function() {

            this.events.hide();
        };

        this.lock = function() {

            this.view.lock();
        };

        this.unlock = function() {

            this.view.unlock();
        };
    };
})(window.Far.Impl);

/*
var modalContent = new Far.Impl.Control(Far.Impl.Modal.Templates.phone,
    {
        name: 'phone',
        model: [{ phone: '123456' }]
    },
    {
        onRendered: function () {

        }
    });
var modal = new Far.Impl.Modal({ name: 'controlId', containerId: 'body' }, [modalContent]);
modal.init();

*/


;
/// <reference path="/Scripts/_references.js"/>

(function (impl) {

    impl.Templates = {
        modal: {
            tag: 'div',
            render: function(item) {
                var id = this.control.deepId();
                this.control.addElement(item, 'Darker', "darker");
                this.control.addElement(item, 'Container', "container");
                this.control.addElement(item, 'Closer', "closer");
                this.control.addElement(item, 'Content', "content");
                return [
                    '<div id="', id, '_darker" class="Modal__darker"></div>',
                    '<div id="', id, '_container" class="Modal__container">',
                    '   <div id="', id, '_closer" class="Modal__container__closer"></div>',
                    '   <div id="', id, '_content" class="Modal__container__content">',
                    '   </div>',
                    ' </div>'
                ].join('');
            }
        }
    };

    impl.View = function(modal) {

        var self = modal;

        this.backdoor = null;
        this.container = null;
        this.closer = null;
        this.content = null;

        this.template = new Far.Impl.Control(
            impl.Templates.modal,
            {
                containerId: self.options.containerId,
                name: self.options.name || 'Modal',
                classList: '',
                controlClassList: ['Modal ',(isset(self.options.size)?'__'+self.options.size:'')].join(' '),
                model: self.model || [{}]
            },
            {
                onRendered: function(items) {

                    if (typeof self.options.onTemplateRendered !== 'undefined') {
                        self.options.onTemplateRendered.call(this);
                    }

                    var item = this.getItem();

                    self.view.backdoor = item.getDarker();
                    self.view.container = item.getContainer();
                    self.view.closer = item.getCloser();
                    self.view.content = item.getContent();

                    self.view.closer.addEventListener('click', self.events.onClose);
                    self.view.backdoor.addEventListener('click', self.events.onClose);
                }
            }
        );

        // текущий контрол в модальном окне
        this.control = null;

        this.render = function() {
            if (typeof self.options.containerId !== 'undefined') {

                self.view.template.appendTo(self.options.containerId);
            }
            else {
                console.error('unsupported render control without containerId');
            }
        };

        this.renderControl = function (control) {

            if (this.control !== null) {
                this.control.destroy();
            }
            this.control = control;
            this.control.parent = this.template;
            this.control.appendTo(this.content.getAttribute('id'));
        };

        this.lock = function () {

            this.template.lock();
        };

        this.unlock = function () {

            this.template.unlock();
        };
    };
})(window.Far.Impl.Modal);

;
/// <reference path="/Scripts/_references.js"/>

(function (impl) {
    impl.Events = function (control) {

        var self = control;

        this.show = function() {

            self.view.template.dom.removeAttribute('hidden');
        };

        this.hide = function() {

            self.view.template.dom.setAttribute('hidden', true);
        };

        this.onClose = function() {

            self.hide();
        };
    };
})(window.Far.Impl.Modal);

;
window.Far.Impl.Validators = {};

;
/// <reference path="/Scripts/_references.js" />

(function (impl) {

    impl.ValidatorStorage = {
        storage: {
            'SimplePhone': {
                'id': {}
            }
        },

        add: function(controlId, validator) {

            if (typeof this.storage.SimplePhone[controlId] !== 'undefined') {

                return false;
            }

            this.storage.SimplePhone[controlId] = validator;
            return true;
        },
        get: function(controlId) {

            return this.storage.SimplePhone[controlId];
        }
    }

    //'+38(050) 955-45-48'
    impl.SimplePhone = function(options) {

        var self = this;

        var controlId = options.controlId;
        var onSuccess = options.onSuccess || function () { };
        var onError = options.onError || function () { };

        var maxLength = 12;

        this.control = null;

        this.init = function() {

            this.control = document.getElementById(controlId);

            if (this.control === null) {

                console.error('SimplePhone ' + controlId + ' undefined');
                return;
            }

            this.control.setAttribute('maxlength', maxLength);
            this.control.placeholder = '38XXXXXXXXXX';
            this.control.addEventListener('keyup', this.onKeyup, false);

            impl.ValidatorStorage.add(controlId, this);

            return this;
        };

        this.getPhone = function(replace) {

            return this.control.value || '';
        };

        this.setPhone = function(value) {

            this.control.value = value || '';
        };

        this.onKeyup = function(e) {
            e = (e) ? e : window.event;
            var charCode = (e.which) ? e.which : e.keyCode;
            if (charCode > 31 && (charCode < 48 || charCode > 57)) {

                e.target.value = replaceValue(e.target.value);

                return false;
            }
            return true;
        }

        var getDigits = function(value) {
            var parts = value.match(/\d+/g);
            if (parts == null) {
                return '';
            }
            return parts.join('');
        };

        var replaceValue = function(value) {

            return value.replace(/[^0-9\.]+/g, '');
        };

        var validate = function () {

            var phone = self.getPhone();
            if (phone.length === 0) {

                return false;
            }

            var digits = getDigits(phone);

            if (digits.length !== maxLength) {

                return false;
            }

            return phone.length === digits.length;
        }

        this.validate = function() {

            var isValid = validate();
            if (isValid) {
                onSuccess();
                return true;
            }
            onError();
            return false;
        }
    }
})(window.Far.Impl.Validators);

;
/// <reference path="../../../../Scripts/_references.js"/>

(function (impl) {

    impl.Calendar = function (options) {

        this.options = options;
        this.returnDatesArray = true;
        this.settings = {
            month: [localizationValues.january, localizationValues.february, localizationValues.march, localizationValues.april, localizationValues.may, localizationValues.june, localizationValues.july, localizationValues.august, localizationValues.september, localizationValues.october, localizationValues.november, localizationValues.december],
            maxRange: 14
        };
        this.model = null;
        this.dragging = false;
        this.renderModel = null;
        this.currentDate = null;
        var controlModel = null;
        var lastDayOfModel = null;
        var self = this;
        this.dateRange = [];

        /*
            model: { date: Date, checked: bool, minus: int, plus: int }, где
    	             date - устанавливаемая дата на календаря, форма '2019-07-19T00:00:00+03:00'
    	             checked - признак +/- дня,
    	             plus - к-во дней выбраных после date,
                     minus - к-во дней выбраный до date
        */
        this.set = function (model) {

            controlModel = model;
			if (typeof model.date === 'string') {
				model.date = this.helpers.formatDateString(model.date);
				//console.error('string date')
				//console.error(model.date);
			}
            if (model.date !== null) {
            	controlModel.date = this.helpers.formatDateObject(new Date(model.date));
            	//console.error(controlModel.date)
            }
            if (controlModel.date) {
                /*
                    если устанавливаемая дата на календаре не попадает в месяц, который отображается на календаре,
    			    тогда необходимо перерисовать календарь, установив месяц из устанавливаемой даты.
                */
                var timestamp = this.helpers.getTimestamp(controlModel.date);
            	if (this.renderModel[0][0].id > timestamp || lastDayOfModel < timestamp) {
                	this.defineRenderModel(controlModel.date);
    	            this.view.calendarTable.refresh(this.renderModel);
    	            this.view.updateDom(controlModel.date.getMonth());
                }
            }
            this.setDateRange();
            this.view.updateActiveDates();
            this.view.changeCheckboxDom();
            this.view.updateFooterBtn();
        };

        this.setPlaceholder = function () {
	        this.view.setPlaceholder();
        };

        this.setDateRange = function () {
	        var i,
		        j,
		        model = this.get(),
		        timestamp,
		        dayModel = null;
        	for (i = 0 ; i < this.view.calendarTable.model.length; i++) {
        		for (j = 0; j < this.view.calendarTable.model[i].length; j++) {
	                this.view.calendarTable.model[i][j].range = false;
	                this.view.calendarTable.model[i][j].checked = false;
        		}
        	}
        	if (typeof model.date ==='undefined' || model.date === null) {
        	    return;
        	}
        	timestamp = this.helpers.getTimestamp(model.date);
            this.dateRange = [];
            if (model.checked || self.settings.range) {
            	var prevTimestamp = timestamp;
	            for (i = 0; i < model.minus; i++) {
		            prevTimestamp = this.helpers.getPrevTimestamp(prevTimestamp);
		            dayModel = this.view.calendarTable.getItem({ id: prevTimestamp, disabled: true });
		            dayModel.range = true;
		            this.dateRange[model.minus - i - 1] = prevTimestamp;
	            }
            }
            dayModel = this.view.calendarTable.getItem({ id: timestamp, disabled: true });
            dayModel.checked = !dayModel.disabled;
            this.dateRange.push(timestamp);
            if (model.checked || self.settings.range) {
            	var nextTimestamp = timestamp;
	            for (i = 0; i < model.plus; i++) {
		            nextTimestamp = this.helpers.getNextTimestamp(nextTimestamp);
		            dayModel = this.view.calendarTable.getItem({ id: nextTimestamp, disabled: true });
		            dayModel.range = true;
		            this.dateRange.push(nextTimestamp);
	            }
            }
            this.dateRange.sort(function (a, b) { return a - b });
        };

        this.getDatesRange = function () {
        	var model = this.get();
			if (model === null) {
				return null;
			}
			var dates = [],
				nowTimestamp = this.helpers.getTimestamp(this.helpers.toShortDate(new Date()));
			for (var i = 0; i < this.dateRange.length; i++) {
				if (this.model.disablePastDays && this.dateRange[i] <= nowTimestamp) {
					continue;
				}
				if (this.model.disabled.indexOf(this.dateRange[i]) !== -1) {
					continue;
				}
				dates.push(this.helpers.timestampToDate(this.dateRange[i]));
			}
			return dates;
        };
        this.get = function () {
            return Object.assign({}, controlModel);
        };

        this.reset = function() {
            this.set(this.model);
        };
        
        this.disableDates = function (date, days) {
            var currentRenderModel = this.renderModel,
                fDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()),
                fTimestamp = this.helpers.getTimestamp(fDate),
                maxDay = this.helpers.addDay(fDate, days),
                maxTimestamp = this.helpers.getTimestamp(maxDay);
            for (var i = 0 ; i < currentRenderModel.length; i++) {
                for (var j = 0; j < currentRenderModel[i].length; j++) {
                    if (currentRenderModel[i][j].id < fTimestamp || currentRenderModel[i][j].id >= maxTimestamp) {
                        currentRenderModel[i][j].disabled = true;
                    }
                }
            }
            this.refresh();
        }
        this.defineRenderModel = function (date) {
            var month = date.getMonth(),
                year = date.getFullYear(),
                modelDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()),
                firstDay = new Date(year, month, 1),
                lastDay = new Date(year, month + 1, 0),
                lastDayTSTMP = this.helpers.getTimestamp(lastDay),
                firstDayOfWeek = this.helpers.getDay(firstDay),
                currentDate = new Date(firstDay),
                monthModel = [],
                containLastDay = false;
            this.currentDate = modelDate;
            function getWeek(date, disabled) {
                var days = [],
                    timestamp = 0,
                    nowDate = new Date(),
                    currentTimestamp = this.helpers.getTimestamp(new Date(nowDate.getFullYear(), nowDate.getMonth(), nowDate.getDate())),
                    dayModel = null;
                for (var i = 0; i < 7; i++) {
                    timestamp = this.helpers.getTimestamp(date);
                    if (timestamp == lastDayTSTMP) {
                        containLastDay = true;
                    }
                    dayModel = {
                        id: timestamp,
                        name: date.getDate(),
                        disabled: currentTimestamp >= timestamp || disabled.indexOf(timestamp) !== -1,
                        hasStatistic: typeof self.model !== 'undefined' && typeof self.model.hasStatistic !== 'undefined' ? self.model.hasStatistic : false,
                        checked: false,
                        range: false
                    };
                    days.push(dayModel);
                    date.setDate(date.getDate() + 1);
                }
                return days;
            } 
            if (firstDayOfWeek != 0) {
                currentDate.setDate(currentDate.getDate() - firstDayOfWeek);
            }
            for (var i = 0; i < 5; i++) {
            	monthModel.push(getWeek.call(this, currentDate, this.model.disabled));
            }
            if (containLastDay === false) {
                monthModel.push(getWeek.call(this, currentDate, this.model.disabled));
                lastDayOfModel = monthModel[5][6].id;
            } else {
                lastDayOfModel = monthModel[4][6].id;
            }
            this.renderModel = monthModel;
        };

        this.refresh = function () {
            this.view.calendarTable.refresh(this.renderModel);
            this.view.updateDom(this.currentDate.getMonth());
        }
        this.render = function () {

            this.view.render();
        };

        this.view = new impl.Calendar.View(this);
        this.events = new impl.Calendar.Events(this);

        /*
            model: { checkboxActive: bool, checkboxDays: int, date: Date, disabled: [], disablePastDays: bool }
        */
        this.init = function (model) {
            /*
                преобразуем масив дат (строки) в масив таймстампов
            */
            var disabled = [];
			if (typeof model.disabled !== 'undefined') {
				var disabled = [];
				for (var i = 0; i < model.disabled.length; i++) {
					var d = typeof model.disabled[i] === 'object' ? this.helpers.toShortDate(model.disabled[i]) : new Date(model.disabled[i]);
					disabled.push(this.helpers.getTimestamp(d));
				}
			}
			model.disabled = disabled;
			model.disablePastDays = model.disablePastDays || true;
            this.model = model;
            this.defineRenderModel(this.model.date);
        };
        this.helpers = {
            addDay: function (date, days) {
                var result = new Date(date);
                result.setDate(date.getDate() + days);
                return result;
            },
            removeDay: function (date, days) {
                var result = new Date(date);
                result.setDate(date.getDate() - days);
                return result;
            },
            getDay: function (date) {
                var day = date.getDay();
                if (day == 0) day = 7;
                return day - 1;
            },
            getTimestamp: function (date) {
                var userTimezoneOffset = 0;// date.getTimezoneOffset() * 60;
                return Math.floor((date.getTime() / 1000) - userTimezoneOffset);
            },
            getNextTimestamp: function (timestamp) {
                /*
                    Из-за смещения времени в разных часовых поясах нужно получить дату из таймстемпа добавить один день и так возращать новый таймстемп
                */
                var temporaryDate = new Date(timestamp * 1000);
                temporaryDate.setDate(temporaryDate.getDate() + 1);
                return temporaryDate.getTime()/1000;
            },
            getPrevTimestamp: function (timestamp) {
                /*
                    Из-за смещения времени в разных часовых поясах нужно получить дату из таймстемпа добавить один день и так возращать новый таймстемп
                */
                var temporaryDate = new Date(timestamp * 1000);
                    temporaryDate.setDate(temporaryDate.getDate() - 1);

                return temporaryDate.getTime() / 1000;
            },
			timestampToDate: function(timestamp) {
				return new Date(timestamp * 1000);
			},
			toShortDate: function(date) {
				return new Date(date.getFullYear(), date.getMonth(), date.getDate());
			},
            format00: function (v) {
	            return ('0' + v.toString()).slice(-2);
            },
            formatDateArgs: function (year, month, day) {
	            return new Date(year, month, day);
            },
            formatDateObject: function (date) {
	            return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);
            },
            formatDateString: function (value) {
	            return this.formatShortDateString(value);
	            //2019-11-28T00:00:00+02:00
	            var y = parseInt(value.substr(0, 4)),
		            m = parseInt(value.substr(5, 2)),
		            d = parseInt(value.substr(8, 2)),
		            date = this.formatDateArgs(y, m, d),
		            zoneOffset = this.format00(date.getTimezoneOffset() / -60);
	            return [y, '-', this.format00(m), '-', this.format00(d), 'T00:00:00+', zoneOffset, ':00'].join('');
            },
            formatShortDateString: function(value) {
	            //2019-11-28T00:00:00+02:00
	            var y = parseInt(value.substr(0, 4)),
		            m = parseInt(value.substr(5, 2)),
		            d = parseInt(value.substr(8, 2));
	            return [y, '-', this.format00(m), '-', this.format00(d)].join('');
			}
        };
    };
})(window.Far.Impl);

;
/// <reference path="/Scripts/_references.js"/>

(function (impl) {
    impl.View = function (calendar) {

        var self = calendar;

        this.calendarTable = null;
        this.calendarPlaceholder = null;
        this.prevButton = null;
        this.nextButton = null;
        this.fromRangeButton = null;
        this.tillRangeButton = null;
        this.checkbox = null;

        this.template = new Far.Impl.Control(
                Far.Impl.Control.Templates.calendarBlock,
                {
                    containerId: self.options.containerId,
                    name: self.options.name || 'calendarPanel',
                    classList: '',
                },
                {
                    onRendered: function (items) {
                        self.view.calendarTable = new Far.Impl.Control(
                              Far.Impl.Control.Templates.calendarTable,
                              {
                                  name: 'calendarTable',
                                  classList: ''
                              },
                              {
                                  onRendered: function (items) {
                                      var table = this.dom.querySelector('tbody');
                                      table.appendChild(self.view.fromRangeButton);
                                      table.appendChild(self.view.tillRangeButton)
	                                  var td = null;
                                      for (var i = 0; i < this.model.length; i++) {
                                          for (var j = 0; j < this.model[i].length; j++) {
	                                          td = this.model[i][j].getCell();
                                              td.addEventListener(self.model.mobile ? farDocument.clickEventName() : 'click', self.events.onClick.bind(td, this.model[i][j]), true);
                                          }
                                      }
                                      if (!self.view.tdHeigh) {
                                          self.view.tdHeigh = td.offsetHeight;
                                      }
                                  }
                              }
                          );

                        self.view.calendarPlaceholder = this.getItem().getCalendarPlaceholder();


                        self.view.prevButton = this.getItem().getPrevButton();
                        self.view.nextButton = this.getItem().getNextButton();
                        self.view.fromRangeButton = this.getItem().getFromRangeButton();
                        self.view.tillRangeButton = this.getItem().getTillRangeButton();

                        self.view.checkbox = this.getItem().getCheckbox();
                        self.view.range = this.getItem().getRange();

                        self.view.prevButton.addEventListener('click', self.events.prevHandler, false);
                        self.view.nextButton.addEventListener('click', self.events.nextHandler, false);
                        if (self.view.checkbox !== null) {
                            self.view.checkbox.addEventListener('click', self.events.onChange, false);
                        }
                        if (self.view.range !== null) {
                            self.view.range.addEventListener(self.model.mobile ? farDocument.clickEventName() : 'click', self.events.onClickRange, false);
                        }
                        if (self.view.fromRangeButton !== null) {
                            if (self.model.mobile) {
                                self.view.fromRangeButton.ontouchstart = self.events.buttonDrag.bind(self.view.fromRangeButton, true);
                            }
                            else {
                                self.view.fromRangeButton.onmousedown = self.events.buttonDrag.bind(self.view.fromRangeButton, true);
                            }
                        }
                        if (self.view.tillRangeButton !== null) {
                            if (self.model.mobile) {
                                self.view.tillRangeButton.ontouchstart = self.events.buttonDrag.bind(self.view.tillRangeButton, false);
                            }
                            else {
                                self.view.tillRangeButton.onmousedown = self.events.buttonDrag.bind(self.view.tillRangeButton, false);
                            }
                        }

                        self.view.template.addChild(self.view.calendarTable);
                        self.view.calendarTable.render(self.renderModel);
                    }
                }
            );
        this.render = function () {

            if (typeof self.options.containerId !== 'undefined') {
                self.view.template.init();
            }
            this.template.render([{
                monthName: self.settings.month[self.model.date.getMonth()],
                year: self.model.date.getFullYear(),
                checkboxActive: self.model.checkboxActive  || false,
                checkboxDays: self.model.checkboxDays,
                prevButtonDisable: true,
                nextButtonDisable: false,
                allowCheckbox: (typeof self.model.allowCheckbox !== 'undefined' ? self.model.allowCheckbox : true),
                type: (typeof self.model.type !== 'undefined' ? self.model.type : '')
            }]);
        };
        this.updateDom = function (monthIndex) {
            var model       = self.model.date,
                currentDate = self.currentDate,
                minDate     = new Date(self.model.min),
                maxDate     = new Date(self.model.max),
                nextYear    = new Date(model.getTime()),
                yearsCount  = self.model.yearsCount || 1;


            nextYear.setFullYear(nextYear.getFullYear() + yearsCount);

            if (currentDate.getFullYear() === minDate.getFullYear() && currentDate.getMonth() === minDate.getMonth()) {
                self.view.prevButton.classList.add('disable');
            } else {
                self.view.prevButton.classList.remove('disable');
            }

            if (currentDate.getFullYear() === maxDate.getFullYear() && currentDate.getMonth() === maxDate.getMonth()) {
                self.view.nextButton.classList.add('disable');
            } else {
                self.view.nextButton.classList.remove('disable');
            }

            self.view.calendarPlaceholder.textContent = self.settings.month[monthIndex] + ' ' + currentDate.getFullYear();
        };
        var firstDayTd = null;
        var lastDayTd = null;
        this.updateActiveDates = function () {
            var model               = self.get(),
	            i, j, td, timestamp,
	            date                = new Date(model.date),
	            dateTimestamp       = self.helpers.getTimestamp(date),
                firstDay            = self.dateRange[0],
                lastDay             = self.dateRange[self.dateRange.length - 1];

            /*
                Очищаем все даты от активных классов
            */

        	if (model.date === null) {
        	    for (i = 0 ; i < this.calendarTable.model.length; i++) {
        	        for (var j = 0; j < this.calendarTable.model[i].length; j++) {
        	            td = this.calendarTable.model[i][j].getCell();
        	            td.classList.remove('active_day_range');
        	            td.classList.remove('active_day');
        	            td.classList.remove('__first_day');
        	            td.classList.remove('__last_day');
        	        }
        	    }
        	    return;
        	}
        	firstDayTd = null;
        	lastDayTd = null;
        	for (i = 0 ; i < this.calendarTable.model.length; i++) {
        		for (var j = 0; j < this.calendarTable.model[i].length; j++) {
        			if (this.calendarTable.model[i][j].disabled) {
	                    continue;
                    }
        			td = this.calendarTable.model[i][j].getCell();
        			if (self.dateRange.indexOf(this.calendarTable.model[i][j].id) !== -1) {
        			    if (!td.classList.contains('active_day_range')) {
        			        td.classList.add('active_day_range');
        			    }
        			    if (this.calendarTable.model[i][j].id == firstDay) {
        			        td.classList.add('__first_day');
        			        firstDayTd = td;
        			    } else {
        			        td.classList.remove('__first_day');
        			    }
        			    if (this.calendarTable.model[i][j].id == lastDay) {
        			        td.classList.add('__last_day');
        			        lastDayTd = td;
        			    } else {
        			        td.classList.remove('__last_day');
        			    }
        			    if (dateTimestamp === this.calendarTable.model[i][j].id) {
        			        if (!td.classList.contains('active_day') && !self.settings.range && (model.minus +  model.plus <= 6)) {
			                    td.classList.add('active_day');
		                    }
	                    }
	                    else {
		                    td.classList.remove('active_day');
	                    }
                    }
                    else {
	                    td.classList.remove('active_day_range');
	                    td.classList.remove('active_day');
	                    td.classList.remove('__first_day');
	                    td.classList.remove('__last_day');
                    }
	            }
        	}
        };
        function hideRangeButtons() {
            self.view.fromRangeButton.style.display = 'none';
            self.view.tillRangeButton.style.display = 'none';
        }
        this.updateRangeButton = function () {
            if (self.model.type !== 'RangeCheckbox') {
                return;
            }
            hideRangeButtons();
            self.view.updateFromRangeButton();
            self.view.updateTillRangeButton();
        }
        this.updateFromRangeButton = function() {
            if (firstDayTd !== null) {
                if (!self.view.tdHeigh) {
                    self.view.tdHeigh = firstDayTd.offsetHeight;
                }
                //console.log('updateFromRangeButton tdHeigh', self.view.tdHeigh);
                var firstTop = firstDayTd.offsetTop + (self.model.mobile ? self.view.tdHeigh / 2 : 0) + (self.model.mobile ? -12 : 12),
                    firstLeft = firstDayTd.offsetLeft;

                //console.log('updateFromRangeButton firstTop', firstTop);
                this.fromRangeButton.style.top = firstTop + 'px';
                this.fromRangeButton.style.left = firstLeft - 12 + 'px';
                this.fromRangeButton.style.display = 'flex';
            }
        }
        this.updateTillRangeButton = function() {
            if (lastDayTd !== null) {
                if (!self.view.tdHeigh && firstDayTd) {
                    self.view.tdHeigh = firstDayTd.offsetHeight;
                }

                var lastTop = lastDayTd.offsetTop + (self.model.mobile ? self.view.tdHeigh / 2 : 0) + (self.model.mobile ? -12 : 12),
                    lastRight = lastDayTd.offsetLeft + lastDayTd.offsetWidth;

                //console.log('updateTillRangeButton lastTop', lastTop);
                this.tillRangeButton.style.top = lastTop + 'px';
                this.tillRangeButton.style.left = lastRight - 12 + 'px';
                this.tillRangeButton.style.display = 'flex';
            }
        }
        this.updateFooterBtn = function () {
            if (self.view.range === null) {
                return;
            }
            if (self.settings.range) {
                self.view.range.classList.add('__active')
                self.view.checkbox.classList.remove('__active')
            } else {
                self.view.range.classList.remove('__active')
                self.view.checkbox.classList.add('__active')
            }
        }
        this.changeCheckboxDom = function () {
            var model = self.get();
            if (this.checkbox === null || self.view.range !== null) {
                return;
            }
            if (model.checked) {
                this.checkbox.classList.add('__active');
            } else {
                this.checkbox.classList.remove('__active');
            }

        };
    };
})(window.Far.Impl.Calendar);

;
/// <reference path="../../../../Scripts/_references.js"/>

(function (impl) {
    impl.Events = function (control) {

        var self = control;

        this.prevHandler = function (e) {

        	var prevMonthModel = new Date(self.currentDate.getFullYear(), self.currentDate.getMonth(), 1);

            if (typeof self.model.min !== 'undefined') {
            	var minDate = new Date(self.model.min),
	                minDate = new Date(minDate.getFullYear(), minDate.getMonth(), 1);
				if (self.helpers.getTimestamp(minDate) === self.helpers.getTimestamp(prevMonthModel)) {
	                return;
                }
            }
            else if (e.target.classList.contains('disable')) {
	            return;
            }

            prevMonthModel.setMonth(prevMonthModel.getMonth() - 1);

            self.defineRenderModel(prevMonthModel);

            self.view.calendarTable.refresh(self.renderModel);

            self.view.updateDom(prevMonthModel.getMonth());

            if (typeof self.options.prevHandlerClick !== 'undefined') {
                self.options.prevHandlerClick.call(self);
            }

            self.setDateRange();
            self.view.updateActiveDates();
            self.view.updateRangeButton();
        };

        this.nextHandler = function (e) {
        	var nextMonthModel = new Date(self.currentDate.getFullYear(), self.currentDate.getMonth(), 1);

            if (typeof self.model.max !== 'undefined') {
            	var maxDate = new Date(self.model.max),
	                maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), 1);
            	if (self.helpers.getTimestamp(maxDate) === self.helpers.getTimestamp(nextMonthModel)) {
		            return;
	            }
            }
            else if (e.target.classList.contains('disable')) {
	            return;
            }

            nextMonthModel.setMonth(nextMonthModel.getMonth() + 1);

            self.defineRenderModel(nextMonthModel);

            self.view.calendarTable.refresh(self.renderModel);

            self.view.updateDom(nextMonthModel.getMonth());

            if (typeof self.options.nextHandlerClick !== 'undefined') {
                self.options.nextHandlerClick.call(self);
            }
            self.setDateRange();
            self.view.updateActiveDates();
            self.view.updateRangeButton();
        };

        this.getCellByCoords = function (x, y) {
            for (i = 0 ; i < self.view.calendarTable.model.length; i++) {
                for (var j = 0; j < self.view.calendarTable.model[i].length; j++) {
                    var td = self.view.calendarTable.model[i][j].getCell(),
                        left = td.offsetLeft + 1,
                        right = td.offsetLeft + td.offsetWidth + 1,
                        top = td.offsetTop,
                        bottom = td.offsetTop + td.offsetHeight;
                    if (x >= left && x <= right && y >= top && y <= bottom) {
                        return td;
                    }
                }
            }
        }
        this.setDateByTd = function (item,from) {
            var model               = self.get(),
                value               = item.getAttribute('value'),
                prevTimestamp       = model.date.getTime() / 1000,
                lastDay             = self.getDatesRange()[self.getDatesRange().length - 1],
                firstDay            = self.getDatesRange()[0],
                lastDayTimestamp    = lastDay.getTime(),
                firstDayTimestamp   = firstDay.getTime(),
                daysFromLag         = Math.ceil(Math.abs(value * 1000 - lastDayTimestamp) / (1000 * 3600 * 24)),
                daysTillLag         = Math.ceil(Math.abs(value * 1000 - firstDayTimestamp) / (1000 * 3600 * 24));

            model.date = new Date(value * 1000);

            if (from) {
                if (daysFromLag >= self.settings.maxRange) {
                    daysFromLag = self.settings.maxRange - 1;
                }
                model.minus = 0;
                model.plus = daysFromLag;
            } else {
                if (daysTillLag >= self.settings.maxRange) {
                    daysTillLag = self.settings.maxRange - 1;
                }
                model.plus = 0;
                model.minus = daysTillLag;
            }
            self.set(model);
            if (from) {
                self.view.updateTillRangeButton();
            } else {
                self.view.updateFromRangeButton();
            }
            if (typeof self.options.onRange !== 'undefined') {
                self.options.onRange.call(self);
            }
        }
        this.buttonDrag = function (from, e) {
            if (!self.settings.range) {
                return;
            }
            self.dragging = true;
            var table               = self.view.calendarTable.dom.querySelector('tbody'),
                target              = this,
                targetCoords        = getCoords(target),
                pageX               = (self.model.mobile ? (event.targetTouches[0] ? event.targetTouches[0].pageX : event.changedTouches[event.changedTouches.length - 1].pageX) : e.pageX),
                pageY               = (self.model.mobile ? (event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length - 1].pageY) : e.pageY),
                shiftX              = pageX - targetCoords.left,
                shiftY              = pageY - targetCoords.top,
                tableCoords         = getCoords(table),
                lastTargetLeft      = 0,
                lastTargetTop       = 0;

            if (self.model.mobile) {
                document.ontouchmove = function (e) {
                    moveButton(e);
                }
            } else {
                document.onmousemove = function (e) {
                    moveButton(e);
                }
            }
            if (self.model.mobile) {
                document.ontouchend = function (e) {
                    document.ontouchmove = document.ontouchstart = null;
                    setTimeout(function () {
                        self.dragging = false;
                        self.view.updateRangeButton();
                    }, 50);
                }
            } else {
                document.onmouseup = function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    document.onmousemove = document.onmouseup = null;
                    setTimeout(function () {
                        self.dragging = false;
                        self.view.updateRangeButton();
                    }, 50);
                }
            }
            function moveButton(e) {
                var pageX       = (self.model.mobile ? (event.targetTouches[0] ? event.targetTouches[0].pageX : event.changedTouches[event.changedTouches.length-1].pageX) : e.pageX),
                    pageY       = (self.model.mobile ? (event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length - 1].pageY) : e.pageY),
                    newLeft     = pageX - shiftX - tableCoords.left + target.offsetWidth / 2,
                    newTop      = (pageY - shiftY - tableCoords.top + self.view.calendarTable.model[0][0].getCell().offsetHeight) //Так как кнопки находяться не внутри table а в контейнере календаря, нужен отступ сверху до начала табилицы
                    rightEdge   = table.offsetWidth - target.offsetWidth / 2,
                    topEdge     = (table.offsetHeight - target.offsetHeight + self.view.calendarTable.model[0][0].getCell().offsetHeight)

                if (newLeft < 0) {
                    newLeft = 0;
                }
                if (newTop < self.view.calendarTable.model[0][0].getCell().offsetHeight) {
                    newTop = self.view.calendarTable.model[0][0].getCell().offsetHeight;
                }
                if (newLeft > rightEdge) {
                    newLeft = rightEdge;
                }
                if (newTop > topEdge) {
                    newTop = topEdge;
                }

                lastTargetLeft = newLeft;
                lastTargetTop = newTop;

                setTimeout(function () {
                    var td = self.events.getCellByCoords(lastTargetLeft, lastTargetTop);
                    if (typeof td === 'undefined') {
                        td = self.events.getCellByCoords(lastTargetLeft + 5, lastTargetTop - 5);
                    };
                    if (td.classList.contains('__disabled')) {
                        return;
                    }
                    self.events.setDateByTd(td, from);
                }, 100);
                target.style.left = newLeft + 'px';
                target.style.top = newTop + 'px';
            }
            function getCoords(elem) {
                var box = elem.getBoundingClientRect();
                return {
                    top: box.top + pageYOffset,
                    left: box.left + pageXOffset
                };

            }
        }
        this.onChange = function (e) {            
            var model = self.get();
            if (typeof model.checked === 'undefined') {
                model.checked = self.model.checkboxActive;
                self.settings.range = false;
            } else {
                if (self.model.type && self.model.type === 'RangeCheckbox' && !self.settings.range) {
                    return;
                }
                if (self.model.type === 'RangeCheckbox') {
                    model.checked = true;
                } else {
                    model.checked = !model.checked;
                }
                self.settings.range = false;
            }

            //скидываем значение +/- на дефолтные
            model.minus = self.model.checkboxDays;
            model.plus = self.model.checkboxDays;

            self.set(model);

            self.view.updateRangeButton();
            if (typeof self.options.onChange !== 'undefined') {
                self.options.onChange(model.checked);
            }
        };
        this.onClickRange = function () {
            var model = self.get();
            model.checked = false;
            model.range = true;
            self.settings.range = true;
            self.set(model);
            if (!self.dragging) {
                self.view.updateRangeButton();
            }
        }

    	/* Событие клика в ячейке
    		 item: { id: timestamp, name: string, disabled: bool, checked: bool }
			 	id -
				name -
				disabled -
				checked -
		*/
        var firstClick = true;
        function rangeHandler(item, model) {
            model.minus = 0;
            if (firstClick) {
                model.date = new Date(item.id * 1000);
                model.plus = 0;
                firstClick = false
            }
            else {
                var prevTimestamp = model.date.getTime() / 1000,
                    daysLag = Math.ceil(Math.abs(item.id * 1000 - prevTimestamp * 1000) / (1000 * 3600 * 24));
                if (daysLag >= self.settings.maxRange) {
                    daysLag = self.settings.maxRange - 1;
                }
                model.plus = daysLag;
                if (prevTimestamp > item.id) {
                    model.date = new Date(item.id * 1000)
                }
                firstClick = true;
            }

            return model;
        }
        this.onClick = function (item, e) {
			if (typeof item.disabled !== 'undefined' && item.disabled === true) {

				return;
            }
            if (e.stopImmediatePropagation) {
                e.stopImmediatePropagation();
            }
            e.preventDefault();
            e.stopPropagation();

			var prevModel = self.get();

			if (typeof self.settings.range !== 'undefined' && self.settings.range) {
			    prevModel = rangeHandler(item,prevModel);
            }
            else {
			    if (typeof prevModel.checked === 'undefined') {
			        prevModel.checked = self.model.checkboxActive;
                }
                else {
			        prevModel.checked = prevModel.checked;
			    }
			    prevModel.date = new Date(item.id * 1000);
			    //скидываем значение +/- на дефолтные
			    prevModel.minus = self.model.checkboxDays;
			    prevModel.plus = self.model.checkboxDays;
            }
            window.requestAnimationFrame(async function () {
                self.set(prevModel);

                self.view.updateRangeButton();
                if (typeof self.options.onClick !== 'undefined') {
                    self.options.onClick.call(self);
                }
            });
        };
    };
})(window.Far.Impl.Calendar);


;
/// <reference path="../../Scripts/_references.js" />

(function(ns) {
	ns.SearchForm.prototype.create = function() {
		var form, destination, cityFrom, date, nights, tourists, stars, meals, mobile = false;

		if (typeof this.options.controlsToHide === 'undefined') {
			this.options.controlsToHide = [];
		}

		form = new window.Far.Impl.SearchForm({
			mobile: mobile,
			container: document.getElementById('Search_form_container'),
			controlsToHide: this.options.controlsToHide || [],
			searchModel: this.options.searchModel,
			specialCode: this.options.specialCode,
			specialPrefix: this.options.specialPrefix,
			onFirstModelLoaded: this.options.onFirstModelLoaded || function() {},
			onRendered: this.options.onRendered || function() {},
			onSearchClick: this.options.onSearchClick || function (response) {
				var url = '/tours/catalog/' + response.data.hash;
				if (this.settings.specialCode !== '') {
					url += '/?show-type=' + this.settings.specialCode;
				}
				document.location.href = localizationFn.localizeUrl(url, localizationFn.current);
			},
			openInNewTab: this.options.openInNewTab || false,
			allowAdvancedButton: this.options.allowAdvancedButton || false,
			instructions: this.options.instructions || [],
			searchButtonTextKey: this.options.searchButtonTextKey,
			apiRegisterUrl: this.options.apiRegisterUrl,
			isBus: this.options.isBus,
		});
		form.component = this.component;
		
		destination = form.addControl('Destination', 'Destination', { mobile: mobile });
		cityFrom = form.addControl('CityFrom', 'CityFrom', { mobile: mobile });
		date = form.addControl('Date', 'Date', { mobile: mobile });
		nights = form.addControl('Nights', 'Nights', { mobile: mobile });
		tourists = form.addControl('Tourists', 'Tourists', { mobile: mobile });
		stars = form.addControl('Stars', 'Stars', { mobile: mobile });
		meals = form.addControl('Meals', 'Meals', { mobile: mobile });

		form.config = {
		    advanced: { controls: [cityFrom, destination, date, nights, tourists, stars, meals], active: false },
			simple: { controls: [cityFrom, destination, date, nights, tourists, stars, meals], active: false }
		};

		form.configure(this.options.type);

		form.init();

		return form;
	};
})(window.Far);

;
//--work functions

/// <reference path="_references.js" />

var GA_helper =
    {
        Ga_gid: function () {
            return GA_helper.getCookie("_gid");
        },
        deviceGuid: function () {
            return GA_helper.getCookie("GuestId");
        },
        getCookie: function (name) { var name = name + "="; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ""; },
    };

var spotter = {
    deviceGuid: {
        get: function () {

            try {
                return GA_helper.deviceGuid();
            }
            catch (err) {

            }

            return '0';
        }
    },
    dataLayer: {
        pageType: function () {
            var url = document.URL.toString().toLocaleLowerCase();
            var url_no_pars = location.protocol + '//' + location.host;// + location.pathname;
            //var lang = @Far.Localization.FarHttpLocalization.Lang == 'ru' ? '' : '/' + localization;
            //url_no_pars = url_no_pars + lang;

            //homepage
            if (url == url_no_pars ||
                url == url_no_pars + '/' ||
                url == url_no_pars + '/#' ||
                url.indexOf(url_no_pars + '/?') >= 0 ||
                url.indexOf(url_no_pars + '?') >= 0) {
                return 'homepage';
            }

            //searchCatalog
            if (url.indexOf('tours/catalog') >= 0) {
                return 'searchCatalog';
            }

            //tourCart
            if (url.indexOf('hotel/') >= 0 && url.indexOf('/?q=') >= 0) {
                return 'tourCart';
            }

            //hotelPage
            if (url.indexOf('hotel/') >= 0 && url.indexOf('/?q=') < 0) {
                return 'hotelPage';
            }

            //checkout
            if (url.indexOf('checkout/') >= 0) {
                return 'checkout';
            }

            //specialHot
            if (url.indexOf('tours/show-hot') >= 0) {
                return 'specialHot';
            }

            //specialRecomended
            if (url.indexOf('tours/show-more-recommended') >= 0) {
                return 'specialRecomended';
            }

            //specialEarly
            if (url.indexOf('tours/early') >= 0) {
                return 'specialEarly';
            }

            //specialMastercard
            if (url.indexOf('/mastercard-bilshe') >= 0) {
                return 'specialMastercard';
            }

            //thankYouPage
            if (url.indexOf('order/complite') >= 0) {
                return 'thankYouPage';
            }

            if (url.indexOf('/hotels/') >= 0) {
                if (url.length > url.indexOf('/hotels/') + 8) {
                    var len = url.substring(url.indexOf('/hotels/') + 8).split('/').length;
                    var num = 0;
                    if (url.endsWith('/')) num += 1;
                    //landingCountry
                    if (len == num + 1 && url.substring(url.indexOf('/hotels/') + 8).split('/')[0].length == 2) return 'landingCountry';
                    //landingRegion
                    if (len == num + 2) return 'landingRegion';
                    //landingResort
                    if (len == num + 3) return 'landingResort';
                }
            }


            //var protocol = location.protocol;
            //var slashes = protocol.concat("//");
            //var host = slashes.concat(window.location.hostname); console.dir(host)


            return 'unknowPage';
        }
    },
    promocodes: {
        get: function () {

            var name = 'promo';

            var nameEQ = name + "=";
            var ca = document.cookie.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) == ' ') c = c.substring(1, c.length);
                if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
            }
            return 'undefined';
        },
        movement: {


            //source - полная ссылка

            //deviceGuid - идентификатор устройства пользователя

            //pageType - тип страницы (dataLayer_pageType_dic)

            //actionType тип события с промокодом (promocodes_actionType_dic)

            fixLog: function (actionType) {

                var promocode = spotter.promocodes.get();

                if (promocode != 'undefined') {
                    var obj = {
                        deviceGuid: spotter.deviceGuid.get(),
                        pageType: spotter.dataLayer.pageType(),
                        source: document.URL,
                        promoValue: promocode,
                        actionType: actionType
                    }

                    var xmlhttp = new XMLHttpRequest();
                    xmlhttp.open("POST", "/ru/spotter/promocodes/fix");
                    xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                    xmlhttp.send(JSON.stringify(obj));
                }
            }
        }
    },
    helper: {


    },
    email: {

    },
    userMap: {
        settings: {
            synkItterationCount: 10
        },
        DB: {
            //получаем все данные
            select: function () {
                var umStorage = window.localStorage;

                var storageObjString = umStorage.getItem("userMapStorage");
                //проверяем, создано ли хпанилище
                if (storageObjString === null) {

                    var list = [];
                    var objString = JSON.stringify(list);

                    //если хранилища нету, создаем и возвпащаем его значение
                    umStorage.setItem("userMapStorage", objString);
                    return list;
                }

                return JSON.parse(storageObjString);

            },
            //добавляем запись
            add: function (row) {
                var table = spotter.userMap.DB.select();
                table.push(row);
                var objString = JSON.stringify(table);
                var umStorage = window.localStorage;
                umStorage.setItem("userMapStorage", objString);
            },
            //перезаписуем таблицу
            overwrite: function (rows) {
                var objString = JSON.stringify(rows);
                var umStorage = window.localStorage;
                umStorage.setItem("userMapStorage", objString);
            }
        },
        //синхронизация
        synck: function () {
            var table = spotter.userMap.DB.select();
            var synkItems = [];
            var othersItems = [];
            var itterationCount = spotter.userMap.settings.synkItterationCount;

            for (var i = 0; i < table.length; i++) {
                if (i < itterationCount) {
                    synkItems.push(table[i]);
                }
                else {
                    othersItems.push(table[i]);
                }
            }

            if (synkItems.length > 0) {
                //var jsonString = JSON.stringify(synkItems);
                //var xmlhttp = new XMLHttpRequest();
                //xmlhttp.open("POST", "/ru/spotter/usermap/fix");
                //xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                //xmlhttp.send(jsonString);
            }

            spotter.userMap.DB.overwrite(othersItems);
        },
        //регистрация события
        event: function (action, json) {
            var timeStamp = Math.round((new Date()).getTime() / 1000);
            var jsonString = JSON.stringify(json);
            var obj = {
                pageTypeSlug: spotter.dataLayer.pageType(),
                actionTypeSlug: action,
                source: document.URL,
                deviceType: deviceConfig.type,
                deviceGuid: GA_helper.deviceGuid(),
                GaId: GA_helper.Ga_gid(),
                unixTimestamp: timeStamp,
                actionData: {
                    objectJson: jsonString
                }
            };

            ///
            if (obj.actionTypeSlug == "pageEnter") {
                spotter.esputnik.abandoned_cart.pushToken = spotter.esputnik.esputnikPushToken.get();
                if (spotter.esputnik.abandoned_cart.pushToken == null 
                    || 
                    spotter.esputnik.abandoned_cart.pushToken=='null'
                    ) {
	                try {
		                es('getPushToken',
			                function(pushToken) {
				                spotter.esputnik.abandoned_cart.pushToken = pushToken;
				                spotter.esputnik.esputnikPushToken.set(pushToken);
			                });
	                } catch (ex) {
	                }
                }
            }


            ///События для ухода из страницы чекаута 
            if (obj.pageTypeSlug == "checkout" && obj.actionTypeSlug == "pageExit") {

                try {
                    checkout.fix('Сохранение данных формы');
                    spotter.esputnik.abandoned_cart.fix(spotter.esputnik.abandoned_cart.pushToken);

                }
                catch (error) {
                    console.error('Ошибка сохранения данных при выходе из страницы checkout');
                }
            }

            console.log(action);
            console.log(json);
            console.log(obj);

            spotter.userMap.DB.add(obj);
        }
    },
    esputnik: {
        esputnikPushToken: {
            get: function () {
                var umStorage = window.localStorage;
                var result = umStorage.getItem("userAbandonedCartStorage_guid");

                if (typeof result == 'undefined' || result == null) {
                    return null;
                }
                else {

                    return result;
                }
            },
            set: function (token) {
                var umStorage = window.localStorage;
                umStorage.setItem("userAbandonedCartStorage_guid", token);
            }
        },
        abandoned_cart: {
            pushToken: null,
            fix: function (pushToken) {
                {

                    if (pushToken == null &&
                        (
                            spotter.esputnik.abandoned_cart.pushToken == null
                        || spotter.esputnik.abandoned_cart.pushToken == 'null')
                        )
                    {
                        console.error('esputnik.abandoned_cart_push: pushToken is null');
                        return;
                    }

                    spotter.esputnik.abandoned_cart.pushToken = pushToken;

                    var pushObjJson = {
                        array: [
                                {
                                    name: checkout.settings.hotelName,
                                    imageUrl: checkout.settings.hotelImage,
                                    url: window.location.href,
                                    price: checkout.settings.priceUAH
                                    //currency: checkout.settings.currency,
                                    //price: checkout.settings.price,
                                    //priceUAH: checkout.settings.priceUAH,
                                    //prepaySum: checkout.settings.prepaySum,
                                    //language: checkout.settings.language,
                                    //stars: checkout.settings.stars
                                }
                        ]
                    }

                    var pushObj = [
                        { name: "name", value: $('#TourBooking_Client_Name').val().trim() },
                        { name: "email", value: $('#TourBooking_Client_Email').val().trim() },
                        { name: "phone", value: $('#TourBooking_Client_Phone').val().trim() },
                        { name: "json", value: JSON.stringify(pushObjJson) }
                    ];


                    var DB_obj = {
                        pushToken: pushToken,
                        pushObj: pushObj
                    };

                    spotter.esputnik.abandoned_cart.DB.add(DB_obj);

                }
            },
            DB: {
                settings: {
                    synkItterationCount: 1
                },
                //получаем все данные
                select: function () {
                    var umStorage = window.localStorage;

                    var storageObjString = umStorage.getItem("userAbandonedCartStorage");
                    //проверяем, создано ли хпанилище
                    if (storageObjString === null) {

                        var list = [];
                        var objString = JSON.stringify(list);

                        //если хранилища нету, создаем и возвпащаем его значение
                        umStorage.setItem("userAbandonedCartStorage", objString);
                        return list;
                    }

                    return JSON.parse(storageObjString);

                },
                getHash: function (jsonObj) {

                    if (typeof jsonObj == 'undefined' || jsonObj == null) {
                        return 0;
                    }

                    var jsonString = JSON.stringify(jsonObj);

                    var hash = 0, i, chr;
                    if (jsonString.length === 0) return hash;
                    for (i = 0; i < jsonString.length; i++) {
                        chr = jsonString.charCodeAt(i);
                        hash = ((hash << 5) - hash) + chr;
                        hash |= 0;
                    }
                    return hash;
                },
                //добавляем запись
                add: function (row) {
                    var table = spotter.esputnik.abandoned_cart.DB.select();

                    var row = {
                        rowHash: spotter.esputnik.abandoned_cart.DB.getHash(row),
                        data: row
                    };

                    table.push(row);
                    var objString = JSON.stringify(table);
                    var umStorage = window.localStorage;
                    umStorage.setItem("userAbandonedCartStorage", objString);
                },
                synck: function () {

                    console.warn('spotter.esputnik.abandoned_cart.DB.synck: start synk');

                    var table = spotter.esputnik.abandoned_cart.DB.select();
                    var synkItems = [];
                    var othersItems = [];
                    var itterationCount = spotter.esputnik.abandoned_cart.DB.settings.synkItterationCount;

                    for (var i = 0; i < table.length; i++) {
                        if (i < itterationCount) {
                            synkItems.push(table[i]);
                        }
                        else {
                            othersItems.push(table[i]);
                        }
                    }

                    for (sI = 0; sI < synkItems.length; sI++) {
                        var data_ = synkItems[sI].data;
                        //es('sendEvent', 'abandoned_cart_push', data_.pushToken, data_.pushObj);
                        if (spotter.esputnik.abandoned_cart.pushToken != null
                            &&
                            spotter.esputnik.abandoned_cart.pushToken != 'null') {
	                        try {
		                        es('sendEvent', 'abandoned_cart_push', spotter.esputnik.abandoned_cart.pushToken, data_.pushObj);
	                        } catch (ex) {
	                        }
                        }
                        
                    }

                    spotter.esputnik.abandoned_cart.DB.overwrite(othersItems);
                },
                //перезаписуем таблицу
                overwrite: function (rows) {
                    var objString = JSON.stringify(rows);
                    var umStorage = window.localStorage;
                    umStorage.setItem("userAbandonedCartStorage", objString);
                }
            }
        }
    },
    deviceInfo: {
        get: function () {
            var date = new Date();
            var app_device = {
                time_zone: -1 * date.getTimezoneOffset() / 60,
                ipv4: globalSystemSettings.ip4,
                device_guid: globalSystemSettings.guestId,
                browser: {
                    product_sub: navigator.productSub,
                    vendor: navigator.vendor,
                    max_touch_points: navigator.maxTouchPoints,
                    hardware_concurrency: navigator.hardwareConcurrency,
                    app_code_name: navigator.appCodeName,
                    app_name: navigator.appName,
                    app_version: navigator.appVersion,
                    platform: navigator.platform,
                    product: navigator.product,
                    user_agent: navigator.userAgent,
                    language: navigator.language,
                    on_line: navigator.onLine,
                    cookie_enabled: navigator.cookieEnabled,
                    do_not_track: navigator.doNotTrack
                },
                browser_plugins: function () {
                    var L = navigator.plugins.length;
                    var obj = [];


                    for (var i = 0; i < L; i++) {

                        var item = {
                            name: navigator.plugins[i].name,
                            version: navigator.plugins[i].version,
                            installed: true,
                            enabled: true
                        }

                        obj.push(item);
                    }

                    return obj;
                },
                screen: {
                    avail_width: screen.availWidth,
                    avail_height: screen.availHeight,
                    width: screen.width,
                    height: screen.height,
                    color_depth: screen.colorDepth,
                    pixel_depth: screen.pixelDepth,
                    avail_left: screen.availLeft,
                    avail_top: screen.availTop,
                    orientation: 'type:' + (screen.orientation ? screen.orientation.type : '') + ', ' + 'angle:' + (screen.orientation ? screen.orientation.angle : '')
                }
            }

            return app_device;
        },
        fix: function () {

            var deviceInfoString = JSON.stringify(spotter.deviceInfo.get());

            var obj = {
                deviceGuid: GA_helper.deviceGuid(),
                GaId: GA_helper.Ga_gid(),
                deviceType: deviceConfig.type,
                deviceInfo: deviceInfoString
            };

            if (spotter.deviceInfo.DB.add(obj)) {
                //var jsonString = JSON.stringify(obj);
                //var xmlhttp = new XMLHttpRequest();
                //xmlhttp.open("POST", "/ru/spotter/usermap/fixDevice");
                //xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                //xmlhttp.send(jsonString);
            }
        },
        DB: {
            //получаем все данные
            select: function () {
                var umStorage = window.localStorage;

                var storageObjString = umStorage.getItem("userMapDeviceStorage");
                //проверяем, создано ли хпанилище
                if (storageObjString === null) {

                    var list = [];
                    var objString = JSON.stringify(list);

                    //если хранилища нету, создаем и возвпащаем его значение
                    umStorage.setItem("userMapDeviceStorage", objString);
                    return list;
                }

                return JSON.parse(storageObjString);

            },
            //добавляем запись
            add: function (row) {

                var rowHash = spotter.deviceInfo.getHash(row);
                var isExist = false;
                var table = spotter.deviceInfo.DB.select();


                for (i = 0; i < table.length; i++) {
                    if (table[i] == rowHash) {
                        isExist = true;
                    }
                }
                if (!isExist) {
                    table.push(rowHash);
                    var objString = JSON.stringify(table);
                    var umStorage = window.localStorage;
                    umStorage.setItem("userMapDeviceStorage", objString);
                    return true;
                }

                return false;
            }
        },
        getHash: function (jsonObj) {

            if (typeof jsonObj == 'undefined' || jsonObj == null) {
                return 0;
            }

            var obj = {
                DiId: jsonObj.deviceGuid,
                GaId: jsonObj.GaId
            };

            var jsonString = JSON.stringify(obj);

            var hash = 0, i, chr;
            if (jsonString.length === 0) return hash;
            for (i = 0; i < jsonString.length; i++) {
                chr = jsonString.charCodeAt(i);
                hash = ((hash << 5) - hash) + chr;
                hash |= 0;
            }
            return hash;
        }
    },
    checkout: {
        DB: {
            settings: {
                synkItterationCount: 3
            },
            //получаем все данные
            select: function () {
                var umStorage = window.localStorage;

                var storageObjString = umStorage.getItem("userCheckOutStorage");
                //проверяем, создано ли хпанилище
                if (storageObjString === null) {

                    var list = [];
                    var objString = JSON.stringify(list);

                    //если хранилища нету, создаем и возвпащаем его значение
                    umStorage.setItem("userCheckOutStorage", objString);
                    return list;
                }

                return JSON.parse(storageObjString);

            },
            getHash: function (jsonObj) {

                if (typeof jsonObj == 'undefined' || jsonObj == null) {
                    return 0;
                }

                var jsonString = JSON.stringify(jsonObj);

                var hash = 0, i, chr;
                if (jsonString.length === 0) return hash;
                for (i = 0; i < jsonString.length; i++) {
                    chr = jsonString.charCodeAt(i);
                    hash = ((hash << 5) - hash) + chr;
                    hash |= 0;
                }
                return hash;
            },
            //добавляем запись
            add: function (row) {
                var table = spotter.checkout.DB.select();

                var row = {
                    rowHash: spotter.checkout.DB.getHash(row),
                    data: row
                };


                var isExist = false;
                for (i = 0; i < table.length; i++) {
                    if (table[i].rowHash == row.rowHash) {
                        isExist = true;
                    }
                }
                if (!isExist) {
                    table.push(row);

                    var objString = JSON.stringify(table);
                    var umStorage = window.localStorage;
                    umStorage.setItem("userCheckOutStorage", objString);
                }
            },
            //перезаписуем таблицу
            overwrite: function (rows) {
                var objString = JSON.stringify(rows);
                var umStorage = window.localStorage;
                umStorage.setItem("userCheckOutStorage", objString);
            },
            synck: function () {
                var table = spotter.checkout.DB.select();
                var synkItems = [];
                var othersItems = [];
                var itterationCount = spotter.checkout.DB.settings.synkItterationCount;

                for (var i = 0; i < table.length; i++) {
                    if (i < itterationCount) {
                        synkItems.push(table[i]);
                    }
                    else {
                        othersItems.push(table[i]);
                    }
                }

                for (sI = 0; sI < synkItems.length; sI++) {
                    var jsonString = JSON.stringify(synkItems[sI].data);
                    var xmlhttp = new XMLHttpRequest();
                    xmlhttp.open("POST", "/order/check/fast-order-data/");
                    xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                    xmlhttp.send(jsonString);
                }

                spotter.checkout.DB.overwrite(othersItems);
            }
        }
    }
};


var spotterDocumentReady_loaded = false;

farDocument.onReady(function () {
    if (spotterDocumentReady_loaded === true) return;

    spotterDocumentReady_tryGetToken();


    setTimeout(function () {

        //---synk abonded esputnik abandoned_cart data
        try {
            spotter.esputnik.abandoned_cart.DB.synck();
        }
        catch (error) {
            console.error('spotter.esputnik.abandoned_cart.DB.synck:' + error);
        }
        //---end synk abonded esputnik abandoned_cart data

    }, 4000);


    spotterDocumentReady_loaded = true;
});

function spotterDocumentReady_tryGetToken() {
    setTimeout(function () {

        console.error('get spotter.esputnik.abandoned_cart.pushToken --->');

        spotter.esputnik.abandoned_cart.pushToken = spotter.esputnik.esputnikPushToken.get();
        if (spotter.esputnik.abandoned_cart.pushToken == null) {
            es('getPushToken', function (pushToken) {

                if (pushToken != null&&pushToken != 'null') {

                    console.error('spotter.esputnik.abandoned_cart.pushToken = ' + pushToken);
                    spotter.esputnik.abandoned_cart.pushToken = pushToken;
                    spotter.esputnik.esputnikPushToken.set(pushToken);
                } else {
                    setTimeout(function () {
                        console.error('get spotter.esputnik.abandoned_cart.pushToken retry --->');
                        es('getPushToken', function (pushToken) {
                            if (pushToken != null&&pushToken != 'null') {
                                console.error('spotter.esputnik.abandoned_cart.pushToken = ' + pushToken);
                                spotter.esputnik.abandoned_cart.pushToken = pushToken;
                                spotter.esputnik.esputnikPushToken.set(pushToken);
                            }
                        });
                    }, 3000);
                }
            });
        }

    }, 20000);
}


document.addEventListener("DOMContentLoaded", function (event) {

});

;
/*

e 								m 		c
showOthersClick					true	true
tourBuyClick					true	true
searchForm_showBigForm			true	true
searchForm_changeAirport		true	true
searchForm_changeCountry		true	true
searchForm_changeCheckOut		true	true
searchForm_changeNight			true	true
searchForm_changeTourist		true	true
searchForm_changeStars			true	true
searchForm_changeResort			true	true
searchForm_changeMeals			true	true
searchForm_changeHotels			true	true
searchClick						true	true
filter_setResort				true	true
filter_setBudget				true	true
filter_setResortParsmeters		true	true
filter_setHotelParsmeters		true	true
filter_setHotelRating			true	true
filter_setMeals					true	true
filter_setHotelStars			true	true
filter_sortByPrice				true	true
filter_sortByRating				true	true
filter_sortByPriceQuality		true	true
filter_show						true	true
pageExit						true	true
pageEnter						true	true
catalogMap_open					true	true
catalogMap_close				true	true
thankYouPage					true	true
checkoutClick					true	true
checkoutRequestClick			true	true
checkoutBuyClick				true	true
loadDetalComment				true	true
showGallery						true	true
menuClick_description			true	true
menuClick_calendar				true	true
menuClick_weather				true	true
menuClick_detal					true	true
menuClick_reviews				true	true
menuClick_recomendedTours		true	true
showBigMapClick					true	true
otherTourTabClick				true	true
calendatTabClick				true	true
tour_departureTimeRequestClick	true	true
subscribe_catalogPage           true    true
fastOrder_callMe                true    true
fastOrder_callMe_showPopup      true    true

 */

function userDataCollector() {
	/*

	This Class contain all events, required in http://148.251.187.224:8090/pages/viewpage.action?pageId=678560339

	*/
	var self = this;


	// this.settings contain all variables, required in this class
	this.settings 	= {
		debug: false,
		debug_spotter: false,
		synk_first_timeout: 2000,
		synk_timeout: 10000
	};
	this.exec_debug_mode = function() {
		self.settings.debug = true;
		self.settings.debug_spotter = true;
		self.spotter = {
				userMap: {
					event: function(e, m) {
						console.log('UDC >>>>>>>> ');
						console.log(e);
						console.log(JSON.stringify(m));
						console.log(m);
						console.log('<<<<<<<< UDC');
					},
					synck: function(e) {
						console.log('UDC spotter.userMap.synck fire');
						console.log(e);
					}
				},
				deviceInfo: {
					fix: function(e) {
						console.log('UDC spotter.deviceInfo.fix fire');
						console.log(e);
					}
				}
			};
	};
	if (this.settings.debug_spotter) {
		this.exec_debug_mode();
	} else {
		this.spotter = spotter;
	}

	// this.models contain all methods for create required models
	this.models 	= {
		pageEnter: function() {
			if (self.settings.debug) console.log('UDC.models.pageEnter');
			return {
					url: 		self.methods.url.get(),
					referral: 	self.methods.referrer.get()
			};
		},
		pageExit: function() {
			if (self.settings.debug) console.log('UDC.models.pageExit');
			return {
					url: 		self.methods.url.get(),
					referral: 	self.methods.referrer.get()
			};
		},
		searchFormData: function() {
			if (self.settings.debug) console.log('UDC.models.searchFormData');
			return {
				formData: self.methods.search_form.get()
			};
		},
		filterFormData: function() {
			if (self.settings.debug) console.log('UDC.models.filterFormData');
			return {
				formData: self.methods.search_form.get(),
				filterData: self.methods.filter_form.get(),
				sortType: self.methods.sorting_form.get()
			};
		},
		tourBuyClick: function(model) {
			if (self.settings.debug) console.log('UDC.models.tourBuyClick');
			return {
				formData: 	self.methods.search_form.get(),
				filterData: self.methods.filter_form.get(),
				sHash: 		self.methods.sHash.get(),
				hotelsId: 	model.key,
				systemKey: 	model.currentTour.SystemKey,
				price: 		model.currentTour.price.redPrice,
				curr: 		model.currentTour.price.currency,
				priceUAH: 	model.currentTour.price.redPriceUAH
			};
		},
		showOthersClick: function(model) {
			if (self.settings.debug) console.log('UDC.models.showOthersClick');
			return {
				hotelsId: 	model.key,
				systemKey: 	model.lastCheapestTour.SystemKey,
				price: 		model.lastCheapestTour.price.redPrice,
				curr: 		model.lastCheapestTour.price.currency,
				priceUAH: 	model.lastCheapestTour.price.redPriceUAH
			};
		},
		checkoutBuyClick: function() {
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey,
				price: 		TP.settings.price,
				curr: 		TP.settings.cyrrency,
				priceUAH: 	TP.settings.priceUAH,
				referral: 	self.methods.referrer.get()
			});
		},
		checkoutRequestClick: function() {
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey,
				price: 		TP.settings.price,
				curr: 		TP.settings.cyrrency,
				priceUah: 	TP.settings.priceUAH
			});
		},
		checkoutClick: function(form_data) {
			return {
				hotelsId: 	window.hotelKey,
				systemKey: 	window.SystemKey,
				price: 		window.price,
				curr: 		window.currency,
				priceUah: 	window.priceUah,
				paySumUah: 	window.paySumUah,
				paySystemType:form_data.payType_humanize,
				name: 		form_data.client.name,
				email: 		form_data.client.email,
				phone: 		form_data.client.phone
			};
		},
		thankYouPage: function() {
			return {
				systemKey: 	window.order_id,
				orderId:  	window.SystemKey,
				invoiceId: 	window.invoiceId
			};
		},
		loadDetalComment: function(commentId) {
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey,
				commentId: 	commentId,
			});
		},
		showGallery: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		menuClick_description: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		menuClick_calendar: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		menuClick_weather: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		menuClick_detal: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		menuClick_reviews: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		menuClick_recomendedTours: function(){
			return (typeof TP == 'undefined'?{}:{
				hotelsId: 	TP.settings.currentHotelKey,
				systemKey: 	TP.settings.currentSystemKey
			});
		},
		tour_departureTimeRequestClick: function(hotelsId, systemKey) {
			return {
				hotelsId: hotelsId,
				systemKey:systemKey
			};
		},
		otherTourTabClick: function () {
		    return (typeof TP == 'undefined' ? {} : {
		        hotelsId: TP.settings.currentHotelKey,
		        systemKey: TP.settings.currentSystemKey
		    });
		},
		calendatTabClick: function () {
		    return (typeof TP == 'undefined' ? {} : {
		        hotelsId: TP.settings.currentHotelKey,
		        systemKey: TP.settings.currentSystemKey
		    });
		},
		showBigMapClick: function () {
		    return (typeof TP == 'undefined' ? {} : {
		        hotelsId: TP.settings.currentHotelKey,
		        systemKey: TP.settings.currentSystemKey
		    });
		},
		catalogMap_open: function() {
			return {
				formData: 	self.methods.search_form.get(),
				filterData: self.methods.filter_form.get(),
				sHash: self.methods.sHash.get()
			};
		},
		catalogMap_close: function() {
			return {
				formData: 	self.methods.search_form.get(),
				filterData: self.methods.filter_form.get(),
				sHash: self.methods.sHash.get()
			};
		},
		subscribe_catalogPage: function() {
		    return {
		        formData: 	self.methods.search_form.get(),
		        filterData: self.methods.filter_form.get(),
		        sortType: self.methods.sorting_form.get(),
		        contact: self.methods.contactEmail.get(),
		        hotelsCount: self.methods.searchHotels.get(),
		    };
		},
		fastOrder_callMe: function() {
		    return {
		        url: 	self.methods.url.get(),
		        contact: self.methods.contactPhone.get(),
		    };
		},
		fastOrder_callMe_showPopup: function() {
		    return {
		        url: 	self.methods.url.get(),
		    };
		},
	};

	// this.methods contain all methods for gettings and setting values;
	this.methods 	= {
		set_all_by_default: function() {
			if (self.settings.debug) console.log('UDC.methods.set_all_by_default');
			self.methods.origin.set(self.methods.origin.default());
			self.methods.url.set(self.methods.url.default());
			self.methods.referrer.set(self.methods.referrer.default());
			return {};
		},
		contactEmail:{
		    get: function() {
		        return document.querySelector('.subscribe_form__input').value;
		    },
		    set: function() { },
		    default: function () { }
		},
		contactPhone: {
		    get: function () {
		    	var phoneInput = document.getElementById(callback__phone),
		    		value = (phoneInput?phoneInput.value:'');
		        return value.replace(/\(/gi, '').replace(/\)/gi, '').replace(/\-/gi, '').replace(/ /gi, '').replace('+', '');
		    },
		    set: function () { },
		    default: function () { }
		},
		searchHotels: {
		    get: function () {
		        return (typeof farSearchCatalog != 'undefined' ? farSearchCatalog.filter.uniqueHotels.length : hotelsSearchCatalog.filter.uniqueHotels);
		    },
		    set: function () { },
		    default: function () { }
		},
		origin: {
			get: function() {
				return self.settings.origin;
			},
			set: function(str) {
				self.settings.origin = str;
			},
			default: function() {
				return document.location.origin;
			}
		},
		url: {
			get: function() {
				return self.settings.url;
			},
			set: function(str) {
				self.settings.url = str;
			},
			default: function() {
				return window.location.href;
			}
		},
		referrer: {
			get: function() {
				return self.settings.referrer;
			},
			set: function(str) {
				self.settings.referrer = str;
			},
			default: function() {
				return document.referrer;
			}
		},
		search_form: {
			get: function() {
				return (typeof advancedSearch=='undefined'?{}:advancedSearch.getData());
			},
			set: function() {},
			default: function() {}
		},
		filter_form: {
			get: function() {
			    return (typeof results_filter == 'undefined' ? {} : results_filter.model_coverters.settings_to_spotter());
			},
			set: function() {},
			default: function() {}
		},
		sorting_form: {
			get: function() {
				if (typeof farSearchCatalog == 'undefined') return '';
				var sort_order = 'ASC';
				switch (farSearchCatalog.views.sortDir) {
					case 'p_down':
					case 'ra_down':
						sort_order = 'ASC';
					break;
					case 'p_up':
						sort_order = 'DESC';
					break;
				}
				return sort_order;
			},
			set: function() {},
			default: function() {}
		},
		sHash: {
			get: function() {
				if (typeof sHash == 'undefined') {
					if (typeof window.sHash == 'undefined') {
						var sHash = '';
					} else {
						var sHash = window.sHash;
					}
				}
				return sHash;
			},
			set: function() {},
			default: function() {}
		}
	};

	this.queryes 	= {
		pageEnter: function() {
			var model = self.models.pageEnter();
			self.spotter.userMap.event('pageEnter',model);
		},
		pageExit: function() {
			var model = self.models.pageExit();
			self.spotter.userMap.event('pageExit',model);
			self.synk.query();
		},
		searchClick: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchClick',model);
		},
		searchForm_showBigForm: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_showBigForm',model);
		},
		searchForm_changeAirport: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeAirport',model);
		},
		searchForm_changeCountry: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeCountry',model);
		},
		searchForm_changeCheckOut: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeCheckOut',model);
		},
		searchForm_changeNight: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeNight',model);
		},
		searchForm_changeTourist: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeTourist',model);
		},
		searchForm_changeStars: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeStars',model);
		},
		searchForm_changeResort: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeResort',model);
		},
		searchForm_changeMeals: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeMeals',model);
		},
		searchForm_changeHotels: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeHotels',model);
		},
		searchForm_changeKidsAge: function() {
			var model = self.models.searchFormData();
			self.spotter.userMap.event('searchForm_changeKidsAge',model);
		},
		filter_sortByPrice: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_sortByPrice',model);
		},
		filter_sortByRating: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_sortByRating',model);
		},
		filter_sortByPriceQuality: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_sortByPriceQuality',model);
		},
		filter_show: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_show',model);
		},
		filter_setResort: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setResort',model);
		},
		filter_setBudget: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setBudget',model);
		},
		filter_setResortParsmeters: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setResortParsmeters',model);
		},
		filter_setHotelParsmeters: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setHotelParsmeters',model);
		},
		filter_setHotelRating: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setHotelRating',model);
		},
		filter_setMeals: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setMeals',model);
		},
		filter_setHotelStars: function() {
			var model = self.models.filterFormData();
			self.spotter.userMap.event('filter_setHotelStars',model);
		},
		tourBuyClick: function(parent) {
			var model = self.models.tourBuyClick(parent.Hotel.getModel(parent.SystemKey));
			self.spotter.userMap.event('tourBuyClick',model);
		},
		showOthersClick: function(parent) {
			var model = self.models.tourBuyClick(parent.Hotel.getModel());
			self.spotter.userMap.event('showOthersClick',model);
		},
		checkoutBuyClick: function() {
			var model = self.models.checkoutBuyClick();
			self.spotter.userMap.event('checkoutBuyClick',model);
		},
		checkoutRequestClick: function() {
			var model = self.models.checkoutRequestClick();
			self.spotter.userMap.event('checkoutRequestClick',model);
		},
		checkoutClick: function() {
			var form_data 	= checkout.getFormData(),
				model 		= self.models.checkoutClick(form_data);
			self.spotter.userMap.event('checkoutClick',model);
		},
		thankYouPage: function() {
			var model = self.models.thankYouPage();
			self.spotter.userMap.event('thankYouPage',model);
		},
		loadDetalComment: function() {
			var commentId = $(this).data('comment_id'),
				model = self.models.loadDetalComment(commentId);
			self.spotter.userMap.event('loadDetalComment',model);
		},
		showGallery: function() {
			var model = self.models.showGallery();
			self.spotter.userMap.event('showGallery',model);
		},
		menuClick_description: function() {
			var model = self.models.menuClick_description();
			self.spotter.userMap.event('menuClick_description',model);
		},
		menuClick_calendar: function() {
			var model = self.models.menuClick_calendar();
			self.spotter.userMap.event('menuClick_calendar',model);
		},
		menuClick_weather: function() {
			var model = self.models.menuClick_weather();
			self.spotter.userMap.event('menuClick_weather',model);
		},
		menuClick_detal: function() {
			var model = self.models.menuClick_detal();
			self.spotter.userMap.event('menuClick_detal',model);
		},
		menuClick_reviews: function() {
			var model = self.models.menuClick_reviews();
			self.spotter.userMap.event('menuClick_reviews',model);
		},
		menuClick_recomendedTours: function() {
			var model = self.models.menuClick_recomendedTours();
			self.spotter.userMap.event('menuClick_recomendedTours',model);
		},
		tour_departureTimeRequestClick: function(e) {
			var el 			= e,
				hotelID 	= el.getAttribute('data-key'),
				systemkey 	= el.getAttribute('data-id'),
				model 		= self.models.tour_departureTimeRequestClick(hotelID, systemkey);
			self.spotter.userMap.event('tour_departureTimeRequestClick',model);
		},
		otherTourTabClick: function () {
		    var model = self.models.otherTourTabClick();
		    self.spotter.userMap.event('otherTourTabClick', model);
		},
		calendatTabClick: function () {
		    var model = self.models.calendatTabClick();
		    self.spotter.userMap.event('calendatTabClick', model);
		},
		showBigMapClick: function () {
		    var model = self.models.showBigMapClick();
		    self.spotter.userMap.event('showBigMapClick', model);
		},
		catalogMap_open: function() {
			var model = self.models.catalogMap_open();
			self.spotter.userMap.event('catalogMap_open',model);
		},
		catalogMap_close: function() {
			var model = self.models.catalogMap_close();
			self.spotter.userMap.event('catalogMap_close',model);
		},
		catalogMap_openClose: function() {
			if (typeof results_filter == 'undefined') return;
			if (typeof results_filter.methods.map__is_active == 'undefined'||!results_filter.methods.map__is_active) {
				self.queryes.catalogMap_open();
			} else {
				self.queryes.catalogMap_close();
			}
		},
		subscribe_catalogPage: function() {
		    var model = self.models.subscribe_catalogPage();
		    if (isValidEmailAddress(model.contact)) {
		        self.spotter.userMap.event('subscribe_catalogPage', model);
		    }
		},
		fastOrder_callMe: function() {
		    var model = self.models.fastOrder_callMe();
		    if (model.contact.length == 12) {
		        self.spotter.userMap.event('fastOrder_callMe', model);
		    }
	    },
		fastOrder_callMe_showPopup: function() {
	        var model = self.models.fastOrder_callMe_showPopup();
	        self.spotter.userMap.event('fastOrder_callMe_showPopup',model);
	    },
	};

	this.helpers = {
		get_tour_from_renderTours: function(parentSystemKey, SystemKey) {
			var local_tour = undefined;
			if (typeof parentSystemKey=='undefined') {
				if (typeof SystemKey=='undefined') {
					local_tour = undefined;
				} else {
					if (typeof render.tours[SystemKey]!='undefined') {
						local_tour = render.tours[SystemKey];
					} else {
						local_tour = (typeof farSearchCatalog == 'undefined'?undefined:farSearchCatalog.tours.getStorage().tours[SystemKey]);
					}
				}
			} else {
				if (parentSystemKey==SystemKey) {
					local_tour = render.tours[SystemKey];
				} else {
					if (typeof render.tours[parentSystemKey] == 'undefined') {
						local_tour = (typeof farSearchCatalog == 'undefined'?undefined:farSearchCatalog.tours.getStorage().tours[SystemKey]);
					} else {
						for (var i=0; i<render.tours[parentSystemKey].other.length;i++) {
							if (render.tours[parentSystemKey].other[i].SystemKey==SystemKey) {
								local_tour = render.tours[parentSystemKey].other[i];
							}
						}
					}
				}
			}
			return local_tour;
		},
		result_filter_checkbox_class: function(group) {
			var clas = '';
			switch (group) {
				case 'resorts':
					clas = 'filter_setResort';
				break;
				case 'price':
					clas = 'filter_setBudget';
				break;
				case 'resortProperties':
					clas = 'filter_setResortParsmeters';
				break;
				case 'hotelProperties':
					clas = 'filter_setHotelParsmeters';
				break;
				case 'rates':
					clas = 'filter_setHotelRating';
				break;
				case 'meals':
					clas = 'filter_setMeals';
				break;
				case 'stars':
					clas = 'filter_setHotelStars';
				break;
			}
			return 'UDC__'+clas;
		},
		result_filter_sort_helper: function(sort_type) {
			var clas = '';
			switch (sort_type) {
				case 'price':
					clas = 'filter_sortByPrice';
				break;
				case 'rating':
					clas = 'filter_sortByRating';
				break;
				case 'farvater_recommended':
					clas = 'filter_sortByPriceQuality';
				break;
			}
			return 'UDC__'+clas;
		}
	};

	this.synk = {
		timeout: null,
		start: function() {
			if (self.settings.debug) console.log('UDC.synk.start');
			self.synk.timeout = setTimeout(self.synk.query,self.settings.synk_timeout);
		},
		query: function() {
		    self.spotter.userMap.synck();
		    self.spotter.deviceInfo.fix();

		    //---synk abonded checkout data
		    try{
		        spotter.checkout.DB.synck();
		    }
		    catch(error){
		        console.error('spotter.checkout.DB.synck:' + error);
		    }
		    //---end synk abonded checkout data

			self.synk.start();
		},
		break: function() {
			clearTimeout(self.synk.timeout);
			self.synk.timeout = null;
		}
	};

	this.init = function() {
		self.methods.set_all_by_default();
		self.synk.timeout = setTimeout(self.synk.query,self.settings.synk_first_timeout);
		self.queryes.pageEnter();
		window.Far.Events.onUnload.add('userDataCollector__onUnload', self.queryes.pageExit);
		window.Far.Events.bodyClick.add('userDataCollector__UDC', {}, function(e){
		    window.Far.Events.bodyClick.checkNodeClassMultiple({
		        UDC__subscribe_catalogPage: self.queryes.subscribe_catalogPage,
		        UDC__filter_sortByPrice: self.queryes.filter_sortByPrice,
		        UDC__filter_sortByRating: self.queryes.filter_sortByRating,
		        UDC__filter_sortByPriceQuality: self.queryes.filter_sortByPriceQuality,
		        UDC__filter_show: self.queryes.filter_show,
		        UDC__filter_setResort: self.queryes.filter_setResort,
		        UDC__filter_setBudget: self.queryes.filter_setBudget,
		        UDC__filter_setResortParsmeters: self.queryes.filter_setResortParsmeters,
		        UDC__filter_setHotelParsmeters: self.queryes.filter_setHotelParsmeters,
		        UDC__filter_setHotelRating: self.queryes.filter_setHotelRating,
		        UDC__filter_setMeals: self.queryes.filter_setMeals,
		        UDC__filter_setHotelStars: self.queryes.filter_setHotelStars,
		        UDC__catalogMap_openClose: self.queryes.catalogMap_openClose,
		        UDC__catalogMap_open: self.queryes.catalogMap_open,
		        UDC__catalogMap_close: self.queryes.catalogMap_close,

		        UDC__tourBuyClick: self.queryes.tourBuyClick,
		        UDC__showOthersClick: self.queryes.showOthersClick,
		        UDC__checkoutRequestClick: self.queryes.checkoutRequestClick,
		        UDC__checkoutClick: self.queryes.checkoutClick,
		        UDC__loadDetalComment: self.queryes.loadDetalComment,
		        UDC__showGallery: self.queryes.showGallery,
		        UDC__menuClick_description: self.queryes.menuClick_description,
		        UDC__menuClick_calendar: self.queryes.menuClick_calendar,
		        UDC__menuClick_weather: self.queryes.menuClick_weather,
		        UDC__menuClick_detal: self.queryes.menuClick_detal,
		        UDC__menuClick_reviews: self.queryes.menuClick_reviews,
		        UDC__menuClick_recomendedTours: self.queryes.menuClick_recomendedTours,
		        UDC__otherTourTabClick: self.queryes.otherTourTabClick,
		        UDC__calendatTabClick: self.queryes.calendatTabClick,
		        UDC__showBigMapClick: self.queryes.showBigMapClick,

		        UDC__checkoutBuyClick: self.queryes.checkoutBuyClick,

		        UDC__fastOrder_callMe: self.queryes.fastOrder_callMe,
		        UDC__fastOrder_callMe_showPopup: self.queryes.fastOrder_callMe_showPopup,

		        UDC__searchClick: self.queryes.searchClick,
		        UDC__searchForm_showBigForm: self.queryes.searchForm_showBigForm,
		        UDC__searchForm_changeAirport: self.queryes.searchForm_changeAirport,
		        UDC__searchForm_changeCountry: self.queryes.searchForm_changeCountry,
		        UDC__searchForm_changeCheckOut: self.queryes.searchForm_changeCheckOut,
		        UDC__searchForm_changeNight: self.queryes.searchForm_changeNight,
		        UDC__searchForm_changeTourist: self.queryes.searchForm_changeTourist,
		        UDC__searchForm_changeStars: self.queryes.searchForm_changeStars,
		        UDC__searchForm_changeResort: self.queryes.searchForm_changeResort,
		        UDC__searchForm_changeMeals: self.queryes.searchForm_changeMeals,
		        UDC__searchForm_changeHotels: self.queryes.searchForm_changeHotels,
		        UDC__searchForm_changeKidsAge: self.queryes.searchForm_changeKidsAge,
		        UDC__tour_departureTimeRequestClick: self.queryes.tour_departureTimeRequestClick
		    }, e);
		});
	};
	this.init();
}

var farUserDataCollector;
farDocument.onReady(function () {

    window.farUserDataCollector = new userDataCollector();
});

;
/// <reference path="_references.js" />

var farAnalytics = {
	pushEvent: function (source, eventName, category, data) {
		//console.log(arguments);
		return;
        var guestId = Cookies.get('GuestId');
        if (typeof guestId == 'undefined' || guestId.length < 32) {
            return;
        }
        var model = {
            guestId: Cookies.get('GuestId'),
            source: source,
            eventName: eventName,
            category: category,
            data: JSON.stringify(data)
        };
        ExecuteActionCROS(
            'https://my.farvater.travel/analytics/createevent',
            model,
            {},
            function (response) {},
            function (response) {}
       );
    }
};

/**
 * Facebook Pixel tour model.
 * @typedef {{hotelId: number; hotelName: string; checkIn: string; checkOut: string; country: string; resort: string; region: string;  adults: number; children: number; priceUah: number}} PXL_TOUR
 */

 /**
  * JFon short version
  * @typedef {{
  * hotelId: number; 
  * hotel: { value: string }; 
  * checkIn: { value: string }; 
  * nights: number; 
  * countryName: string; 
  * region: { RegionHash: number; RegionName: string; ResortHash: number; ResortName: string }; 
  * adl: number; 
  * kids: number; 
  * priceUAH: number}} sJFon
  */

/**
* Enum for values.
* @readonly
* @enum {string}
*/
var PXL_EVENTS = {
    Search: 'Search',
    ViewContent: 'ViewContent',
    AddToCart: 'AddToCart',
    InitiateCheckout: 'InitiateCheckout',
    Purchase: 'Purchase'
};

window.PXL = window.PXL || {
    /**
     * @type {PXL_TOUR}
     */
    tourModel: null,
    
    /**
     * 
     * @param {PXL_EVENTS} eventName
     * @param {any} model
     */
    trackAny: function (eventName, model) {
        if (typeof fbq !== 'undefined') {
            console.log(eventName, model);
            if (typeof model !== 'undefined') {
                fbq('track', eventName, model);
            }
            else {
                fbq('track', eventName);
            }
        }
        else {
            if (typeof window.pxlDataLayer === 'undefined') {
                window.pxlDataLayer = [];
            }
            window.pxlDataLayer.push({
                eventName,
                model
            });
        }
    },

    /**
     * 
     * @param {PXL_EVENTS} eventName
     * @param {PXL_TOUR} model
     */
    trackTour: function (eventName) {
        if (window.PXL.tourModel === void 0) {
            return;
        }
        window.PXL.trackAny(eventName, {
            content_ids: window.PXL.tourModel.hotelId.toString(),
            content_type: 'hotel',
            content_name: window.PXL.tourModel.hotelName,
            city: window.PXL.tourModel.resort,
            region: window.PXL.tourModel.region,
            num_adults: window.PXL.tourModel.adults,
            checkin_date: window.PXL.tourModel.checkIn,
            checkout_date: window.PXL.tourModel.checkOut,
            country: window.PXL.tourModel.country,
            num_children: window.PXL.tourModel.children,
            value: window.PXL.tourModel.priceUah,
            currency: 'UAH'
        });
    },

    /**
     * 
     */
    viewContent: function () {
        window.PXL.trackTour(PXL_EVENTS.ViewContent);
    },

    /**
     * 
     */
    addToCart: function () {
        window.PXL.trackTour(PXL_EVENTS.AddToCart);
    },

    /**
     * 
     */
    initiateCheckout: function () {
        window.PXL.trackTour(PXL_EVENTS.InitiateCheckout);
    },

    /**
     * 
     */
    purchase: function () {
        window.PXL.trackTour(PXL_EVENTS.Purchase);
    },

    /**
     * 
     * @param {sJFon[]} tours
     */
    search: function (tours) {
        /** @type {Map<number, sJFon[]>} */
        var resortedHotels = new Map();
        tours.forEach(function (tour) {
            if (window.PXL.trackedHotels.indexOf(tour.hotelId) === -1) {
                window.PXL.trackedHotels.push(tour.hotelId);
                if (!resortedHotels.has(tour.region.ResortHash)) {
                    resortedHotels.set(tour.region.ResortHash, []);
                }
                resortedHotels.get(tour.region.ResortHash).push(tour);
            }
        });
        resortedHotels.forEach(function (hotels) {
            var country = hotels[0].countryName,
                resort = hotels[0].region.ResortName,
                region = hotels[0].region.RegionName,
                adults = hotels[0].adl,
                kids = hotels[0].kids,
                checkIn = new Date(hotels[0].checkIn.value),
                nights = hotels[0].nights,
                checkOut = new Date(checkIn).addDays(nights);
            window.PXL.trackAny('Search', {
                content_ids: '["' + hotels.map(function (hotel) { return hotel.hotelId.toString() }).join('", "') + '"]',
                content_type: 'hotel',
                city: resort,
                region: region,
                num_adults: adults,
                checkin_date: window.PXL.dateToString(checkIn),
                checkout_date: window.PXL.dateToString(checkOut),
                country: country,
                num_children: kids
            });
        });
    },

    /**
     * @type {number[]}
     */
    trackedHotels: [],

    dateToString: function (date) {
        var dd = ('0' + date.getDate()).toString().slice(-2),
            mm = ('0' + (date.getMonth() + 1)).toString().slice(-2),
            yyyy = date.getFullYear();
        return [yyyy, mm, dd].join('-');
    }
}

if (typeof window.dataLayer === 'undefined') window.dataLayer = [];

var GTM = {

    cookieName: 'clickinfo',
    getCookieValue: function () {
        var value = (typeof Cookies !== 'undefined' ? Cookies.get(this.cookieName) || '' : '');
        return value;
    },
    setCookieValue: function (value) {
        Cookies.set(this.cookieName, value, { expires: 365 });
    },
    ///m1234567889.block8
    setCookieClickInfo: function (systemKey, listType) {
        var value = this.getCookieValue();
        if (value.length > 0) value += '_';
        value += systemKey + '.' + listType;
        this.setCookieValue(value);
    },
    removeCookieClickInfo: function (systemKey) {
        var fresh = [];
        var value = this.getCookieValue();
        var pairs = value.split('_');
        for (var i = 0; i < pairs.length; i++) {
            var data = pairs[i].split('.');
            if (data[0] != systemKey) fresh.push(pairs[i]);
        }
        value = fresh.join('_');
        this.setCookieValue(value);
    },
    getCookieClickInfo: function (systemKey) {
        var value = this.getCookieValue();
        if (value.length == 0) return 'block5';
        var pairs = value.split('_');
        for (var i = 0; i < pairs.length; i++) {
            var data = pairs[i].split('.');
            if (data[0] == systemKey) {
                this.removeCookieClickInfo(data[0]);
                return data[1];
            }
        }
        return 'block5';
    },
    blocks: {
        'block1': 'Блок горящие туры',
        'block2': 'Блок фарватер рекомендует',
        'block3': 'Самые недорогие туры',
        'block4': 'Другие цены',
        'block5': 'Search Results',
        'block6': 'Лучшее предложение',
        'block7': 'Избранные',
        'block8': 'Горящие',
        'block9': 'Раннее бронирование',
        'block10': 'Cashback 5%',
        'block11': 'Страница горящие туры',
        'block12': 'Страница рекомендуемые туры'
    },
    trackedIds: {},
    proxyImpressions: function (ids, blockId) {
        if (typeof blockId == 'undefined') {
            var listType = this.blocks['block9'];
        } else{
            if (blockId.indexOf('block') == 0) {
                var listType = this.blocks[blockId];
            } else {
                var listType = blockId;
            }
        }        var res = [];
        for (var i = 0; i < ids.length; i++) {
            var id = ids[i];
            if (!this.trackedIds.hasOwnProperty(id)) {
                this.trackedIds[id] = {};
                this.trackedIds[id][blockId] = true;
                res.push(id);
            }
            else if (!this.trackedIds[id].hasOwnProperty(blockId) && (blockId == 'block3' || blockId == 'block4' || blockId == 'block5' || blockId == 'block6')) {
                this.trackedIds[id][blockId] = true;
                res.push(id);
            }
        }
        if (res.length != 0) this.impression(res, listType, blockId);
    },
    proxyImpressionsEx: function(tours, blockId) {
    	var filtered = [],
			len = tours.length,
			tour,
			i;
    	for (i = 0; i < len; i++) {
    		tour = tours[i];
    		if (this.trackedIds.hasOwnProperty(blockId) && this.trackedIds[blockId].hasOwnProperty(tour.id)) {
    			continue;
    		}
    		if (!this.trackedIds.hasOwnProperty(blockId)) {
    			this.trackedIds[blockId] = {};
    		}
    		if (!this.trackedIds[blockId].hasOwnProperty(tour.id)) {
    			this.trackedIds[blockId][tour.id] = true;
    		}
    		filtered.push(tour);
    	}
    	if (filtered.length != 0) {
    		dataLayer.push({
    			'event': 'aktivator',
    			'ecommerce': {
    				'currencyCode': 'UAH',
    				'impressions': filtered
    			}
    		});
    	}
    	console.log(dataLayer);
    },
    searchTour: function (fields) {
        var data = {
            'event': 'manual_click',
            'category': 'Поиск тура',
            'otkuda': fields.from,
            'kuda': fields.to,
            'kurort': fields.curort,
            'hotel': fields.hotels,
            'days_to_start': fields.days,
            'nights': fields.nights,
            'vzrosl': fields.old,
            'deti': fields.child,
            'hotel_cat': fields.stars,
            'pitanie': fields.eat
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'manual_click', 'Поиск тура', data);
        console.log(dataLayer);

        if (typeof window.partnersLog !== 'undefined') {
            //SearchBtnClick
            partnersLog.send(4);
        }
    },

    trackPage: function (page, len) {
        var pageType = '';
        switch (page) {
            case 'Home_Index':
                pageType = 'home';
                break;
            case 'Tours_Catalog':
                pageType = 'search_results';
                break;
            case 'hotels_Hotel':
                pageType = 'product_page';
                break;
            case 'Home_myFavoritList':
                pageType = 'favorites';
                break;
            case 'Home_hotTours':
                pageType = 'hot_tours_page';
                break;
            case 'Home_showMoreRecommended':
                pageType = 'recommended';
                break;
            case 'hotels_List':
                if (len == 4) {
                    pageType = 'region';
                }
                else if (len == 5) {
                    pageType = 'resort';
                }
                else {
                    pageType = 'country';
                }
                break;
            case 'order_TourCart':
                pageType = 'checkout';
                break;
            default:
                pageType = 'others';
                break;
        }

        var gtmData = { 'event': 'page_type', 'page_type': pageType };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'page_type', pageType, {});
    },
    manualClick: function (category, link) {
        var gtmData = {
            'event': 'manual_click',
            'category': category
        };
        if (typeof link != 'undefined') {
            gtmData.manual_link = link;
        }
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'manual_click', category, gtmData);
        console.log(dataLayer);
    },
    trackEvent: function(event, category) {
        dataLayer.push({
            'event': event,
            'category': category
        });
        farAnalytics.pushEvent('GTM', event, category, {});
    },
    feedBack: function (title, e) {
        var data = {
            'event': e,
            'category': title
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', e, title, data);
        console.log(dataLayer);
    },
    feedBackWithPhone: function (title, e, phone) {

        phone = phone.replace(/\+/gi, '').replace(/\(/gi, '').replace(/\)/gi, '').replace(/-/gi, '').replace(/ /gi, '');
        var data = {
            'event': e,
            'category': title,
            'phone_number': phone
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', e, title, data);
        console.log(dataLayer);
        console.log('feedBackWithPhone action: ' + phone);
    },
    subscribePrices: function (price, new_price) {
        price = price || 0;
        var percent = price == 0 ? 0 : Math.abs(Math.round((parseInt(new_price) * 100 / parseInt(price)) - 100));
        var data = {
            'event': 'Отправка формы',
            'category': 'Изменение цен на отель',
            'real_price': price || 0,
            'new_price': new_price,
            'percent': percent
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы', 'Изменение цен на отель', data);
        console.log(dataLayer);
    },
    addFavorite: function (id, e) {
    	var block = e.target.closest('div[data-block-id]');
    	var blockId = 'block5';
		if (block !== null) {
			blockId = block.getAttribute('data-block-id') || 'block5';
		}
        
		var listType = GTM.blocks[blockId] || 'Search Results';
        var fields = GTM.getTourData(id, listType, blockId);

        console.log('============fields=============');
        console.log(fields);
        console.log('============fields=============');


        if (fields == null) return;
        var data = {
            'event': 'manual_click',
            'category': 'Избранное',
            'blok_name': listType,
            'kuda': fields.to,
            'kurort': fields.curort,
            'hotel': fields.hotel,
            'hotel_cat': [fields.stars],
            'perelet': fields.transport,
            'days_to_start': fields.days,
            'nights': fields.nights,
            'vzrosl': fields.old,
            'deti': fields.child,
            'nomer_type': fields.number,
            'pitanie': fields.eat
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'manual_click', 'Избранное', data);
        console.log(dataLayer);
    },
    addCurrentFavorite: function () {
        if (typeof window.tour_properties == 'undefined') return;
        var data = {
            'event': 'manual_click',
            'category': 'Избранное',
            'blok_name': 'Others',
            'kuda': window.tour_properties.kuda,
            'kurort': window.tour_properties.kurort,
            'hotel': window.tour_properties.hotel,
            'hotel_cat': [window.tour_properties.hotel_cat],
            'perelet': window.tour_properties.perelet,
            'days_to_start': window.tour_properties.days_to_start,
            'nights': window.tour_properties.nights,
            'vzrosl': window.tour_properties.vzrosl,
            'deti': window.tour_properties.deti,
            'nomer_type': window.tour_properties.nomer_type,
            'pitanie': window.tour_properties.pitanie
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'manual_click', 'Избранное', data);
        console.log(dataLayer);
    },
    impression: function (ids, listType, blockId) {
        var items = [];
        for (var i = 0; i < ids.length; i++) {
            var id = ids[i];
            var data = this.getTourData(id, listType, blockId);
            if (data == null) continue;

            items.push({
                'name': data.hotel,
                'id': data.id,
                'price': data.price + '.00',
                'brand': data.operator + ', ' + data.to + ', ' + data.curort,
                'category': data.stars,
                'variant': data.variant,
                'list': listType,
                'position': data.position
            });
        }
        if (items.length != 0) {
            dataLayer.push({
                'event': 'aktivator',
                'ecommerce': {
                    'currencyCode': 'UAH',
                    'impressions': items
                }
            });
        }
        console.log(dataLayer);
    },
    productClickEx: function(listType, hotelKey, hotelName, priceUah, brand, stars, variants, position, systemKey, e) {
	    console.log('productClickEx');

	    var blockId = 'block5';
	    if (typeof e !== 'undefined' && typeof e.target !== 'undefined' && e.target !== null) {
		    var section = e.target.closest('.favGtmSection');
		    if (section !== null) {
			    blockId = section.getAttribute('data-block-id') || 'block5';
		    }
	    }
	    var listType = this.blocks[blockId] || 'Search Results';
	    var items = [
		    {
			    'name': hotelName,
			    'id': hotelKey,
			    'price': priceUah,
			    'brand': brand,
			    'category': stars,
			    'variant': variants,
			    'position': position
		    }
	    ];

	    this.setCookieClickInfo(systemKey, blockId);

	    var gtmData = {
		    'event': 'productClick',
		    'ecommerce': {
			    'click': {
				    'actionField': { 'list': listType },
				    'products': items
			    }
		    }
	    };
	    dataLayer.push(gtmData);
	    farAnalytics.pushEvent('GTM', 'productClick', 'ecommerce', gtmData);

	    console.log(dataLayer);
    },
    productClick: function (ids, e) {
        
        var blockId = 'block5';
        var section = e.target.closest('.favGtmSection');
        if (section !== null) {
        	blockId = section.getAttribute('data-block-id') || 'block5';
        }
        var listType = this.blocks[blockId] || 'Search Results';
        var items = [];
        for (var i = 0; i < ids.length; i++) {
            var id = ids[i];
            var data = this.getTourData(id, listType, blockId);
            if (data == null) continue;

            items.push({
                'name': data.hotel,
                'id': data.id,
                'price': data.price + '.00',
                'brand': data.operator + ', ' + data.to + ', ' + data.curort,
                'category': data.stars,
                'variant': data.variant,
                'position': data.position
            });

            this.setCookieClickInfo(data.systemKey, blockId);
        }
        if (items.length != 0) {
            var gtmData = {
                'event': 'productClick',
                'ecommerce': {
                    'click': {
                        'actionField': { 'list': listType },
                        'products': items
                    }
                }
            };
            dataLayer.push(gtmData);
            farAnalytics.pushEvent('GTM', 'productClick', 'ecommerce', gtmData);

        }
        console.log(dataLayer);
    },

    ///ОТСЛЕЖИВАНИЕ ДОПОЛНИТЕЛЬНЫХ ПАРАМЕТРОВ СТРАНИЦЫ ТУРА
    additionalTourInfo: function (model, isBest, isRecommended, isHot, isDiscounted, tourFreeCancel) {
        var variant = this.joinVariant(isBest, isRecommended, isHot, isDiscounted, tourFreeCancel);
        model.hotel_variant = variant;
        dataLayer.push(model);
        farAnalytics.pushEvent('GTM', 'additionalTourInfo', 'ecommerce', model);
        console.log(dataLayer);

    },
    ///3. ПРОСМОТР ИНФОРМАЦИИ О ТУРЕ
    viewTourInfo: function (model, isBest, isRecommended, isHot, isDiscounted, systemKey, tourFreeCancel) {
        var variant = this.joinVariant(isBest, isRecommended, isHot, isDiscounted, tourFreeCancel);
        model.variant = variant;
        var blockId = this.getCookieClickInfo(systemKey);
        var listType = this.blocks[blockId];
        var gtmData = {
            'event': 'aktivator',
            'ecommerce': {
                'detail': {
                    'actionField': { 'list': listType },
                    'products': [
                        model
                    ]
                }
            }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'viewTourInfo', 'ecommerce', gtmData);
        console.log(dataLayer);
    },
    ///4. ПРОСМОТР ИНФОРМАЦИИ О других турах
    viewTourInfoOthers: function (model, isBest, isRecommended, isHot, isDiscounted) {
        var variant = this.joinVariant(isBest, isRecommended, isHot, isDiscounted);
        model.variant = variant;
        var gtmData = {
            'ecommerce': {
                'detail': {
                    'actionField': { 'list': 'Другие цены' },
                    'products': [
                        model
                    ]
                }
            }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'viewTourInfo', 'ecommerce', gtmData);
        console.log(dataLayer);
    },

    //ПК и моб. GTM для новой формы подписки на Стране (с корабликом).
    subscribeCountry: function() {
        var data = {
            'event': 'Отправка формы',
            'category': 'Подписка на интересные туры'
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы', 'Подписка на интересные туры', data);
        console.log(dataLayer);
    },

    ///mastercard bilshe 
    subscribeMastercardBilshe: function (phone) {
        phone = phone.replace(/\+/gi, '').replace(/\(/gi, '').replace(/\)/gi, '').replace(/-/gi, '').replace(/ /gi, '');

        var data = {
            'event': 'Отправка формы с MastercardBilshe',
            'category': 'Подписка на заказ обратного звонка',
            'phone_number': phone
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы с MastercardBilshe', 'Подписка на заказ обратного звонка', data);
        console.log(dataLayer);
    },

    subscribeTaggedForm: function (email, tag, phone) {
	    var data = {
		    'event': 'Отправка формы',
		    'category': tag
	    };
		if (typeof phone !== 'undefined') {
			data.phone_number = phone;
		}
		if (typeof email !== 'undefined') {
			data.email = email;
		}
	    dataLayer.push(data);
	    farAnalytics.pushEvent('GTM', 'Отправка формы', tag, data);
	    console.log(dataLayer);
    },

    addToCart: function (model) {
        model.quantity = 1;
        var gtmData = {
            'event': 'addToCart',
            'ecommerce': {
                'currencyCode': 'UAH',
                'add': {
                    'products': [
                        model
                    ]
                }
            }
        };
        dataLayer.push(gtmData);
        //farAnalytics.pushEvent('GTM', 'addToCart', 'ecommerce', gtmData);
        console.log('dataLayer', dataLayer);


        PXL.addToCart();
    },
    checkoutStep1: function (model, option) {
        model.quantity = 1;
        var gtmData = {
            'event': 'checkout',
            'ecommerce': {
                'checkout': {
                    'actionField': {
                        'step': 1,
                        'option': option
                    },
                    'products': [
                        model
                    ]
                }
            },
            'eventCallback': function () { }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'checkout', 'step1', gtmData);
        console.log(dataLayer);
    },
    checkoutStep2: function (model, option) {
        if (typeof option == 'undefined') {
            option = 'Contacts';
        }
        model.quantity = 1;
        var gtmData = {
            'event': 'checkout',
            'ecommerce': {
                'checkout': {
                    'actionField': {
                        'step': 2,
                        'option': option
                    },
                    'products': [
                        model
                    ]
                }
            },
            'eventCallback': function () { }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'checkout', 'step2', gtmData);
        console.log(dataLayer);
    },
    checkoutStep3: function (model, option) {
        if (typeof option == 'undefined') {
            option = '';
        }
        model.quantity = 1;
        var gtmData = {
            'event': 'checkout',
            'ecommerce': {
                'checkout': {
                    'actionField': {
                        'step': 3,
                        'option': option
                    },
                    'products': [
                        model
                    ]
                }
            },
            'eventCallback': function () { }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'checkout', 'step3', gtmData);
        console.log(dataLayer);
    },
    checkoutStep4: function (model, option) {
        if (typeof option == 'undefined') {
            option = 'I agree';
        }
        model.quantity = 1;
        var gtmData = {
            'event': 'checkout',
            'ecommerce': {
                'checkout': {
                    'actionField': {
                        'step': 4,
                        'option': option
                    },
                    'products': [
                        model
                    ]
                }
            },
            'eventCallback': function () { }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'checkout', 'step4', gtmData);
        console.log(dataLayer);
    },
    checkoutPurchase: function (invoiceId, price, coupon) {
        return;
        var product = window.products;
        product.quantity = 1;
        product.coupon = coupon || '';
        if (typeof invoiceId != 'undefined' && invoiceId.indexOf('-+') > 0) {
            invoiceId = invoiceId.substring(0,invoiceId.indexOf('-+'));
        }
        if (typeof price == 'undefined') price = product.price;
        var gtmData = {
            'event': 'aktivator',
            'ecommerce': {
                'purchase': {
                    'actionField': {
                        'id': invoiceId,
                        'affiliation': 'Online Store',
                        'revenue': price,
                        'tax': '0.00',
                        'shipping': '0.00',
                        'coupon': coupon
                    },
                    'products': [
                        product
                    ]
                }
            }
        };
        dataLayer.push(gtmData);
        farAnalytics.pushEvent('GTM', 'checkout', 'purchase', gtmData);
        console.log(dataLayer);
    },

    timeOfDeparture: function(phone) {

        phone = phone.replace(/\+/gi, '').replace(/\(/gi, '').replace(/\)/gi, '').replace(/-/gi, '').replace(/ /gi, '');
        
        var data = {
            'event': 'Отправка формы',
            'category': 'Запрос времени вылета',
            'phone_number': phone
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы', 'Запрос времени вылета', data);
        console.log(dataLayer);
    },

    subscribeForBestPrice: function() {

        var data = {
            'event': 'Отправка формы',
            'category': 'Подписка'
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы', 'Подписка', data);
        console.log(dataLayer);
    },

    fastOrderPurchase: function(phone) {
        
        phone = phone.replace(/\+/gi, '').replace(/\(/gi, '').replace(/\)/gi, '').replace(/-/gi, '').replace(/ /gi, '');

        var data = {
            'event': 'Отправка формы',
            'category': 'Купить в один клик',
            'phone_number': phone
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы', 'Купить в один клик', data);
        console.log(dataLayer);
    },
    orderStep1Purchase: function (phone, partnerType) {

        phone = phone.replace(/\+/gi, '').replace(/\(/gi, '').replace(/\)/gi, '').replace(/-/gi, '').replace(/ /gi, '');

        var data = {
            'event': 'Отправка формы',
            'category': 'Покупка тура. Шаг 1. ' + partnerType,
            'phone_number': phone
        };
        dataLayer.push(data);
        farAnalytics.pushEvent('GTM', 'Отправка формы', 'Купить в один клик', data);
        console.log(dataLayer);
    },

    getTourData: function (id, listType, blockId) {

	    if (!render.tours.hasOwnProperty(id)) {
            console.log(render.tours.hasOwnProperty(id));
            return null;
        }
        var tour = render.tours[id];

        var fieldsGTM = {
            blok_name: listType,
            id: tour.hotelKey,
            to: tour.countryName,
            curort: tour.region != null && tour.region.ResortName != null ? tour.region.ResortName : tour.address,
            hotel: tour.hotel.value,
            stars: tour.star.value,
            transport: tour.type === 'plain' ? 'yes' : 'no',
            days: '',
            nights: tour.nights.toString(),
            old: tour.adl,
            child: tour.kids,
            number: '',
            eat: tour.meal.value,
            price: tour.priceUAH,
            operator: tour.operatorName,
            position: 1,
            systemKey: tour.SystemKey
        };

        if (typeof tour.room != 'undefined' && tour.room != '') fieldsGTM.number = tour.room;
        if (typeof tour.htplace != 'undefined' && tour.htplace != '') fieldsGTM.number += ' (' + tour.htplace + ')';

        var statuses = [];

        //var isHot = window.isHotTour(tour.checkIn.value);
        //if (isHot) statuses.push('Горящие')
        //if (parseFloat(tour.rate) > 7.8) statuses.push('Рекомендованный');
        //if (farSearchToursView1.isBest(tour.hotelKey)) statuses.push('Лучшее предложение');
        if (tour.isHot) statuses.push('Горящие');
        if (tour.isRecommended) statuses.push('Рекомендованный');
        if (tour.isBest) statuses.push('Лучшее предложение');
        if (tour.chd) statuses.push('Скидка');
        if (typeof tour.isEarly != 'undefined' && tour.isEarly === true) statuses.push('Раннее бронирование');

        fieldsGTM.variant = statuses.join(', ');
        fieldsGTM.list = listType;

        var dateFrom = moment(tour.checkIn.value, 'YYYY-MM-DD').format('DD.MM.YYYY');
        var days = dateDiffUseMoment(dateFrom);
        fieldsGTM.days = days;

        fieldsGTM.position = 1;
		/*
        var section = document.querySelector('.favGtmSection[data-block-id="' + blockId + '"]');
        if (section !== null) {
            var el = section.querySelector('.Hotel[data-id="' + tour.SystemKey + '"]');
            if (el !== null) {
                var position = el.getAttribute('data-position') || 1;
                if (!isNaN(position)) fieldsGTM.position = parseInt(position);
            }
        }
		*/
        return fieldsGTM;
    },
    joinVariant: function (isBest, isRecommended, isHot, isDiscounted, tourFreeCancel) {
        var variants = [];
        if (isHot) variants.push('Горящий');
        if (isRecommended) variants.push('Рекомендованный');
        if (isBest) variants.push('Лучшая цена');
        if (isDiscounted) variants.push('Скидка');
        if (typeof tourFreeCancel !== 'undefined') {
        	if (tourFreeCancel === true) {
        		variants.push('Отмена');
        	}
        }
        var variant = variants.join(', ');
        return variant;
    }
};

if (window.GTM_INITED === void 0) {
    window.GTM_INITED = true;
    farDocument.onReady(function () {
        document.querySelectorAll('#header .row > div:last-child div > button, #header .row > div:last-child > a').forEach(function (node) {
            node.addEventListener('click', function () { GTM.feedBack('Обратная связь', 'manual_click'); }, true);
        });

        document.querySelectorAll('.callBackSale a.sendFeed').forEach(function (node) {
            node.addEventListener('click', function () { GTM.feedBack('Заказать обратный звонок', 'manual_click'); }, true);
        });

        document.querySelectorAll('#header .callBackPopup_init, .callBack.feedBack .sendFeed').forEach(function (node) {
            node.addEventListener('click', function () { GTM.feedBack('Заказать обратный звонок', 'manual_click'); }, true);
        });

        document.querySelectorAll('#hotel_actualize_panel a').forEach(function (node) {
            node.addEventListener('click', function () { GTM.addToCart(window.products); }, true);
        });

        var node = document.getElementById('writeAboutUsBlock');
        if (node != null) {
            node.querySelector('a').addEventListener('click',
                function () {
                    GTM.manualClick('О нас пишут', this.getAttribute('href'));
                });
        }

        document.querySelectorAll('#reviews .fb a, #aboutus_say .press__link').forEach(function (node) {
            node.addEventListener('click', function () { GTM.manualClick('О нас говорят'); }, true);
        });

        document.querySelectorAll('.socials a').forEach(function (node) {
            node.addEventListener('click', function () { GTM.manualClick('Мы	в соцсетях', this.getAttribute('href')); }, true);
        });

        //$(document.body).on('click',
        //	'div.T_favo.mm.fav_a',
        //	function(e) {
        //		//GTM.addFavorite(this, e);
        //	});

        //$(document.body).on('click',
        //	'a.G_cont, .detal-info-tour-link',
        //	function(e) {
        //		//GTM.addFavorite(this, e);

        //		var link = $(this),
        //			pane = link.closest('.tour'),
        //			systemKey = pane.attr('data-id');
        //		if (pane.hasClass('best')) {
        //			bests.addItem(systemKey);
        //		}
        //		if (link.hasClass('tour__more-link')) {
        //			systemKey = link.closest('.tour__more-item').attr('data-id');
        //		}
        //		GTM.productClick([systemKey], e);
        //	});
    });
}
;
function ExecuteService(params, url, callbackSuccess, callbackError) {
    $.ajax({
        type: "POST",
        url: ConvertUrlTooLocalization(url),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: asmxParams(url, params),
        success: function (data) {
            if (checkError(data)) {
                callbackSuccess(data);
            }
        },
        error: callbackError
    });
}
function ExecuteServiceWithContext(url, data, context, callbackSuccess, callbackError) {
    $.ajax({
        type: 'POST',
        url: ConvertUrlTooLocalization(url),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: JSON.stringify(asmxData(url, data)),
        context: { context: context, callbackSuccess: callbackSuccess, callbackError: callbackError },
        success: function (response) {
            var data = (typeof response.d == 'object') ? response.d : JSON.parse(response.d);
            if (checkError(response)) {
                this.callbackSuccess.call(this.context, data);
            }
            else {
                this.callbackError.call(this.context, data);
            }
        },
        error: function (response) {
            this.callbackError.call(this.context, response);
        }
    });
}

function ExecuteUrl(params, url, callbackSuccess, callbackError) {
    $.ajax({
        type: "POST",
        url: ConvertUrlTooLocalization(url),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: asmxParams(url, params),
        cache: false,
        context: { callbackSuccess: callbackSuccess, callbackError: callbackError },
        success: function (response) {
            this.callbackSuccess(response);
        },
        error: function () {
            this.callbackError();
        }
    });
}

function ExecuteUrlSynk(params, url, callbackSuccess, callbackError) {
    $.ajax({
        type: "POST",
        url: ConvertUrlTooLocalization(url),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: asmxParams(url, params),
        cache: false,
        async: false,
        context: { callbackSuccess: callbackSuccess, callbackError: callbackError },
        success: function (response) {
            this.callbackSuccess(response);
        },
        error: function () {
            this.callbackError();
        }
    });
}


function ExecuteUrlEx(url, data, context, callbackSuccess, callbackError) {
    $.ajax({
        type: 'POST',
        url: ConvertUrlTooLocalization(url),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: JSON.stringify(asmxData(url, data)),
        context: {
            context: context,
            callbackSuccess: callbackSuccess,
            callbackError: callbackError
        },
        success: function (response) {
            var data = JSON.parse(response.d);
            this.callbackSuccess.call(this.context, data);
        },
        error: function () {
            if (typeof this.callbackError != 'undefined') {
                this.callbackError();
            }
        }
    });
}

function ExecuteActionString(url, data, context, callbackSuccess, callbackError) {

    var postModel = { postDataModel: JSON.stringify(data) }

    $.ajax({
        type: 'POST',
        url: url,
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: JSON.stringify(postModel),
        context: {
            context: context,
            callbackSuccess: callbackSuccess,
            callbackError: callbackError
        },
        success: function (response) {
            console.log('=============== response for ' + url + '================');
            console.log(response);
            console.log('===============================');
            this.callbackSuccess.call(this.context, response);
        },
        error: function () {
            if (typeof this.callbackError != 'undefined') {
                this.callbackError();
            }
        }
    });
}

function ExecuteAction(url, data, context, callbackSuccess, callbackError) {
    var u = ConvertUrlTooLocalization(url);
    //alert(localization);
    //alert(u);
    var method = (context || {}).method || 'POST';


    Far.Global.jsonRequest({
	    method: method,
	    url: url,
	    model: {
		    context: context,
		    callbackSuccess: callbackSuccess,
		    callbackError: callbackError
	    },
		data: 
			asmxData(url, data)
		,
	    onSuccess: function(response) {
		    this.model.callbackSuccess.call(this.model.context, response);
	    },
	    onError: function() {
		    if (typeof this.callbackError != 'undefined') {
			    this.model.callbackError.call(this.model.context);
		    }
	    }
    });
    return;

    $.ajax({
        type: method,
        url: u,
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: JSON.stringify(asmxData(url, data)),
        context: {
            context: context,
            callbackSuccess: callbackSuccess,
            callbackError: callbackError
        },
        success: function (response) {
            this.callbackSuccess.call(this.context, response);
        },
        error: function () {
            if (typeof this.callbackError != 'undefined') {
                this.callbackError.call(this.context);
            }
        }
    });
}

function ExecuteAction_withReturn(url, data, context, callbackSuccess, callbackError, callbackBeforeSend) {
    var u = ConvertUrlTooLocalization(url);
    //alert(localization);
    //alert(u);
    var method = (context || {}).method || 'POST';
    return $.ajax({
        type: method,
        url: u,
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: JSON.stringify(asmxData(url, data)),
        context: {
            context: context,
            callbackSuccess: callbackSuccess,
            callbackError: callbackError,
            callbackBeforeSend: callbackBeforeSend
        },
        beforeSend: function() {
            if (typeof this.callbackBeforeSend != 'undefined') {
                this.callbackBeforeSend.call(this.context);
            }
        },
        success: function (response) {
            this.callbackSuccess.call(this.context, response);
        },
        error: function () {
            if (typeof this.callbackError != 'undefined') {
                this.callbackError.call(this.context);
            }
        }
    });
};

function ExecuteActionCROS(url, data, context, callbackSuccess, callbackError) {
    $.ajax({
        type: 'POST',
        url: ConvertUrlTooLocalization(url),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: JSON.stringify(asmxData(url, data)),
        crossDomain: true,
        context: {
            context: context,
            callbackSuccess: callbackSuccess,
            callbackError: callbackError
        },
        success: function (response) {
            this.callbackSuccess.call(this.context, response);
        },
        error: function () {
            if (typeof this.callbackError != 'undefined') {
                this.callbackError.call(this.context);
            }
        }
    });
};

function ExecuteServiceEx(url, request) {

    request.xhr = $.ajax({
        type: 'POST',
        url: ConvertUrlTooLocalization(url) + request.query,
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        data: asmxParams(url, request.data.params),
        context: { request: request },
        cache: false,
        success: function (response, textStatus, jqXHR) {

            if (!response.d) {

                farSearchRequests.endRequest(this.request, false);
            }
            else {

                farSearchRequests.endRequest(this.request, true);

                if (response.d.success === true) {

                    if (typeof response.d.data.tours == 'undefined' || response.d.data.tours == null) {

                        response.d.data.tours = [];
                    }

                    console.log('-->request end: operatonName: ' + this.request.data.operatorName + '; countryId: ' +
                        this.request.countryId + '; page: ' + this.request.page + '; LENGTH: ' + response.d.data.tours.length);

                    this.request.completer.onSuccess.call(this.request, response.d.data);
                }
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {

            farSearchRequests.endRequest(this.request, false);
            this.request.completer.onError.call(this.request, jqXHR, textStatus, errorThrown);
        }
    });
}

function post(path, params, method) {
    method = method || "post"; // Set method to post by default if not specified.

    // The rest of this code assumes you are not using a library.
    // It can be made less wordy if you use one.
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", path);

    for (var key in params) {
        if (params.hasOwnProperty(key)) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", params[key]);

            form.appendChild(hiddenField);
        }
    }

    document.body.appendChild(form);
    form.submit();
}

function checkError(data) {
    if (data.hasOwnProperty('cached')) return true;
    if (typeof data.d == 'object') return true;
    if (parseInt(data.d.indexOf('errorCode')) != -1) {
        var error = $.parseJSON(data.d);
        window.location = '/errors?message=' + error.errorCode;
        return false;
    }
    return true;
}

function checkError2(data) {

}

function globalError(msg) {
    if (globalConnectionStatus)
    { /*alert('Помилка выполнения запроса!');*/ }
}

//check  connections
function checkConnection() {
    //if (globalUT == '528')
    //if (!timerExecuted) {
    //    $.ajax({
    //        type: "GET",
    //        url: globalCheckConnectionURl,
    //        success: function (data, textStatus, jqXHR) {
    //            var result = jqXHR.responseText;

    //            switch (result) {
    //                case 'online':
    //                    checkConnection_online();
    //                    break;
    //                case 'offline':
    //                    checkConnection_offline();
    //                    break;
    //            }

    //            timerExecuted = false;
    //        },
    //        error: function (XMLHttpRequest, textStatus, errorThrown) {
    //            checkConnection_offline();
    //            timerExecuted = false;
    //        }
    //    });
    //    timerExecuted = true;
    //}
}
function checkConnection_offline() {
    globalConnectionStatus = false;
    if ($('#connectionsStatusDiv').size() == 0) {
        $('#global_connectionStatus').prepend('<div id="connectionsStatusDiv" style="padding:5px; display:none;" class="bg-red fs-small bold c-white ta-c well">Без доступу до Інтернет<br><a class="cur-pointer c-lgray refrechConnection" href="javascript:void(0)" onclick="checkConnection();$(\'.refrechConnection\').html(\'Поновлюю підключення...\');">Повторити спробу</a></div>');
        $('#connectionsStatusDiv').show();
        $('.visible-online').hide();
        $('.visible-offline').show();
        if ($('#global_sync_status').size() > 0) {

            if (!$('#operations-sal-data-table-content').is(':visible') & !$('#operations-buy-data-table-content').is(':visible')) {
                alert('Систему переведено в режим роботи без підключення до мережі Інтернет!\nВ цьому режимі ви маєте змогу виконувати валютні операції.');
                departments_show_container('operations');
            }
        }
        if (globalTimerInterval <= 270000) {
            window.clearInterval(globalTimer);
            globalTimerInterval = globalTimerInterval * 3;
            globalTimer = window.setInterval(checkConnection, globalTimerInterval);
        }
    }
}
function checkConnection_online() {
    globalConnectionStatus = true;
    $('#connectionsStatusDiv').remove();
    $('.visible-online').show();
    $('.visible-offline').hide();
    window.clearInterval(globalTimer);
    globalTimerInterval = 10000;
    globalTimer = window.setInterval(checkConnection, globalTimerInterval);
}

//timer
var globalTimerInterval = 10000;
var timerExecuted = false;


//--------
function ConvertUrlTooLocalization(url, action) {
    if (typeof action != 'undefined') {
        if (action && localization == "ru") {
            return url;
        }
    }
    if (url == "") {
        url = "/" + localization;
    } else if (url.indexOf("https") == 0 || url.indexOf("http") == 0) {
        return url;
    } else {
        if (url.indexOf(".asmx") > 0) {
            //return url;
            for (var i = 0; i < localizationAll.length; i++) {
                if (url.includes("lang=" + localizationAll[i])) { return url; }
            }
            url = url + "?lang=" + localization;
        } else {
            for (var i = 0; i < localizationAll.length; i++) {
                if (url.indexOf("/" + localizationAll[i]) == 0) {
                    return url;
                } else if (url.indexOf(localizationAll[i]) == 0) {
                    return "/" + url;
                }
            }
            url = "/" + localization + "/" + trimStart('/', url);
        }
    }
    return url
}

function trimStart(character, string) {
    var startIndex = 0;

    while (string[startIndex] === character) {
        startIndex++;
    }

    return string.substr(startIndex);
}

function asmxParams(url, string) {
    if (url.indexOf(".asmx") > 0) {
        string = "{lang:'" + localization + "'," + trimStart('{', string);
    }
    return string;
}

function asmxData(url, data) {
    if (url.indexOf(".asmx") > 0) {
        data.lang = localization;
    }
    return data;
}
 




;
/*!
 * JavaScript Cookie v2.1.2
 * https://github.com/js-cookie/js-cookie
 *
 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
 * Released under the MIT license
 */
;(function (factory) {
	if (typeof define === 'function' && define.amd) {
		define(factory);
	} else if (typeof exports === 'object') {
		module.exports = factory();
	} else {
		var OldCookies = window.Cookies;
		var api = window.Cookies = factory();
		api.noConflict = function () {
			window.Cookies = OldCookies;
			return api;
		};
	}
}(function () {
	function extend () {
		var i = 0;
		var result = {};
		for (; i < arguments.length; i++) {
			var attributes = arguments[ i ];
			for (var key in attributes) {
				result[key] = attributes[key];
			}
		}
		return result;
	}

	function init (converter) {
		function api (key, value, attributes) {
			var result;
			if (typeof document === 'undefined') {
				return;
			}

			// Write

			if (arguments.length > 1) {
				attributes = extend({
					path: '/'
				}, api.defaults, attributes);

				if (typeof attributes.expires === 'number') {
					var expires = new Date();
					expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
					attributes.expires = expires;
				}

				try {
					result = JSON.stringify(value);
					if (/^[\{\[]/.test(result)) {
						value = result;
					}
				} catch (e) {}

				if (!converter.write) {
					value = encodeURIComponent(String(value))
						.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
				} else {
					value = converter.write(value, key);
				}

				key = encodeURIComponent(String(key));
				key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
				key = key.replace(/[\(\)]/g, escape);

				return (document.cookie = [
					key, '=', value,
					attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
					attributes.path    && '; path=' + attributes.path,
					attributes.domain  && '; domain=' + attributes.domain,
					attributes.secure ? '; secure' : ''
				].join(''));
			}

			// Read

			if (!key) {
				result = {};
			}

			// To prevent the for loop in the first place assign an empty array
			// in case there are no cookies at all. Also prevents odd result when
			// calling "get()"
			var cookies = document.cookie ? document.cookie.split('; ') : [];
			var rdecode = /(%[0-9A-Z]{2})+/g;
			var i = 0;

			for (; i < cookies.length; i++) {
				var parts = cookies[i].split('=');
				var cookie = parts.slice(1).join('=');

				if (cookie.charAt(0) === '"') {
					cookie = cookie.slice(1, -1);
				}

				try {
					var name = parts[0].replace(rdecode, decodeURIComponent);
					cookie = converter.read ?
						converter.read(cookie, name) : converter(cookie, name) ||
						cookie.replace(rdecode, decodeURIComponent);

					if (this.json) {
						try {
							cookie = JSON.parse(cookie);
						} catch (e) {}
					}

					if (key === name) {
						result = cookie;
						break;
					}

					if (!key) {
						result[name] = cookie;
					}
				} catch (e) {}
			}

			return result;
		}

		api.set = api;
		api.get = function (key) {
			return api(key);
		};
		api.getJSON = function () {
			return api.apply({
				json: true
			}, [].slice.call(arguments));
		};
		api.defaults = {};

		api.remove = function (key, attributes) {
			api(key, '', extend(attributes, {
				expires: -1
			}));
		};

		api.withConverter = init;

		return api;
	}

	return init(function () {});
}));


;
/*
Правила:
1. 	Абсолютно все отели, которые строятся через Hotel есть в window.Far.Hotels.
	ВНИМАНИЕ! Если отель приезжает в любой другой блок (например отель есть в избранном и в каталоге)
	он будет ПЕРЕЗАПИСАН и НОДА отеля уже будет содержать другую ноду!
2. 	При new Hotel карточка НЕ рендерится! Рендер карточки вызывается вручную
3. 	Нода срендереной карточки отеля находиться в свойстве Hotel.element
4. 	При добавлении тура в Hotel используется метод Hotel.addTour
5. 	Отель может быть в двух родителях Catalog или StandartHotelParent. Catalog пока что не желательно использовать как родителя
6. 	Родитель ВСЕГДА содержит обьект Hotels, при вызове new Hotel родитель в свойство Hotels получает этот отель
7. 	Туры в отель всегда содержатся внутри Hotel.Tours. Каждый элемент это обьект из конструктора Tour
8. 	Самый дешевый тур доступен в свойстве Hotel.lastCheapestTour. Это свойство не бывает пустым

Базовый пример:
// Создаем родителя для отелей
var HotelsParent = new StandartHotelParent({
	id: 'some ID' // этот параметр не обязателен, НО крайне желателен, т.к. на основании этого параметра отели и их дочерние элементы получают часть атрибута id
});

// где-то в коде добавляем отель
var hotel = (isset(HotelsParent.Hotels[model.hotelKey])?HotelsParent.Hotels[model.hotelKey]:null);
if (hotel==null) {
	// создаем отель, тур будет добавлен автоматически
	hotel = new Hotel(HotelsParent, model);
	// рендерим отель
	hotel.render();
} else {
	// добавляем тур
	hotel.addTour(model);
	// редерить не нужно,
	// тур будет добавлен в другие варианты автоматически
	// если тур дешевле предидущего самого душевого тура,
	// и карточка отеля была срендерена то все атрибуты будут заменены автоматически
	// если был открыт календарь или другие варианты, то эти блоки будут перерендерены (точнее в блок будет добавлен тот тур, который добавили)
}
*/

function StandartHotelParent(model) {
	/*
		Простейший конструктор родителя для отелей.
		Используется всегда там, где нет какой-либо необходимости в полноценном Каталоге
	*/
	var self = this;
	this.Hotels = {};
	this.init = function(model) {
		if (!isset(model.id)) model.id = rendomId();
		self.id = model.id;
		if (!isset(model.hotelClassName)) model.hotelClassName = '';
		var LastHotelsMode = window.Far.Hotels_ViewMode.get(self);
		if (isset(model.hotelClassName)) {
			self.hotelClassName = model.hotelClassName;
		} else {
			self.hotelClassName = (LastHotelsMode ? '__' + LastHotelsMode : model.hotelClassName);
		}
		if (!isset(model.lazyLoad)) model.lazyLoad = 500;
		self.lazyLoad = model.lazyLoad;
		if (!isset(model.onHotelClickEvent)) model.onHotelClickEvent = emptyFunc();
		self.onHotelClickEvent = model.onHotelClickEvent;
		if (!isset(model.othersDesign)) model.othersDesign = 'callendar';
		self.othersDesign = model.othersDesign;
		if (!isset(model.containerHorisontal)) model.containerHorisontal = false;
		self.containerHorisontal = model.containerHorisontal;
		if (!isset(model.calendarMinColumns)) model.calendarMinColumns = (is_mobile()?7:7);
		self.calendarMinColumns = model.calendarMinColumns;
		if (!isset(model.calendarMaxColumns)) model.calendarMaxColumns = (is_mobile()?7:7);
		self.calendarMaxColumns = model.calendarMaxColumns;
		if (!isset(model.hotelDescriptions)) model.hotelDescriptions = {};
		self.hotelDescriptions = model.hotelDescriptions;
		if (!isset(model.sort)) model.sort = 'priceDESC';
		if (!isset(model.useWeather)) model.useWeather = model.useWeather;
		self.sort = model.sort;
		self.useOperatorsIcons = (isset(model.useOperatorsIcons)?model.useOperatorsIcons:false);
		self.useOthersQuery = (isset(model.useOthersQuery)?model.useOthersQuery:false);
		if (isset(model.Map)) self.Map = model.Map;
		self.othersDisableCallendar = (isset(model.othersDisableCallendar)?model.othersDisableCallendar:false);
		self.othersDisableList = (isset(model.othersDisableList)?model.othersDisableList:false);
		if (self.othersDisableCallendar) {
			self.othersDesign = 'list';
		} else if (self.othersDisableList) {
			self.othersDesign = 'callendar';
		}
		self.onNewHotel = (isset(model.onNewHotel)?model.onNewHotel:[]);
		self.onNewTour = (isset(model.onNewTour)?model.onNewTour:[]);
		self.onNewCheapestTour = (isset(model.onNewCheapestTour)?model.onNewCheapestTour:[]);
	};
	this.init(model);

	this.clear = function() {
		self.Hotels = {};
	};

	this.setOrder = function (m) {
		self.sort = m;
		for (var o in self.Hotels) {
			self.Hotels[o].setOrder();
		}
	}
}

/*
	Методы для установки, хранения и применения режима дизайна карточек отелей
*/
window.Far.Hotels_ViewMode = {
	set: function(mode, Catalog, element) {
		switch (mode) {
			case '':
			case 'horisontal':
			case 'middle':
			case 'minimal':
			case 'tableRow':
			case 'wide':
			case 'openInsideBlock':
				for (var k in Catalog.Hotels) Catalog.Hotels[k].setViewMode(mode);
				Catalog.hotelClassName = [mode, ' __', mode].join('');
				localStorage.setItem([Catalog.id,'hotelClassName'].join('__'), mode);
			break;
		}
		if (isset(element)&&element) {
			var btns = element.parentNode.querySelectorAll('button');
			for (var i=btns.length-1;i>=0;i--) btns[i].classList.remove('__active');
			element.classList.add('__active');
		}
		var cntr = document.getElementById('result-container');
		if (cntr) {
			if (mode=='tableRow') {
				cntr.classList.add('__bg');
			} else {
				cntr.classList.remove('__bg');
			}
		}
	},
	get: function(Catalog) {
		return localStorage.getItem([Catalog.id,'hotelClassName'].join('__'));
	}
};

window.Far.Hotels = {};

function Hotel(Catalog, tourModel) {
	var self = this;
	// Копируем общие методы Отеля
	for (var m in HotelSharedMethods) self[m] = HotelSharedMethods[m];
	/*
		Каталог отеля, может быть null, Catalog или StandartHotelParent.
		Везде, где используется каталог, должна быть проверка !self.Catalog.
		Проверить, если использован Catalog можно так: self.hasRealCatalog(self)
	*/
	this.Catalog = Catalog;
	// Все туры в отель
	this.Tours = {};
	// Мусорка
	this.tmp = {};
	/*
		Основная модель Отеля
		Модель содержит данные, которые касаются исключительно отеля.
		Модель не может и не должна содержать в себе какие либо параметры тура 
	*/
	this.model = {
		name: tourModel.hotel.value,	// Название отеля
		key: tourModel.hotelKey,	// Ключ отеля
		url: tourModel.hotelUrl,	// Ссылка на отель
		latitude: tourModel.latitude,	// Широта
		longitude: tourModel.longitude,	// Долгота
		photo: HotelSharedMethods.getMainPhoto(tourModel.hotelId, deviceConfig.type == 'Mobile' ? 'detail' : 'thumb360'),	// Главное фото
		country: tourModel.countryName,	// Название страны
		countryID: tourModel.countryID,	// ИД страны
		countryNameAccusativeCase: isset(tourModel.countryNameAccusativeCase)&&tourModel.countryNameAccusativeCase?tourModel.countryNameAccusativeCase:tourModel.countryName,	// Название страны
		region: tourModel.region.RegionName,	// Название региона
		regionID: tourModel.region.RegionHash,	// ИД региона
		resort: tourModel.region.ResortName,	// Название курорта
		resortNameAccusativeCase: isset(tourModel.resortNameAccusativeCase)&&tourModel.resortNameAccusativeCase?tourModel.resortNameAccusativeCase:tourModel.region.ResortName,	// Название курорта
		resortID: tourModel.region.ResortHash,	// ИД курорта
		stars: tourModel.star.value,	// Значение звездности отеля
		description: (isset(tourModel.description)?tourModel.description:''),	// Описание
		rating: Math.ceil(parseFloat(tourModel.rate.split(',').join('.')) * 100),	// Рейтинг
		reviewsCount: (isset(tourModel.idsForText) && tourModel.idsForText !== null && isset(tourModel.idsForText.reviewsCount) && tourModel.idsForText.reviewsCount ? parseInt(tourModel.idsForText.reviewsCount) : 0),	// Количество отзывов
		othersActive: false,	// Флаг активности (видимости) других вариантов на карточке отеля
		currentDesign: (this.Catalog ? this.Catalog.othersDesign : 'list'),	// Текущий дизайн карточки отеля
		fake: tourModel.fake || false	// Флаг фейковости отеля
	};
	/*
		Если такой отель еще не был зарегестрирован в глобальном хранилище отелей, регистрируем. 
	*/
	if (!isset(window.Far.Hotels[this.model.key])) {
		window.Far.Hotels[this.model.key] = self;
	}
	/*
		Если есть каталог, забрасываем в его хранилище отелей отель
	*/
	if (this.Catalog) this.Catalog.Hotels[this.model.key] = self;
	/*
		Переменная, хранящая самый дешевый тур в отель.
		Крайне важно, не указывать что-либо в эту переменную.
		Отель сам ее заполняет в методе self.addTour(tourModel).
	*/
	this.lastCheapestTour = null;
	// Переменная, которая хранит ноду отеля (срендереный ДОМ элемент)
	this.element = null;
	// Убийца ивентов
	this.unsetClick = unsetClick;
	this.AddrOverEvent = function(e) {
		/*
			Наведение на адрес
			Метод устанавливает фокус на карточку на карте
		*/
		self.log('Hotel::AddrOverEvent');
		if (self.hasRealCatalog(self)) {
			if (!self.Catalog.Map.elements.map.hidden) {
				self.Catalog.Map.setCurrent(self.model.key);
			}
		} else {
			if (typeof farSearchCatalog.resultsFilter !== 'undefined' &&  farSearchCatalog.resultsFilter.methods.map__is_active&&farSearchCatalog.googleMaps.initialized) {
				farSearchCatalog.googleMaps.onHotelOver(self.model.key, 15);
			}
		}
	};
	this.AddrClickEvent = function(e){
		/*
			Клик на адрес
			ВНИМАНИЕ! Метод самоинициализирует карту
		*/
		self.log('Hotel::AddrClickEvent');
		if (!self.Catalog) return;
		if (self.hasRealCatalog(self)) {
			// Если используется полноценный каталог, пусть сам разруливает все.
			self.Catalog.Map.openMap();
			self.Catalog.Map.setCurrent(self.model.key);
		} else if (isset(window.farSearchCatalog)) {
			// Если используется какой-либо другой тип каталога, нужно все делать ручками
			if (is_desktop()) {
				farSearchCatalog.googleMaps.onClickEvent();
			// var f = function() {
				if (isset(results_filter)&&results_filter.methods.advanced_form_search__is_visible) {
					$('.catalog_show_search_wrapper').collapse('show');
				}
				if (!farSearchCatalog.resultsFilter.methods.map__is_active) {
					farSearchCatalog.resultsFilter.methods.desktop__show_map();
					if (isset(results_filter)&&farSearchCatalog.views.container().find('.Hotel').length > 2) {
						results_filter.scroller.methods.scroll_item_to_position(
							results_filter.scroller.settings.items_scroll_in[1],
							$(self.element).position().top
						);
					}
				}
				if (farSearchCatalog.googleMaps.initialized) {
					// f();
					farSearchCatalog.googleMaps.onHotelOver(self.model.key, 15);
				// } else {
				// 	farSearchCatalog.googleMaps.onFirstLoadedEvent = f;
				// 	farSearchCatalog.googleMaps.onFirstHotelsAddCallback = function() {
				// 		farSearchCatalog.googleMaps.onHotelOver(self.model.key, 15);
				// 	};
				}
			}
		}
	};
	this.render = function() {
		/*
			Ссылка к разширенному методу рендера
		*/
		self._render(self);
	};
	this.otherButtonClickEvent = function(e){
		/*
			Клик ивент на кнопку другие варианты
			Метод работает в обе стороны: открыть/закрыть
		*/
		// self.log('Hotel::otherButtonClickEvent');
		e.preventDefault();
		var el = e.currentTarget;
		if (!self.model.othersActive) {
			// Если не активен, показываем
			if(self.Catalog&&self.Catalog.useOthersQuery) {
				self.others.query(el);
			}else {
				self.others.show(el);
			}
		} else {
			// Если активен, прячем
			self.others.hide(el);
		}
		return false;
	};
	/*
		Колекция методов и переменных для других вариантов
	*/
	this.others = {
		pageSize: 10, // Количество элементов для одного запроса
		pageIndex: 1, // Текущая страница запроса
		query: function(el) {
			var postModel = farSearchCatalog.requests.getPostModel();
			postModel.mapKey = self.model.key;
			postModel.firstCount = 10
			farSearchCatalog.requests.read(postModel,function(tours){
				tours.map(function(tour) {
					self.addTour(tour)
					return tour;
				});
				self.others.show(el);
			});
			/*
				Запрос других вариантов.
				Метод Делает запрос на АПИ для получения других вариантов туров в отель.
				Метод самозаполняет колекцию туров (где создаются туры и определяются самый дешевый тур)
			*/
			// self.log('Hotel::others::query');
			return;
			if (!isset(model)) model = {};
			window.Far.Global.jsonRequest({
				method: 'POST',
				url: '/tour/ReadResultsWithPars',
				data: {
					firstCount: self.others.pageSize,
					pageIndex: -1,
					//SystemKey: (self.lastCheapestTour?self.lastCheapestTour.model.SystemKey:null),
					MapKey: self.model.key,
					//hotelModel: self.model,
					//tourModel: (self.lastCheapestTour?self.lastCheapestTour.model:null)
				},
				onSuccess: function (response) {
					if (!isset(response.data)||!response.data||!isset(response.data.sResult)||!response.data.sResult||!response.data.sResult.length) {
						// Если АПИ вернуло хоть что-то
						var l = response.data.sResult.length;
						// Добавляем туры
						for (var i=0;i<l;i++) self.addTour(response.data.sResult[i]);
						// Выполняем ежезапросный колбек
						if (isset(model.callback)) model.callback(self);
						if (response.data.hasMore) {
							// Есть еще туры, плюсуем указатель страницы и делаем новый запрос
							self.others.pageIndex++;
							self.others.query();
						} else {
							// Выполняем финальный колбек
							if (isset(model.totalCallback)) model.totalCallback(self);
						}
					}
				}
			});
		},
		show: function(el) {
			/*
				Показываем другие варианты
			*/
			// self.log('Hotel::others::show');
			if (self.model.othersActive) return; // Если активно, уходим
			self.model.othersActive = true;
			if (isset(el)) el.classList.add('__active');
			self.element.classList.add('__othersOpened');
			self.renderOthers(self);
			self.element._others.hidden = false;
		},
		hide: function(el) {
			/*
				Прячем другие варианты
			*/
			// self.log('Hotel::others::hide');
			if (!self.model.othersActive) return; // Если не активно, уходим
			self.model.othersActive = false;
			self.element.classList.remove('__othersOpened');
			if (isset(el)) el.classList.remove('__active');
			removeChilds(self.element._others);
			self.element._others.hidden = true;
		}
	}
	this.onDepartureTimeClick = function (e) {
		/*
			Клик на времени вылета
		*/
		e.preventDefault();
		flights.initEvent(this);
		return false;
	};
	this.getModel = function(SystemKey) {
		/*
			Получение специальной, назвисимой, статической модели отеля.
			Методом не стоит пользоваться для получения модели отеля или самого дешевого тура.
			Метод возвращает статические, не изменяемые данные
		*/
		// self.log('Hotel::getModel');
		var model = Object.assign({}, self.model);
		model.Tours = {};
		for (var s in self.Tours) model.Tours[s]=self.Tours[s].model;
		model.lastCheapestTour = self.lastCheapestTour.model;
		model.Hotel = self;
		if (isset(SystemKey)) {
			model.currentTour = self.Tours[SystemKey].model;
		} else {
			model.currentTour = model.lastCheapestTour;
		}
		return model;
	};
	this.callendarClickEvent = function(e) {
		/*
			Клик на календарь
		*/
		// self.log('Hotel::callendarClickEvent');
		e.preventDefault();
		var el = e.currentTarget;
		if (!el.classList.contains('__active')) {
			self.model.currentDesign = 'callendar';
			if (self.Catalog) self.Catalog.othersDesign = 'callendar';
			removeChilds(el._body);
			el._body.appendChild(self.renderOthersCallendar());
			self.hightlightMinMaxPrices(self);
			el.classList.add('__active');
			for (var i=(el._sisters.length - 1);i>=0;i--) el._sisters[i].classList.remove('__active');
		}
		return false;
	};
	this.AccomodationOptionsClick = function(e) {
		/*
			Клик на кнопку Варианты размещений
		*/
		// self.log('Hotel::AccomodationOptionsClick');
		e.preventDefault();
		var el = e.currentTarget;
		if (!el.classList.contains('__active')) {
			el.classList.add('__active');
			self.model.currentDesign = 'list';
			if (self.Catalog) self.Catalog.othersDesign = 'list';
			removeChilds(el._body);
			el._body.appendChild(self.renderOthersList());
			self.hightlightMinMaxPrices(self);
			for (var i=(el._sisters.length - 1);i>=0;i--) el._sisters[i].classList.remove('__active');
		}
		return false;
	};
	this.sortToursEvent = function(e) {
		/*
			Клик на сортировщики тура в вариантах размещения
		*/
		// self.log('Hotel::sortToursEvent');
		if (!e.target.classList.contains('__active')) {
			var lis = e.target.parentNode.getElementsByTagName('li');
			for (var i=(lis.length-1);i>=0;i--) lis[i].classList.remove('__active');
			e.target.classList.add('__active');
			var btn = e.target.parentNode.parentNode.getElementsByTagName('button');
			btn[0].classList.remove('__active');
		}
		e.target._o = (e.target._o?false:true);
		if (e.target._o) {
			e.target.classList.add('__desc');
			e.target.classList.remove('__asc');
		} else {
			e.target.classList.add('__asc');
			e.target.classList.remove('__desc');
		}
		self.sortTours(e.target._s, e.target._o);
	};
	this.sortTours = function(sort, order) {
		/*
			Сортировка туров внутри карточки отеля.
			Метод перебирает все туры в отель и ставит им позицию.
			Никаких перерисовок нет и быть не может, только чистый CSS
		*/
		// self.log('Hotel::sortTours');
		if (!self.model.othersActive) return;
		var SystemKey;
		var o = (order?-1:1);
		switch (sort) {
			case 'date':
				var dateFloat = new Date().getTime();
				for (SystemKey in self.Tours) {
					if (self.Tours[SystemKey].element) self.Tours[SystemKey].element.style.order = (self.Tours[SystemKey].model.checkIn.getTime()-dateFloat)*o;
				}
			break;
			case 'nights':
				for (SystemKey in self.Tours) {
					if (self.Tours[SystemKey].element) self.Tours[SystemKey].element.style.order = self.Tours[SystemKey].model.nights*o;
				}
			break;
			case 'room':
				for (SystemKey in self.Tours) {
					if (self.Tours[SystemKey].element) self.Tours[SystemKey].element.style.order = self.Tours[SystemKey].model.room.length*o;
				}
			break;
			case 'meal':
				for (SystemKey in self.Tours) {
					if (self.Tours[SystemKey].element) self.Tours[SystemKey].element.style.order = self.Tours[SystemKey].model.meal.length*o;
				}
			break;
			case 'price':
				for (SystemKey in self.Tours) {
					if (self.Tours[SystemKey].element) self.Tours[SystemKey].element.style.order = (self.Tours[SystemKey].model.price.priceUAH>self.Tours[SystemKey].model.price.redPriceUAH?self.Tours[SystemKey].model.price.redPriceUAH:self.Tours[SystemKey].model.price.priceUAH)*o;
				}
			
			break;
		}
		self.element._othersBody.scrollTop = 0;
	};
	this.updateOthers = function(SystemKey) {
		/*
			Метод ссылка на обновление других вариантов
		*/
		if (!self.model.othersActive) return;
		self._updateOthers(SystemKey, self);
	};
	this.setViewMode = function(mode) {
		/*
			Метод ссылка на смену дизайна карточки отеля
		*/
		
		self._setViewMode(mode, self);
	};
	this.renderOthersList = function() {
		/*
			Метод ссылка на рендеринг Вариантов размещения
		*/
		return self._renderOthersList(self);
	};
	this.renderOthersCallendar = function() {
		/*
			Метод ссылка на рендеринг Календаря цен
		*/
		return self._renderOthersCallendar(self);
	};
	this.setOrder = function() {
		/*
			Метод для указания текущей позиции елемента внутри родителя.
			Родитель должен быть dispay:flex.
			Метод ничего не перерендеривает, используется чистый CSS
		*/
		// self.log('Hotel::setOrder');
		if (!self.element) return;
		if (self.Catalog&&self.Catalog.hotelsMode=='preview') return;
		var o = 0,
			sort = (self.Catalog?self.Catalog.sort:'priceDESC');
		switch (sort) {
			case 'priceDESC':
			case 'priceASC':
			case 'bestsDESC':
			case 'bestsASC':
				o = (self.lastCheapestTour.model.price.priceUAH>self.lastCheapestTour.model.price.redPriceUAH?self.lastCheapestTour.model.price.redPriceUAH:self.lastCheapestTour.model.price.priceUAH);
			break;
			case 'ratingDESC':
			case 'ratingASC':
			case 'rateDESC':
			case 'rateASC':
				o = self.model.rating;
			break;
		}
		o = (!o||is_empty(o)?(self.Catalog&&self.Catalog.isDesc?Number.MIN_SAFE_INTEGER:Number.MAX_SAFE_INTEGER):o);
		if (o==self.element.style.order) return;
		self.element.style.order = o;
		if (self.Catalog&&self.Catalog.lazyLoad&&self.element&&isset(self.element._img)&&isset(self.element._img.lazy)&&self.element._img.lazy) {
			self.element._img.lazy.precheck();
			setTimeout(self.element._img.lazy.precheck, 500);
		}
	};

	this.setCustomOrder = function (sort, dir, order) {
		
		switch (sort) {
			case 'nights':
				self.element.style.order = dir * self.lastCheapestTour.model.nights;
				break;
			case 'rate':
				self.element.style.order = dir * self.model.rating;
				break;
			case 'price':
				self.element.style.order = dir * (self.lastCheapestTour.model.price.priceUAH > self.lastCheapestTour.model.price.redPriceUAH
					? self.lastCheapestTour.model.price.redPriceUAH
					: self.lastCheapestTour.model.price.priceUAH);
				break;
			case 'date':
				self.element.style.order = dir * self.lastCheapestTour.model.checkIn.getTime() / 1000;
				break;
			case 'hotel':
			case 'room':
			case 'meal':
			case 'resort':
				self.element.style.order = dir * order;
				break;
			case 'weather':
				self.element.style.order = dir * (typeof self.lastCheapestTour.model.wheather !== 'undefined' ? self.lastCheapestTour.model.wheather.temperature : 1);
				break;
		}
	};

	this.fillOthersToursButton = function() {
		/*
			Метод заполняет значениями различные области карточки отеля
		*/
		// self.log('Hotel::fillOthersToursButton');
		if (!self.element||!self.element._othersButton) return;
		var toursCount = (Object.keys(self.Tours).length - 1);
		if (self.element._othersButton) {
			self.element._othersButtonCounter.innerHTML = toursCount;
			//self.element._othersButton.hidden = (toursCount?false:true);
		}
	};
	/*
		Коллекция методов и переменных для работы с контроллером карт
	*/
	this.MapController = {
		inited: false,
		init: function() {
			/*
				Прединициализация контроллера карт
			*/
			// self.log('Hotel::MapController::init');
			if (self.MapController.inited) return;
			self.MapController.inited = true;
			if (self.Catalog&&isset(self.Catalog.Map)&&self.Catalog.Map&&self.model.latitude&&self.model.longitude&&self.element) {
				self.element._address.classList.add('__hasMap');
				self.element._address.addEventListener('click', self.AddrClickEvent);
				if (is_desktop()) {
					self.element._address.addEventListener('mouseover', self.AddrOverEvent);
				}
				if (self.hasRealCatalog(self)) self.Catalog.Map.renderMarkers();
			}
		}
	};
	this.ratingClickEvent = function(e) {
		/*
			Клик ивент на рейтинг. Т.к. блок рейтинга находиться внутри ссылки (фото),
			клик должен отменить все действия
		*/
		if (e) {
			e.preventDefault();
			e.stopPropagation();
		}
		var url = [self.element._linkableElements[0].getAttribute('href'),'#emotions'].join('');
		var win = window.open(url, '_blank');
  		win.focus();
		return false;
	};
	this.addTour = function (tourModel) {
		/*
			Метод ссылка на инициализатор туров
		*/
		self.addTourInitializer(tourModel, self);
	};
	// Логирование времени
	this.lt = {};
	this.logT = function(n) {
		/*
			..
		*/
		if (!isset(self.lt[n])) self.lt[n] = {a:window.performance.now(),b:[]};
		var t = window.performance.now() - self.lt[n].a;
		self.lt[n].b.push(t);
		self.log(['Hotel::logT::',n,' #(',(self.lt[n].b.length-1),')\n',self.lt[n].b.join('\n ')].join(''));
	};
	// Конец Логирование времени
	this.init = function(tourModel) {
		/*
			Главная функция инициализации
		*/
		self.addTour(tourModel);
		if (self.Catalog) for (var i=(self.Catalog.onNewHotel.length - 1);i>=0;i--) self.Catalog.onNewHotel[i](self);
	};
	this.init(tourModel);
	this.anyTourLinkClick = function (e) {

		var model = {
			Hotel: self,
			Tour: this.Tour,
			HotelKey: self.model.key,
			SystemKey: this.SystemKey,
			_price: this._price,
			e: e,
			this: this
		};

		var tour = this.Tour;
		var statuses = [];

		if (this.Tour.model.is.hot) {
			statuses.push('Горящие');
		}
		if (this.Tour.model.is.recommended) {
			statuses.push('Рекомендованный');
		}
		if (this.Tour.model.price.redPriceUAH > 0 && this.Tour.model.price.redPriceUAH < this.Tour.model.price.priceUAH) {
			statuses.push('Скидка');
		}
		if (this.Tour.model.is.early) {
			statuses.push('Раннее бронирование');
		}
		if (this.Tour.model.is.tourFreeCancel) {
			statuses.push('Отмена');
		}

		var resort = this.Hotel != null ? this.Hotel.model.resort : '';
		var position = 1;
		if (typeof e !== 'undefined') {
			var cntDom = e.target.closest('.farSearchCatalog');
			var hotelDom = e.target.closest('.Hotel');
			if (cntDom !== null && hotelDom != null) {
				position = Array.from(cntDom.children).indexOf(hotelDom) + 1;
			}
		}
		GTM.productClickEx(
			'Search Results', //0 
			this.Hotel.model.key, //1
			this.Hotel.model.name, //2
			this.Tour.model.price.redPriceUAH > 0 && this.Tour.model.price.redPriceUAH < this.Tour.model.price.priceUAH ? this.Tour.model.price.redPriceUAH : this.Tour.model.price.priceUAH, //3
			this.Tour.model.operator.name + ', ' + this.Hotel.model.country + ', ' + resort, //4,5,6
			this.Hotel.model.stars, //7
			statuses.join(', '), //8
			position, //9
			this.SystemKey);
	};
}



/*
	Общие методы отелей.
	Колекция была создана для экономии оперативной памяти устройства
	и оптимизации скомпилированного кода
*/
var HotelSharedMethods = {
	calendarMinColumns: (is_mobile()? 7 : 7), 	// Минимальное количество колонок в календаре
	calendarMaxColumns: (is_mobile()? 7 : 7), 	// Максимальное количество колонок в календаре
	log: console.warn, 							// Метод логирования
	getMainPhoto: function (mapKey, size) {
		// Андрей, это же метод отеля...
		return this.getPhotoIndex(mapKey, 0, size);
	},
	getPhotoIndex: function(mapKey, index, size) {
		// Андрей, это же метод отеля и он сам знает почти все перечисленые атрибуты... Как так?
		return [imageServicesURL, '/mapkey/', mapKey, '/', index, '?size=', size].join('');
	},
	_updateOthers: function(SystemKey, self) {
		/*
			Обновление других вариантов
			Магический метод, который обновляет другие варианты исходя из системкея.
			Метод делает все сам. Рисует, обновляет календарь или другие варианты.
		*/
		// self.log('Hotel::_updateOthers');
		if (self.model.currentDesign == 'callendar') {
			var tbody = self.element.querySelector(['#TABLE',(self.Catalog?self.Catalog.id:''),self.model.key].join('--')),
				link = self.Tours[SystemKey].renderLink(),
				tr;
			if (tbody) {
				var nights = self.Tours[SystemKey].model.nights,
					td,
					date = self.Tours[SystemKey].model.checkIn.clone();
				tr = self.element.querySelector(['#TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,nights].join('--'));
				date.setHours(0);
				date.setMinutes(0);
				date.setSeconds(0);
				date.setMilliseconds(0);
				date = date.getTime();
				if (isset(window.SearchForm) && date > window.SearchForm.model.dateFrom.toJsDate().addDays(6).getTime()) return;
				if (tr) {
					td = self.element.querySelector(['#TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,nights,date].join('--'));
					if (td) {
						if (!td._tour||td._tour.model.price.redPrice>self.Tours[SystemKey].model.price.redPrice) {
							td.innerHTML = '';
							td.appendChild(link);
							td._tour = self.Tours[SystemKey];
						}
					} else {
						return;
						var trs = tbody.getElementsByTagName('tr'),
							theadTR = tbody.parentNode.getElementsByTagName('thead')[0].getElementsByTagName('tr')[0],
							th, dateObject, d, m, id, i;
						if (date>tbody._max_date) {
							while (tbody._max_date<date) {
								tbody._max_date = (tbody._max_date + 86400000);
								th = createElement({tag:'th'});
								dateObject = new Date(tbody._max_date);
								d = dateObject.getDate();
								d = (d<10?'0'+d:d);
								m = (dateObject.getMonth()+1);
								m = (m<10?'0'+m:m);
								th.innerHTML = [d,m].join('.');
								theadTR.appendChild(th);
								for (i=(trs.length - 1);i>=0;i--) {
									id = ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,trs[i]._nights,tbody._max_date].join('--');
									td = createElement('td');
									td.id = id;
									if (tbody._max_date==date) {
										td.appendChild(link);
									}
									trs[i].appendChild(td);
								}
							}
						} else if (date<tbody._min_date) {
							while (tbody._min_date>date) {
								tbody._min_date = (tbody._min_date - 86400000);
								th = createElement({tag:'th'});
								dateObject = new Date(tbody._min_date);
								d = dateObject.getDate();
								d = (d<10?'0'+d:d);
								m = (dateObject.getMonth()+1);
								m = (m<10?'0'+m:m);
								th.innerHTML = [d,m].join('.');
								theadTR.insertBefore(th, theadTR.firstChild);
								for (i=(trs.length - 1);i>=0;i--) {
									id = ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,trs[i]._nights,tbody._min_date].join('--');
									td = createElement({tag: 'td'});
									td.id = id;
									if (tbody._min_date==date) {
										td.appendChild(link);
									}
									trs[i].insertBefore(td, trs[i].firstChild);
								}
							}
						}
					}
				} else {
					tr = createElement({
						tag: 'tr',
						id: ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,nights].join('--')
					});
					var x = tbody._min_date,
						minimal = (self.Catalog?self.Catalog.calendarMinColumns:self.calendarMinColumns),
						maximal = (self.Catalog?self.Catalog.calendarMaxColumns:self.calendarMaxColumns),
						nightsBar = self.element.querySelector(['#BAR',(self.Catalog?self.Catalog.id:''),self.model.key].join('--')),
						nightsBarItem = createElement({
							innerHTML: [nights,LL.getMethering('nights',nights)].join(' ')
						});
					while(x<=tbody._max_date||minimal>0) {
						if (maximal>0) {
							td = createElement({
								tag: 'td',
								id: ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,nights,x].join('--')
							});
							if (x==date) {
								td.appendChild(link);
							}
							tr.appendChild(td);
							x = (x + 86400000);
						}
						minimal--;
						maximal--;
					}
					if (tbody._min_nights>nights) {
						tbody._min_nights = nights;
						tbody.insertBefore(tr, tbody.firstChild);
						nightsBar.insertBefore(nightsBarItem, nightsBar.firstChild);
					} else if (tbody._max_nights<nights) {
						tbody._max_nights = nights;
						tbody.appendChild(tr);
						nightsBar.appendChild(nightsBarItem);
					}
				}
			}
		} else if (self.model.currentDesign=='list') {
			self.Tours[SystemKey].render();
			self.element._othersBody.appendChild(self.Tours[SystemKey].element);
		}
		self.hightlightMinMaxPrices(self);
	},
	_renderOthersList: function(self) {
		/*
			Метод рендеринга вариантов размещений
		*/
		// self.log('Hotel::_renderOthersList');
		var horisontal = false;
		if (self.element.classList.contains('__horisontal')||self.element.classList.contains('__wide')||self.element.classList.contains('__middle')) horisontal = true;
		self.element._othersContainer = createElement({
			className: ['Hotel__others__list ToursList ',(horisontal?'__horisontal':'__list')].join(''),
		});
		if (self.Catalog&&self.Catalog.containerHorisontal) self.setViewMode('horisontal');
		var header = createElement({
			className: 'list__header'
		});
		var sortersOpener = createElement({
			tag: 'button',
			innerHTML: localizationValues.sortBy,
			events: {
				click: self.sortByClick
			}
		});
		header.appendChild(sortersOpener);
		var sortersContainer = createElement({tag: 'ul'});
		var sortersItem;
		sortersItem = createElement({
			tag: 'li',
			innerHTML: localizationValues.departureDate,
			className: '__asc',
			events: {
				click: self.sortToursEvent
			}
		});
		sortersItem._s = 'date';
		sortersItem._o = false;
		sortersContainer.appendChild(sortersItem);
		sortersItem = createElement({
			tag: 'li',
			innerHTML: localizationValues.tourPeriod,
			className: '__asc',
			events: {
				click: self.sortToursEvent
			}
		});
		sortersItem._s = 'nights';
		sortersItem._o = false;
		sortersContainer.appendChild(sortersItem);

		sortersItem = createElement({
			tag: 'li',
			innerHTML: localizationValues.roomType,
			className: '__asc',
			events: {
				click: self.sortToursEvent
			}
		});
		sortersItem._s = 'room';
		sortersItem._o = false;
		sortersContainer.appendChild(sortersItem);

		sortersItem = createElement({
			tag: 'li',
			innerHTML: localizationValues.meal,
			className: '__asc',
			events: {
				click: self.sortToursEvent
			}
		});
		sortersItem._s = 'meal';
		sortersItem._o = false;
		sortersContainer.appendChild(sortersItem);

		sortersItem = createElement({
			tag: 'li',
			innerHTML: localizationValues.tourPrice,
			className: '__active __asc',
			events: {
				click: self.sortToursEvent
			}
		});
		sortersItem._s = 'price';
		sortersItem._o = false;
		sortersContainer.appendChild(sortersItem);

		header.appendChild(sortersContainer);
		self.element._othersContainer.appendChild(header);
		self.element._othersBody = createElement({
			tag: 'ul',
			className: 'list__body',
			style: {
				flexDirection: 'column'
			}
		});
		for (var SystemKey in self.Tours) {
			if (self.Tours[SystemKey].model.fake) continue;
			self.Tours[SystemKey].render();
			self.element._othersBody.appendChild(self.Tours[SystemKey].element);
		}
		self.element._othersContainer.appendChild(self.element._othersBody);
		var footer = createElement({
			className: 'list__footer'
		});
		self.element._othersContainer.appendChild(footer);
		return self.element._othersContainer;
	},
	_createCallendarMatrix: function(self, ignoreSF) {
		/*
			Метод создания матрицы для календаря цен
		*/
		var matrix 		= {},
			emptyDates 	= true,
			emptyNights = true,
			min_date 	= Number.MAX_SAFE_INTEGER,
			max_date 	= Number.MIN_SAFE_INTEGER,
			min_nights 	= Number.MAX_SAFE_INTEGER,
			max_nights 	= Number.MIN_SAFE_INTEGER,
			date,
			nights,
			minimal,
			maximal,
			x,
			ordered = {},
			sfDate = (ignoreSF?0:(isset(window.SearchForm)?window.SearchForm.model.dateFrom.toJsDate().addDays(6).getTime():0));
		for (var SystemKey in self.Tours) {
			if (self.Tours[SystemKey].model.fake) continue;
			date = self.Tours[SystemKey].model.checkIn.clone();
			date.setHours(0);
			date.setMinutes(0);
			date.setSeconds(0);
			date.setMilliseconds(0);
			date = date.getTime();
			if (!ignoreSF && date > sfDate) continue;
			nights = self.Tours[SystemKey].model.nights;
			if (!isset(matrix[nights])) matrix[nights] = {};
			if (!isset(matrix[nights][date])) matrix[nights][date] = [];
			matrix[nights][date].push(SystemKey);
			if (min_date>date) min_date = date;
			if (max_date<date) max_date = date;
			if (min_nights>nights) min_nights = nights;
			if (max_nights<nights) max_nights = nights;
			emptyDates = false;
			emptyNights = false;
		}
		for (nights in matrix) {
			x = min_date;
			minimal = (self.Catalog?self.Catalog.calendarMinColumns:self.calendarMinColumns);
			maximal	= (self.Catalog?self.Catalog.calendarMaxColumns:self.calendarMaxColumns);
			while(x<=max_date||minimal>0) {
				if (maximal>0) {
					if (!isset(matrix[nights][x])) matrix[nights][x] = [];
					x = (x + 86400000);
				}
				minimal--;
				maximal--;
			}
		}
		if (emptyDates||emptyNights) {
			return ignoreSF?{matrix:{},min_date:0,max_date:0,min_nights:0,max_nights:0}:self._createCallendarMatrix(self, true);
		} else {
			Object.keys(matrix).sort().forEach(function(key_1) {
				var ordered_2 = {};
				Object.keys(matrix[key_1]).sort().forEach(function(key_2) {
					ordered_2[key_2] = matrix[key_1][key_2];
				});
				ordered[key_1] = ordered_2;
			});
			matrix = ordered;
			return {
				matrix: matrix,
				min_date: min_date,
				max_date: max_date,
				min_nights: min_nights,
				max_nights: max_nights
			};
		}
	},
	_renderOthersCallendar: function(self) {
		/*
			Метод рендеринга календаря цен.
		*/
		self.element._othersContainer = createElement({
			className: 'Hotel__others__list __callendar'
		});
		if (self.Catalog&&self.Catalog.containerHorisontal) self.setViewMode('horisontal');
		var header = createElement({
			className: 'list__header'
		});
		self.element._othersContainer.appendChild(header);
		self.element._othersBody = createElement({
			className: 'list__body'
		});
		var tmp = self._createCallendarMatrix(self, false),
			matrix = tmp.matrix,
			min_date = tmp.min_date,
			max_date = tmp.max_date,
			min_nights = tmp.min_nights,
			max_nights = tmp.max_nights;
		
		var tr, th, td,
			ToursCallendar = createElement({tag: 'div', className: 'ToursCallendar'}),
			nightsBar = createElement({tag: 'div', className: 'ToursCallendar__bar', id: ['BAR',(self.Catalog?self.Catalog.id:''),self.model.key].join('--')}),
			tableContainer = createElement({tag: 'div', className: 'ToursCallendar__container'}),
			footer = createElement({
				tag: 'div',
				className: 'ToursCallendar__footer'
			}),
			nightsBarItem,
			table = createElement({tag: 'table'}),
			thead = createElement({tag: 'thead'}),
			tbody = createElement({tag: 'tbody', id: ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key].join('--')}),
			tfoot = createElement({tag: 'tfoot'});
		self.tmp.tableContainer = tableContainer;
		if (isset(self.tmp.tableContainer__scrollLeft)) {
			self.tmp.tableContainer.scrollLeft = self.tmp.tableContainer__scrollLeft;
		}
		var tStart 	= function(e) {
						if (is_desktop()) {
							self.tmp.tSpos = (self.tmp.tableContainer.scrollLeft + e.clientX);
						} else {
							self.tmp.tSpos = (self.tmp.tableContainer.scrollLeft + e.targetTouches[0].clientX);
						}
						this.addEventListener(window.Far.eventsNaming.touchmove(), tMove);
						this.addEventListener(window.Far.eventsNaming.touchend(), tEnd);
					},
			tMove 	= function(e) {
						if (is_desktop()) {
							self.tmp.tableContainer.scrollLeft = (self.tmp.tSpos-e.clientX);
						} else {
							self.tmp.tableContainer.scrollLeft = (self.tmp.tSpos-e.changedTouches[0].clientX);
						}
					},
			tEnd 	= function(e) {
						self.tmp.tableContainer__scrollLeft = self.tmp.tableContainer.scrollLeft;
						this.removeEventListener(window.Far.eventsNaming.touchmove(), tMove);
						this.removeEventListener(window.Far.eventsNaming.touchend(), tEnd);
					};
		footer.addEventListener(window.Far.eventsNaming.touchstart(), tStart);
		table.appendChild(thead);
		table.appendChild(tbody);
		table.appendChild(tfoot);
		tbody._min_date = min_date;
		tbody._max_date = max_date;
		tbody._min_nights = min_nights;
		tbody._max_nights = max_nights;
		var filled_header = false,
			link, dateObject, d, m, cheapestTour, i;
		for (nights in matrix) {
			nightsBarItem = createElement({tag: 'div'});
			nightsBarItem.innerHTML = [nights,LL.getMethering('nights',nights)].join(' ');
			nightsBar.appendChild(nightsBarItem);
			if (!filled_header) {
				tr = createElement({tag: 'tr'});
				for (date in matrix[nights]) {
					th = createElement({tag: 'th'});
					dateObject = new Date(parseInt(date));
					d = dateObject.getDate();
					d = (d<10?'0'+d:d);
					m = (dateObject.getMonth()+1);
					m = (m<10?'0'+m:m);
					th.innerHTML = [d,m].join('.');
					tr.appendChild(th);
				}
				thead.appendChild(tr);
			}
			filled_header = true;
			tr = createElement({tag: 'tr'});
			tr.id = ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,nights].join('--');
			for (date in matrix[nights]) {
				td = createElement({tag: 'td'});
				td.id = ['TABLE',(self.Catalog?self.Catalog.id:''),self.model.key,nights,date].join('--');
				td._tour = null;
				if (matrix[nights][date].length) {
					cheapestTour = null;
					for (i=(matrix[nights][date].length-1);i>=0;i--) {
						if (!cheapestTour||self.Tours[matrix[nights][date][i]].model.redPrice<cheapestTour.model.redPrice) {
							cheapestTour = self.Tours[matrix[nights][date][i]];
						}
					}
					td.appendChild(cheapestTour.renderLink());
					td._tour = cheapestTour;
				}
				tr.appendChild(td);
			}
			tbody.appendChild(tr);
		}
		tableContainer.appendChild(table);
		ToursCallendar.appendChild(nightsBar);
		ToursCallendar.appendChild(tableContainer);
		ToursCallendar.appendChild(footer);
		self.element._othersBody.appendChild(ToursCallendar);
		self.element._othersContainer.appendChild(self.element._othersBody);
		footer = createElement({tag: 'div', className: 'list__footer'});
		self.element._othersContainer.appendChild(footer);
		return self.element._othersContainer;
	},
	orderedPricesMaxClick: function(item,k) {
		/*
			Метод отрисовки максимальной цены в календаре
		*/
		if (!k) item.classList.add('__maximal');
	},
	orderedPricesMinClick: function(item,k) {
		/*
			Метод отрисовки минимальной цены в календаре
		*/
		if (!k) item.classList.add('__minimal');
	},
	getCheapestTour: function(self) {
		/*
			Метод получения самого дешевого тура в отель.
			Из внешних обьектов нужно использовать только ссылку на переменную self.lastCheapestTour
		*/
		// self.log('Hotel::getCheapestTour');
		var cheapestTour = null, SystemKey;
		for (SystemKey in self.Tours) {
			if (!cheapestTour||cheapestTour.model.price.redPrice>self.Tours[SystemKey].model.price.redPrice) {
				cheapestTour = self.Tours[SystemKey];
			}
		}
		return cheapestTour;
	},
	fillTextsByTour: function(self) {
		/*
			Метод заполнения ДОМ элементов карточки отеля значениями самого дешевого тура
		*/
		// self.log('Hotel::fillTextsByTour');
		if (!self.element) return;
		var d, m, i,
			tourUrl,
			fake = self.model.fake, fakeCheapest = self.lastCheapestTour.model.fake;
		if (self.Catalog && self.hasRealCatalog(self) && isset(self.Catalog.hotelSpecialLinx) && isset(self.Catalog.hotelSpecialLinx[self.model.key])) {
			for (i = (self.element._linkableElements.length - 1) ; i >= 0; i--) {
			    if (self.lastCheapestTour.model.SystemKey.startsWith('0p0')) {
					var href = [];
					if (self.Catalog.hotelSpecialLinx[self.model.key].indexOf('/getsearchcataloglink') == -1) {
						href.push('/getsearchcataloglink');
					}
					href.push(self.Catalog.hotelSpecialLinx[self.model.key]);
					self.element._linkableElements[i].setAttribute('href', localizationFn.localizeUrl(href.join(''), localizationFn.current));
					tourUrl = localizationFn.localizeUrl(href.join(''), localizationFn.current);
				}
				else {
					tourUrl = self.lastCheapestTour.link();
					self.element._linkableElements[i].setAttribute('href', tourUrl);
				}
			}
		} else {
			for (i = (self.element._linkableElements.length - 1); i >= 0; i--) {
				self.element._linkableElements[i].setAttribute('href', self.lastCheapestTour.link());
			}
			tourUrl = self.lastCheapestTour.link();
		}
		//if (self.element._address) self.element._address.setAttribute('data-icon-after', (self.Catalog&&self.Catalog.useOperatorsIcons?['Operators_',self.lastCheapestTour.model.operator.int].join(''):null));
		self.element._params.nights.innerHTML = [localizationValues.onSomewhat, ' <ins>', self.lastCheapestTour.model.nights, '</ins> ', LL.getMethering('nights', self.lastCheapestTour.model.nights)].join('');
		self.element._params.nights.setAttribute('title', self.element._params.nights.innerText);
		if (self.lastCheapestTour.model.flyInclude) {
			self.element._params.flyInclude.innerHTML = [localizationValues.flightIncluded, ' (', localizationValues.from, ' ', self.lastCheapestTour.model.cityFrom.name, ')'].join('');
			self.element._params.flyInclude.style.color = '';
		}
		else if (self.lastCheapestTour.model.type === 'bus') {
			self.element._params.flyInclude.innerHTML = [localizationValues.busIncluded, ' (', localizationValues.from, ' ', self.lastCheapestTour.model.cityFrom.name, ')'].join('');
			self.element._params.flyInclude.style.color = '';
			self.element._params.flyInclude.classList.add('__bus');
		}
		else {
			self.element._params.flyInclude.innerHTML = localizationValues.flightNotIncluded;
			self.element._params.flyInclude.style.color = 'var(--c-red)';
		}
		self.element._params.flyInclude.setAttribute('title', self.element._params.flyInclude.innerText);
		d = self.lastCheapestTour.model.checkIn.getDate();
		d = (d<10?'0'+d:d);
		m = (self.lastCheapestTour.model.checkIn.getMonth()+1);
		m = (m < 10 ? '0' + m : m);
		self.imageAltAnTitle(self);
		 
		if (self.element._params.checkInValue) {
			if (self.lastCheapestTour.model.flyInclude) {
				self.element._params.checkInValue.innerHTML = [localizationValues.fly, ' <ins>', d, '.', m, '</ins> '].join('');
			} else {
				self.element._params.checkInValue.innerHTML = [localizationValues.start, ' <ins>', d, '.', m, '</ins> '].join('');
			}
			switch (self.lastCheapestTour.model.type) {
				case 'plain':
					self.element._params.checkIn.classList.add('__plane');
					self.element._params.checkIn.classList.remove('__noair');
					self.element._params.checkIn.classList.remove('__bus');
				break;
				case 'noair':
					self.element._params.checkIn.classList.remove('__plane');
					self.element._params.checkIn.classList.add('__noair');
					self.element._params.checkIn.classList.remove('__bus');
				break;
				case 'bus':
					self.element._params.checkIn.classList.remove('__plane');
					self.element._params.checkIn.classList.remove('__noair');
					self.element._params.checkIn.classList.add('__bus');
				break;
			}
		}
		if (self.element._params.departureTime)	{
			if (self.lastCheapestTour.model.flyInclude) {
				var hiddenDeparture = fake || fakeCheapest;
				if (!hiddenDeparture) {
					if (self.Catalog&&isset(self.Catalog.static)&&self.Catalog.static) {
						hiddenDeparture = true;
					}
				}
				self.element._params.departureTime.hidden = hiddenDeparture;
				self.element._params.departureTime.innerHTML = localizationValues.time;
				self.element._params.departureTime.setAttribute('data-id', self.lastCheapestTour.model.SystemKey);
				self.element._params.departureTime.setAttribute('data-url', tourUrl);
			} else {
				self.element._params.departureTime.hidden = true;
			}
		}

		self.element._params.checkIn.setAttribute('title', self.element._params.checkIn.innerText);

		self.element._params.room.innerHTML = ['<ins>', self.lastCheapestTour.model.room, '</ins>'].join('');
		self.element._params.room.setAttribute('title', self.element._params.room.innerText);
		self.element._params.room.hidden = fakeCheapest;
		
		self.element._params.meal.innerHTML = self.lastCheapestTour.model.meal;
		self.element._params.meal.setAttribute('data-code', self.lastCheapestTour.model.mealShort);
		self.element._params.meal.setAttribute('title', self.element._params.meal.innerText);
		self.element._params.meal.hidden = fakeCheapest;

		
		if (isset(self.useWeather) && self.useWeather === true) {
			if (typeof self.lastCheapestTour.model.wheather !== 'undefined') {
				self.element._params.weather.innerHTML = ['<i title="', self.lastCheapestTour.model.wheather.feature, '" class="weather_icon ', self.lastCheapestTour.model.wheather.icon, '"></i>', self.lastCheapestTour.model.wheather.temperature, '°C'].join('');
				self.element._params.weather.hidden = false;
			}
			else {
				self.element._params.weather.hidden = true;
			}
		}

		self.element._params.tourists.innerHTML = [self.touristsText(self.lastCheapestTour.model)].join('') ;
		self.element._params.tourists.setAttribute('title', self.touristsText(self.lastCheapestTour.model));
		var currencySymbol = getCurrencySymbol(self.lastCheapestTour.model.price.currency),
			priceText = [currencySymbol,intHumanize(self.lastCheapestTour.model.price.price>self.lastCheapestTour.model.price.redPrice?self.lastCheapestTour.model.price.redPrice:self.lastCheapestTour.model.price.price)].join(''),
			priceUAHText = [intHumanize(self.lastCheapestTour.model.price.priceUAH > self.lastCheapestTour.model.price.redPriceUAH ? self.lastCheapestTour.model.price.redPriceUAH : self.lastCheapestTour.model.price.priceUAH), ' ', localizationValues.currency_uah].join('');
		var mode = '';
		if (self.Catalog) mode = self.Catalog.hotelsMode;
		var pp;
		switch (mode) {
			case 'preview':
				self.element._price.old.style.display = 'none';
				self.element._price.new.style.display = 'none';
				if(self.element._favoritesButton) {
					self.element._favoritesButton.style.display = 'none';
				}
				if(self.element._priceSubscribe) {
					self.element._priceSubscribe.style.display = 'none';
				}
				self.element._price.uah.style.display = 'none';
				self.element._linkButton.setAttribute('style', 'margin-top:calc(var(--s-bs)*0.5)!important');
				if (self.lastCheapestTour.model.SystemKey.startsWith('0p0') && !self.lastCheapestTour.model.price.priceUAH) {
					self.element._price.uah.innerText = localizationValues.find_out_the_price;
					self.element._linkButton.innerText = localizationValues.find_out_the_price;
				} else {
					pp = [localizationValues.from3, priceUAHText].join(' ');
					self.element._price.uah.innerText = pp;
					self.element._linkButton.innerText = pp;
				}
			break;
			default:
				self.element._price.old.innerHTML = (self.lastCheapestTour.model.price.price>self.lastCheapestTour.model.price.redPrice?[currencySymbol,intHumanize(self.lastCheapestTour.model.price.price)].join(''):'');
				self.element._price.new.innerHTML = priceText;
				self.element._price.uah.innerText = priceUAHText;
				self.element._linkButton.innerText = priceUAHText;
			break;
		}

		if (self.element._params.departureTime) {
			var hiddenDeparture = fake;
			if (!hiddenDeparture) {
				if (self.Catalog&&isset(self.Catalog.static)&&self.Catalog.static) {
					hiddenDeparture = true;
				}
			}
			self.element._params.departureTime.hidden = hiddenDeparture;
		}

		self.element._price.price.hidden = fakeCheapest;
		self.element._price.old.hidden = fakeCheapest;
		self.element._price.new.hidden = fakeCheapest;
		self.element._linkButton.hidden = fakeCheapest;
		if (self.element._favoritesButton) self.element._favoritesButton.hidden = fakeCheapest;

		if (self.element._preloader != null) {
			self.element._preloader.hidden = !fakeCheapest;
		}

		if (self.lastCheapestTour.model.SystemKey.startsWith('0p0')) {
			var Pdesc = (self.Catalog&&isset(self.Catalog.hotelDescriptions[self.model.key])&&!is_empty(self.Catalog.hotelDescriptions[self.model.key])?self.Catalog.hotelDescriptions[self.model.key]:'');
			if (is_empty(Pdesc)) Pdesc = self.model.description;
			if (is_empty(Pdesc)) Pdesc = self.element._description.innerHTML;
			self.model.description = Pdesc;
			if (is_empty(self.model.description)) {
				self.element._description.innerHTML = '<div></div>';
			} else {
				self.element._description.innerHTML = self.model.description;
			}
		} else {
			self.element._description.innerHTML = '';
		}

		var oldBadges = self.element._photo.getElementsByTagName('dl'),
			parent, badge, desc, hasBadge = false;
		for (i=(oldBadges.length - 1);i>=0;i--) self.element._badges.removeChild(oldBadges[i]);

		if (self.lastCheapestTour.model.price.price !== self.lastCheapestTour.model.price.redPrice) {
			parent = createElement('dl');
			parent.className = '__right';
			badge = createElement('dt');
			badge.className = '__discount';
			badge.innerHTML = ['-', intHumanize(self.lastCheapestTour.model.price.price-self.lastCheapestTour.model.price.redPrice), currencySymbol,].join('');
			desc = createElement('dd');
			desc.innerHTML = localizationValues.tour_with_discount;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
		}
		
		if (!hasBadge && self.lastCheapestTour.model.is.hot) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__hot';
			badge.innerHTML = localizationValues.hot_tours;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.hot_tours_description2;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.tourFreeCancel) {
			parent = createElement({
				tag: 'dl',
				events: {
					click: function (e) {
						e.preventDefault();
						var f = function () {
							window.Far.Script({
								src: '/NewDesign/Scripts/Components/InsuranceModal.js',
								addBuildNumber: true,
								callback: function () {
								}
							});
							if (!isset(window.Far.InsuranceModal)) {
								setTimeout(f, 100);
							} else {
								window.Far.InsuranceModal.showModal();
							}
						};
						f();
					}
				}
			});
			badge = createElement({
				tag: 'dt',
				className: '__insurance',
				innerHTML: localizationValues.free_cancellation,
				attributes: {
					'data-icon-after': 'information-solid'
				}
			});
			parent.appendChild(badge);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (!hasBadge && self.lastCheapestTour.model.is.early) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__early';
			badge.innerHTML = localizationValues.early_tours;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.early_tours_description;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (!hasBadge && self.lastCheapestTour.model.is.recommended) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__recommended';
			badge.innerHTML = localizationValues.recommended_tours;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.recommended_tours_description2;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (!hasBadge && false && self.lastCheapestTour.model.is.bestDeal) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__bestDeal';
			badge.innerHTML = localizationValues.best_deal_tours;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.best_deal_tours_description2;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (!hasBadge && false && self.lastCheapestTour.model.is.choiceFarvater) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__choiceFarvater';
			badge.innerHTML = localizationValues.Farvater_choice;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.recommended_tours_description2;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (!hasBadge && false && self.lastCheapestTour.model.is.promo) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__promo';
			badge.innerHTML = localizationValues.promo_tours;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.promo_tours_description;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		
		if (self.lastCheapestTour.model.is.blackFriday) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__blackFriday';
			badge.innerHTML = localizationValues.Key_Key000001594;
			desc = createElement('dd');
			desc.className = '__blackFriday_desc';
			desc.innerHTML = localizationValues.Key_Key000001595;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.isViber) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__viber';
			badge.innerHTML = localizationValues.Key_Key000001367;
			desc = createElement('dd');
			desc.className = '__viber_desc';
			desc.innerHTML = localizationValues.Key_Key000001390;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.isMonobank) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__monobank';
			badge.innerHTML = localizationValues.Key_Key000001329;
			desc = createElement('dd');
			desc.className = '__monobank_desc';
			desc.innerHTML = localizationValues.Key_Key000001332;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		/*
		if (self.lastCheapestTour.model.is.otp) {
			parent = createElement({
				tag: 'dl',
				events: {
					click: function (e) {
						e.preventDefault();
						var f = function () {
							window.Far.Script({
								src: '/NewDesign/Scripts/Components/OtpModal.js',
								addBuildNumber: true,
								callback: function () {
								}
							});
							if (!isset(window.Far.OtpModal)) {
								setTimeout(f, 100);
							} else {
								window.Far.OtpModal.showModal();
							}
						};
						f();
					}
				}
			});
			badge = createElement({
				tag: 'dt',
				className: '__otp',
				innerHTML: localizationValues.Key_Key000000521,
			});
			parent.appendChild(badge);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		*/

		if (self.lastCheapestTour.model.is.uklon) {
			parent = createElement({
				tag: 'dl',
				events: {
					click: function (e) {
						e.preventDefault();
						var f = function () {
							window.Far.Script({
								src: '/NewDesign/Scripts/Components/UklonModal.js',
								addBuildNumber: true,
								callback: function () {
								}
							});
							if (!isset(window.Far.UklonModal)) {
								setTimeout(f, 100);
							}
							else {
								window.Far.UklonModal.showModal();
							}
						};
						f();
					}
				}
			});
			badge = createElement({
				tag: 'dt',
				className: '__uklon',
				innerHTML: localizationValues.uklon_tour_badge
			});
			parent.appendChild(badge);
			if (window.deviceConfig.type === 'Desktop') {
				desc = createElement({
					tag: 'dd',
					innerHTML: localizationValues.uklon_tour_badge_title
				});
				parent.appendChild(desc);
			}
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.healthCertificate) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__health';
			badge.innerHTML = localizationValues.Key_Key000000956 || 'Сертификат здоровья';
			desc = createElement('dd');
			desc.innerHTML = localizationValues.Key_Key000000957_description || 'Сертификат здоровья';
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		else if (self.lastCheapestTour.model.is.worksIn2020) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__works';
			badge.innerHTML = localizationValues.Key_Key000000954 || 'Работает в 2020 году';
			desc = createElement('dd');
			desc.innerHTML = localizationValues.Key_Key000000955_description || 'Работает в 2020 году';
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		//Бесплатный ПЦР-тест
		if (self.lastCheapestTour.model.is.freePCRTest) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__pcr';
			badge.innerHTML = localizationValues.Key_Key000000990 || 'Бесплатный ПЦР-тест';
			desc = createElement('dd');
			desc.innerHTML = localizationValues.Key_Key000000991_description || 'ПЦР тест бесплатно в рекомендуемых лабораториях туроператора. Компенсация в размере 799 грн на человека по прибытию с отдыха с результатами теста других лабораторий Украины.';
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.isLastSeats) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__lastSeats';
			badge.innerHTML = localizationValues.Key_Key000001422;
			parent.appendChild(badge);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
        if (self.lastCheapestTour.model.is.freeTransfer) {
            var descKey = 'Key_Key000001589';
            if (self.lastCheapestTour.model.cityFrom.code === 'KIV') {
                descKey = 'Key_Key000001601';
            }
            else if (self.lastCheapestTour.model.cityFrom.code === 'SCV') {
                descKey = 'Key_Key000001600';
            }
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__freeTransfer';
			badge.innerHTML = localizationValues.Key_Key000001588;
			desc = createElement('dd');
            desc.innerHTML = localizationValues[descKey];//localizationValues.Key_Key000001589;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.brightUP) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__brightUP';
			badge.innerHTML = localizationValues.Key_Key000001590;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.Key_Key000001591;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
		if (self.lastCheapestTour.model.is.bonusX2) {
			parent = createElement('dl');
			badge = createElement('dt');
			badge.className = '__bonusX2';
			badge.innerHTML = localizationValues.Key_Key000001592;
			desc = createElement('dd');
			desc.innerHTML = localizationValues.Key_Key000001593;
			parent.appendChild(badge);
			parent.appendChild(desc);
			self.element._badges.appendChild(parent);
			hasBadge = true;
		}
	},
	touristsText: function(model) {
		/*
			Метод генерации текста о туристах
		*/
		var touristsCount = (model.tourists.adl+model.tourists.kids),
			touristsText = [localizationValues.price_for, ' ', touristsCount, ' ', LL.getMethering('tourists', touristsCount)];
		if (model.tourists.kids) {
			touristsText.push(' (');
			touristsText.push(localizationValues.including);
			touristsText.push(' ');
			touristsText.push(model.tourists.kids);
			touristsText.push(' ');
			touristsText.push(LL.getMethering('kids',model.tourists.kids));
			touristsText.push(')');
		}
		return touristsText.join('');
	},
	sortByClick: function(e) {
		/*
			Клик ивент на кнопки сортировки
		*/
		var el = e.currentTarget;
		if (el.classList.contains('__active')) {
			el.parentNode.parentNode.classList.remove('__activeHeader');
			el.classList.remove('__active');
		} else {
			el.parentNode.parentNode.classList.add('__activeHeader');
			el.classList.add('__active');
		}
	},
	dealText: function(model) {
		/*
			Метод генерации текста о специальном типе тура
		*/
		if (model.hot) {
			return localizationValues.hot_tours
		} else if (model.early) {
			return localizationValues.early_tours
		} else if (model.recommended) {
			return localizationValues.recommended_tours
		} else if (model.bestDeal) {
			return localizationValues.best_deal_tours
		} else if (model.choiceFarvater) {
			return localizationValues.Farvater_choice
		} else if (model.promo) {
			return localizationValues.promo_tours
		}
		return '';
	},
	imgTextAlt: function(self) {
		/*
			Метод генерации текста для альт атрибута изображений
		*/
		return [localizationValues.hot_tours/*self.dealText(self.lastCheapestTour.model.is)*/, self.model.name, self.model.countryNameAccusativeCase, self.model.resortNameAccusativeCase, new Date().getFullYear()].join(' ');
	},
	imgTextTitle: function(self) {
		/*
			Метод генерации текста о для тайтл атрибута изображений
		*/
		return [localizationValues.Tours_in, self.model.name, self.model.countryNameAccusativeCase, /*self.model.resortNameAccusativeCase, */ new Date().getFullYear()+'.', localizationValues.Photos_Reviews_Prices].join(' ');
	},
	imageAltAnTitle: function(self) {
		/*
			Метод установки альт и тайтл атрибутов к изображению
		*/
		if (self.element) {
			self.element._img.setAttribute('alt', self.imgTextAlt(self));
			self.element._img.setAttribute('title', self.imgTextTitle(self));
		}
	},
	addTourInitializer: function(tourModel, self) {
		/*
			Метод инициализации добавления нового тура в отель
		*/
		// self.log('Hotel::addTourInitializer');
		var i;
		if (isset(tourModel.other)&&tourModel.other&&tourModel.other.length) {
			if (self.Catalog&&(!isset(self.Catalog.static)||!self.Catalog.static)) {
				for (var i=(tourModel.other.length-1);i>=0;i--) {
					self.addTourInitializer(tourModel.other[i], self);
				}
			}
		}
		if (isset(self.Tours[tourModel.SystemKey])) return;
		self.Tours[tourModel.SystemKey] = new Tour(self, tourModel);
		if (self.Catalog) for (i=(self.Catalog.onNewTour.length - 1);i>=0;i--) self.Catalog.onNewTour[i](self.Tours[tourModel.SystemKey]);
		if (self.Catalog&&self.hasRealCatalog(self)) self.Catalog.setMinMaxPrice(self.Tours[tourModel.SystemKey]);
		self.fillOthersToursButton();
		var cheapestTour = self.getCheapestTour(self);
		self.updateOthers(tourModel.SystemKey);

		// This part of function fill broke if this is not a cheapest tour!
		if (self.lastCheapestTour!==null&&cheapestTour.model.SystemKey===self.lastCheapestTour.model.SystemKey) return;
		self.lastCheapestTour = cheapestTour;
		if (self.Catalog) for (i=(self.Catalog.onNewCheapestTour.length - 1);i>=0;i--) self.Catalog.onNewCheapestTour[i](self.lastCheapestTour);
		self.model.fake = cheapestTour.model.fake;
		if (!self.element) {
			self.element = document.getElementById([(self.Catalog?self.Catalog.id:''),'--',self.model.key].join(''));
			if (self.element) {
				self.element.Hotel = self;
				self.element._address = self.element.querySelector('.Hotel__address');
				if (self.Catalog&&isset(self.Catalog.Map)&&self.Catalog.Map&&self.model.latitude&&self.model.longitude) {
					self.element._address.addEventListener('click', self.AddrClickEvent);
					if (is_desktop()) {
						self.element._address.addEventListener('mouseover', self.AddrOverEvent);
					}
				}
				self.element._img = self.element.querySelector('.Hotel__photo img');
				if (!isset(self.element._img.Lazy)) {
					self.element._img.lazyConfig = {
						rootMargin: '150px 150px',
						threshold: 0
					};
					new Lazy(self.element._img);
				}
				self.element._badges = self.element.querySelector('.Hotel__photo__badges');
				self.element._badges.addEventListener('click', self.unsetClick);
				self.element._description = self.element.querySelector('.Hotel__description');
				self.element._linkButton = self.element.querySelector('.Hotel__linkButton');
				self.element._others = self.element.querySelector('.Hotel__others');
				self.element._othersButton = self.element.querySelector('.Hotel__othersButton');
				if (self.element._othersButton) {
					self.element._othersButton.addEventListener('click', self.otherButtonClickEvent);
					self.element._othersButtonCounter = self.element._othersButton.querySelector('span');
				}
				self.element._favoritesButton = self.element.querySelector('.Favorites_button');
				var params = self.element.querySelector('.Hotel__params');
				self.element._params = {
					checkIn: 	params.querySelector('.Hotel__params__checkIn'),
					flyInclude: params.querySelector('.Hotel__params__flyInclude'),
					meal: 		params.querySelector('.Hotel__params__meal'),
					nights: 	params.querySelector('.Hotel__params__nights'),
					room: 		params.querySelector('.Hotel__params__room'),
					tourists: 	params.querySelector('.Hotel__params__tourists'),
					checkInValue: params.querySelector('.Hotel__params__checkIn span:nth-child(1)'),
					departureTime: params.querySelector('.Hotel__params__checkIn span:nth-child(2)')
				};
				self.element._photo = self.element.querySelector('.Hotel__photo');
				self.element._price = {
					price: self.element.querySelector('.Hotel__price'),
					new: self.element.querySelector('.Hotel__price .Hotel__price__new'),
					old: self.element.querySelector('.Hotel__price .Hotel__price__old'),
					uah: self.element.querySelector('.Hotel__price .Hotel__price__uah')
				};
				self.element._footerDesc = self.element.querySelector('.Hotel__footerDesc');
				self.element._title = self.element.querySelector('.Hotel__title');
				self.element._linkableElements = [self.element._photo,self.element._title,self.element._linkButton];
				self.setObjecatibleElements(self);
			}
		}
		self.MapController.init();
		self.fillTextsByTour(self);
		self.setOrder();
	},
	hasRealCatalog: function(self) {
		/*
			Метод проверки, настоящий ли каталог используется как родитель отеля
		*/
		return (isset(window.Catalog_) && self.Catalog instanceof Catalog_);
	},
	_setViewMode: function(mode, self) {
		/*
			Метод установки текущего дизайна карточки отеля
		*/
		// self.log('Hotel::_setViewMode');
		if (!self.element) return;
		switch (mode) {
			case 'horisontal':
			case '__horisontal':
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (!self.element.classList.contains('__horisontal')) self.element.classList.add('__horisontal');
				if (isset(self.element._othersContainer)&&!self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.add('__horisontal');
				self.removeGallery(self);
			break;
			case 'middle':
			case '__middle':
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (!self.element.classList.contains('__middle')) self.element.classList.add('__middle');
				if (isset(self.element._othersContainer)&&!self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.add('__horisontal');
				self.removeGallery(self);
			break;
			case 'minimal':
			case '__minimal':
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (!self.element.classList.contains('__minimal')) self.element.classList.add('__minimal');
				if (isset(self.element._othersContainer)&&self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.remove('__horisontal');
				self.removeGallery(self);
			break;
			case 'tableRow':
			case '__tableRow':
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (!self.element.classList.contains('__tableRow')) self.element.classList.add('__tableRow');
				if (isset(self.element._othersContainer)&&self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.remove('__horisontal');
				self.removeGallery(self);
			break;
			case 'fullTableRow':
			case '__fullTableRow':
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (!self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (!self.element.classList.contains('__fullTableRow')) self.element.classList.add('__fullTableRow');
				if (isset(self.element._othersContainer)&&self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.remove('__horisontal');
				self.removeGallery(self);
			break;
			case 'wide':
			case '__wide':
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (!self.element.classList.contains('__wide')) self.element.classList.add('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (isset(self.element._othersContainer)&&!self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.add('__horisontal');
				self.addGallery(self);
			break;
			case 'openInsideBlock':
			case '__openInsideBlock':
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (!self.element.classList.contains('__openInsideBlock')) self.element.classList.add('__openInsideBlock');
				if (isset(self.element._othersContainer)&&!self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.add('__horisontal');
				self.removeGallery(self);
			break;
			default:
				if (self.element.classList.contains('__horisontal')) self.element.classList.remove('__horisontal');
				if (self.element.classList.contains('__middle')) self.element.classList.remove('__middle');
				if (self.element.classList.contains('__minimal')) self.element.classList.remove('__minimal');
				if (self.element.classList.contains('__tableRow')) self.element.classList.remove('__tableRow');
				if (self.element.classList.contains('__wide')) self.element.classList.remove('__wide');
				if (self.element.classList.contains('__openInsideBlock')) self.element.classList.remove('__openInsideBlock');
				if (isset(self.element._othersContainer)&&self.element._othersContainer.classList.contains('__horisontal')) self.element._othersContainer.classList.remove('__horisontal');
				self.removeGallery(self);
			break;
		}
	},
	addGallery: function(self) {
		/*
			Метод генерации и встраивания галереи на карточку отеля
		*/
		// self.log('Hotel::addGallery');
		if (!self.element) return;
		if (!isset(self.element._Gallery)) {
			var alt = self.imgTextAlt(self),
				tit = self.imgTextTitle(self);
			self.element._Gallery = createElement({
				tag: 'div',
				className: 'Hotel__photo__Gallery',
				innerHTML: [
					'<img data-src="', self.getPhotoIndex(self.model.key, 0, 'catalog'), '" alt="', alt, '" title="', tit, '">',
					'<img data-src="', self.getPhotoIndex(self.model.key, 1, 'catalog'), '" alt="', alt, '" title="', tit, '">',
					'<img data-src="', self.getPhotoIndex(self.model.key, 2, 'catalog'), '" alt="', alt, '" title="', tit, '">',
					'<img data-src="', self.getPhotoIndex(self.model.key, 3, 'catalog'), '" alt="', alt, '" title="', tit, '">',
					'<img data-src="', (self.model.latitude && self.model.longitude ? 'https://staticmaps.farvater.travel/get/' + self.model.key : self.getPhotoIndex(self.model.key, 4, 'catalog')), '" alt="', alt, '" title="', tit, '">'
				].join('')
			});
			var imgs = self.element._Gallery.querySelectorAll('img');
			for (var i=(imgs.length-1);i>=0;i--) {
				imgs[i].lazyConfig = {
					rootMargin: '150px 150px',
					threshold: 0
				};
				new Lazy(imgs[i]);
			}
		}
		self.element._photo.appendChild(self.element._Gallery);
	},
	removeGallery: function(self) {
		/*
			Метод удаления галереи из карточки отеля
		*/
		// self.log('Hotel::removeGallery');
		if (!self.element||!isset(self.element._Gallery)) return;
		var g = self.element._photo.querySelector('.Hotel__photo__Gallery');
		if (g) self.element._photo.removeChild(g);
	},
	ratingToText: ratingToText,
	_render: function(self) {
		/*
			Метод рендеринга карточки отеля
		*/
		// self.log('Hotel::_render');
		if (self.element) return;
		var fake = self.model.fake;
		self.element = createElement({
			className: ['Hotel', (self.Catalog ? self.Catalog.hotelClassName : '')].join(' '),
			id: [(self.Catalog ? self.Catalog.id : ''), '--', self.model.key].join(''),
			hidden: true,
			attributes: {
				hotelKey: self.model.key
			}
		});
		self.element.Hotel = self;
		if (self.Catalog && self.Catalog.containerHorisontal) self.setViewMode('horisontal');
		var documentFragment = document.createDocumentFragment();
		self.element._photo = createElement({
			tag: 'a',
			className: 'Hotel__photo UDC__tourBuyClick',
			attributes: {
				href: '#',
				target: '_blank'
			},
			events: {
				click: function(e) {
					var el = e.target;
					while (!el.classList.contains('Hotel__photo')) {
						if (el.classList.contains('Hotel__rating')) {
							e.preventDefault();
							e.stopPropagation();
							self.ratingClickEvent(false);
							return false;
						}
						el = el.parentNode;
					}
				}
			}
		});
		if (self.element.classList.contains('__wide')) self.addGallery(self);
		self.element._img = createElement({
			tag: 'img',
			attributes: {
				alt: '',
				title: ''
			}
		});
		
		if (self.Catalog && self.Catalog.lazyLoad) {
			self.element._img.setAttribute('data-src', self.model.photo);
			self.element._img.lazyConfig = {
				rootMargin: '150px 150px',
				threshold: 0
			};
			new Lazy(self.element._img);
		} else {
			self.element._img.setAttribute('src', self.model.photo);
		}

		// if init swiper
		if (window.SeoPage) {
			//start swiper
			function initSeoPageSwiper() {
				var alt = self.imgTextAlt(self),
					tit = self.imgTextTitle(self),
					idnt = Date.now();

				self.element.swiper = {
					plugin: null,
					swiperEl: document.createElement('div'),
					swiperPag: document.createElement('div'),
					swiperPrev: document.createElement('div'),
					swiperNext: document.createElement('div')
				};
				self.element.swiper.swiperPag.className = 'swiper-pagination';
				self.element.swiper.swiperPrev.className = 'swiper-button-prev';
				self.element.swiper.swiperNext.className = 'swiper-button-next';
				self.element.swiper.swiperEl.className = 'swiper swiper-' + idnt + ' swiper-photos-gallery-container show fix-btns-seo';
				self.element.swiper.swiperEl.innerHTML = ['\
			<div class="swiper-wrapper">\
				<div class="swiper-slide">\
					<img alt="', alt, '" title="', tit, '" src="', self.getPhotoIndex(self.model.key, 0, "catalog"), '">\
				</div>\
				<div class="swiper-slide">\
					<img alt="', alt, '" title="', tit, '" src="', self.getPhotoIndex(self.model.key, 1, "catalog"), '">\
				</div>\
				<div class="swiper-slide">\
					<img alt="', alt, '" title="', tit, '" src="', self.getPhotoIndex(self.model.key, 2, "catalog"), '">\
				</div>\
				<div class="swiper-slide">\
					<img alt="', alt, '" title="', tit, '" src="', self.getPhotoIndex(self.model.key, 3, "catalog"), '">\
				</div>\
				<div class="swiper-slide">\
					<img alt="', alt, '" title="', tit, '" src="', (self.model.latitude && self.model.longitude) ? 'https://staticmaps.farvater.travel/get/' + self.model.key : self.getPhotoIndex(self.model.key, 3, "catalog"), '">\
				</div>\
			</div>'].join('');

				self.element.swiper.swiperEl.appendChild(self.element.swiper.swiperPag);
				self.element.swiper.swiperEl.appendChild(self.element.swiper.swiperPrev);
				self.element.swiper.swiperEl.appendChild(self.element.swiper.swiperNext);

				self.element.swiper.plugin = new Swiper(self.element.swiper.swiperEl, {
					direction: 'horizontal',
					loop: false,
					grabCursor: true,
					pagination: {
						el: self.element.swiper.swiperPag,
						clickable: true,
						type: 'bullets' // fact..
					},
					navigation: {
						nextEl: self.element.swiper.swiperNext,
						prevEl: self.element.swiper.swiperPrev,
					},
				});

				self.element._photo.appendChild(self.element.swiper.swiperEl);

				//end swiper
			}
			Far.Script2Async({
				src: '/plugins/swiperjs/swiper-bundle.min.js',
				addBuildNumber: false,
				outside: true,
				callback: function () {
					initSeoPageSwiper();
				}
			});
		}
		else {
			self.element._photo.appendChild(self.element._img);
		}

		self.element._badges = createElement({
			className: 'Hotel__photo__badges',
			click: self.unsetClick
		});
		self.element._photo.appendChild(self.element._badges);
		// self.element._photo.appendChild(self.element._img);
		documentFragment.appendChild(self.element._photo);

		var stars = createElement({
			className: 'Hotel__stars stars',
			attributes: {
				'data-stars': self.model.stars
			},
			innerHTML: starsRenderInner(self.model.stars)
		});
		documentFragment.appendChild(stars);

		var r = (self.model.rating / 100);
		r = (r == 10 ? r : r.toFixed(1));
		var ratingTXT = self.ratingToText(r),
			rating = createElement({
			className: 'Hotel__rating',
			attributes: {
				title: localizationValues.Rating,
			},
			innerHTML: ['<b data-tile="', ratingTXT, '" ',(self.model.reviewsCount?'':'class="__inv"'),'>', r, '</b>', (self.model.reviewsCount ? ['<small>', self.model.reviewsCount, ' ', LL.getMethering('reviews', self.model.reviewsCount), '</small>'].join('') : '')].join(''),
			events: {
				click: self.ratingClickEvent
			}
		});
		self.element._photo.appendChild(rating);

		self.element._title = createElement({
			tag: 'a',
			className: 'Hotel__title UDC__tourBuyClick',
			innerHTML: self.model.name,
			attributes: {
				href: '#',
				target: '_blank'
			}
		});
		documentFragment.appendChild(self.element._title);

		self.element._address = createElement({
			className: 'Hotel__address',
			//attributes: {
			//	'data-icon-after': (self.Catalog&&self.Catalog.useOperatorsIcons?['Operators_',self.lastCheapestTour.model.operator.int].join(''):null)
			//},
			innerHTML: ['<span><ins>',self.model.country,', </ins><span>',self.model.resort,'</span></span>'].join(''),
		});
		if (self.Catalog&&isset(self.Catalog.Map) && self.Catalog.Map && self.model.latitude && self.model.longitude) {
			self.element._address.classList.add('__hasMap');
			self.element._address.addEventListener('click', self.AddrClickEvent);
			if (is_desktop()) {
				self.element._address.addEventListener('mouseover', self.AddrOverEvent);
			}
		}
		documentFragment.appendChild(self.element._address);

		self.element._description = createElement({
			className: 'Hotel__description',
			innerHTML: self.model.description,
		});
		documentFragment.appendChild(self.element._description);

		var params = createElement({
			tag: 'ul',
			className: 'Hotel__params'
		});
		self.element._params = {};
		self.element._params.checkIn = createElement({
			tag: 'li',
			className: 'Hotel__params__checkIn',
		});

		self.element._params.checkInValue = createElement({
			tag: 'span'
		});
		self.element._params.checkIn.appendChild(self.element._params.checkInValue);
		var hiddenDeparture = fake;
		if (!hiddenDeparture) {
			if (self.Catalog&&isset(self.Catalog.static)&&self.Catalog.static) {
				hiddenDeparture = true;
			}
		}
		self.element._params.departureTime = createElement({
			tag: 'span',
			className: 'departure_time UDC__tour_departureTimeRequestClick',
			attributes: {
				'data-key': self.model.key,
				hidden: hiddenDeparture
			},
			events: {
				click: self.onDepartureTimeClick
			}
		});
		self.element._params.checkIn.appendChild(self.element._params.departureTime);
		params.appendChild(self.element._params.checkIn);

		self.element._params.flyInclude = createElement({
			tag: 'li',
			className: 'Hotel__params__flyInclude'
		});
		params.appendChild(self.element._params.flyInclude);

		self.element._params.nights = createElement({
			tag: 'li',
			className: 'Hotel__params__nights'
		});
		params.appendChild(self.element._params.nights);

		self.element._params.tourists = createElement({
			tag: 'li',
			className: 'Hotel__params__tourists'
		});
		params.appendChild(self.element._params.tourists);

		self.element._params.room = createElement({
			tag: 'li',
			className: 'Hotel__params__room',
			attributes: {
				hidden: fake
			}
		});
		params.appendChild(self.element._params.room);

		self.element._params.meal = createElement({
			tag: 'li',
			className: 'Hotel__params__meal',
			attributes: {
				hidden: fake
			}
		});
		params.appendChild(self.element._params.meal);

		if(isset(self.useWeather)&& self.useWeather === true) {
			self.element._params.weather = createElement({
			tag: 'li',
			className: 'Hotel__params__weather',
			attributes: {
				hidden: fake
			}
			});
			params.appendChild(self.element._params.weather);
		}

		documentFragment.appendChild(params);

		var footer = createElement({
			className: 'Hotel__footer'
		});
		self.element._footerDesc = createElement({
			className: 'Hotel__footerDesc'
		});
		footer.appendChild(self.element._footerDesc);
		self.element._priceSubscribe = createElement({
			tag:'div',
			className: 'Hotel__priceSubscribe btn __silver',
			innerText: localizationValues.follow,
			attributes: {
				'data-icon': 'fanBell'
			},
			events: {
				click:  function() {
					 window.Far.Script({
					 	src: '/NewDesign/Scripts/Components/hotelPriceSubscribe.js',
						addBuildNumber: true,
						callback: function () {
	                    	var d = self.lastCheapestTour.model.checkIn.getDate();
								d = (d<10?'0'+d:d);
							var m = (self.lastCheapestTour.model.checkIn.getMonth()+1);
								m = (m < 10 ? '0' + m : m);
							window.Far.HotelPriceSubscribe.showModal({
								systemKey: self.lastCheapestTour.model.SystemKey,
								flyInclude: self.lastCheapestTour.model.flyInclude,
	                           	hotelName: self.model.name,
	                           	checkIn: d + '.' + m,
	                           	cityFrom: self.lastCheapestTour.model.cityFrom.name,
	                           	tourists: (self.lastCheapestTour.model.tourists.adl + self.lastCheapestTour.model.tourists.kids),
	                           	nights:  self.lastCheapestTour.model.nights,
	                           	room: self.lastCheapestTour.model.room,
	                           	meal: self.lastCheapestTour.model.meal,
                                mapKey: self.lastCheapestTour.Hotel.model.key
							})
	                    }
	                });
				}
			}
			
		})
		var price = createElement({
			className: 'Hotel__price',
			attributes: {
				hidden: fake
			}
		});
		self.element._price = {};
		self.element._price.price = price;
		self.element._price.old = createElement({
			tag: 'del',
			className: 'Hotel__price__old',
			attributes: {
				hidden: fake
			}
		});
		price.appendChild(self.element._price.old);
		self.element._price.new = createElement({
			tag: 'span',
			className: 'Hotel__price__new',
			attributes: {
				hidden: fake
			}
		});
		price.appendChild(self.element._price.new);
			self.element._price.uah = createElement({
				tag: 'b',
				className: 'Hotel__price__uah',
				attributes: {
					'data-icon': 'checkedPrice'
				}
			});
			price.appendChild(self.element._price.uah);
		footer.appendChild(price);
		self.element._linkButton = createElement({
			tag: 'a',
			className: 'Hotel__linkButton UDC__tourBuyClick btn __goldGradient __md',
			attributes: {
				'data-text': localizationValues.Select||'Выбрать',
				href: '#',
				target: '_blank',
				'data-icon': 'checkedPrice',
				hidden: fake
			}
		});
		footer.appendChild(self.element._linkButton);
		self.element._othersButton = createElement({
			tag: 'button',
			hidden: false,
			className: 'Hotel__othersButton btn __azureBorder UDC__showOthersClick',
			innerHTML: [localizationValues.otherPrices, ' '].join(''),
			events: {
				click: self.otherButtonClickEvent
			}
		});
		self.element._othersButtonCounter = createElement({ tag: 'span' });
		self.element._othersButton.appendChild(self.element._othersButtonCounter);
		if(self.Catalog &&  self.Catalog.static == true) {

		}else {
			footer.appendChild(self.element._othersButton);
		}
		// var f = function() {
		// 	if (!isset(window.Far.Services.Favorites)) {
		// 		setTimeout(f, 100);
		// 	} else {
		// 		self.element._favoritesButton = window.Far.Services.Favorites.renderButton(self);
		// 		self.element._favoritesButton.hidden = self.model.fake || false;
		// 		footer.appendChild(self.element._favoritesButton);
		// 	}
		// };
		// f();
		footer.appendChild(self.element._priceSubscribe);
		self.element._preloader = null;
		if (fake) {
			self.element._preloader = createElement({
				tag: 'div',
				className: 'Hotel__preloader',
				innerHTML: '<img src="/img/loader/line-loader.gif">'
			});
			footer.appendChild(self.element._preloader);
		}

		documentFragment.appendChild(footer);

		self.element._linkableElements = [
			self.element._photo,
			self.element._title,
			self.element._linkButton
		];
		for (var i = (self.element._linkableElements - 1); i >= 0; i--) {
			if (self.Catalog&&self.Catalog.onHotelClickEvent) {
				self.element._linkableElements[i].addEventListener('click', self.Catalog.onHotelClickEvent);
			}
			self.element._linkableElements[i].setAttribute('target', '_blank');
		}

		self.element._others = createElement({
			className: 'Hotel__others',
			hidden: true
		});
		documentFragment.appendChild(self.element._others);
		self.element.appendChild(documentFragment);
		self.fillOthersToursButton();
		self.setOrder();
		self.fillTextsByTour(self);
		self.element.hidden = false;
		self.setObjecatibleElements(self);


		
	},
	setObjecatibleElements: function (self) {
		 
		/*
			Метод указания ссылки на self тем елементам, которые в нем нуждаются
		*/
		// self.log('Hotel::setObjecatibleElements');
		var objecatibleElements = self.element._linkableElements.clone();
		objecatibleElements.push(self.element._address);
		objecatibleElements.push(self.element._favoritesButton);
		if (self.element._othersButton) objecatibleElements.push(self.element._othersButton);
		for (var i=(objecatibleElements.length-1);i>=0;i--) if (isset(objecatibleElements[i])&&objecatibleElements[i]) objecatibleElements[i].Hotel = self;
		for (var i=(self.element._linkableElements.length-1);i>=0;i--) {
			if (!isset(self.element._linkableElements.atlc)) {
				self.element._linkableElements[i].atlc = true;
				self.element._linkableElements[i]._price = self.lastCheapestTour.model.price.redPrice;
				self.element._linkableElements[i].SystemKey = self.lastCheapestTour.model.SystemKey;
				self.element._linkableElements[i].Tour = self.lastCheapestTour;
				self.element._linkableElements[i].addEventListener('click', self.anyTourLinkClick);
			}
		}
	},
	renderOthers: function(self) {
		/*
			Метод рендеринга других вариантов
		*/
		// self.log('Hotel::renderOthers');
		var container = createElement({
			className: 'Hotel__others__container'
		});
		var header = createElement({
			className: 'Hotel__others__container__header'
		});
		var body = createElement({
			className: 'Hotel__others__container__body'
		});
		var buttonCallendar;
		if (!self.Catalog||!self.Catalog.othersDisableCallendar) {
			buttonCallendar = createElement({
				tag: 'button',
				innerHTML: localizationValues.discount_calendar,
				events: {
					click: self.callendarClickEvent
				}
			});
			if ((!self.Catalog&&self.model.currentDesign=='callendar')||(self.Catalog&&self.Catalog.othersDesign=='callendar')) buttonCallendar.classList = '__active';
			header.appendChild(buttonCallendar);
			buttonCallendar._body = body;
			buttonCallendar._sisters = [];
		}
		var buttonList;
		if (!self.Catalog||!self.Catalog.othersDisableList) {
			buttonList = createElement({
				tag: 'button',
				innerHTML: localizationValues.AccomodationOptions,
				events: {
					click: self.AccomodationOptionsClick
				}
			});
			if ((!self.Catalog&&self.model.currentDesign=='list')||(self.Catalog&&self.Catalog.othersDesign=='list')) buttonList.classList = '__active';
			header.appendChild(buttonList);
			buttonList._body = body;
			buttonList._sisters = [];
		}
		if (!self.Catalog||(!self.Catalog.othersDisableCallendar&&!self.Catalog.othersDisableList&&isset(buttonCallendar)&&isset(buttonList))) {
			buttonCallendar._sisters.push(buttonList);
			buttonList._sisters.push(buttonCallendar);
		}
		container.appendChild(header);
		var design = (self.Catalog?self.Catalog.othersDesign:self.model.currentDesign);
		if (design=='callendar') {
			body.appendChild(isset(self.element._othersContainer)?self.element._othersContainer:self.renderOthersCallendar());
		} else if (design=='list') {
			body.appendChild(isset(self.element._othersContainer)?self.element._othersContainer:self.renderOthersList());
		}
		container.appendChild(body);
		var footer = createElement({tag: 'div'});
		footer.className = 'Hotel__others__container__footer';
		container.appendChild(footer);
		self.element._others.appendChild(container);
		self.hightlightMinMaxPrices(self);
	},
	hightlightMinMaxPrices: function(self) {
		/*
			Метод подсветки градиента цен для ссылок на туры внутри календаря
		*/
		// self.log('Hotel::hightlightMinMaxPrices');
		if (self.model.currentDesign=='callendar') {
			var parent = self.element.querySelector(['#TABLE',(self.Catalog?self.Catalog.id:''),self.model.key].join('--'));
			if (!parent) return;
			var linx = parent.getElementsByTagName('a'),
				prices = {},
				i;
			for (i=(linx.length - 1);i>=0;i--) {
				if (!isset(prices[linx[i]._price])) prices[linx[i]._price] = [];
				prices[linx[i]._price].push(linx[i]);
				linx[i].classList.remove('__max');
				linx[i].classList.remove('__maximal');
				linx[i].classList.remove('__min');
				linx[i].classList.remove('__minimal');
			}
			var orderedPrices = {};
			/*
				Проверяем если ли в календаре цены, если нет то возращемся.Если цены есть подсвечиваем самую дешевую.
				Падало когда календарь был пустой
			*/
			if(Object.keys(prices).length == 0) {
				return;
			}
			Object.keys(prices).sort().forEach(function(key) {
				orderedPrices[key] = prices[key];
			});
			var keys = Object.keys(orderedPrices).map(simpleParseInt),
				max = keys.clone().max(),
				min = keys.clone().min();
			orderedPrices[max].forEach(self.orderedPricesMaxClick);
			orderedPrices[min].forEach(self.orderedPricesMinClick);
			var elementsLength = Object.keys(orderedPrices).length;
			if (elementsLength>=3) {
				var o = parseInt(elementsLength / 2);
				o = (o>2?2:o);
				var MaN=0, MiN=0,
					maxs = Object.keys(orderedPrices).slice(o),
					mins = Object.keys(orderedPrices).slice(0, o),
					ii;
				for (i=(maxs.length - 1);i>=0;i--) {
					if (MaN>=3) break;
					for (ii=(orderedPrices[maxs[i]].length - 1);ii>=0;ii--) {
						orderedPrices[maxs[i]][ii].classList.add('__max');
						MaN++;
						if (MaN>=3) break;
					}
				}
				for (i=(mins.length - 1);i>=0;i--) {
					if (MiN>=3) break;
					for (ii=(orderedPrices[mins[i]].length - 1);ii>=0;ii--) {
						orderedPrices[mins[i]][ii].classList.add('__min');
						MiN++;
						if (MiN>=3) break;
					}
				}
			}
		} else if (self.model.currentDesign=='list') {
		}
	},

	getGTMModel: function (self, listType) {

		var variants = [];
		if (self.lastCheapestTour.model.is.hot) {
			variants.push('Горящие');
		}
		if (self.lastCheapestTour.model.is.recommended) {
			variants.push('Рекомендованный');
		}
		if (self.lastCheapestTour.model.price.redPriceUAH < self.lastCheapestTour.model.price.priceUAH) {
			variants.push('Скидка');
		}
		if (self.lastCheapestTour.model.is.early) {
			variants.push('Раннее бронирование');
		}
		if (self.lastCheapestTour.model.is.tourFreeCancel) {
			variants.push('Отмена');
		}
		var position = 0,
			cnt = self.element.closest('.favGtmSection'),
			blockId = 'block5';
		try {
			if (cnt !== null) {
				var list = cnt.querySelector('.TourListSlider__list');
				if (list !== null) {
					position = Array.from(list.children).indexOf(self.element) + 1;
				}
				blockId = cnt.getAttribute('data-block-id');
			}
		}
		catch (e) { }
		
		return {
			'name': self.model.name,
			'id': self.model.key,
			'price': [self.lastCheapestTour.model.price.redPriceUAH, '.00'].join(''),
			'brand': [self.lastCheapestTour.model.operator.name, self.model.country, self.model.resort].join(', '),
			'category': self.model.stars,
			'variant': variants.join(', '),
			'list': GTM.blocks[blockId] || 'Search Results',
			'position': position
		};
	},

	observer: function (self) {
		
		self.observer = new LazyElement(self.element, undefined, function () {
			var cnt = self.element.closest('.favGtmSection');
			if (cnt === null) {
				return;
			}
			gtmImpressionStorage.push(self.getGTMModel(self));
			if (gtmImpressionTimer !== null) {
				clearTimeout(gtmImpressionTimer);
			}
			var blockId = cnt.getAttribute('data-block-id');
			gtmImpressionTimer = setTimeout(function () {
				GTM.proxyImpressionsEx(gtmImpressionStorage, blockId);
				gtmImpressionStorage = [];
				gtmImpressionTimer = null;
			}, 3000);
		});
	}
};


var gtmImpressionStorage = [],
	gtmImpressionTimer = null;
 ;

if (typeof window.SeoPage == 'undefined') {
    window.SeoPage = false;
}

window.Far.Tours = {};

function Tour(Hotel, tourModel) {
	var self = this;
	this.Hotel = Hotel;
	this.Catalog = Hotel.Catalog;
	this.blackFridayDays = {
		'23': { '102': ['23'] },
		'24': { '102': ['23'] },
		'25': { '102': ['51', '83'], '81': ['51'], '111': ['51'] },
		'26': { '102': ['51', '83', '25'], '81': ['51'], '111': ['51'] },
		'27': { '102': ['25', '83'] },
		'28': { '102': ['25', '23', '51'], '81': ['51'], '111': ['51'] },
		'29': { '102': ['25', '23', '51'], '81': ['51'], '111': ['51'] }
	};
	this.isMonobank = function (tourModel) {
		return false; //return tourModel.operatorIdInt !== 62 && tourModel.operatorIdInt !== 110;
	};

    this.isBlackFriday = function (tourModel) {
        return tourModel.IsBlackFriday;
		if (window.BFEvent && !window.BFEvent()) {
			return false;
		}
		var countryId = Number(tourModel.countryID);
		var operatorId = Number(tourModel.operatorIdInt);

		if (countryId === 25) {
			if ([120, 119, 124, 117, 111, 70, 123].includes(operatorId)) {
				return true;
			}
		}
		if (operatorId === 119) {
			if ([51, 47, 23, 81, 86, 80, 54, 71, 59, 83, 74, 0, 42].includes(countryId)) {
				return true;
			}
		}
		if (operatorId === 120) {
			if ([23, 59, 83].includes(countryId)) {
				return true;
			}
		}
		/*
		if (tourModel.operatorIdInt !== 102 && tourModel.operatorIdInt !== 81 && tourModel.operatorIdInt !== 111) {
			return false;
		}
		if (100 - tourModel.chd * 100 / tourModel.price > 0) {
			var date = new Date().getDate().toString();
			return typeof self.blackFridayDays[date] !== 'undefined'
				&& typeof self.blackFridayDays[date][tourModel.operatorIdInt.toString()] !== 'undefined'
				&& self.blackFridayDays[date][tourModel.operatorIdInt.toString()].indexOf(tourModel.countryID) !== -1;
		}
		return false;
		*/
	};

	this.isFreeTransfer = function (tourModel) {
		var price = tourModel.priceUAH > tourModel.redPriceUAH ? tourModel.redPriceUAH : tourModel.priceUAH;
		var tourists = tourModel.adl + tourModel.kids;
		return self.freeTransferSettings.operators.includes(tourModel.operatorIdInt)
			&& self.freeTransferSettings.townfroms.includes(tourModel.idsForText.airportId)
			&& self.freeTransferSettings.countries.includes(tourModel.idsForText.countryid)
			&& (
				(tourists === 2 && price >= self.freeTransferSettings.prices['2'])
				|| (tourists === 3 && price >= self.freeTransferSettings.prices['3'])
				|| (tourists === 4 && price >= self.freeTransferSettings.prices['4'])
				|| (tourists > 4 && price >= self.freeTransferSettings.prices['5'])
			);
	};

	this.isBrightUP = function (tourModel) {
        return new Date() < new Date(2024, 11, 2, 23, 59, 59, 0) && [23,71,81].includes(tourModel.idsForText.countryid) && (tourModel.operatorIdInt === 62 || tourModel.operatorIdInt === 110);
	};

	this.isBonusX2 = function (tourModel) {
		if (self.isBlackFriday(tourModel)) {
			return false;
		}
		return new Date() < new Date(2023, 11, 1);
	};


	this.freeTransferSettings = {
		operators: [110],
		townfroms: [30, 24],
		countries: [25, 83],
		prices: {
			2: 45000,
			3: 60000,
			4: 70000,
			5: 90000
		}
	};

	this.model = {
		SystemKey:  tourModel.SystemKey,
		tourists: {
			adl: 	tourModel.adl,
			ages: 	tourModel.ages,
			kids: 	tourModel.kids
		},
		price: {
			price: 			parseInt(tourModel.price),
			redPrice: 		parseInt(tourModel.chd?tourModel.chd:tourModel.price),
			priceUAH: 		parseInt(tourModel.priceUAH),
			redPriceUAH:    parseInt(tourModel.redPriceUAH),
			currency: 		tourModel.currency
		},
		cityFrom: {
			code:   tourModel.cityFromCode,
			name:   tourModel.cityFromName
		},
		is: {
			bestDeal: 			tourModel.isBestDeal,
			early: 				tourModel.isEarly,
			hot: 				tourModel.isHot,
			promo: 				tourModel.isPromo,
			recommended: 		tourModel.isRecommended,
			choiceFarvater:		tourModel.IsChoiceFarvater,
			regular:			tourModel.AdditionalInfo == null ? false : tourModel.AdditionalInfo.HasFlightExtraPrice, // ���������� ���
			tourFreeCancel:		!window.SeoPage && tourModel.tourFreeCancel,
			blackFriday:		self.isBlackFriday(tourModel),
			otp:				window.isOtpEnable ? (tourModel.isOtp || false) : false,
			healthCertificate:	tourModel.HealthCertificate || false,
			worksIn2020:		tourModel.WorksIn2020 || false,
			freePCRTest:		tourModel.IsFreePCRTest || false,
			uklon:				false,
			isMonobank:			self.isMonobank(tourModel),
			isViber:			false, //new Date() < new Date(2022, 0, 16) && prTourId(tourModel.operatorIdInt) != 6 && (tourModel.redPriceUAH > 0 ? tourModel.redPriceUAH : tourModel.priceUAH) >= 25000,
			isLastSeats:		tourModel.isLastSeats,
			freeTransfer:		self.isFreeTransfer(tourModel),
			brightUP:			self.isBrightUP(tourModel),
			bonusX2:			self.isBonusX2(tourModel)
		},
		type: 		tourModel.type,
		flyInclude: (tourModel.flyInclude=='true'||tourModel.flyInclude===true?true:false),
		checkIn: 	new Date(formatShortDateString(tourModel.checkIn.value)),
		meal: 		tourModel.meal.value,
		mealShort: 	getShortMeal(tourModel.meal.value),
		nights: 	parseInt(tourModel.nights),
		room: 		tourModel.room,
		operator: 	{
			id:     tourModel.operatorId,
			int:    prTourId(tourModel.operatorIdInt),
			name:   tourModel.operatorName
		},
		fake:       (isset(tourModel.fake) && tourModel.fake),
		wheather:   tourModel.wheather
	};

	if (!isset(window.Far.Tours[this.model.SystemKey])) {
		window.Far.Tours[this.model.SystemKey] = self;
	}
	this.element = null;
	this.log = this.Hotel.log;
	this.render = function() {
		// self.log('Hotel::Tour::render');
		if (self.element!==null) return;
		var d, m;
		self.element = createElement({
			tag: 'li',
			className: 'Tour',
			id: [(self.Catalog?self.Catalog.id:''),'--',self.Hotel.model.key,'--',self.model.SystemKey].join(''),
			style: {
				order: (self.model.price.priceUAH>self.model.price.redPriceUAH?self.model.price.redPriceUAH:self.model.price.priceUAH)
			}
		});
		d = self.model.checkIn.getDate();
		d = (d<10?'0'+d:d);
		m = (self.model.checkIn.getMonth()+1);
		m = (m<10?'0'+m:m);
		var ul 		= createElement('ul'),
			checkIn = createElement({
				tag: 'li',
				className: 'Tour__checkIn',
				childs: [
					createElement({
						tag: 'span',
						innerText: [d, '.', m, ' '].join('')
					}),
					(self.model.flyInclude?DepartureTime.render(self.model.SystemKey, self.Hotel.model.key, self.link()):null),
					createElement({
						tag: 'span',
						innerHTML: [
							'<span class="Tour__checkIn__flyInclude">', (self.model.flyInclude ? [localizationValues.flightIncluded, ' (', localizationValues.from5, ' ', self.model.cityFrom.name, ')'].join('') : localizationValues.flightNotIncluded), '</span>'
						].join('')
					})
				]
			}),
			nights 	= createElement({
				tag: 'li',
				className: 'Tour__nights',
				innerText: [localizationValues.onSomewhat, ' ', self.model.nights, ' ', LL.getMethering('nights', self.model.nights)].join('')
			}),
			room 	= createElement({
				tag: 'li',
				className: 'Tour__room',
				innerText: self.model.room
			}),
			meal 	= createElement({
				tag: 'li',
				className: 'Tour__meal',
				innerText: self.model.meal
			}),
			price 	= createElement({
				tag: 'li',
				className: 'Tour__price',
				innerHTML: [(self.model.price.priceUAH > self.model.price.redPriceUAH ? ['<del>', intHumanize(self.model.price.priceUAH), ' ', localizationValues.currency_uah, '</del>'].join('') : '')].join(''),
				//attributes: {
				//	'data-icon': (self.Catalog&&self.Catalog.useOperatorsIcons?['Operators_',self.model.operator.int].join(''):null),
				//},
				childs: [
					createElement({
						tag: 'a',
						className: 'btn __goldGradient UDC__tourBuyClick',
						attributes: {
							target: '_blank',
							href: self.link()
						},
						model: {
							SystemKey: self.model.SystemKey,
							Hotel: self.Hotel,
							_price: self.model.price.redPrice,
							Tour: self
						},
						events: {
							click: self.Hotel.anyTourLinkClick
						},
						innerText: [intHumanize(self.model.price.redPriceUAH), ' ', localizationValues.currency_uah].join('')
					})
				]
			});
		var documentFragment = document.createDocumentFragment();
		documentFragment.appendChild(checkIn);
		documentFragment.appendChild(nights);
		documentFragment.appendChild(room);
		documentFragment.appendChild(meal);
		documentFragment.appendChild(price);
		ul.appendChild(documentFragment);
		self.element.appendChild(ul);
	};

	this.renderLink = function() {
		// self.log('Hotel::Tour::renderLink');
		return createElement({
				tag: 'a',
				innerText: [getCurrencySymbol(self.model.price.currency),' ',intHumanize(self.model.price.redPrice)].join(''),
				className: 'UDC__tourBuyClick',
				attributes: {
					target: '_blank',
					href: self.link()
				},
				model: {
					SystemKey: self.model.SystemKey,
					Hotel: self.Hotel,
					_price: self.model.price.redPrice,
					Tour: self
				},
				events: {
					click: self.Hotel.anyTourLinkClick
				}
			});
	};
	var link = null;
	this.link = function() {
		// self.log('Hotel::Tour::link');
	    //if (!link) link = localizationFn.localizeUrl([(self.model.SystemKey.startsWith('0p0') ? self.Hotel.model.key : self.Hotel.model.url), '/?q=', self.model.SystemKey].join(''), localizationFn.current);
		if (!link) link = localizationFn.localizeUrl([self.Hotel.model.url, self.model.SystemKey.startsWith('0p0') ? '' : ('/?q=' + self.model.SystemKey)].join(''), localizationFn.current);
		return link;
	};
	this.isUklon = function () {
		return false;
		//return self.model.flyInclude && self.model.price.redPriceUAH >= 24000 && typeof self.model.cityFrom.code !== 'undefined' && self.model.cityFrom.code.toUpperCase() !== 'NON';
	};

	//this.model.is.uklon = this.isUklon();
}

;
function Star_(model) {
	var self = this;

	this.model = {};

	this.init = function(model) {
		model = parseInt(model);
		self.model.id = model;
		self.model.int = starIdToInt(model);
		self.model.element = starsRender(self.model.int);
		self.model.name = starIdToName(model);
		self.model.localizedName = starIdToLocalizedName(model);
	};
	this.init(model);
}

function starsRender(v) {
    if (isNaN(v)||v<1) return '';
    var html = [];
    html.push('<span class="stars">');
    html.push(starsRenderInner(v));
    html.push('</span>');
    return html.join('');
}

function starsRenderInner(v) {
    if (isNaN(v)||v<1) return '&nbsp;';
    var html = [],
        i = 5;
    while (v>0) {
        html.push('');
        v--;
        i--;
    }
    while (i>0) {
        html.push('');
        i--;
    }
    return html.join('');
}

function starIdToInt(v) {
	var i;
	switch (v) {
		case '0':
		case 0:
			i=1;
		break;
		case '1':
		case 1:
			i=2;
		break;
		case '3':
		case 3:
			i=3;
		break;
		case '4':
		case 4:
			i=4;
		break;
		case '7':
		case 7:
		default:
			i=5;
		break;
	}
	return i;
}



function starIdToName(v) {
	var i;
	switch (v) {
		case '0':
		case 0:
			i=1;
		break;
		case '1':
		case 1:
			i=2;
		break;
		case '3':
		case 3:
			i=3;
		break;
		case '4':
		case 4:
			i=4;
		break;
		case '7':
		case 7:
			i=5;
		break;
		case '9':
		case 9:
			i='HV 2';
		break;
		case '10':
		case 10:
			i='VILLA';
		break;
		case '11':
		case 11:
			i='HV 1';
		break;
		case '12':
		case 12:
			i='APP';
		break;
	}
	return i;
}

function starIdToLocalizedName(v) {
	var i;
	switch (v) {
		case '0':
		case 0:
			i=starsRenderInner(1);
		break;
		case '1':
		case 1:
			i=starsRenderInner(2);
		break;
		case '3':
		case 3:
			i=starsRenderInner(3);
		break;
		case '4':
		case 4:
			i=starsRenderInner(4);
		break;
		case '7':
		case 7:
			i=starsRenderInner(5);
		break;
		case '9':
		case 9:
			i=localizationValues.hv2_stars;
		break;
		case '10':
		case 10:
			i=localizationValues.villa_stars;
		break;
		case '11':
		case 11:
			i=localizationValues.hv1_stars;
		break;
		case '12':
		case 12:
			i=localizationValues.app_stars;
		break;
	}
	return i;
}

;
function Meal_(model) {
	var self = this;

	this.model = {};

	this.init = function(model) {
		model = parseInt(model);
		self.model.id = model;
		self.model.name = mealIdToName(model);
		self.model.localizedName = mealIdToLocalizedName(model);
	};
	this.init(model);
}

function getShortMeal(v) {
    var s = v,
    	m = v.match(/\((.*?)\)/);
	if (m) s = m[1];
	return s;
}

function mealIdToName(v) {
	var i;
	switch (v) {
		case '0':
		case 0:
			i='BB';
		break;
		case '1':
		case 1:
			i='AI';
		break;
		case '2':
		case 2:
			i='UAI';
		break;
		case '4':
		case 4:
			i='FB';
		break;
		case '5':
		case 5:
			i='HB';
		break;
		case '6':
		case 6:
			i='ro';
		break;
	}
	return i;
}

function mealIdToLocalizedName(v) {
	var i;
	switch (v) {
		case '0':
		case 0:
			i=localizationValues.BB;
		break;
		case '1':
		case 1:
			i=localizationValues.AI;
		break;
		case '2':
		case 2:
			i=localizationValues.UAI;
		break;
		case '4':
		case 4:
			i=localizationValues.FB;
		break;
		case '5':
		case 5:
			i=localizationValues.HB;
		break;
		case '6':
		case 6:
			i=localizationValues.ro;
		break;
	}
	return i;
}

;
function DepartureTime_() {
	var self = this;
	this.collection = [];
	this.render = function(systemKey, mapKey, url) {
		return createElement({
			tag: 'span',
			className: 'departureTime',
			innerText: localizationValues.FlyTime,
			attributes: {
				'data-id': systemKey,
				'data-key': mapKey,
				'data-url': url
			},
			events: {
				click: self.onClick
			}
		});
	};

	this.onClick = function () {
		flights.initEvent(this);
		return false;
	}
}
var DepartureTime = new DepartureTime_();

;
function get_flights() {

    var self = this;
    this.inited = false;
    this.store = {};
    this.limitIterations = 2;

    this.getFlight = function (systemKey) {
        this.store[systemKey].iteration++;

        if (this.store[systemKey].iteration > this.limitIterations) {

            this.store[systemKey].onComplete({ statusCode: 500, statusMessage: 'error' });

            return;
        }

        var url = '/tour/flightsinfo/' + systemKey;
        ExecuteAction(url, '', { systemKey: systemKey },
            function (response) {

                if (response.statusCode === 200) {

                    if (typeof response.data != 'undefined'
                        && response.data != null
                        && typeof response.data.flights != 'undefined'
                        && response.data.flights != null
                    ) {

                        self.store[this.systemKey].onComplete(response);

                        return;
                    }
                }

                self.getFlight(this.systemKey);
            },
            function () {

                self.getFlight(this.systemKey);
            }
        );
    };

    var getBtnHTML = function (systemKey, hotelKey, departureTime) {

        if (typeof departureTime != 'undefined' && departureTime != null && departureTime !== '') {

            return departureTime;
        }
        else {

            return [
                '<a  class="ticketInfoPopup_init" data-id="',
                systemKey,
                '" data-key="',
                hotelKey,
                '" title="',
                localizationValues.contactManager,
                '" data-icon="question1"></a>'
            ].join('');
        }
    };

    var getDepartureTime = function (response) {
        if (response.statusCode !== 200
            || typeof response.data == 'undefined'
            || response.data == null
            || typeof response.data.flights == 'undefined'
            || response.data.flights == null
            || typeof response.data.flights.from == 'undefined'
            || response.data.flights.from == null
            || typeof response.data.flights.from.departure == 'undefined'
            || response.data.flights.from.departure == null
            || typeof response.data.flights.from.departure.time == 'undefined'
            || response.data.flights.from.departure.time == null
        ) {

            return null;
        }

        return response.data.flights.from.departure.time;
    };

    var preloader = function () {

        return '<img src="/img/loader/line.gif" />';
    };
    this.initEvent = function (btn) {
        if (btn.getAttribute('d') != null) {
            return false;
        }
        if (typeof btn.getAttribute('data-id') === null) {

            btn.remove();
            return false;
        }
        var systemKey = btn.getAttribute('data-id'),
	        hotelKey = btn.getAttribute('data-key'),
	        url = btn.getAttribute('data-url');
        if (self.store.hasOwnProperty(systemKey) && self.store[systemKey].response != null) {
	        self.store[systemKey].btn = btn;
        	self.store[systemKey].onComplete();
            return false;
        }

        self.store[systemKey] = {
            systemKey: systemKey,
            hotelKey: hotelKey,
            btn1:function () {
                return $('.departure_time[data-id="' + this.systemKey + '"]');
            },
			btn: btn,
            iteration: 0,
            response: null,
            complete: false,
            onComplete: function (response) {
                //var btn = this.btn();
                if (arguments.length != 0) {

                    this.complete = true;
                    this.response = response;
                    this.btn.classList.add('__complete');
                    this.btn.setAttribute('d', 1);
                }

                var departureTime = getDepartureTime(this.response);
                var html = getBtnHTML(this.systemKey, this.hotelKey, departureTime);
                this.btn.innerHTML = html;
                if (typeof departureTime != 'undefined' && departureTime != null && departureTime !== '') {

                }
                else {
                	this.requestDepartureTimeEl = this.btn.querySelector('a');
                	this.requestDepartureTimeEl.addEventListener('click', function () {
                    	window.Far.DepartureTimeCallback.showModal({systemKey: systemKey, hotelKey: hotelKey, url: url});
                    }, true)
                }
            },
			requestDepartureTimeEl: null
        };

        btn.innerHTML = preloader();

        self.getFlight(systemKey);
    };
    this.addEvent = function (selector) {
        $(selector).on('click', function () {
            self.initEvent(selector);
        });
    };
    this.init = function () {

    };
}

var flights;
commonDocument.onReady(function() {
	flights = new get_flights();
	flights.init();
});

;

(function () {
	function DepartureTimeCallback() {
		var self = this;

		this.currentModel = null;

		this.formEl = null;
		this.successEl = null;
		this.errorEl = null;
		this.getCountryName = function (code) {
			return window.countryCodes[code][localizationFn.current];
		};
		this.addError = function () {
			self.inner.classList.add('has-error');
		};
		this.removeError = function () {
			self.inner.classList.remove('has-error');
		};
		this.isValidPhone = function (phone) {
			phone = phone.replace(/[_()+\- ]/g, '');
			return phone.length == 12;
		};
		this.getPhone = function () {
			var code = self.formEl.querySelector('.phoneDropdownMenuButton_selected .phone_symbols_code').getAttribute('value');
			var digits = self.formEl.querySelector('[name="OrderCallback__input"]').value;
			return code + digits;
		};
		this.getSelectedCountryCode = function () {
			return parseInt(self.formEl.querySelector('.phoneDropdownMenu .phoneDropdownMenuButton_selected .phone_symbols_code').getAttribute('value'));
		};
		this.createCountryCode = function () {
			/*
			var html = '\
                <button class="btn btn-secondary dropdown-toggle form-control phoneDropdownMenuButton" type="button" data-toggle="dropdown_" aria-haspopup="true" aria-expanded="false">\
                    <span class="phoneDropdownMenuButton_selected">\
                        <img src="/content/phone_symbols/380.png" height="19" alt="" />\
                        <span class="phone_symbols_code" value="380">+380</span>\
                    </span>\
                </button>\
                <div class="dropdown-menu" aria-labelledby="phoneDropdownMenuButton">\
                    <span class="dropdown-item" value="380">\
                        <img src="/content/phone_symbols/380.png" height="19" alt="" />\
                        <span class="phone_symbols_code" value="380">+380</span>\
                        <span class="phone_symbols_country">' + self.getCountryName('380') + '</span>\
                    </span>\
                    <span class="dropdown-item" value="375">\
                        <img src="/content/phone_symbols/375.png" height="19" alt="" />\
                        <span class="phone_symbols_code" value="375">+375</span>\
                        <span class="phone_symbols_country">' + self.getCountryName('375') + '</span>\
                    </span>\
                </div>';
			*/
			var html = '\
                <button class="btn btn-secondary dropdown-toggle form-control phoneDropdownMenuButton" type="button" data-toggle="dropdown_" aria-haspopup="true" aria-expanded="false">\
                    <span class="phoneDropdownMenuButton_selected">\
                        <img src="/content/phone_symbols/380.png" height="19" alt="" />\
                        <span class="phone_symbols_code" value="380">+380</span>\
                    </span>\
                </button>';
			var dropdown = document.createElement('DIV');
			dropdown.className = 'dropdown phoneDropdownMenu';
			dropdown.innerHTML = html;

			var container = document.createElement('DIV');
			container.className = 'phoneWithCodeContainer';

			self.inner = document.createElement('DIV');
			self.inner.className = 'phoneWithCodeInput';

			container.appendChild(self.inner);

			self.inner.appendChild(dropdown);

			self.inner.appendChild(FormControl.renderControl({
				type: 'tel',
				className: 'OrderCallback__Modal__input',
				name: 'OrderCallback__input',
				onInited: function (fc) {
					inputMaskFormControl2(fc, self.getSelectedCountryCode);
				},
				labelStyles: (deviceConfig.type == 'Desktop' ? 'width:200px;' : ''),
				attributes: {
					//placeholder: '(XX)XXX-XX-XX',
					//'data-pattern': '(00)000-00-00'
				}
			}));
			var items = container.querySelectorAll('.dropdown-item');
			for (var i = 0; i < items.length; i++) {
				items[i].onclick = function (e) {
					var item = e.target.closest('.dropdown-item');
					var selected = self.inner.querySelector('.phoneDropdownMenuButton_selected');
					selected.innerHTML = item.innerHTML;
				}
			}

			return container;
		};

		this.modalRenderDOM = function () {
			if (isset(self.ModalDOM)) return self.ModalDOM;

			self.formEl = createElement({ tag: 'div', id: 'DepartureTime_content_form' });
			self.ModalDOM = createElement({tag:'div'});
			self.ModalDOM.appendChild(self.formEl);

			self.formEl.appendChild(createElement({
				tag: 'div',
				className: 'h1',
				style: {
					color: 'var(--c-azure)'
				},
				innerText: localizationValues.requestDeparture
			}));
			self.formEl.appendChild(createElement({
				tag: 'p',
				innerText: localizationValues.pleaseLeavePhone,
				attributes: {
					style: 'font-weight: 400;font-size: 16px;line-height: 1.2;'
				}
			}));
			self.formEl.appendChild(createElement({
				tag: 'p',
				innerText: localizationValues.priceVary,
				attributes: {
					style: 'color: #9e9e9e;margin-bottom:24px;'
				}
			}));
			self.formEl.appendChild(self.createCountryCode());
			/*
			self.formEl.phoneInput = FormControl.renderControl({
				type: 'tel',
				className: 'DepartureTimeCallback__Modal__input',
				name: 'DepartureTimeCallback__input',
				onInited: inputMaskFormControl,
				labelStyles: (deviceConfig.type == 'Desktop' ? 'width:200px;' : ''),
				attributes: {
					placeholder: '+38(XXX)XXX-XX-XX',
					'data-pattern': '+38(000)000-00-00'
				}
			});
			self.formEl.appendChild(self.formEl.phoneInput);
			*/
			self.formEl.appendChild(createElement({
				tag: 'img',
				className: 'arrowImg',
				attributes: {
					src: '/img/Arrow.svg'
				}
			}));
			self.formEl.submitButton = createElement({
				tag: 'button',
				className: 'btn __lg __goldGradient DepartureTimeCallback__Modal__btn',
				innerHTML: localizationValues.callWait,
				attributes: {
					style: 'margin-top: 24px'
				},
				events: {
					click: function () {
						var phone = self.getPhone();
						if (self.isValidPhone(phone)) {
							self.removeError();
							self.sendRequest(phone);
						} else {
							self.addError();
						}
					}
				}
			});
			self.formEl.appendChild(self.formEl.submitButton);

			self.successEl = createElement({ tag: 'div', id: 'DepartureTime_content_success', attributes: { hidden: true } });
			self.successEl.appendChild(createElement({ tag: 'h3', innerHTML: localizationValues.requestAccept, attributes: { style: 'font-weight: 300;font-size: 30px;color: #00aeef;margin-bottom:20px;' } }));
			self.successEl.phoneInput = FormControl.renderControl({
				type: 'tel',
				className: 'DepartureTimeCallback__Modal__input',
				name: 'DepartureTimeCallback__input',
				onInited: function (fc) {
					inputMaskFormControl2(fc, self.getSelectedCountryCode);
				},
				labelStyles: (deviceConfig.type == 'Desktop' ? 'width:200px;' : ''),
				attributes: {
					//placeholder: '+38(XXX)XXX-XX-XX',
					//'data-pattern': '+38(000)000-00-00'
				}
			});
			self.successEl.appendChild(self.successEl.phoneInput);
			self.successEl.appendChild(createElement({ tag: 'p', innerHTML: localizationValues.ThanksManagerWillContactYou, attributes: { style: 'font-size:16px;font-weight:400;margin-top:20px;' } }));
			self.ModalDOM.appendChild(self.successEl);

			self.errorEl = createElement({ tag: 'div', id: 'DepartureTime_content_error', attributes: { hidden: true } });
			self.ModalDOM.appendChild(self.errorEl);

			return self.ModalDOM;
		};
		this.sendRequest = function (phone) {
			if (!isset(self.ModalDOM.Loader)) self.ModalDOM.Loader = new Loader_({ parent: self.ModalDOM });


			var phone_show = phone;

			var url = self.currentModel.url;
			var systemKey = self.currentModel.systemKey;
			var mapKey = self.currentModel.hotelKey;
			phone = phone.replace(/\(/gi, '').replace(/\)/gi, '').replace(/\-/gi, '').replace(/ /gi, '');

			self.ModalDOM.Loader.start();

			window.Far.Global.jsonRequest({
				method: 'POST',
				url: '/costom-messages/send-airplane-request',
				data: {
					phone: phone,
					url: url,
					key: mapKey,
					systemKey: systemKey
				},
				onSuccess: function (response) {
					self.ModalDOM.Loader.stop();

					switch (response.resultCode) {
						case 200:

							if (typeof GTM !== 'undefined') {
								GTM.timeOfDeparture(phone);
							}

							//self.formEl.phoneInput.input.FormControl.hasSuccess(true);
							//self.formEl.phoneInput.input.FormControl.unsetAvailable();
 							self.formEl.hidden = true;
							self.successEl.hidden = false;
							self.successEl.phoneInput.input.FormControl.hasSuccess(true);
							self.successEl.phoneInput.input.value = phone_show;
							setTimeout(self.Modal.hide, 5000);

							break;
						case 401:
							self.formEl.submitButton.hidden = true;
							self.formEl.appendChild(createElement({tag:'p',innerText: response.resultMessage}));
							break;
					}
				},
				onError: function (response) {
					self.ModalDOM.Loader.stop();
					self.formEl.phoneInput.input.FormControl.hasError(true);
				}
			});
		};
		this.showModal = function (model) {
			this.currentModel = model;
			if (!isset(self.Modal)) {
				window.Far.require.FormControl();
				var f = function () {
					if (!isset(window.FormControl)) {
						setTimeout(self.showModal, 10);
						return;
					}
					window.Far.Script({
						src: '/NewDesign/Scripts/Components/Modal.js',
						callback: function () {
							self.Modal = new Modal({
								id: 'DepartureTime__Modal',
								className: '',
								size: 'md',
								innerDOM: self.modalRenderDOM(),
								image: {
									src: '/img/Plane-Tail.jpg',
									position: 'left'
								}
							});
							self.Modal.show();
						}
					});
				};
				f();
			} else {
				self.formEl.hidden = false;
				self.successEl.hidden = true;
				self.errorEl.hidden = true;
				self.Modal.show();
			}
		};
		this.init = function () {
		};
		this.init();
	}

	window.Far.DepartureTimeCallback = new DepartureTimeCallback();
})();;
/// <reference path="../../_references.js" />
var render = {
    imageSize: '',
    tours: {},
    renderHtml: function (tour, position, containerId) {

        return render_.renderHtmlCallback(tour, position, containerId);
    },

    renderHtmlFavorite: function (tour) {
        if (typeof tour.other == 'undefined') {
            console.log('renderHtmlFavorite: typeof tour.other == undefined');
            console.log(tour);
        }

        //this.tours[tour.SystemKey] = tour;

        var url = '';
        if (tour.hotelUrl == null || tour.hotelUrl == '' || tour.hotelUrl.indexOf('/hotel/') == -1) {
            url = '/tour/' + tour.SystemKey + '/'
        }
        else {
            url = tour.hotelUrl + '/?q=' + tour.SystemKey;
        }
        url = ConvertUrlTooLocalization(url, true);
        var tourCityFromName = tour.cityFromName;
        if (tourCityFromName.length > 2) {
            tourCityFromName = ' (из ' + tour.cityFromName + ')';
        }
        else {
            tourCityFromName = '';
        }

        var flyTypeValue = tour.type === 'plain' ? 'Перелет включен' + tourCityFromName : tour.type === 'noair' ? '<span class="red">Перелет не включен</span>' : 'Проезд автобусом включен';
        var flyInclude = tour.type === 'plain' ? 'yes' : 'no';

        var slices = [];
        var currency = tour.currency == 'USD' ? '$' : tour.currency == 'EUR' ? '&euro;' : tour.currency;
        var discountPercent = 0;
        if (parseInt(tour.chd) > 0) {
            discountPercent = parseInt(tour.price) - parseInt(tour.chd); //Math.ceil(100 - parseInt(tour.chd) * 100 / parseInt(tour.price));
        }
        var touristsCount = parseInt(tour.adl) + parseInt(tour.kids);

        slices.push('<div class="tour box-lighteen horizontal extrashort" id="favorite-tour-{0}"  data-id="{0}" data-key="{1}" >'.format(tour.SystemKey, tour.hotelKey));
        slices.push('    <div class="row">');
        slices.push('        <div class="col-fictive pull-right tour__image__container" style="width: 45%">');
        slices.push('          <i class="ic ic-icon-remove tour__remove"></i>');
        slices.push('            <a class="tour__image gtm_tour_other_detail_link" href="{0}" target="_blank">'.format(url));
        //slices.push('                <img src="{0}" alt="{1}" title="{1}">'.format(tour.photo.replace('size=catalog', 'size=detail'), tour.hotel.value));
        //slices.push('                <img src="{0}" alt="{1}" title="{1}">'.format(tour.photo, tour.hotel.value));

        if (this.imageSize == 'big') {
            slices.push('                <img src="{0}" alt="{1}" title="{1}" />'.format(tour.photo.replace('size=catalog', 'size=detail'), tour.hotel.value));
        }
        else {
            slices.push('                <img src="{0}" alt="{1}" title="{1}" />'.format(tour.photo, tour.hotel.value));
        }

        // if (globalSystemSettings.render.viewPartner == 'mastercard') {
        //     slices.push('            <div class="tour__tag mastercard">-5%</div>');
        // }
        // else {
        // }
            if (discountPercent > 0) {
                slices.push('            <div class="tour__tag">-{0}{1}</div>'.format(discountPercent, currency));
            }

        slices.push('            </a>');
        slices.push('        </div>');
        slices.push('        <div class="col-fictive col-lg-4 tour__texts__container" style="width: 55%;">');
        slices.push('            <div class="tour__geo" data-resort="{2}">{0}, {1}</div>'.format(tour.countryName, tour.region.ResortName, (tour.region != null ? tour.region.ResortName : tour.address)));
        slices.push('            <div class="tour__title" data-operator="{2}"><a href="{0}" class="text-link gtm_tour_other_detail_link" target="_blank">{1}</a></div>'.format(url, tour.hotel.value, tour.operatorName));
        slices.push('            <div class="tour__rating" data-star="{0}">'.format(isNaN(tour.star.value) ? 0 : parseInt(tour.star.value)));
        slices.push('                <div class="stars">');
        if (!isNaN(tour.star.value)) {
            var stars = parseInt(tour.star.value);
            for (var i = 0; i < stars; i++) {
                slices.push('           <span class="star active"></span>');
            }
            for (var j = stars + 1; j < 6; j++) {
                slices.push('           <span class="star"></span>');
            }
        }
        slices.push('               </div>');
        slices.push('               <span class="pull-right">{0}/10</span>'.format(tour.rate || 1));
        //slices.push('               <span class="pull-right">{0}/10 <i class="ic ic-comments"></i> 46</span>'.format(tour.rate || 1));
        slices.push('           </div>');
        slices.push('       </div>');

        slices.push('       <div class="clearfix"></div>');
        slices.push('       <div class="col-fictive tour__price-container"><div class="tour__price" data-price-uah="{2}">{0}{1} '.format(currency, parseInt(tour.chd) > 0 ? tour.chd : tour.price, tour.priceUAH));
        if (parseInt(tour.chd) > 0) {
            slices.push('           <small><del>{0}{1}</del></small>'.format(currency, parseInt(tour.price)));
        }

        slices.push('        </div></div>');

        slices.push('</div>');

        var html = slices.join('');


        return html;
    },

    renderTour: function (tour, cnt, position, containerId) {

        var html = render.renderHtml(tour, position, containerId);
        var el = $(html);
        cnt.append(el);
    },

    renderTourWithReplace: function (tour, cnt, position, containerId) {
        var renderItems = render3.renderHtmlCallback(tour, position,containerId);
        renderItems.render(function(){
            cnt.replaceWith(this.html);
        });
    },

    refreshTour: function (tour, cnt, position, containerId) {

        var box = cnt.find('> .tour[data-key="' + tour.hotelKey + '"]'),
            othersBox = box.find('.tour__others__container'),
            prevOthersCount = 0,
            currentOthersCount = tour.other.length;

        //if (othersBox.length) {

        //    prevOthersCount = parseInt(othersBox.attr('data-others-count'));
        //}
        //if (prevOthersCount == currentOthersCount) return;

        if (box.attr('data-id') == tour.SystemKey) {

            return;
        }

        console.log('refresh = ' + tour.SystemKey)
        render.renderTourWithReplace(tour, box, position, containerId);
    },

    renderOtherHtml: function (tour, other, ind) {

        this.tours[other.SystemKey] = other;

        var otherCityFromName = '';
        if (otherCityFromName.length > 2) {
            otherCityFromName = ' (из ' + other.cityFromName + ')';
        }
        else {
            otherCityFromName = '';
        }

        var flyTypeValue = other.type === 'plain' ? 'Перелет включен' + otherCityFromName : other.type === 'noair' ? '<span class="red">Перелет не включен</span>' : 'Проезд автобусом включен';
        var flyInclude = tour.type === 'plain' ? 'yes' : 'no';
        var slices = [];
        var currency = other.currency == 'USD' ? '$' : other.currency == 'EUR' ? '&euro;' : other.currency;
        var discountPercent = 0;
        if (parseInt(other.chd) > 0) {
            discountPercent = parseInt(other.price) - parseInt(other.chd); //Math.ceil(100 - parseInt(other.chd) * 100 / parseInt(other.price));
        }
        var touristsCount = parseInt(other.adl) + parseInt(other.kids);
        var url = '';
        if (other.hotelUrl == null || other.hotelUrl == '' || other.hotelUrl.indexOf('/hotel/') == -1) {
            url = '/tour/' + other.SystemKey + '/'
        }
        else {
            url = other.hotelUrl + '/?q=' + other.SystemKey;
        }

        slices.push('<div class="col-fictive tour__more-item" id="tour-{0}"  data-id="{0}" data-key="{1}" data-url="{2}" style="display: {3}">'.format(other.SystemKey, other.hotelKey, url, ind < 6 ? 'block' : 'none'));
        slices.push('   <ul class="tour__params">');
        slices.push('       <li><i class="{2}" data-flyinclude="{1}"></i> {0}</li>'.format(flyTypeValue, flyInclude, flyTypeValue == 'Проезд автобусом включен' ? 'glyphicon glyphicon-road c-gray-2' : 'ic ic-jet-ready'));

        //slices.push('       <li><i class="ic ic-jet-icon"></i> Вылет {0} '.format(other.checkIn.value.asShortDate()));
        //slices.push('       <li><i class="ic ic-jet-icon" data-jet-date="{1}"></i> Вылет {0} <span class="departure_time c-gray-3">Время</span></li>'.format(other.checkIn.value.asShortDate(), other.checkIn.value));
        if (other.type == 'plain') {
            slices.push('               <li><i class="ic ic-jet-icon" data-jet-date="{1}"></i> Вылет {0} <span class="departure_time c-gray-3">Время</span></li>'.format(other.checkIn.value.asShortDate(), other.checkIn.value));
        }
        else {
            slices.push('               <li><i class="glyphicon glyphicon-flag c-gray-2" data-jet-date="{1}"></i> Начало {0}</li>'.format(other.checkIn.value.asShortDate(), other.checkIn.value));
        }

        slices.push('       <li><i class="ic ic-days"></i> На {0} {1}</li>'.format(other.nights, getMetering(parseInt(other.nights), 'night')));
        slices.push('       <li><i class="ic ic-user-icon"></i> {0} {1}</li>'.format(touristsCount, getMetering(touristsCount, 'tourist')));
        slices.push('       <li class="line-height-fix" title="{0}({1})"><i class="ic ic-bed-icon"></i> {0}({1})</li>'.format(other.room, other.htplace));
        switch (other.meal.value.toLowerCase()) {
            case "ro":
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>Без питания (RO)</li>');
                break;
            case "bb":
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>Завтрак (BB)</li>');
                break;
            case "hb":
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>Завтрак + ужин (HB)</li>');
                break;
            case 'fb':
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>Завтрак, обед + ужин (FB)</li>');
                break;
            case "ai":
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>Bсе включено (AI)</li>');
                break;
            case "uai":
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>Ультра все включено (UAI)</li>');
                break;
            default:
                slices.push('               <li><i class="glyphicon glyphicon-cutlery c-gray-2"></i>{0}</li>'.format(other.meal.value));
                break;
        }
        slices.push('   </ul>');
        slices.push('   <div class="tour__price-container">');
        slices.push('       <div class="tour__price"><span class="fs-large">{0}{1}</span> '.format(currency, parseInt(other.chd) > 0 ? other.chd : other.price));
        if (parseInt(other.chd) > 0) {
            slices.push('<small><del>{0}{1}</del></small>'.format(currency, parseInt(other.price)));
        }

        var isActive = '';

        if (typeof favoritTours != 'undefined') {
            if (favoritTours.tourIsFavorit(other.SystemKey)) {
                isActive = 'active';
            }
        }

        slices.push('   <span class="add-to-faworite" data-id="{0}" data-key="{1}"><i class="ic ic-heart {2}"></i></span>'.format(other.SystemKey, other.hotelKey, isActive));
        slices.push('   </div>');
        slices.push('   <a class="btn btn-block btn-blue_4 tour__more-link gtm_tour_other_detail_link" href="{0}" target="_blank">Посмотреть тур</a>'.format(url));
        slices.push('</div>');
        slices.push('</div>');

        return slices.join('');
    },

    renderPricelessHtml: function (tour, cnt, position) {

        this.tours[tour.SystemKey] = tour;

        var url = '';
        if (tour.hotelUrl == null || tour.hotelUrl == '' || tour.hotelUrl.indexOf('/hotel/') == -1) {
            url = '/tour/' + tour.SystemKey + '/'
        }
        else {
            url = tour.hotelUrl + '/?q=' + tour.SystemKey;
        }

        position = position || 1;

        var tourCityFromName = '';
        if (tourCityFromName.length > 2) {
            tourCityFromName = ' (из ' + tour.cityFromName + ')';
        }
        else {
            tourCityFromName = '';
        }

        var flyTypeValue = tour.type === 'plain' ? 'Перелет включен' + tourCityFromName : tour.type === 'noair' ? '<span class="red">Перелет не включен</span>' : 'Проезд автобусом включен';
        var flyInclude = tour.type === 'plain' ? 'yes' : 'no';

        var currency = tour.currency == 'USD' ? '$' : tour.currency == 'EUR' ? '&euro;' : tour.currency;
        var discountPercent = 0;
        if (parseInt(tour.chd) > 0) {
            discountPercent = parseInt(tour.price) - parseInt(tour.chd); //Math.ceil(100 - parseInt(tour.chd) * 100 / parseInt(tour.price));
        }
        var touristsCount = parseInt(tour.adl) + parseInt(tour.kids);

        var slices = [];

        slices.push('<li class="tour z-list__item" data-id="{0}" data-key="{1}" data-position="{2}">'.format(tour.SystemKey, tour.hotelKey, position));
        slices.push('   <div class="row">');
        slices.push('       <div class="col-xs-8">');
        slices.push('           <a target="_blank" class="tour__title z-list__item__title gtm_tour_other_detail_link" href="{0}" data-operator="{2}"><b>{1}</b></a>'.format(url, tour.hotel.value, tour.operatorName));
        slices.push('           <div class="tour__geo z-list__item__geo" data-resort="{2}">{0}, {1}</div>'.format(tour.countryName, tour.address, (tour.region != null ? tour.region.ResortName : tour.address)));
        slices.push('           <div class="z-list__item__data">');
        switch (tour.meal.value.toLowerCase()) {
            case "ro":
                slices.push('Без питания (RO)');
                break;
            case "bb":
                slices.push('Завтрак (BB)');
                break;
            case "hb":
                slices.push('Завтрак + ужин (HB)');
                break;
            case 'fb':
                slices.push('Завтрак, обед + ужин (FB)');
                break;
            case "ai":
                slices.push('Всё включено (AI)');
                break;
            case "uai":
                slices.push('Ультра все включено (UAI)');
                break;
            default:
                slices.push(tour.meal.value);
                break;
        }
        if (tour.type == 'plain') {
            slices.push('<br />Вылет {0} ({1} {2})</div>'.format(tour.checkIn.value.asShortDate(), tour.nights, getMetering(parseInt(tour.nights), 'night')));
        }
        else {
            slices.push('<br />Начало {0} ({1} {2})</div>'.format(tour.checkIn.value.asShortDate(), tour.nights, getMetering(parseInt(tour.nights), 'night')));
        }
        slices.push('       </div>');
        slices.push('       <div class="col-xs-4">');
        slices.push('           <div class="tour__rating z-list__item__rating" data-star="{0}">'.format(isNaN(tour.star.value) ? 0 : parseInt(tour.star.value)));
        slices.push('               <div class="stars">');
        slices.push('                   <span class="star active"></span>{0}'.format(tour.star.value));
        slices.push('               </div>');
        slices.push('           </div>');
        slices.push('           <div class="ic-jet-ready z-list__item__price" data-flyinclude="{2}">{0} {1}</div>'.format(currency, parseInt(tour.chd) > 0 ? tour.chd : tour.price, flyInclude));
        slices.push('       </div>');
        slices.push('   </div>');
        slices.push('</li>');

        var html = slices.join('');
        var el = $(html);
        cnt.append(el);
    },

    onReady: function () {
		
        $(document).ready(function () {
            $(document).on('click', '.add-to-faworite', function (e) {

                var tourFields = {
                    blok_name: '',
                    to: '',
                    curort: '',
                    hotel: '',
                    stars: '',
                    transport: '',
                    days: '',
                    nights: '',
                    old: '',
                    child: '',
                    number: '',
                    eat: ''
                };

                var heart = $(this);
                var id = null,
                    key = null;
                var box = null;

                id = heart.attr('data-id'),
                    key = heart.attr('data-key');

                if (typeof id == 'undefined' || id == null || id == '') {

                    if (heart.closest('.tour').length > 0) {
                        box = heart.closest('.tour');
                    }
                    else {
                        if (heart.closest('.tour-in-cart').length > 0) {
                            box = heart.closest('.tour-in-cart');
                        }
                    }

                    id = box.attr('data-id'),
                        key = box.attr('data-key');
                }

                //if (typeof box == 'undefined' || box == null || !box.length || box.length == 0) {
                //    box = heart.closest('div[data-key]');
                //}



                //if (typeof box == 'undefined' || box == null || !box.length || box.length == 0) {
                //    var _id = heart.attr('data-id'),
                //        _key = heart.attr('data-key');
                //    if (typeof _id == 'undefined' || _id == null || _id == '') {
                //        return;
                //    }
                //}

                //if (id == null) {
                //    id = box.attr('data-id'),
                //    key = box.attr('data-key');
                //}

                heart.find('.ic-heart').toggleClass('active');

                var hasClass = false;


                if (heart.find('.ic-heart').hasClass('active')) {
                    hasClass = true;
                }

                if (typeof favoritTours != 'undefined') {
                    if (!hasClass)
                    { favoritTours.removeTour(id); }
                    else {
                        favoritTours.addTour(id, key, e);
                    }
                }
            });

            $(document).on('click', '.tour__more-others-link', function () {
                var link = $(this),
                    index = parseInt(link.attr('data-index')),
                    next = index + 6;
                if (index == -1) {
                    link.attr('data-index', 6);
                    link.html('<span>ПОКАЗАТЬ ЕЩЕ ТУРЫ <i class="ic ic-refresh pull-right"></i></span>');
                    link.closest('.tour__others__container').find('.btn-closer').trigger('click');
                    return false;
                }

                var cols = link.closest('.row').find('.tour__more-item');
                for (var i = index; i < next; i++) {
                    if (cols.length < i) break;
                    $(cols[i]).show();
                }
                if (cols.length < next) {
                    next = -1;
                    link.find('span').html('<span>ПОКАЗАНЫ ВСЕ ВАРИАНТЫ, СВЕРНУТЬ <i class="ic ic-chevron-up closer-close" style="position: absolute; right: 0; top: 0;"></i></span>');
                }
                link.attr('data-index', next);

                return false;
            });
        });
    }
};

// window.commonDocument.onReady(function() {
// 	render.onReady();
// });

;
/// <reference path="_references.js" />


(function(){
    function render3() {
        var self = this;
        
        this.tours = {};

        this.currentDebugHotel = '83809';

        this.addTour = function(tour) {
            if (!self.HotelsParent.Map&&isset(window.farSearchCatalog)) {
                self.HotelsParent.Map = true;
                for (var i in self.HotelsParent.Hotels) self.HotelsParent.Hotels[i].MapController.init();
            }
            self.tours[tour.SystemKey] = tour;
            if (isset(self.HotelsParent.Hotels[tour.hotelKey])) {
                self.HotelsParent.Hotels[tour.hotelKey].addTour(tour);
            } else {
                self.HotelsParent.Hotels[tour.hotelKey] = new Hotel(self.HotelsParent, tour);
            }
        };
        this.renderHtml = function(tour, position, sortOrder, open_more, classList, id) {
            self.addTour(tour);
            self.HotelsParent.Hotels[tour.hotelKey].render();
            return self.HotelsParent.Hotels[tour.hotelKey].element;
        };
        this.boc__get_real_price = function(tour) {
            return {
                priceUAH:       parseInt(tour.priceUAH),
                redPriceUAH:    parseInt(tour.redPriceUAH),
                price:          parseInt(tour.price),
                chd:            parseInt(tour.chd),
                realPriceUAH:   parseInt(tour.priceUAH),
                realPriceUSD:   parseInt(tour.chd)>0?parseInt(tour.chd):parseInt(tour.price),
                currency:       tour.currency
            };
        };
        this.renderHtmlCallback = function (hotel, position, sortOrder, open_more, classList, callback) {
            return self.renderHtml(hotel, position, sortOrder, open_more, classList);
        };
        this.refreshTour = alert;
        this.get_currency_symbol = getCurrencySymbol;
        this.renderPricelessHtml = function() {};
        this.initHotelsDesignChanger__inited = false;
        this.initHotelsDesignChanger = function() {
            if (self.initHotelsDesignChanger__inited) return;
            self.HotelsDesignChanger = document.getElementById('render3__HotelsDesignChanger');
            if (self.HotelsDesignChanger) {
                var btns = self.HotelsDesignChanger.querySelectorAll('button'),
                    prev = window.Far.Hotels_ViewMode.get(self.HotelsParent);
                for (var i=btns.length-1;i>=0;i--) {
                    var mode = btns[i].getAttribute('data-mode');
                    btns[i].addEventListener('click', function(){
                        var mode = this.getAttribute('data-mode');
                        window.Far.Hotels_ViewMode.set(mode, self.HotelsParent, this);
                    });
                    if (prev==mode) {
                        window.Far.Hotels_ViewMode.set(mode, self.HotelsParent, btns[i]);
                    }
                }
                self.initHotelsDesignChanger__inited = true;
            } else {
                setTimeout(self.initHotelsDesignChanger, 50);
            }
        }
        this.init = function() {
            farDocument.onReady(function(){
                commonDocument.onReady(function(){
                    self.HotelsParent = new StandartHotelParent({
                        id: 'render',
                        hotelClassName: typeof window.render3Options !== 'undefined' && typeof window.render3Options.hotelClassName !== 'undefined' ? window.render3Options.hotelClassName : '__horisontal',
                        Map: null,
                        useOperatorsIcons: true,
                        useOthersQuery: true
                    });
                });
            });
        };
        this.init();
        this.tour_btn_local_model = function (tour) {
            return {
                hotelKey: tour.hotelKey,
                SystemKey: tour.SystemKey,
                price: (parseInt(tour.chd) > 0 ? tour.chd : tour.price),
                currency: tour.currency,
                priceUAH: (tour.redPriceUAH > 0 ? tour.redPriceUAH : tour.priceUAH)
            };
        };
        this.tour_btn_local_model__in_json = function (tour) {
            return JSON.stringify(self.tour_btn_local_model(tour));
        };
        //Разделаем строку пробелами по розрядам
        this.stringSeparations = function (string) {
            var separatedString = string.replace(/(\d)(?=(\d{3})+(\D|$))/g, '$1 ');
            return separatedString;
        };
    }
    function renderItemModel(element,systemKey,id) {
        this.element = element;
        this.systemKey = systemKey;
        this.id = id;
        this.render = function(domCreator) {
            domCreator.call(this);
        };
        this.addEvents = function() {
        };
    }
    function f() {
        if (typeof window.Far.require=='undefined') {
            setTimeout(f, 50);
            return;
        }
        window.Far.require.Hotel(function(){
            window.render = new render3();
            window.render3= window.render;
        });
    }
    f();
})();

window.commonDocument.onReady(function() {
	$.fn.isInViewport = function() {
	    var elementTop = $(this).offset().top;
	    var elementBottom = elementTop + $(this).outerHeight();
	    var viewportTop = $(window).scrollTop();
	    var viewportBottom = viewportTop + $(window).height();
	    return elementBottom > viewportTop && elementTop < viewportBottom;
	};
});;
var FixedBanner = function(settings) {
	/*
		settings: {
			id: 'myId', 			// REQUIRED. String
			closable: true, 		// NOT REQUIRED. Boolean
			position: { 			// NOT REQUIRED. Object
				desktop: ['top','right'], 			// NOT REQUIRED. Array
				mobile: ['bottom','left','right'], 	// NOT REQUIRED. Array
			},
			background: 'black', 	// NOT REQUIRED. String, background, black||white||azure||gold. Default is white
			content: { 				// REQUIRED. Object
				url: 'url', 					// REQUIRED. String, URL only
				image: 'url', 					// NOT REQUIRED. String, URL only
				header: 'any you want', 		// NOT REQUIRED. String, html||text
				title: 'My super Title', 		// NOT REQUIRED. String, html||text,
				stars: 4, 						// NOT REQUIRED. Int, 1-5, use starsRender(value) to render
				price: {						// NOT REQUIRED. Object
					price: 638, 					// NOT REQUIRED. Int
					currency: '$',					// NOT REQUIRED, used only if price.price is setted. String, text
					priceUAH: 21479					// NOT REQUIRED. Int
				}
			}
		}
	 */
	var self = this;
	this.element = null;
	this.content = null;
	this.closeButton = null;
	this.settings = settings;
	this.onHide = [];
	this.hide = function() {
		if (self.element.hidden) return;
		for (var i = 0; i < self.onHide.length; i++) self.onHide[i]();
		self.element.hidden = true;
		document.body.classList.remove('__has_FixedBanner');
		self.closeButton.removeEventListener('click', self.hide);
	};
	this.onShow = [];
	this.show = function() {
		if (!self.element.hidden) return;
		for (var i = 0; i < self.onShow.length; i++) self.onShow[i]();
		self.element.hidden = false;
		document.body.classList.add('__has_FixedBanner');
		self.closeButton.addEventListener('click', self.hide);
	};
	this.toggle = function() {
		if (self.element.hidden) {
			self.show();
		}
		else {
			self.hide();
		}
	};
	this.render = function() {
		var html = [
			'<div id="', self.settings.id, '" ',
			'class="FixedBanner ',
			'__background_', (isset(self.settings.background) ? self.settings.background : 'white'), ' ',
			(isset(self.settings.position)
				? [
					(isset(self.settings.position.desktop) ? ['__desktop_', self.settings.position.desktop.join(' __desktop_'), ' '].join('') : ''),
					(isset(self.settings.position.mobile) ? ['__mobile_', self.settings.position.mobile.join(' __mobile_'), ' '].join('') : '')
				].join('')
				: ''),
			'">',
			self.renderContent(),
			(isset(self.settings.closable) && self.settings.closable ? self.renderCloseButton() : ''),
			'</div>'
		].join('');
		self.element = createElementFromHTML(html);
		self.element.hidden = true;
		document.getElementById('body').appendChild(self.element);
		self.content = document.getElementById(self.settings.id + '__content');
		self.closeButton = document.getElementById(self.settings.id + '__closeButton');
	};
	this.renderContent = function() {
		var html = [
			'<a id="', self.settings.id, '__content" class="FixedBanner__content" href="', self.settings.content.url, '">',
			(isset(self.settings.content.image) ? ['<img src="', self.settings.content.image, '" alt="Image" class="FixedBanner__image"/>'].join('') : ''),
			(isset(self.settings.content.header) ? ['<div class="FixedBanner__header">', self.settings.content.header, '</div>'].join('') : ''),
			(isset(self.settings.content.title) ? ['<div class="FixedBanner__title">', self.settings.content.title, '</div>'].join('') : ''),
			(isset(self.settings.content.stars) || isset(self.settings.content.price)
				? [
					'<div class="FixedBanner__price_and_stars">',
					(isset(self.settings.content.stars) ? ['<div class="FixedBanner__stars">', starsRender(self.settings.content.stars), '</div>'].join('') : ''),
					(isset(self.settings.content.price) && Object.keys(self.settings.content.price).length
						? [
							'<div class="FixedBanner__price">',
							(isset(self.settings.content.price.price) && isset(self.settings.content.price.currency) ? ['<b>', self.settings.content.price.currency, summHumanize(self.settings.content.price.price), '</b>'].join('') : ''),
							(isset(self.settings.content.price.priceUAH) ? ['<span>(', summHumanize(self.settings.content.price.priceUAH), ' ', localizationValues.currency_uah, ')</span>'].join('') : ''),
							'</div>'
						].join('')
						: ''),
					'</div>'
				].join('')
				: ''),
			'<a>',
		].join('');
		return html;
	};
	this.renderCloseButton = function() {
		var html = [
			'<button id="', self.settings.id, '__closeButton" class="FixedBanner__closeButton" title="', localizationValues.Close, '">',
			'<span></span>',
			'<span></span>',
			'</button>'
		].join('');
		return html;
	};
};

var UnfinishedCheckout_ = function() {
	var self = this;
	this.carts = {};
	this.banner = null;
	this.currentSystemKey = null;
	this.log = function() {};
	this.getLocalStorage = function() {
		self.log('getLocalStorage');
		var carts = localStorage.getItem('UnfinishedCheckout');
		if (carts == null) return {};
		carts = JSON.parse(carts);
		var d = new Date().getTime(),
			n = {};
		for (var x in carts) {
			if (carts[x].UCdate >= (d - (1000 * 60 * 60 * 24))) n[x] = carts[x];
		}
		return n;
	};
	this.setLocalStorage = function(carts) {
		self.log('setLocalStorage', carts);
		localStorage.setItem('UnfinishedCheckout', JSON.stringify(carts));
	};
	this.addLocalStorage = function(systemKey, model) {
		self.log('addLocalStorage', systemKey, model);
		if (!systemKey) return;
		model.UCdate = new Date().getTime();
		var prev = {}; // if need to save ALL carts -> self.getLocalStorage();
		prev[systemKey] = model;
		self.setLocalStorage(prev);
	};
	this.removeLocalStorage = function(systemKey) {
		self.log('removeLocalStorage', systemKey);
		var prev = self.getLocalStorage();
		if (isset(prev[systemKey])) {
			delete prev[systemKey];
			self.setLocalStorage(prev);
		}
	};
	this.emptyLocalStorage = function() {
		self.setLocalStorage([]);
		self.carts = [];
	};
	this.startBanner = function() {
		self.log('startBanner');
		if (!Object.keys(self.carts).length) return;
		var currentSystemKey = Object.keys(self.carts)[0],
			cart = Object.assign({}, self.carts[currentSystemKey]);
		self.currentSystemKey = currentSystemKey;
		self.banner = new FixedBanner({
			id: 'UnfinishedCheckoutBanner',
			closable: true,
			position: {
				desktop: ['top', 'right'],
				mobile: ['bottom', 'left', 'right'],
			},
			background: 'black',
			content: {
				url: cart.url,
				image: cart.image,
				header: '<i data-icon="arrow-right2"></i> ' + localizationValues.FinishTourCheckout,
				title: cart.title,
				stars: cart.stars,
				price: {
					price: cart.price.price,
					currency: cart.price.currency,
					priceUAH: cart.price.priceUAH
				}
			}
		});
		self.banner.render();
		self.banner.content.addEventListener('click',
			function() {
				window.farUserDataCollector.spotter.userMap.event('unfinishedCheckoutBanner_click',
					{
						hotelsId: cart.hotelKey,
						systemKey: currentSystemKey,
						price: {
							uah: cart.price.priceUAH,
							curr: cart.price.price,
							currCode: cart.price.currency
						}
					});
			});
		self.banner.onHide.push(function() {
			self.emptyLocalStorage();
		});
		if (window.location.href.indexOf('checkout') == -1 && window.location.href.indexOf('complite') == -1 && window.location.href.indexOf('/diia/return-link') == -1) {
			self.banner.show();
		}
	};
	this.init = function() {
		self.log('init');
		var prev = self.getLocalStorage();
		if (Object.keys(prev)) {
			self.carts = prev;
			self.startBanner();
		}
	};

	farDocument.onReady(function() {
		self.init();
	});
};
window.UnfinishedCheckout = undefined;
(function() {
	var carts = localStorage.getItem('UnfinishedCheckout');
	if (carts || typeof (itsCheckout) !== 'undefined') {
		window.UnfinishedCheckout = new UnfinishedCheckout_();
	}
})();;
var sbjs = (function () {

    var delimiter = '|||';

    var data = {

        containers: {
            current: 'sbjs_current',
            current_extra: 'sbjs_current_add',
            first: 'sbjs_first',
            first_extra: 'sbjs_first_add',
            session: 'sbjs_session',
            udata: 'sbjs_udata',
            promocode: 'sbjs_promo'
        },

        service: {
            migrations: 'sbjs_migrations'
        },

        delimiter: delimiter,

        aliases: {

            main: {
                type: 'typ',
                source: 'src',
                medium: 'mdm',
                campaign: 'cmp',
                content: 'cnt',
                term: 'trm'
            },

            extra: {
                fire_date: 'fd',
                entrance_point: 'ep',
                referer: 'rf'
            },

            session: {
                pages_seen: 'pgs',
                current_page: 'cpg'
            },

            udata: {
                visits: 'vst',
                ip: 'uip',
                agent: 'uag'
            },

            promo: 'code'

        },

        pack: {

            main: function (sbjs) {
                return (
                    data.aliases.main.type + '=' + sbjs.type + data.delimiter +
                    data.aliases.main.source + '=' + sbjs.source + data.delimiter +
                    data.aliases.main.medium + '=' + sbjs.medium + data.delimiter +
                    data.aliases.main.campaign + '=' + sbjs.campaign + data.delimiter +
                    data.aliases.main.content + '=' + sbjs.content + data.delimiter +
                    data.aliases.main.term + '=' + sbjs.term
                );
            },

            extra: function (timezone_offset) {
                return (
                    data.aliases.extra.fire_date + '=' + utils.setDate(new Date, timezone_offset) + data.delimiter +
                    data.aliases.extra.entrance_point + '=' + document.location.href + data.delimiter +
                    data.aliases.extra.referer + '=' + (document.referrer || terms.none)
                );
            },

            user: function (visits, user_ip) {
                return (
                    data.aliases.udata.visits + '=' + visits + data.delimiter +
                    data.aliases.udata.ip + '=' + user_ip + data.delimiter +
                    data.aliases.udata.agent + '=' + navigator.userAgent
                );
            },

            session: function (pages) {
                return (
                    data.aliases.session.pages_seen + '=' + pages + data.delimiter +
                    data.aliases.session.current_page + '=' + document.location.href
                );
            },

            promo: function (promo) {
                return (
                    data.aliases.promo + '=' + utils.setLeadingZeroToInt(utils.randomInt(promo.min, promo.max), promo.max.toString().length)
                );
            }

        }
    };

    var terms = {

        traffic: {
            utm: 'utm',
            organic: 'organic',
            referral: 'referral',
            typein: 'typein'
        },

        referer: {
            referral: 'referral',
            organic: 'organic',
            social: 'social'
        },

        none: '(none)',
        oops: '(Houston, we have a problem)'

    };

    var cookies = {

        encodeData: function (s) {
            return encodeURIComponent(s).replace(/\!/g, '%21')
                .replace(/\~/g, '%7E')
                .replace(/\*/g, '%2A')
                .replace(/\'/g, '%27')
                .replace(/\(/g, '%28')
                .replace(/\)/g, '%29');
        },

        decodeData: function (s) {
            try {
                return decodeURIComponent(s).replace(/\%21/g, '!')
                    .replace(/\%7E/g, '~')
                    .replace(/\%2A/g, '*')
                    .replace(/\%27/g, "'")
                    .replace(/\%28/g, '(')
                    .replace(/\%29/g, ')');
            } catch (err1) {
                // try unescape for backward compatibility
                try { return unescape(s); } catch (err2) { return ''; }
            }
        },

        set: function (name, value, minutes, domain, excl_subdomains) {
            var expires, basehost;

            if (minutes) {
                var date = new Date();
                date.setTime(date.getTime() + (minutes * 60 * 1000));
                expires = '; expires=' + date.toGMTString();
            } else {
                expires = '';
            }
            if (domain && !excl_subdomains) {
                basehost = ';domain=.' + domain;
            } else {
                basehost = '';
            }
            document.cookie = this.encodeData(name) + '=' + this.encodeData(value) + expires + basehost + '; path=/';
        },

        get: function (name) {
            var nameEQ = this.encodeData(name) + '=',
                ca = document.cookie.split(';');

            for (var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) === ' ') { c = c.substring(1, c.length); }
                if (c.indexOf(nameEQ) === 0) {
                    return this.decodeData(c.substring(nameEQ.length, c.length));
                }
            }
            return null;
        },

        destroy: function (name, domain, excl_subdomains) {
            this.set(name, '', -1, domain, excl_subdomains);
        },

        parse: function (yummy) {

            var cookies = [],
                data = {};

            if (typeof yummy === 'string') {
                cookies.push(yummy);
            } else {
                for (var prop in yummy) {
                    if (yummy.hasOwnProperty(prop)) {
                        cookies.push(yummy[prop]);
                    }
                }
            }

            for (var i1 = 0; i1 < cookies.length; i1++) {
                var cookie_array;
                data[this.unsbjs(cookies[i1])] = {};
                if (this.get(cookies[i1])) {
                    cookie_array = this.get(cookies[i1]).split(delimiter);
                } else {
                    cookie_array = [];
                }
                for (var i2 = 0; i2 < cookie_array.length; i2++) {
                    var tmp_array = cookie_array[i2].split('='),
                        result_array = tmp_array.splice(0, 1);
                    result_array.push(tmp_array.join('='));
                    data[this.unsbjs(cookies[i1])][result_array[0]] = this.decodeData(result_array[1]);
                }
            }

            return data;

        },

        unsbjs: function (string) {
            return string.replace('sbjs_', '');
        }

    };

    var uri = {

        parse: function (str) {
            var o = this.parseOptions,
                m = o.parser[o.strictMode ? 'strict' : 'loose'].exec(str),
                uri = {},
                i = 14;

            while (i--) { uri[o.key[i]] = m[i] || ''; }

            uri[o.q.name] = {};
            uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
                if ($1) { uri[o.q.name][$1] = $2; }
            });

            return uri;
        },

        parseOptions: {
            strictMode: false,
            key: ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'],
            q: {
                name: 'queryKey',
                parser: /(?:^|&)([^&=]*)=?([^&]*)/g
            },
            parser: {
                strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
                loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
            }
        },

        getParam: function (custom_params) {
            var query_string = {},
                query = custom_params ? custom_params : window.location.search.substring(1),
                vars = query.split('&');

            for (var i = 0; i < vars.length; i++) {
                var pair = vars[i].split('=');
                if (typeof query_string[pair[0]] === 'undefined') {
                    query_string[pair[0]] = pair[1];
                } else if (typeof query_string[pair[0]] === 'string') {
                    var arr = [query_string[pair[0]], pair[1]];
                    query_string[pair[0]] = arr;
                } else {
                    query_string[pair[0]].push(pair[1]);
                }
            }
            return query_string;
        },

        getHost: function (request) {
            return this.parse(request).host.replace('www.', '');
        }

    };

    var utils = {

        escapeRegexp: function (string) {
            return string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
        },

        setDate: function (date, offset) {
            var utc_offset = date.getTimezoneOffset() / 60,
                now_hours = date.getHours(),
                custom_offset = offset || offset === 0 ? offset : -utc_offset;

            date.setHours(now_hours + utc_offset + custom_offset);

            var year = date.getFullYear(),
                month = this.setLeadingZeroToInt(date.getMonth() + 1, 2),
                day = this.setLeadingZeroToInt(date.getDate(), 2),
                hour = this.setLeadingZeroToInt(date.getHours(), 2),
                minute = this.setLeadingZeroToInt(date.getMinutes(), 2),
                second = this.setLeadingZeroToInt(date.getSeconds(), 2);

            return (year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
        },

        setLeadingZeroToInt: function (num, size) {
            var s = num + '';
            while (s.length < size) { s = '0' + s; }
            return s;
        },

        randomInt: function (min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }

    };

    var params = {

        fetch: function (prefs) {

            var user = prefs || {},
                params = {};

            // Set `lifetime of the cookie` in months
            params.lifetime = this.validate.checkFloat(user.lifetime) || 6;
            params.lifetime = parseInt(params.lifetime * 30 * 24 * 60);

            // Set `session length` in minutes
            params.session_length = this.validate.checkInt(user.session_length) || 30;

            // Set `timezone offset` in hours
            params.timezone_offset = this.validate.checkInt(user.timezone_offset);

            // Set `campaign param` for AdWords links
            params.campaign_param = user.campaign_param || false;

            // Set `term param` and `content param` for AdWords links
            params.term_param = user.term_param || false;
            params.content_param = user.content_param || false;

            // Set `user ip`
            params.user_ip = user.user_ip || terms.none;

            // Set `promocode`
            if (user.promocode) {
                params.promocode = {};
                params.promocode.min = parseInt(user.promocode.min) || 100000;
                params.promocode.max = parseInt(user.promocode.max) || 999999;
            } else {
                params.promocode = false;
            }

            // Set `typein attributes`
            if (user.typein_attributes && user.typein_attributes.source && user.typein_attributes.medium) {
                params.typein_attributes = {};
                params.typein_attributes.source = user.typein_attributes.source;
                params.typein_attributes.medium = user.typein_attributes.medium;
            } else {
                params.typein_attributes = { source: '(direct)', medium: '(none)' };
            }

            // Set `domain`
            if (user.domain && this.validate.isString(user.domain)) {
                params.domain = { host: user.domain, isolate: false };
            } else if (user.domain && user.domain.host) {
                params.domain = user.domain;
            } else {
                params.domain = { host: uri.getHost(document.location.hostname), isolate: false };
            }

            // Set `referral sources`
            params.referrals = [];

            if (user.referrals && user.referrals.length > 0) {
                for (var ir = 0; ir < user.referrals.length; ir++) {
                    if (user.referrals[ir].host) {
                        params.referrals.push(user.referrals[ir]);
                    }
                }
            }

            // Set `organic sources`
            params.organics = [];

            if (user.organics && user.organics.length > 0) {
                for (var io = 0; io < user.organics.length; io++) {
                    if (user.organics[io].host && user.organics[io].param) {
                        params.organics.push(user.organics[io]);
                    }
                }
            }

            params.organics.push({ host: 'bing.com', param: 'q', display: 'bing' });
            params.organics.push({ host: 'yahoo.com', param: 'p', display: 'yahoo' });
            params.organics.push({ host: 'about.com', param: 'q', display: 'about' });
            params.organics.push({ host: 'aol.com', param: 'q', display: 'aol' });
            params.organics.push({ host: 'ask.com', param: 'q', display: 'ask' });
            params.organics.push({ host: 'globososo.com', param: 'q', display: 'globo' });
            params.organics.push({ host: 'go.mail.ru', param: 'q', display: 'go.mail.ru' });
            params.organics.push({ host: 'rambler.ru', param: 'query', display: 'rambler' });
            params.organics.push({ host: 'tut.by', param: 'query', display: 'tut.by' });

            params.referrals.push({ host: 't.co', display: 'twitter.com' });
            params.referrals.push({ host: 'plus.url.google.com', display: 'plus.google.com' });


            return params;

        },

        validate: {

            checkFloat: function (v) {
                return v && this.isNumeric(parseFloat(v)) ? parseFloat(v) : false;
            },

            checkInt: function (v) {
                return v && this.isNumeric(parseInt(v)) ? parseInt(v) : false;
            },

            isNumeric: function (v) {
                return !isNaN(v);
            },

            isString: function (v) {
                return Object.prototype.toString.call(v) === '[object String]';
            }

        }

    };

    var migrations = {

        go: function (lifetime, domain, isolate) {

            var migrate = this.migrations,
                _with = { l: lifetime, d: domain, i: isolate };

            var i;

            if (!cookies.get(data.containers.first) && !cookies.get(data.service.migrations)) {

                var mids = [];
                for (i = 0; i < migrate.length; i++) { mids.push(migrate[i].id); }

                var advance = '';
                for (i = 0; i < mids.length; i++) {
                    advance += mids[i] + '=1';
                    if (i < mids.length - 1) { advance += data.delimiter; }
                }
                cookies.set(data.service.migrations, advance, _with.l, _with.d, _with.i);

            } else if (!cookies.get(data.service.migrations)) {

                // We have only one migration for now, so just
                for (i = 0; i < migrate.length; i++) {
                    migrate[i].go(migrate[i].id, _with);
                }

            }

        },

        migrations: [

            {
                id: '1418474375998',
                version: '1.0.0-beta',
                go: function (mid, _with) {

                    var success = mid + '=1',
                        fail = mid + '=0';

                    var safeReplace = function ($0, $1, $2) {
                        return ($1 || $2 ? $0 : data.delimiter);
                    };

                    try {

                        // Switch delimiter and renew cookies
                        var _in = [];
                        for (var prop in data.containers) {
                            if (data.containers.hasOwnProperty(prop)) {
                                _in.push(data.containers[prop]);
                            }
                        }

                        for (var i = 0; i < _in.length; i++) {
                            if (cookies.get(_in[i])) {
                                var buffer = cookies.get(_in[i]).replace(/(\|)?\|(\|)?/g, safeReplace);
                                cookies.destroy(_in[i], _with.d, _with.i);
                                cookies.destroy(_in[i], _with.d, !_with.i);
                                cookies.set(_in[i], buffer, _with.l, _with.d, _with.i);
                            }
                        }

                        // Update `session`
                        if (cookies.get(data.containers.session)) {
                            cookies.set(data.containers.session, data.pack.session(0), _with.l, _with.d, _with.i);
                        }

                        // Yay!
                        cookies.set(data.service.migrations, success, _with.l, _with.d, _with.i);

                    } catch (err) {
                        // Oops
                        cookies.set(data.service.migrations, fail, _with.l, _with.d, _with.i);
                    }
                }
            }

        ]

    };

    var init = function (prefs) {

        var p = params.fetch(prefs);
        var get_param = uri.getParam();
        var domain = p.domain.host,
            isolate = p.domain.isolate,
            lifetime = p.lifetime;

        migrations.go(lifetime, domain, isolate);

        var __sbjs_type,
            __sbjs_source,
            __sbjs_medium,
            __sbjs_campaign,
            __sbjs_content,
            __sbjs_term;

        function mainData() {
            var sbjs_data;
            if (
                typeof get_param.utm_source !== 'undefined' ||
                typeof get_param.utm_medium !== 'undefined' ||
                typeof get_param.utm_campaign !== 'undefined' ||
                typeof get_param.utm_content !== 'undefined' ||
                typeof get_param.utm_term !== 'undefined' ||
                typeof get_param.gclid !== 'undefined' ||
                typeof get_param.yclid !== 'undefined' ||
                typeof get_param[p.campaign_param] !== 'undefined' ||
                typeof get_param[p.term_param] !== 'undefined' ||
                typeof get_param[p.content_param] !== 'undefined'
            ) {
                setFirstAndCurrentExtraData();
                sbjs_data = getData(terms.traffic.utm);
            } else if (checkReferer(terms.traffic.organic)) {
                setFirstAndCurrentExtraData();
                sbjs_data = getData(terms.traffic.organic);
            } else if (!cookies.get(data.containers.session) && checkReferer(terms.traffic.referral)) {
                setFirstAndCurrentExtraData();
                sbjs_data = getData(terms.traffic.referral);
            } else if (!cookies.get(data.containers.first) && !cookies.get(data.containers.current)) {
                setFirstAndCurrentExtraData();
                sbjs_data = getData(terms.traffic.typein);
            } else {
                return cookies.get(data.containers.current);
            }

            return sbjs_data;
        }

        function getData(type) {

            switch (type) {

                case terms.traffic.utm:

                    __sbjs_type = terms.traffic.utm;

                    if (typeof get_param.utm_source !== 'undefined') {
                        __sbjs_source = get_param.utm_source;
                    } else if (typeof get_param.gclid !== 'undefined') {
                        __sbjs_source = 'google';
                    } else if (typeof get_param.yclid !== 'undefined') {
                        __sbjs_source = 'yandex';
                    } else {
                        __sbjs_source = terms.none;
                    }

                    if (typeof get_param.utm_medium !== 'undefined') {
                        __sbjs_medium = get_param.utm_medium;
                    } else if (typeof get_param.gclid !== 'undefined') {
                        __sbjs_medium = 'cpc';
                    } else if (typeof get_param.yclid !== 'undefined') {
                        __sbjs_medium = 'cpc';
                    } else {
                        __sbjs_medium = terms.none;
                    }

                    if (typeof get_param.utm_campaign !== 'undefined') {
                        __sbjs_campaign = get_param.utm_campaign;
                    } else if (typeof get_param[p.campaign_param] !== 'undefined') {
                        __sbjs_campaign = get_param[p.campaign_param];
                    } else if (typeof get_param.gclid !== 'undefined') {
                        __sbjs_campaign = 'google_cpc';
                    } else if (typeof get_param.yclid !== 'undefined') {
                        __sbjs_campaign = 'yandex_cpc';
                    } else {
                        __sbjs_campaign = terms.none;
                    }

                    if (typeof get_param.utm_content !== 'undefined') {
                        __sbjs_content = get_param.utm_content;
                    } else if (typeof get_param[p.content_param] !== 'undefined') {
                        __sbjs_content = get_param[p.content_param];
                    } else {
                        __sbjs_content = terms.none;
                    }

                    if (typeof get_param.utm_term !== 'undefined') {
                        __sbjs_term = get_param.utm_term;
                    } else if (typeof get_param[p.term_param] !== 'undefined') {
                        __sbjs_term = get_param[p.term_param];
                    } else {
                        __sbjs_term = getUtmTerm() || terms.none;
                    }

                    break;

                case terms.traffic.organic:
                    __sbjs_type = terms.traffic.organic;
                    __sbjs_source = __sbjs_source || uri.getHost(document.referrer);
                    __sbjs_medium = terms.referer.organic;
                    __sbjs_campaign = terms.none;
                    __sbjs_content = terms.none;
                    __sbjs_term = terms.none;
                    break;

                case terms.traffic.referral:
                    __sbjs_type = terms.traffic.referral;
                    __sbjs_source = __sbjs_source || uri.getHost(document.referrer);
                    __sbjs_medium = __sbjs_medium || terms.referer.referral;
                    __sbjs_campaign = terms.none;
                    __sbjs_content = uri.parse(document.referrer).path;
                    __sbjs_term = terms.none;
                    break;

                case terms.traffic.typein:
                    __sbjs_type = terms.traffic.typein;
                    __sbjs_source = p.typein_attributes.source;
                    __sbjs_medium = p.typein_attributes.medium;
                    __sbjs_campaign = terms.none;
                    __sbjs_content = terms.none;
                    __sbjs_term = terms.none;
                    break;

                default:
                    __sbjs_type = terms.oops;
                    __sbjs_source = terms.oops;
                    __sbjs_medium = terms.oops;
                    __sbjs_campaign = terms.oops;
                    __sbjs_content = terms.oops;
                    __sbjs_term = terms.oops;
            }
            var sbjs_data = {
                type: __sbjs_type,
                source: __sbjs_source,
                medium: __sbjs_medium,
                campaign: __sbjs_campaign,
                content: __sbjs_content,
                term: __sbjs_term
            };

            return data.pack.main(sbjs_data);

        }

        function getUtmTerm() {
            var referer = document.referrer;
            if (get_param.utm_term) {
                return get_param.utm_term;
            } else if (referer && uri.parse(referer).host && uri.parse(referer).host.match(/^(?:.*\.)?yandex\..{2,9}$/i)) {
                try {
                    return uri.getParam(uri.parse(document.referrer).query).text;
                } catch (err) {
                    return false;
                }
            } else {
                return false;
            }
        }

        function checkReferer(type) {
            var referer = document.referrer;
            switch (type) {
                case terms.traffic.organic:
                    return (!!referer && checkRefererHost(referer) && isOrganic(referer));
                case terms.traffic.referral:
                    return (!!referer && checkRefererHost(referer) && isReferral(referer));
                default:
                    return false;
            }
        }

        function checkRefererHost(referer) {
            if (p.domain) {
                if (!isolate) {
                    var host_regex = new RegExp('^(?:.*\\.)?' + utils.escapeRegexp(domain) + '$', 'i');
                    return !(uri.getHost(referer).match(host_regex));
                } else {
                    return (uri.getHost(referer) !== uri.getHost(domain));
                }
            } else {
                return (uri.getHost(referer) !== uri.getHost(document.location.href));
            }
        }

        function isOrganic(referer) {

            var y_host = 'yandex',
                y_param = 'text',
                g_host = 'google';

            var y_host_regex = new RegExp('^(?:.*\\.)?' + utils.escapeRegexp(y_host) + '\\..{2,9}$'),
                y_param_regex = new RegExp('.*' + utils.escapeRegexp(y_param) + '=.*'),
                g_host_regex = new RegExp('^(?:www\\.)?' + utils.escapeRegexp(g_host) + '\\..{2,9}$');

            if (
                !!uri.parse(referer).query &&
                !!uri.parse(referer).host.match(y_host_regex) &&
                !!uri.parse(referer).query.match(y_param_regex)
            ) {
                __sbjs_source = y_host;
                return true;
            } else if (!!uri.parse(referer).host.match(g_host_regex)) {
                __sbjs_source = g_host;
                return true;
            } else if (!!uri.parse(referer).query) {
                for (var i = 0; i < p.organics.length; i++) {
                    if (
                        uri.parse(referer).host.match(new RegExp('^(?:.*\\.)?' + utils.escapeRegexp(p.organics[i].host) + '$', 'i')) &&
                        uri.parse(referer).query.match(new RegExp('.*' + utils.escapeRegexp(p.organics[i].param) + '=.*', 'i'))
                    ) {
                        __sbjs_source = p.organics[i].display || p.organics[i].host;
                        return true;
                    }
                    if (i + 1 === p.organics.length) {
                        return false;
                    }
                }
            } else {
                return false;
            }
        }

        function isReferral(referer) {
            if (p.referrals.length > 0) {
                for (var i = 0; i < p.referrals.length; i++) {
                    if (uri.parse(referer).host.match(new RegExp('^(?:.*\\.)?' + utils.escapeRegexp(p.referrals[i].host) + '$', 'i'))) {
                        __sbjs_source = p.referrals[i].display || p.referrals[i].host;
                        __sbjs_medium = p.referrals[i].medium || terms.referer.referral;
                        return true;
                    }
                    if (i + 1 === p.referrals.length) {
                        __sbjs_source = uri.getHost(referer);
                        return true;
                    }
                }
            } else {
                __sbjs_source = uri.getHost(referer);
                return true;
            }
        }

        function setFirstAndCurrentExtraData() {
            cookies.set(data.containers.current_extra, data.pack.extra(p.timezone_offset), lifetime, domain, isolate);
            if (!cookies.get(data.containers.first_extra)) {
                cookies.set(data.containers.first_extra, data.pack.extra(p.timezone_offset), lifetime, domain, isolate);
            }
        }

        (function setData() {

            // Main data
            cookies.set(data.containers.current, mainData(), lifetime, domain, isolate);
            if (!cookies.get(data.containers.first)) {
                cookies.set(data.containers.first, cookies.get(data.containers.current), lifetime, domain, isolate);
            }

            // User data
            var visits, udata;
            if (!cookies.get(data.containers.udata)) {
                visits = 1;
                udata = data.pack.user(visits, p.user_ip);
            } else {
                visits = parseInt(cookies.parse(data.containers.udata)[cookies.unsbjs(data.containers.udata)][data.aliases.udata.visits]) || 1;
                visits = cookies.get(data.containers.session) ? visits : visits + 1;
                udata = data.pack.user(visits, p.user_ip);
            }
            cookies.set(data.containers.udata, udata, lifetime, domain, isolate);

            // Session
            var pages_count;
            if (!cookies.get(data.containers.session)) {
                pages_count = 1;
            } else {
                pages_count = parseInt(cookies.parse(data.containers.session)[cookies.unsbjs(data.containers.session)][data.aliases.session.pages_seen]) || 1;
                pages_count += 1;
            }
            cookies.set(data.containers.session, data.pack.session(pages_count), p.session_length, domain, isolate);

            // Promocode
            if (p.promocode && !cookies.get(data.containers.promocode)) {
                cookies.set(data.containers.promocode, data.pack.promo(p.promocode), lifetime, domain, isolate);
            }

        })();

        return cookies.parse(data.containers);

    };

    return {
        v: 1,
        init: function (prefs) {
            this.get = init(prefs);
            if (prefs && prefs.callback && typeof prefs.callback === 'function') {
                prefs.callback(this.get);
            }
        }
    }
})();

sbjs.init();;
// This script must be LAST in Bundle

farDocument.run();;
