PageSourceSearch

https://lehome.ru/bitrix/js/main/core/core.js

js lehome.ru collected 2026-10-08 20:19:30 UTC 118,161 bytes, 5,860 lines download raw bytes

1/**********************************************************************/
2/*********** Bitrix JS Core library ver 0.9.0 beta ********************/
3/**********************************************************************/
4
5;(function(window){
6
7if (!!window.BX && !!window.BX.extend)
8	return;
9
10var _bxtmp;
11if (!!window.BX)
12{
13	_bxtmp = window.BX;
14}
15
16window.BX = function(node, bCache)
17{
18	if (BX.type.isNotEmptyString(node))
19	{
20		var ob;
21
22		if (!!bCache && null != NODECACHE[node])
23			ob = NODECACHE[node];
24		ob = ob || document.getElementById(node);
25		if (!!bCache)
26			NODECACHE[node] = ob;
27
28		return ob;
29	}
30	else if (BX.type.isDomNode(node))
31		return node;
32	else if (BX.type.isFunction(node))
33		return BX.ready(node);
34
35	return null;
36};
37
38BX.debugEnableFlag = true;
39
40// language utility
41BX.message = function(mess)
42{
43	if (BX.type.isString(mess))
44	{
45		if (typeof BX.message[mess] == "undefined")
46		{
47			BX.onCustomEvent("onBXMessageNotFound", [mess]);
48			if (typeof BX.message[mess] == "undefined")
49			{
50				BX.debug("message undefined: " + mess);
51				BX.message[mess] = "";
52			}
53
54		}
55
56		return BX.message[mess];
57	}
58	else
59	{
60		for (var i in mess)
61		{
62			if (mess.hasOwnProperty(i))
63			{
64				BX.message[i] = mess[i];
65			}
66		}
67		return true;
68	}
69};
70
71if(!!_bxtmp)
72{
73	for(var i in _bxtmp)
74	{
75		if(_bxtmp.hasOwnProperty(i))
76		{
77			if(!BX[i])
78			{
79				BX[i]=_bxtmp[i];
80			}
81			else if(i=='message')
82			{
83				for(var j in _bxtmp[i])
84				{
85					if(_bxtmp[i].hasOwnProperty(j))
86					{
87						BX.message[j]=_bxtmp[i][j];
88					}
89				}
90			}
91		}
92	}
93
94	_bxtmp = null;
95}
96
97var
98
99/* ready */
100__readyHandler = null,
101readyBound = false,
102readyList = [],
103
104/* list of registered proxy functions */
105proxySalt = Math.random(),
106proxyId = 1,
107proxyList = [],
108
109/* getElementById cache */
110NODECACHE = {},
111
112/* List of denied event handlers */
113deniedEvents = [],
114
115/* list of registered event handlers */
116eventsList = [],
117
118/* list of registered custom events */
119customEvents = {},
120
121/* list of external garbage collectors */
122garbageCollectors = [],
123
124/* list of loaded CSS files */
125cssList = [],
126cssInit = false,
127
128/* list of loaded JS files */
129jsList = [],
130jsInit = false,
131
132
133/* browser detection */
134bSafari = navigator.userAgent.toLowerCase().indexOf('webkit') != -1,
135bOpera = navigator.userAgent.toLowerCase().indexOf('opera') != -1,
136bFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') != -1,
137bChrome = navigator.userAgent.toLowerCase().indexOf('chrome') != -1,
138bIE = document.attachEvent && !bOpera,
139
140/* regexps */
141r = {
142	script: /<script([^>]*)>/ig,
143	script_end: /<\/script>/ig,
144	script_src: /src=["\']([^"\']+)["\']/i,
145	script_type: /type=["\']([^"\']+)["\']/i,
146	space: /\s+/,
147	ltrim: /^[\s\r\n]+/g,
148	rtrim: /[\s\r\n]+$/g,
149	style: /<link.*?(rel="stylesheet"|type="text\/css")[^>]*>/i,
150	style_href: /href=["\']([^"\']+)["\']/i
151},
152
153eventTypes = {
154	click: 'MouseEvent',
155	dblclick: 'MouseEvent',
156	mousedown: 'MouseEvent',
157	mousemove: 'MouseEvent',
158	mouseout: 'MouseEvent',
159	mouseover: 'MouseEvent',
160	mouseup: 'MouseEvent',
161	focus: 'MouseEvent',
162	blur: 'MouseEvent'
163},
164
165lastWait = [],
166
167CHECK_FORM_ELEMENTS = {tagName: /^INPUT|SELECT|TEXTAREA|BUTTON$/i},
168
169PRELOADING = 1, PRELOADED = 2, LOADING = 3, LOADED = 4,
170assets = {},
171isAsync = null;
172
173BX.MSLEFT = 1;
174BX.MSMIDDLE = 2;
175BX.MSRIGHT = 4;
176
177BX.ext = function(ob)
178{
179	for (var i in ob)
180	{
181		if(ob.hasOwnProperty(i))
182		{
183			this[i] = ob[i];
184		}
185	}
186};
187
188/* OO emulation utility */
189BX.extend = function(child, parent)
190{
191	var f = function() {};
192	f.prototype = parent.prototype;
193
194	child.prototype = new f();
195	child.prototype.constructor = child;
196
197	child.superclass = parent.prototype;
198	if(parent.prototype.constructor == Object.prototype.constructor)
199	{
200		parent.prototype.constructor = parent;
201	}
202};
203
204BX.namespace = function(namespace)
205{
206	var parts = namespace.split(".");
207	var parent = BX;
208
209	if (parts[0] === "BX")
210	{
211		parts = parts.slice(1);
212	}
213
214	for (var i = 0; i < parts.length; i++) {
215
216		if (typeof parent[parts[i]] === "undefined")
217		{
218			parent[parts[i]] = {};
219		}
220		parent = parent[parts[i]];
221	}
222
223	return parent;
224};
225
226BX.debug = function()
227{
228	if (BX.debugStatus())
229	{
230		if (window.console && window.console.log)
231			window.console.log('BX.debug: ', arguments.length > 0 ? arguments : arguments[0]);
232		if (window.console && window.console.trace)
233			console.trace();
234	}
235};
236
237BX.debugEnable = function(flag)
238{
239	flag = typeof (flag) == 'boolean'? flag: true;
240	BX.debugEnableFlag = flag;
241};
242
243BX.debugStatus = function()
244{
245	return BX.debugEnableFlag || true;
246};
247
248BX.is_subclass_of = function(ob, parent_class)
249{
250	if (ob instanceof parent_class)
251		return true;
252
253	if (parent_class.superclass)
254		return BX.is_subclass_of(ob, parent_class.superclass);
255
256	return false;
257};
258
259BX.clearNodeCache = function()
260{
261	NODECACHE = {};
262	return false;
263};
264
265BX.bitrix_sessid = function() {return BX.message("bitrix_sessid"); };
266
267/* DOM manipulation */
268/**
269 * Creates the specified HTML element
270 * @param {String} tag
271 * @param {Object} [data]
272 * @param {Document} [context]
273 * @returns {Element}
274 */
275BX.create = function(tag, data, context)
276{
277	context = context || document;
278
279	if (null == data && typeof tag == 'object' && tag.constructor !== String)
280	{
281		data = tag; tag = tag.tag;
282	}
283
284	var elem;
285	if (BX.browser.IsIE() && !BX.browser.IsIE9() && null != data && null != data.props && (data.props.name || data.props.id))
286	{
287		elem = context.createElement('<' + tag + (data.props.name ? ' name="' + data.props.name + '"' : '') + (data.props.id ? ' id="' + data.props.id + '"' : '') + '>');
288	}
289	else
290	{
291		elem = context.createElement(tag);
292	}
293
294	return data ? BX.adjust(elem, data) : elem;
295};
296
297BX.adjust = function(elem, data)
298{
299	var j,len;
300
301	if (!elem.nodeType)
302		return null;
303
304	if (elem.nodeType == 9)
305		elem = elem.body;
306
307	if (data.attrs)
308	{
309		for (j in data.attrs)
310		{
311			if(data.attrs.hasOwnProperty(j))
312			{
313				if (j == 'class' || j == 'className')
314					elem.className = data.attrs[j];
315				else if (j == 'for')
316					elem.htmlFor = data.attrs[j];
317				else if(data.attrs[j] == "")
318					elem.removeAttribute(j);
319				else
320					elem.setAttribute(j, data.attrs[j]);
321			}
322		}
323	}
324
325	if (data.style)
326	{
327		for (j in data.style)
328		{
329			if(data.style.hasOwnProperty(j))
330			{
331				elem.style[j] = data.style[j];
332			}
333		}
334	}
335
336	if (data.props)
337	{
338		for (j in data.props)
339		{
340			if(data.props.hasOwnProperty(j))
341			{
342				elem[j] = data.props[j];
343			}
344		}
345	}
346
347	if (data.events)
348	{
349		for (j in data.events)
350		{
351			if(data.events.hasOwnProperty(j))
352			{
353				BX.bind(elem, j, data.events[j]);
354			}
355		}
356	}
357
358	if (data.dataset)
359	{
360		for (j in data.dataset)
361		{
362			if(data.dataset.hasOwnProperty(j))
363			{
364				elem.dataset[j] = data.dataset[j]
365			}
366		}
367	}
368
369	if (data.children && data.children.length > 0)
370	{
371		for (j=0,len=data.children.length; j<len; j++)
372		{
373			if (BX.type.isNotEmptyString(data.children[j]))
374				elem.innerHTML += data.children[j];
375			else if (BX.type.isElementNode(data.children[j]))
376				elem.appendChild(data.children[j]);
377		}
378	}
379	else if (data.text)
380	{
381		BX.cleanNode(elem);
382		elem.appendChild((elem.ownerDocument || document).createTextNode(data.text));
383	}
384	else if (typeof data.html !== 'undefined')
385	{
386		elem.innerHTML = data.html;
387	}
388
389	return elem;
390};
391
392BX.remove = function(ob)
393{
394	if (ob && null != ob.parentNode)
395		ob.parentNode.removeChild(ob);
396	ob = null;
397	return null;
398};
399
400BX.cleanNode = function(node, bSuicide)
401{
402	node = BX(node);
403	bSuicide = !!bSuicide;
404
405	if (node && node.childNodes)
406	{
407		while(node.childNodes.length > 0)
408			node.removeChild(node.firstChild);
409	}
410
411	if (node && bSuicide)
412	{
413		node = BX.remove(node);
414	}
415
416	return node;
417};
418
419BX.html = function(node, html, parameters)
420{
421	if(typeof html == 'undefined')
422		return node.innerHTML;
423
424	if(typeof parameters == 'undefined')
425		parameters = {};
426
427	html = BX.processHTML(html.toString());
428
429	var assets = [];
430	var inlineJS = [];
431
432	if(typeof html.STYLE != 'undefined' && html.STYLE.length > 0)
433	{
434		for(var k in html.STYLE)
435			assets.push(html.STYLE[k]);
436	}
437
438	if(typeof html.SCRIPT != 'undefined' && html.SCRIPT.length > 0)
439	{
440		for(var k in html.SCRIPT)
441		{
442			if(html.SCRIPT[k].isInternal)
443				inlineJS.push(html.SCRIPT[k].JS);
444			else
445				assets.push(html.SCRIPT[k].JS);
446		}
447	}
448
449	if(parameters.htmlFirst && typeof html.HTML != 'undefined' && node)
450	{
451		node.innerHTML = html.HTML;
452	}
453
454	var p = new BX.Promise();
455
456	var afterAsstes = function(){
457		if(!parameters.htmlFirst && typeof html.HTML != 'undefined' && node)
458		{
459			node.innerHTML = html.HTML;
460		}
461
462		for(var k in inlineJS)
463		{
464			BX.evalGlobal(inlineJS[k]);
465		}
466
467		if(BX.type.isFunction(parameters.callback))
468		{
469			parameters.callback();
470		}
471
472		p.fulfill();
473	};
474
475	if(assets.length > 0)
476	{
477		BX.load(assets, afterAsstes);
478	}
479	else
480	{
481		afterAsstes();
482	}
483
484	return p;
485};
486
487BX.insertAfter = function(node, dstNode)
488{
489	dstNode.parentNode.insertBefore(node, dstNode.nextSibling);
490};
491
492BX.prepend = function(node, dstNode)
493{
494	dstNode.insertBefore(node, dstNode.firstChild);
495};
496
497BX.append = function(node, dstNode)
498{
499	dstNode.appendChild(node);
500};
501
502BX.addClass = function(ob, value)
503{
504	var classNames;
505	ob = BX(ob);
506
507	value = BX.util.trim(value);
508	if (value == '')
509		return ob;
510
511	if (ob)
512	{
513		if (!ob.className)
514		{
515			ob.className = value
516		}
517		else if (!!ob.classList && value.indexOf(' ') < 0)
518		{
519			ob.classList.add(value);
520		}
521		else
522		{
523			classNames = (value || "").split(r.space);
524
525			var className = " " + ob.className + " ";
526			for (var j = 0, cl = classNames.length; j < cl; j++)
527			{
528				if (className.indexOf(" " + classNames[j] + " ") < 0)
529				{
530					ob.className += " " + classNames[j];
531				}
532			}
533		}
534	}
535
536	return ob;
537};
538
539BX.removeClass = function(ob, value)
540{
541	ob = BX(ob);
542	if (ob)
543	{
544		if (ob.className && !!value)
545		{
546			if (BX.type.isString(value))
547			{
548				if (!!ob.classList && value.indexOf(' ') < 0)
549				{
550					ob.classList.remove(value);
551				}
552				else
553				{
554					var classNames = value.split(r.space), className = " " + ob.className + " ";
555					for (var j = 0, cl = classNames.length; j < cl; j++)
556					{
557						className = className.replace(" " + classNames[j] + " ", " ");
558					}
559
560					ob.className = BX.util.trim(className);
561				}
562			}
563			else
564			{
565				ob.className = "";
566			}
567		}
568	}
569
570	return ob;
571};
572
573BX.toggleClass = function(ob, value)
574{
575	var className;
576	ob = BX(ob);
577
578	if (BX.type.isArray(value))
579	{
580		className = ' ' + ob.className + ' ';
581		for (var j = 0, len = value.length; j < len; j++)
582		{
583			if (BX.hasClass(ob, value[j]))
584			{
585				className = (' ' + className + ' ').replace(' ' + value[j] + ' ', ' ');
586				className += ' ' + value[j >= len-1 ? 0 : j+1];
587
588				j--;
589				break;
590			}
591		}
592
593		if (j == len)
594			ob.className += ' ' + value[0];
595		else
596			ob.className = className;
597
598		ob.className = BX.util.trim(ob.className);
599	}
600	else if (BX.type.isNotEmptyString(value))
601	{
602		if (!!ob.classList)
603		{
604			ob.classList.toggle(value);
605		}
606		else
607		{
608			className = ob.className;
609			if (BX.hasClass(ob, value))
610			{
611				className = (' ' + className + ' ').replace(' ' + value + ' ', ' ');
612			}
613			else
614			{
615				className += ' ' + value;
616			}
617
618			ob.className = BX.util.trim(className);
619		}
620	}
621
622	return ob;
623};
624
625BX.hasClass = function(el, className)
626{
627	el = BX(el);
628	if (!el || !BX.type.isDomNode(el))
629	{
630		BX.debug(el);
631		return false;
632	}
633
634	if (!el.className || !className)
635	{
636		return false;
637	}
638
639	if (!!el.classList && !!className && className.indexOf(' ') < 0)
640	{
641		return el.classList.contains(BX.util.trim(className));
642	}
643	else
644		return ((" " + el.className + " ").indexOf(" " + className + " ")) >= 0;
645};
646
647BX.setOpacity = function(ob, percentage)
648{
649	if (ob.style.filter != null)
650	{
651		//IE
652		ob.style.zoom = "100%";
653
654		if (percentage == 100)
655		{
656			ob.style.filter = "";
657		}
658		else
659		{
660			ob.style.filter = 'alpha(opacity=' + percentage.toString() + ')';
661		}
662	}
663	else if (ob.style.opacity != null)
664	{
665		// W3C
666		ob.style.opacity = (percentage / 100).toString();
667	}
668	else if (ob.style.MozOpacity != null)
669	{
670		// Mozilla
671		ob.style.MozOpacity = (percentage / 100).toString();
672	}
673};
674
675BX.hoverEvents = function(el)
676{
677	if (el)
678		return BX.adjust(el, {events: BX.hoverEvents()});
679	else
680		return {mouseover: BX.hoverEventsHover, mouseout: BX.hoverEventsHout};
681};
682
683BX.hoverEventsHover = function(){BX.addClass(this,'bx-hover');this.BXHOVER=true;};
684BX.hoverEventsHout = function(){BX.removeClass(this,'bx-hover');this.BXHOVER=false;};
685
686BX.focusEvents = function(el)
687{
688	if (el)
689		return BX.adjust(el, {events: BX.focusEvents()});
690	else
691		return {mouseover: BX.focusEventsFocus, mouseout: BX.focusEventsBlur};
692};
693
694BX.focusEventsFocus = function(){BX.addClass(this,'bx-focus');this.BXFOCUS=true;};
695BX.focusEventsBlur = function(){BX.removeClass(this,'bx-focus');this.BXFOCUS=false;};
696
697BX.setUnselectable = function(node)
698{
699	node.style.userSelect = node.style.MozUserSelect = node.style.WebkitUserSelect = node.style.KhtmlUserSelect = node.style = 'none';
700	node.setAttribute('unSelectable', 'on');
701};
702
703BX.setSelectable = function(node)
704{
705	node.style.userSelect = node.style.MozUserSelect = node.style.WebkitUserSelect = node.style.KhtmlUserSelect = node.style = '';
706	node.removeAttribute('unSelectable');
707};
708
709BX.styleIEPropertyName = function(name)
710{
711	if (name == 'float')
712		name = BX.browser.IsIE() ? 'styleFloat' : 'cssFloat';
713	else
714	{
715		var res = BX.browser.isPropertySupported(name);
716		if (res)
717		{
718			name = res;
719		}
720		else
721		{
722			var reg = /(\-([a-z]){1})/g;
723			if (reg.test(name))
724			{
725				name = name.replace(reg, function () {return arguments[2].toUpperCase();});
726			}
727		}
728	}
729	return name;
730};
731
732/* CSS-notation should be used here */
733BX.style = function(el, property, value)
734{
735	if (!BX.type.isElementNode(el))
736		return null;
737
738	if (value == null)
739	{
740		var res;
741
742		if(el.currentStyle)
743			res = el.currentStyle[BX.styleIEPropertyName(property)];
744		else if(window.getComputedStyle)
745		{
746			var q = BX.browser.isPropertySupported(property, true);
747			if (!!q)
748				property = q;
749
750			res = BX.GetContext(el).getComputedStyle(el, null).getPropertyValue(property);
751		}
752
753		if(!res)
754			res = '';
755		return res;
756	}
757	else
758	{
759		el.style[BX.styleIEPropertyName(property)] = value;
760		return el;
761	}
762};
763
764BX.focus = function(el)
765{
766	try
767	{
768		el.focus();
769		return true;
770	}
771	catch (e)
772	{
773		return false;
774	}
775};
776
777BX.firstChild = function(el)
778{
779	var e = el.firstChild;
780	while (e && !BX.type.isElementNode(e))
781	{
782		e = e.nextSibling;
783	}
784
785	return e;
786};
787
788BX.lastChild = function(el)
789{
790	var e = el.lastChild;
791	while (e && !BX.type.isElementNode(e))
792	{
793		e = e.previousSibling;
794	}
795
796	return e;
797};
798
799BX.previousSibling = function(el)
800{
801	var e = el.previousSibling;
802	while (e && !BX.type.isElementNode(e))
803	{
804		e = e.previousSibling;
805	}
806
807	return e;
808};
809
810BX.nextSibling = function(el)
811{
812	var e = el.nextSibling;
813	while (e && !BX.type.isElementNode(e))
814	{
815		e = e.nextSibling;
816	}
817
818	return e;
819};
820
821/*
822	params: {
823		obj : html node
824		className : className value
825		recursive : used only for older browsers to optimize the tree traversal, in new browsers the search is always recursively, default - true
826	}
827
828	Search all nodes with className
829*/
830BX.findChildrenByClassName = function(obj, className, recursive)
831{
832	if(!obj || !obj.childNodes) return null;
833
834	var result = [];
835	if (typeof(obj.getElementsByClassName) == 'undefined')
836	{
837		recursive = recursive !== false;
838		result = BX.findChildren(obj, {className : className}, recursive);
839	}
840	else
841	{
842		var col = obj.getElementsByClassName(className);
843		for (i=0,l=col.length;i<l;i++)
844		{
845			result[i] = col[i];
846		}
847	}
848	return result;
849};
850
851/*
852	params: {
853		obj : html node
854		className : className value
855		recursive : used only for older browsers to optimize the tree traversal, in new browsers the search is always recursively, default - true
856	}
857
858	Search first node with className
859*/
860BX.findChildByClassName = function(obj, className, recursive)
861{
862	if(!obj || !obj.childNodes) return null;
863
864	var result = null;
865	if (typeof(obj.getElementsByClassName) == 'undefined')
866	{
867		recursive = recursive !== false;
868		result = BX.findChild(obj, {className : className}, recursive);
869	}
870	else
871	{
872		var col = obj.getElementsByClassName(className);
873		if (col && typeof(col[0]) != 'undefined')
874		{
875			result = col[0];
876		}
877		else
878		{
879			result = null;
880		}
881	}
882	return result;
883};
884
885/*
886	params: {
887		tagName|tag : 'tagName',
888		className|class : 'className',
889		attribute : {attribute : value, attribute : value} | attribute | [attribute, attribute....],
890		property : {prop: value, prop: value} | prop | [prop, prop]
891	}
892
893	all values can be RegExps or strings
894*/
895BX.findChildren = function(obj, params, recursive)
896{
897	return BX.findChild(obj, params, recursive, true);
898};
899
900BX.findChild = function(obj, params, recursive, get_all)
901{
902	if(!obj || !obj.childNodes) return null;
903
904	recursive = !!recursive; get_all = !!get_all;
905
906	var n = obj.childNodes.length, result = [];
907
908	for (var j=0; j<n; j++)
909	{
910		var child = obj.childNodes[j];
911
912		if (_checkNode(child, params))
913		{
914			if (get_all)
915				result.push(child);
916			else
917				return child;
918		}
919
920		if(recursive == true)
921		{
922			var res = BX.findChild(child, params, recursive, get_all);
923			if (res)
924			{
925				if (get_all)
926					result = BX.util.array_merge(result, res);
927				else
928					return res;
929			}
930		}
931	}
932
933	if (get_all || result.length > 0)
934		return result;
935	else
936		return null;
937};
938
939BX.findParent = function(obj, params, maxParent)
940{
941	if(!obj)
942		return null;
943
944	var o = obj;
945	while(o.parentNode)
946	{
947		var parent = o.parentNode;
948
949		if (_checkNode(parent, params))
950			return parent;
951
952		o = parent;
953
954		if (!!maxParent &&
955			(BX.type.isFunction(maxParent)
956				|| typeof maxParent == 'object'))
957		{
958			if (BX.type.isElementNode(maxParent))
959			{
960				if (o == maxParent)
961					break;
962			}
963			else
964			{
965				if (_checkNode(o, maxParent))
966					break;
967			}
968		}
969	}
970	return null;
971};
972
973BX.findNextSibling = function(obj, params)
974{
975	if(!obj)
976		return null;
977	var o = obj;
978	while(o.nextSibling)
979	{
980		var sibling = o.nextSibling;
981		if (_checkNode(sibling, params))
982			return sibling;
983		o = sibling;
984	}
985	return null;
986};
987
988BX.findPreviousSibling = function(obj, params)
989{
990	if(!obj)
991		return null;
992
993	var o = obj;
994	while(o.previousSibling)
995	{
996		var sibling = o.previousSibling;
997		if(_checkNode(sibling, params))
998			return sibling;
999		o = sibling;
1000	}
1001	return null;
1002};
1003
1004BX.checkNode = function(obj, params)
1005{
1006	return _checkNode(obj, params);
1007};
1008
1009BX.findFormElements = function(form)
1010{
1011	if (BX.type.isString(form))
1012		form = document.forms[form]||BX(form);
1013
1014	var res = [];
1015
1016	if (BX.type.isElementNode(form))
1017	{
1018		if (form.tagName.toUpperCase() == 'FORM')
1019		{
1020			res = form.elements;
1021		}
1022		else
1023		{
1024			res = BX.findChildren(form, CHECK_FORM_ELEMENTS, true);
1025		}
1026	}
1027
1028	return res;
1029};
1030
1031BX.isParentForNode = function(whichNode, forNode)
1032{
1033
1034	if(!BX.type.isDomNode(whichNode) || !BX.type.isDomNode(forNode))
1035		return false;
1036
1037	while(true){
1038
1039		if(whichNode == forNode)
1040			return true;
1041
1042		if(forNode && forNode.parentNode)
1043			forNode = forNode.parentNode;
1044		else
1045			break;
1046	}
1047
1048	return false;
1049};
1050
1051BX.clone = function(obj, bCopyObj)
1052{
1053	var _obj, i, l;
1054	if (bCopyObj !== false)
1055		bCopyObj = true;
1056
1057	if (obj === null)
1058		return null;
1059
1060	if (BX.type.isDomNode(obj))
1061	{
1062		_obj = obj.cloneNode(bCopyObj);
1063	}
1064	else if (typeof obj == 'object')
1065	{
1066		if (BX.type.isArray(obj))
1067		{
1068			_obj = [];
1069			for (i=0,l=obj.length;i<l;i++)
1070			{
1071				if (typeof obj[i] == "object" && bCopyObj)
1072					_obj[i] = BX.clone(obj[i], bCopyObj);
1073				else
1074					_obj[i] = obj[i];
1075			}
1076		}
1077		else
1078		{
1079			_obj =  {};
1080			if (obj.constructor)
1081			{
1082				if (BX.type.isDate(obj))
1083					_obj = new Date(obj);
1084				else
1085					_obj = new obj.constructor();
1086			}
1087
1088			for (i in obj)
1089			{
1090				if (typeof obj[i] == "object" && bCopyObj)
1091					_obj[i] = BX.clone(obj[i], bCopyObj);
1092				else
1093					_obj[i] = obj[i];
1094			}
1095		}
1096
1097	}
1098	else
1099	{
1100		_obj = obj;
1101	}
1102
1103	return _obj;
1104};
1105
1106// access private. use BX.mergeEx instead.
1107// todo: refactor BX.merge, make it work through BX.mergeEx
1108BX.merge = function(){
1109	var arg = Array.prototype.slice.call(arguments);
1110
1111	if(arg.length < 2)
1112		return {};
1113
1114	var result = arg.shift();
1115
1116	for(var i = 0; i < arg.length; i++)
1117	{
1118		for(var k in arg[i]){
1119
1120			if(typeof arg[i] == 'undefined' || arg[i] == null)
1121				continue;
1122
1123			if(arg[i].hasOwnProperty(k)){
1124
1125				if(typeof arg[i][k] == 'undefined' || arg[i][k] == null)
1126					continue;
1127
1128				if(typeof arg[i][k] == 'object' && !BX.type.isDomNode(arg[i][k]) && (typeof arg[i][k]['isUIWidget'] == 'undefined')){
1129
1130					// go deeper
1131
1132					var isArray = 'length' in arg[i][k];
1133
1134					if(typeof result[k] != 'object')
1135						result[k] = isArray ? [] : {};
1136
1137					if(isArray)
1138						BX.util.array_merge(result[k], arg[i][k]);
1139					else
1140						BX.merge(result[k], arg[i][k]);
1141
1142				}else
1143					result[k] = arg[i][k];
1144			}
1145		}
1146	}
1147
1148	return result;
1149};
1150
1151BX.mergeEx = function()
1152{
1153	var arg = Array.prototype.slice.call(arguments);
1154	if(arg.length < 2)
1155	{
1156		return {};
1157	}
1158
1159	var result = arg.shift();
1160	for (var i = 0; i < arg.length; i++)
1161	{
1162		for (var k in arg[i])
1163		{
1164			if (typeof arg[i] == "undefined" || arg[i] == null || !arg[i].hasOwnProperty(k))
1165			{
1166				continue;
1167			}
1168
1169			if (BX.type.isPlainObject(arg[i][k]) && BX.type.isPlainObject(result[k]))
1170			{
1171				BX.mergeEx(result[k], arg[i][k]);
1172			}
1173			else
1174			{
1175				result[k] = BX.type.isPlainObject(arg[i][k]) ? BX.clone(arg[i][k]) : arg[i][k];
1176			}
1177		}
1178	}
1179
1180	return result;
1181};
1182
1183/* events */
1184BX.bind = function(el, evname, func)
1185{
1186	if (!el)
1187	{
1188		return;
1189	}
1190
1191	if (evname === 'mousewheel')
1192	{
1193		BX.bind(el, 'DOMMouseScroll', func);
1194	}
1195	else if (evname === 'transitionend')
1196	{
1197		BX.bind(el, 'webkitTransitionEnd', func);
1198		BX.bind(el, 'msTransitionEnd', func);
1199		BX.bind(el, 'oTransitionEnd', func);
1200		// IE8-9 doesn't support this feature!
1201	}
1202	else if (evname === 'bxchange')
1203	{
1204		BX.bind(el, "change", func);
1205		BX.bind(el, "cut", func);
1206		BX.bind(el, "paste", func);
1207		BX.bind(el, "drop", func);
1208		BX.bind(el, "keyup", func);
1209
1210		return;
1211	}
1212	else if (evname === 'fullscreenchange')
1213	{
1214		if (document.cancelFullScreen)
1215			BX.bind(el, "fullscreenchange", func);
1216		else if (document.mozCancelFullScreen)
1217			BX.bind(el, "mozfullscreenchange", func);
1218		else if (document.webkitCancelFullScreen)
1219			BX.bind(el, "webkitfullscreenchange", func);
1220	}
1221
1222	if (el.addEventListener) // Gecko / W3C
1223	{
1224		el.addEventListener(evname, func, false);
1225	}
1226	else if (el.attachEvent) // IE
1227	{
1228		el.attachEvent("on" + evname, BX.proxy(func, el));
1229	}
1230	else
1231	{
1232		try
1233		{
1234			el["on" + evname] = func;
1235		}
1236		catch(e)
1237		{
1238			BX.debug(e)
1239		}
1240	}
1241
1242	eventsList[eventsList.length] = {'element': el, 'event': evname, 'fn': func};
1243};
1244
1245BX.unbind = function(el, evname, func)
1246{
1247	if (!el)
1248	{
1249		return;
1250	}
1251
1252	if (evname === 'mousewheel')
1253	{
1254		BX.unbind(el, 'DOMMouseScroll', func);
1255	}
1256	else if (evname === 'transitionend')
1257	{
1258		BX.unbind(el, 'webkitTransitionEnd', func);
1259		BX.unbind(el, 'msTransitionEnd', func);
1260		BX.unbind(el, 'oTransitionEnd', func);
1261	}
1262	else if (evname === 'bxchange')
1263	{
1264		BX.unbind(el, "change", func);
1265		BX.unbind(el, "cut", func);
1266		BX.unbind(el, "paste", func);
1267		BX.unbind(el, "drop", func);
1268		BX.unbind(el, "keyup", func);
1269
1270		return;
1271	}
1272
1273	if(el.removeEventListener) // Gecko / W3C
1274	{
1275		el.removeEventListener(evname, func, false);
1276	}
1277	else if(el.detachEvent) // IE
1278	{
1279		el.detachEvent("on" + evname, BX.proxy(func, el));
1280	}
1281	else
1282	{
1283		el["on" + evname] = null;
1284	}
1285};
1286
1287BX.getEventButton = function(e)
1288{
1289	e = e || window.event;
1290
1291	var flags = 0;
1292
1293	if (typeof e.which != 'undefined')
1294	{
1295		switch (e.which)
1296		{
1297			case 1: flags = flags|BX.MSLEFT; break;
1298			case 2: flags = flags|BX.MSMIDDLE; break;
1299			case 3: flags = flags|BX.MSRIGHT; break;
1300		}
1301	}
1302	else if (typeof e.button != 'undefined')
1303	{
1304		flags = event.button;
1305	}
1306
1307	return flags || BX.MSLEFT;
1308};
1309
1310BX.unbindAll = function(el)
1311{
1312	if (!el)
1313		return;
1314
1315	for (var i=0,len=eventsList.length; i<len; i++)
1316	{
1317		try
1318		{
1319			if (eventsList[i] && (null==el || el==eventsList[i].element))
1320			{
1321				BX.unbind(eventsList[i].element, eventsList[i].event, eventsList[i].fn);
1322				eventsList[i] = null;
1323			}
1324		}
1325		catch(e){}
1326	}
1327
1328	if (null==el)
1329	{
1330		eventsList = [];
1331	}
1332};
1333
1334var captured_events = null, _bind = null;
1335BX.CaptureEvents = function(el_c, evname_c)
1336{
1337	if (_bind)
1338		return;
1339
1340	_bind = BX.bind;
1341	captured_events = [];
1342
1343	BX.bind = function(el, evname, func)
1344	{
1345		if (el === el_c && evname === evname_c)
1346			captured_events.push(func);
1347
1348		_bind.apply(this, arguments);
1349	}
1350};
1351
1352BX.CaptureEventsGet = function()
1353{
1354	if (_bind)
1355	{
1356		BX.bind = _bind;
1357
1358		var captured = captured_events;
1359
1360		_bind = null;
1361		captured_events = null;
1362		return captured;
1363	}
1364	return null;
1365};
1366
1367// Don't even try to use it for submit event!
1368BX.fireEvent = function(ob,ev)
1369{
1370	var result = false, e = null;
1371	if (BX.type.isDomNode(ob))
1372	{
1373		result = true;
1374		if (document.createEventObject)
1375		{
1376			// IE
1377			if (eventTypes[ev] != 'MouseEvent')
1378			{
1379				e = document.createEventObject();
1380				e.type = ev;
1381				result = ob.fireEvent('on' + ev, e);
1382			}
1383
1384			if (ob[ev])
1385			{
1386				ob[ev]();
1387			}
1388		}
1389		else
1390		{
1391			// non-IE
1392			e = null;
1393
1394			switch (eventTypes[ev])
1395			{
1396				case 'MouseEvent':
1397					e = document.createEvent('MouseEvent');
1398					try
1399					{
1400						e.initMouseEvent(ev, true, true, top, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
1401					}
1402					catch (initException)
1403					{
1404						e.initMouseEvent(ev, true, true, window, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
1405					}
1406
1407				break;
1408				default:
1409					e = document.createEvent('Event');
1410					e.initEvent(ev, true, true);
1411			}
1412
1413			result = ob.dispatchEvent(e);
1414		}
1415	}
1416
1417	return result;
1418};
1419
1420BX.getWheelData = function(e)
1421{
1422	e = e || window.event;
1423	e.wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;
1424	return e.wheelData;
1425};
1426
1427BX.proxy_context = null;
1428
1429BX.delegate = function (func, thisObject)
1430{
1431	if (!func || !thisObject)
1432		return func;
1433
1434	return function() {
1435		var cur = BX.proxy_context;
1436		BX.proxy_context = this;
1437		var res = func.apply(thisObject, arguments);
1438		BX.proxy_context = cur;
1439		return res;
1440	}
1441};
1442
1443BX.delegateLater = function (func_name, thisObject, contextObject)
1444{
1445	return function()
1446	{
1447		if (thisObject[func_name])
1448		{
1449			var cur = BX.proxy_context;
1450			BX.proxy_context = this;
1451			var res = thisObject[func_name].apply(contextObject||thisObject, arguments);
1452			BX.proxy_context = cur;
1453			return res;
1454		}
1455		return null;
1456	}
1457};
1458
1459BX._initObjectProxy = function(thisObject)
1460{
1461	if (typeof thisObject['__proxy_id_' + proxySalt] == 'undefined')
1462	{
1463		thisObject['__proxy_id_' + proxySalt] = proxyList.length;
1464		proxyList[thisObject['__proxy_id_' + proxySalt]] = {};
1465	}
1466};
1467
1468BX.proxy = function(func, thisObject)
1469{
1470	if (!func || !thisObject)
1471		return func;
1472
1473	BX._initObjectProxy(thisObject);
1474
1475	if (typeof func['__proxy_id_' + proxySalt] == 'undefined')
1476		func['__proxy_id_' + proxySalt] = proxyId++;
1477
1478	if (!proxyList[thisObject['__proxy_id_' + proxySalt]][func['__proxy_id_' + proxySalt]])
1479		proxyList[thisObject['__proxy_id_' + proxySalt]][func['__proxy_id_' + proxySalt]] = BX.delegate(func, thisObject);
1480
1481	return proxyList[thisObject['__proxy_id_' + proxySalt]][func['__proxy_id_' + proxySalt]];
1482};
1483
1484BX.defer = function(func, thisObject)
1485{
1486	if (!!thisObject)
1487		return BX.defer_proxy(func, thisObject);
1488	else
1489		return function() {
1490			var arg = arguments;
1491			setTimeout(function(){func.apply(this,arg)}, 10);
1492		};
1493};
1494
1495BX.defer_proxy = function(func, thisObject)
1496{
1497	if (!func || !thisObject)
1498		return func;
1499
1500	BX.proxy(func, thisObject);
1501
1502	this._initObjectProxy(thisObject);
1503
1504	if (typeof func['__defer_id_' + proxySalt] == 'undefined')
1505		func['__defer_id_' + proxySalt] = proxyId++;
1506
1507	if (!proxyList[thisObject['__proxy_id_' + proxySalt]][func['__defer_id_' + proxySalt]])
1508	{
1509		proxyList[thisObject['__proxy_id_' + proxySalt]][func['__defer_id_' + proxySalt]] = BX.defer(
1509BX.delegate(func, thisObject));
1510	}
1511
1512	return proxyList[thisObject['__proxy_id_' + proxySalt]][func['__defer_id_' + proxySalt]];
1513};
1514
1515BX.once = function(el, evname, func)
1516{
1517	if (typeof func['__once_id_' + evname + '_' + proxySalt] == 'undefined')
1518	{
1519		func['__once_id_' + evname + '_' + proxySalt] = proxyId++;
1520	}
1521
1522	this._initObjectProxy(el);
1523
1524	if (!proxyList[el['__proxy_id_' + proxySalt]][func['__once_id_' + evname + '_' + proxySalt]])
1525	{
1526		var g = function()
1527		{
1528			BX.unbind(el, evname, g);
1529			func.apply(this, arguments);
1530		};
1531
1532		proxyList[el['__proxy_id_' + proxySalt]][func['__once_id_' + evname + '_' + proxySalt]] = g;
1533	}
1534
1535	return proxyList[el['__proxy_id_' + proxySalt]][func['__once_id_' + evname + '_' + proxySalt]];
1536};
1537
1538BX.bindDelegate = function (elem, eventName, isTarget, handler)
1539{
1540	var h = BX.delegateEvent(isTarget, handler);
1541	BX.bind(elem, eventName, h);
1542	return h;
1543};
1544
1545BX.delegateEvent = function(isTarget, handler)
1546{
1547	return function(e)
1548	{
1549		e = e || window.event;
1550		var target = e.target || e.srcElement;
1551
1552		while (target != this)
1553		{
1554			if (_checkNode(target, isTarget))
1555			{
1556				return handler.call(target, e);
1557			}
1558			if (target && target.parentNode)
1559				target = target.parentNode;
1560			else
1561				break;
1562		}
1563		return null;
1564	}
1565};
1566
1567BX.False = function() {return false;};
1568BX.DoNothing = function() {};
1569
1570// TODO: also check event handlers set via BX.bind()
1571BX.denyEvent = function(el, ev)
1572{
1573	deniedEvents.push([el, ev, el['on' + ev]]);
1574	el['on' + ev] = BX.DoNothing;
1575};
1576
1577BX.allowEvent = function(el, ev)
1578{
1579	for(var i=0, len=deniedEvents.length; i<len; i++)
1580	{
1581		if (deniedEvents[i][0] == el && deniedEvents[i][1] == ev)
1582		{
1583			el['on' + ev] = deniedEvents[i][2];
1584			BX.util.deleteFromArray(deniedEvents, i);
1585			return;
1586		}
1587	}
1588};
1589
1590BX.fixEventPageXY = function(event)
1591{
1592	BX.fixEventPageX(event);
1593	BX.fixEventPageY(event);
1594	return event;
1595};
1596
1597BX.fixEventPageX = function(event)
1598{
1599	if (event.pageX == null && event.clientX != null)
1600	{
1601		event.pageX =
1602			event.clientX +
1603			(document.documentElement && document.documentElement.scrollLeft || document.body && document.body.scrollLeft || 0) -
1604			(document.documentElement.clientLeft || 0);
1605	}
1606
1607	return event;
1608};
1609
1610BX.fixEventPageY = function(event)
1611{
1612	if (event.pageY == null && event.clientY != null)
1613	{
1614		event.pageY =
1615			event.clientY +
1616			(document.documentElement && document.documentElement.scrollTop || document.body && document.body.scrollTop || 0) -
1617			(document.documentElement.clientTop || 0);
1618	}
1619
1620	return event;
1621};
1622
1623/**
1624 * @deprecated
1625 * @see e.preventDefault()
1626 */
1627BX.PreventDefault = function(e)
1628{
1629	if(!e) e = window.event;
1630	if(e.stopPropagation)
1631	{
1632		e.preventDefault();
1633		e.stopPropagation();
1634	}
1635	else
1636	{
1637		e.cancelBubble = true;
1638		e.returnValue = false;
1639	}
1640	return false;
1641};
1642
1643BX.eventReturnFalse = function(e)
1644{
1645	e=e||window.event;
1646	if (e && e.preventDefault) e.preventDefault();
1647	else e.returnValue = false;
1648	return false;
1649};
1650
1651BX.eventCancelBubble = function(e)
1652{
1653	e=e||window.event;
1654	if(e && e.stopPropagation)
1655		e.stopPropagation();
1656	else
1657		e.cancelBubble = true;
1658};
1659
1660/* custom events */
1661/*
1662	BX.addCustomEvent(eventObject, eventName, eventHandler) - set custom event handler for particular object
1663	BX.addCustomEvent(eventName, eventHandler) - set custom event handler for all objects
1664*/
1665BX.addCustomEvent = function(eventObject, eventName, eventHandler)
1666{
1667	/* shift parameters for short version */
1668	if (BX.type.isString(eventObject))
1669	{
1670		eventHandler = eventName;
1671		eventName = eventObject;
1672		eventObject = window;
1673	}
1674
1675	eventName = eventName.toUpperCase();
1676
1677	if (!customEvents[eventName])
1678		customEvents[eventName] = [];
1679
1680	customEvents[eventName].push(
1681		{
1682			handler: eventHandler,
1683			obj: eventObject
1684		}
1685	);
1686};
1687
1688BX.removeCustomEvent = function(eventObject, eventName, eventHandler)
1689{
1690	/* shift parameters for short version */
1691	if (BX.type.isString(eventObject))
1692	{
1693		eventHandler = eventName;
1694		eventName = eventObject;
1695		eventObject = window;
1696	}
1697
1698	eventName = eventName.toUpperCase();
1699
1700	if (!customEvents[eventName])
1701		return;
1702
1703	for (var i = 0, l = customEvents[eventName].length; i < l; i++)
1704	{
1705		if (!customEvents[eventName][i])
1706			continue;
1707		if (customEvents[eventName][i].handler == eventHandler && customEvents[eventName][i].obj == eventObject)
1708		{
1709			delete customEvents[eventName][i];
1710			return;
1711		}
1712	}
1713};
1714
1715// Warning! Don't use secureParams with DOM nodes in arEventParam
1715s
1716BX.onCustomEvent = function(eventObject, eventName, arEventParams, secureParams)
1717{
1718	/* shift parameters for short version */
1719	if (BX.type.isString(eventObject))
1720	{
1721		secureParams = arEventParams;
1722		arEventParams = eventName;
1723		eventName = eventObject;
1724		eventObject = window;
1725	}
1726
1727	eventName = eventName.toUpperCase();
1728
1729	if (!customEvents[eventName])
1730		return;
1731
1732	if (!arEventParams)
1733		arEventParams = [];
1734
1735	var h;
1736	for (var i = 0, l = customEvents[eventName].length; i < l; i++)
1737	{
1738		h = customEvents[eventName][i];
1739		if (!h || !h.handler)
1740			continue;
1741
1742		if (h.obj == window || /*eventObject == window || */h.obj == eventObject) //- only global event handlers will be called
1743		{
1744			h.handler.apply(eventObject, !!secureParams ? BX.clone(arEventParams) : arEventParams);
1745		}
1746	}
1747};
1748
1749BX.bindDebouncedChange = function(node, fn, fnInstant, timeout, ctx)
1750{
1751	ctx = ctx || window;
1752	timeout = timeout || 300;
1753
1754	var dataTag = 'bx-dc-previous-value';
1755	BX.data(node, dataTag, node.value);
1756
1757	var act = function(fn, val){
1758
1759		var pVal = BX.data(node, dataTag);
1760
1761		if(typeof pVal == 'undefined' || pVal != val){
1762			if(typeof ctx != 'object')
1763				fn(val);
1764			else
1765				fn.apply(ctx, [val]);
1766		}
1767	};
1768
1769	var actD = BX.debounce(function(){
1770		var val = node.value;
1771		act(fn, val);
1772		BX.data(node, dataTag, val);
1773	}, timeout);
1774
1775	BX.bind(node, 'keyup', actD);
1776	BX.bind(node, 'change', actD);
1777	BX.bind(node, 'input', actD);
1778
1779	if(BX.type.isFunction(fnInstant)){
1780
1781		var actI = function(){
1782			act(fnInstant, node.value);
1783		};
1784
1785		BX.bind(node, 'keyup', actI);
1786		BX.bind(node, 'change', actI);
1787		BX.bind(node, 'input', actI);
1788	}
1789};
1790
1791BX.parseJSON = function(data, context)
1792{
1793	var result = null;
1794	if (BX.type.isString(data))
1795	{
1796		try {
1797			if (data.indexOf("\n") >= 0)
1798				eval('result = ' + data);
1799			else
1800				result = (new Function("return " + data))();
1801		} catch(e) {
1802			BX.onCustomEvent(context, 'onParseJSONFailure', [data, context])
1803		}
1804	}
1805	else if(BX.type.isPlainObject(data))
1806	{
1807		return data;
1808	}
1809
1810	return result;
1811};
1812
1813/* ready */
1814BX.isReady = false;
1815BX.ready = function(handler)
1816{
1817	bindReady();
1818
1819	if (!BX.type.isFunction(handler))
1820	{
1821		BX.debug('READY: not a function! ', handler);
1822	}
1823	else
1824	{
1825		if (BX.isReady)
1826			handler.call(document);
1827		else if (readyList)
1828			readyList.push(handler);
1829	}
1830};
1831
1832BX.submit = function(obForm, action_name, action_value, onAfterSubmit)
1833{
1834	action_name = action_name || 'save';
1835	if (!obForm['BXFormSubmit_' + action_name])
1836	{
1837		obForm['BXFormSubmit_' + action_name] = obForm.appendChild(BX.create('INPUT', {
1838			'props': {
1839				'type': 'submit',
1840				'name': action_name,
1841				'value': action_value || 'Y'
1842			},
1843			'style': {
1844				'display': 'none'
1845			}
1846		}));
1847	}
1848
1849	if (obForm.sessid)
1850		obForm.sessid.value = BX.bitrix_sessid();
1851
1852	setTimeout(BX.delegate(function() {BX.fireEvent(this, 'click'); if (onAfterSubmit) onAfterSubmit();}, obForm['BXFormSubmit_' + action_name]), 10);
1853};
1854
1855// returns function which runs fn in timeout ms after returned function is finished being called
1856BX.debounce = function(fn, timeout, ctx)
1857{
1858	var timer = 0;
1859
1860	return function()
1861	{
1862		ctx = ctx || this;
1863		var args = arguments;
1864
1865		clearTimeout(timer);
1866
1867		timer = setTimeout(function()
1868		{
1869			fn.apply(ctx, args);
1870		}, timeout);
1871	}
1872};
1873
1874// returns function which runs fn and repeats every timeout ms while returned function is being called
1875BX.throttle = function(fn, timeout, ctx)
1876{
1877
1878	var timer = 0,
1879		args = null,
1880		invoke;
1881
1882	return function()
1883	{
1884		ctx = ctx || this;
1885		args = arguments;
1886		invoke = true;
1887
1888		if(!timer)
1889		{
1890			var q = function()
1891			{
1892				if(invoke)
1893				{
1894					fn.apply(ctx, args);
1895					invoke = false;
1896					timer = setTimeout(q, timeout);
1897				}
1898				else
1899				{
1900					timer = null;
1901				}
1902			};
1903			q();
1904		}
1905	};
1906};
1907
1908/* browser detection */
1909BX.browser = {
1910
1911	IsIE: function()
1912	{
1913		return bIE;
1914	},
1915
1916	IsIE6: function()
1917	{
1918		return (/MSIE 6/i.test(navigator.userAgent));
1919	},
1920
1921	IsIE7: function()
1922	{
1923		return (/MSIE 7/i.test(navigator.userAgent));
1924	},
1925
1926	IsIE8: function()
1927	{
1928		return (/MSIE 8/i.test(navigator.userAgent));
1929	},
1930
1931	IsIE9: function()
1932	{
1933		return !!document.documentMode && document.documentMode >= 9;
1934	},
1935
1936	IsIE10: function()
1937	{
1938		return !!document.documentMode && document.documentMode >= 10;
1939	},
1940
1941	IsIE11: function()
1942	{
1943		return BX.browser.DetectIeVersion() >= 11;
1944	},
1945
1946	IsOpera: function()
1947	{
1948		return bOpera;
1949	},
1950
1951	IsSafari: function()
1952	{
1953		return bSafari;
1954	},
1955
1956	IsFirefox: function()
1957	{
1958		return bFirefox;
1959	},
1960
1961	IsChrome: function()
1962	{
1963		return bChrome;
1964	},
1965
1966	IsMac: function()
1967	{
1968		return (/Macintosh/i.test(navigator.userAgent));
1969	},
1970
1971	IsAndroid: function()
1972	{
1973		return (/Android/i.test(navigator.userAgent));
1974	},
1975
1976	IsIOS: function()
1977	{
1978		return (/(iPad;)|(iPhone;)/i.test(navigator.userAgent));
1979	},
1980
1981	IsMobile: function()
1982	{
1983		return (/(ipad|iphone|android|mobile|touch)/i.test(navigator.userAgent));
1984	},
1985
1986	DetectIeVersion: function()
1987	{
1988		if(BX.browser.IsOpera() || BX.browser.IsSafari() || BX.browser.IsFirefox() || BX.browser.IsChrome())
1989		{
1990			return -1;
1991		}
1992
1993		var rv = -1;
1994		if (!!(window.MSStream) && !(window.ActiveXObject) && ("ActiveXObject" in window))
1995		{
1996			//Primary check for IE 11 based on ActiveXObject behaviour (please see http://msdn.microsoft.com/en-us
1996/library/ie/dn423948%28v=vs.85%29.aspx)
1997			rv = 11;
1998		}
1999		else if (BX.browser.IsIE10())
2000		{
2001			rv = 10;
2002		}
2003		else if (BX.browser.IsIE9())
2004		{
2005			rv = 9;
2006		}
2007		else if (BX.browser.IsIE())
2008		{
2009			rv = 8;
2010		}
2011
2012		if (rv == -1 || rv == 8)
2013		{
2014			var re;
2015			if (navigator.appName == "Microsoft Internet Explorer")
2016			{
2017				re = new RegExp("MSIE ([0-9]+[\.0-9]*)");
2018				if (re.exec(navigator.userAgent) != null)
2019					rv = parseFloat( RegExp.$1 );
2020			}
2021			else if (navigator.appName == "Netscape")
2022			{
2023				//Alternative check for IE 11
2024				rv = 11;
2025				re = new RegExp("Trident/.*rv:([0-9]+[\.0-9]*)");
2026				if (re.exec(navigator.userAgent) != null)
2027					rv = parseFloat( RegExp.$1 );
2028			}
2029		}
2030
2031		return rv;
2032	},
2033
2034	IsDoctype: function(pDoc)
2035	{
2036		pDoc = pDoc || document;
2037
2038		if (pDoc.compatMode)
2039			return (pDoc.compatMode == "CSS1Compat");
2040
2041		return (pDoc.documentElement && pDoc.documentElement.clientHeight);
2042	},
2043
2044	SupportLocalStorage: function()
2045	{
2046		return !!BX.localStorage && !!BX.localStorage.checkBrowser()
2047	},
2048
2049	addGlobalClass: function() {
2050
2051		var globalClass = "bx-core";
2052		if (BX.hasClass(document.documentElement, globalClass))
2053		{
2054			return;
2055		}
2056
2057		//Mobile
2058		if (BX.browser.IsIOS())
2059		{
2060			globalClass += " bx-ios";
2061		}
2062		else if (BX.browser.IsMac())
2063		{
2064			globalClass += " bx-mac";
2065		}
2066		else if (BX.browser.IsAndroid())
2067		{
2068			globalClass += " bx-android";
2069		}
2070
2071		globalClass += (BX.browser.IsMobile() ? " bx-touch" : " bx-no-touch");
2072		globalClass += (BX.browser.isRetina() ? " bx-retina" : " bx-no-retina");
2073
2074		//Desktop
2075		var ieVersion = -1;
2076		if (/AppleWebKit/.test(navigator.userAgent))
2077		{
2078			globalClass += " bx-chrome";
2079		}
2080		else if ((ieVersion = BX.browser.DetectIeVersion()) > 0)
2081		{
2082			globalClass += " bx-ie bx-ie" + ieVersion;
2083			if (ieVersion > 7 && ieVersion < 10 && !BX.browser.IsDoctype())
2084			{
2085				// it seems IE10 doesn't have any specific bugs like others event in quirks mode
2086				globalClass += " bx-quirks";
2087			}
2088		}
2089		else if (/Opera/.test(navigator.userAgent))
2090		{
2091			globalClass += " bx-opera";
2092		}
2093		else if (/Gecko/.test(navigator.userAgent))
2094		{
2095			globalClass += " bx-firefox";
2096		}
2097
2098		BX.addClass(document.documentElement, globalClass);
2099	},
2100
2101	isPropertySupported: function(jsProperty, bReturnCSSName)
2102	{
2103		if (!BX.type.isNotEmptyString(jsProperty))
2104			return false;
2105
2106		var property = jsProperty.indexOf("-") > -1 ? getJsName(jsProperty) : jsProperty;
2107		bReturnCSSName = !!bReturnCSSName;
2108
2109		var ucProperty = property.charAt(0).toUpperCase() + property.slice(1);
2110		var properties = (property + ' ' + ["Webkit", "Moz", "O", "ms"].join(ucProperty + " ") + ucProperty).split(" ");
2111		var obj = document.body || document.documentElement;
2112
2113		for (var i = 0; i < properties.length; i++)
2114		{
2115			var prop = properties[i];
2116			if (obj.style[prop] !== undefined)
2117			{
2118				var prefix = prop == property
2119							? ""
2120							: "-" + prop.substr(0, prop.length - property.length).toLowerCase() + "-";
2121				return bReturnCSSName ? prefix + getCssName(property) : prop;
2122			}
2123		}
2124
2125		function getCssName(propertyName)
2126		{
2127			return propertyName.replace(/([A-Z])/g, function() { return "-" + arguments[1].toLowerCase(); } )
2128		}
2129
2130		function getJsName(cssName)
2131		{
2132			var reg = /(\-([a-z]){1})/g;
2133			if (reg.test(cssName))
2134				return cssName.replace(reg, function () {return arguments[2].toUpperCase();});
2135			else
2136				return cssName;
2137		}
2138
2139		return false;
2140	},
2141
2142	addGlobalFeatures : function(features, prefix)
2143	{
2144		if (!BX.type.isArray(features))
2145			return;
2146
2147		var classNames = [];
2148		for (var i = 0; i < features.length; i++)
2149		{
2150			var support = !!BX.browser.isPropertySupported(features[i]);
2151			classNames.push( "bx-" + (support ? "" : "no-") + features[i].toLowerCase());
2152		}
2153		BX.addClass(document.documentElement, classNames.join(" "));
2154	},
2155
2156	isRetina : function()
2157	{
2158		return window.devicePixelRatio && window.devicePixelRatio >= 2;
2159	}
2160};
2161
2162/* low-level fx funcitons*/
2163BX.show = function(ob, displayType)
2164{
2165	if (ob.BXDISPLAY || !_checkDisplay(ob, displayType))
2166	{
2167		ob.style.display = ob.BXDISPLAY;
2168	}
2169};
2170
2171BX.hide = function(ob, displayType)
2172{
2173	if (!ob.BXDISPLAY)
2174		_checkDisplay(ob, displayType);
2175
2176	ob.style.display = 'none';
2177};
2178
2179BX.toggle = function(ob, values)
2180{
2181	if (!values && BX.type.isElementNode(ob))
2182	{
2183		var bShow = true;
2184		if (ob.BXDISPLAY)
2185			bShow = !_checkDisplay(ob);
2186		else
2187			bShow = ob.style.display == 'none';
2188
2189		if (bShow)
2190			BX.show(ob);
2191		else
2192			BX.hide(ob);
2193	}
2194	else if (BX.type.isArray(values))
2195	{
2196		for (var i=0,len=values.length; i<len; i++)
2197		{
2198			if (ob == values[i])
2199			{
2200				ob = values[i==len-1 ? 0 : i+1];
2201				break;
2202			}
2203		}
2204		if (i==len)
2205			ob = values[0];
2206	}
2207
2208	return ob;
2209};
2210
2211/* some useful util functions */
2212
2213BX.util = {
2214	array_values: function(ar)
2215	{
2216		if (!BX.type.isArray(ar))
2217			return BX.util._array_values_ob(ar);
2218		var arv = [];
2219		for(var i=0,l=ar.length;i<l;i++)
2220			if (ar[i] !== null && typeof ar[i] != 'undefined')
2221				arv.push(ar[i]);
2222		return arv;
2223	},
2224
2225	_array_values_ob: function(ar)
2226	{
2227		var arv = [];
2228		for(var i in ar)
2229			if (ar[i] !== null && typeof ar[i] != 'undefined')
2230				arv.push(ar[i]);
2231		return arv;
2232	},
2233
2234	array_keys: function(ar)
2235	{
2236		if (!BX.type.isArray(ar))
2237			return BX.util._array_keys_ob(ar);
2238		var arv = [];
2239		for(var i=0,l=ar.length;i<l;i++)
2240			if (ar[i] !== null && typeof ar[i] != 'undefined')
2241				arv.push(i);
2242		return arv;
2243	},
2244
2245	_array_keys_ob: function(ar)
2246	{
2247		var arv = [];
2248		for(var i in ar)
2249			if (ar[i] !== null && typeof ar[i] != 'undefined')
2250				arv.push(i);
2251		return arv;
2252	},
2253
2254	object_keys: function(obj)
2255	{
2256		var arv = [];
2257		for(var k in obj)
2258		{
2259			if(obj.hasOwnProperty(k))
2260			{
2261				arv.push(k);
2262			}
2263		}
2264		return arv;
2265	},
2266
2267	array_merge: function(first, second)
2268	{
2269		if (!BX.type.isArray(first)) first = [];
2270		if (!BX.type.isArray(second)) second = [];
2271
2272		var i = first.length, j = 0;
2273
2274		if (typeof second.length === "number")
2275		{
2276			for (var l = second.length; j < l; j++)
2277			{
2278				first[i++] = second[j];
2279			}
2280		}
2281		else
2282		{
2283			while (second[j] !== undefined)
2284			{
2285				first[i++] = second[j++];
2286			}
2287		}
2288
2289		first.length = i;
2290
2291		return first;
2292	},
2293	
2294	array_flip: function ( object ) 
2295	{
2296	    var newObject = {};
2297		
2298	    for (var key in object) 
2299		{
2300	        newObject[object[key]] = key;
2301	    }
2302		
2303	    return newObject;
2304	},
2305
2306	array_unique: function(ar)
2307	{
2308		var i=0,j,len=ar.length;
2309		if(len<2) return ar;
2310
2311		for (; i<len-1;i++)
2312		{
2313			for (j=i+1; j<len;j++)
2314			{
2315				if (ar[i]==ar[j])
2316				{
2317					ar.splice(j--,1); len--;
2318				}
2319			}
2320		}
2321
2322		return ar;
2323	},
2324
2325	in_array: function(needle, haystack)
2326	{
2327		for(var i=0; i<haystack.length; i++)
2328		{
2329			if(haystack[i] == needle)
2330				return true;
2331		}
2332		return false;
2333	},
2334
2335	array_search: function(needle, haystack)
2336	{
2337		for(var i=0; i<haystack.length; i++)
2338		{
2339			if(haystack[i] == needle)
2340				return i;
2341		}
2342		return -1;
2343	},
2344
2345	object_search_key: function(needle, haystack)
2346	{
2347		if (typeof haystack[needle] != 'undefined')
2348			return haystack[needle];
2349
2350		for(var i in haystack)
2351		{
2352			if (typeof haystack[i] == "object")
2353			{
2354				var result = BX.util.object_search_key(needle, haystack[i]);
2355				if (result !== false)
2356					return result;
2357			}
2358		}
2359		return false;
2360	},
2361
2362	trim: function(s)
2363	{
2364		if (BX.type.isString(s))
2365			return s.replace(r.ltrim, '').replace(r.rtrim, '');
2366		else
2367			return s;
2368	},
2369
2370	urlencode: function(s){return encodeURIComponent(s);},
2371
2372	// it may also be useful. via sVD.
2373	deleteFromArray: function(ar, ind) {return ar.slice(0, ind).concat(ar.slice(ind + 1));},
2374	insertIntoArray: function(ar, ind, el) {return ar.slice(0, ind).concat([el]).concat(ar.slice(ind));},
2375
2376	htmlspecialchars: function(str)
2377	{
2378		if(!str.replace) return str;
2379
2380		return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2381	},
2382
2383	htmlspecialcharsback: function(str)
2384	{
2385		if(!str.replace) return str;
2386
2387		return str.replace(/\&quot;/g, '"').replace(/&#39;/g, "'").replace(/\&lt;/g, '<').replace(/\&gt;/g, '>').replace(/\&amp;/g, '&');
2388	},
2389
2390	// Quote regular expression characters plus an optional character
2391	preg_quote: function(str, delimiter)
2392	{
2393		if(!str.replace)
2394			return str;
2395		return str.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&');
2396	},
2397
2398	jsencode: function(str)
2399	{
2400		if (!str || !str.replace)
2401			return str;
2402
2403		var escapes =
2404		[
2405			{ c: "\\\\", r: "\\\\" }, // should be first
2406			{ c: "\\t", r: "\\t" },
2407			{ c: "\\n", r: "\\n" },
2408			{ c: "\\r", r: "\\r" },
2409			{ c: "\"", r: "\\\"" },
2410			{ c: "'", r: "\\'" },
2411			{ c: "<", r: "\\x3C" },
2412			{ c: ">", r: "\\x3E" },
2413			{ c: "\\u2028", r: "\\u2028" },
2414			{ c: "\\u2029", r: "\\u2029" }
2415		];
2416		for (var i = 0; i < escapes.length; i++)
2417			str = str.replace(new RegExp(escapes[i].c, 'g'), escapes[i].r);
2418		return str;
2419	},
2420
2421	nl2br: function(str)
2422	{
2423		if (!str || !str.replace)
2424			return str;
2425
2426		return str.replace(/([^>])\n/g, '$1<br/>');
2427	},
2428
2429	str_pad: function(input, pad_length, pad_string, pad_type)
2430	{
2431		pad_string = pad_string || ' ';
2432		pad_type = pad_type || 'right';
2433		input = input.toString();
2434
2435		if (pad_type == 'left')
2436			return BX.util.str_pad_left(input, pad_length, pad_string);
2437		else
2438			return BX.util.str_pad_right(input, pad_length, pad_string);
2439
2440	},
2441
2442	str_pad_left: function(input, pad_length, pad_string)
2443	{
2444		var i = input.length, q=pad_string.length;
2445		if (i >= pad_length) return input;
2446
2447		for(;i<pad_length;i+=q)
2448			input = pad_string + input;
2449
2450		return input;
2451	},
2452
2453	str_pad_right: function(input, pad_length, pad_string)
2454	{
2455		var i = input.length, q=pad_string.length;
2456		if (i >= pad_length) return input;
2457
2458		for(;i<pad_length;i+=q)
2459			input += pad_string;
2460
2461		return input;
2462	},
2463
2464	strip_tags: function(str)
2465	{
2466		return str.split(/<[^>]+>/g).join('');
2467	},
2468
2469	strip_php_tags: function(str)
2470	{
2471		return str.replace(/<\?(.|[\r\n])*?\?>/g, '');
2472	},
2473
2474	popup: function(url, width, height)
2475	{
2476		var w, h;
2477		if(BX.browser.IsOpera())
2478		{
2479			w = document.body.offsetWidth;
2480			h = document.body.offsetHeight;
2481		}
2482		else
2483		{
2484			w = screen.width;
2485			h = screen.height;
2486		}
2487		return window.open(url, '', 'status=no,scrollbars=yes,resizable=yes,width='+width+',height='+height+',top='+Math.floor((h - height)/2-14)+',left='+Math.floor((w - width)/2-5));
2488	},
2489	
2490	shuffle: function(array) 
2491	{
2492		var temporaryValue, randomIndex;
2493		var currentIndex = array.length;
2494		
2495		while (0 !== currentIndex) 
2496		{
2497			randomIndex = Math.floor(Math.random() * currentIndex);
2498			currentIndex -= 1;
2499			
2500			temporaryValue = array[currentIndex];
2501			array[currentIndex] = array[randomIndex];
2502			array[randomIndex] = temporaryValue;
2503		}
2504		
2505		return array;
2506	},
2507
2508	// BX.util.objectSort(object, sortBy, sortDir) - Sort object by property
2509	// function params: 1 - object for sort, 2 - sort by property, 3 - sort direction (asc/desc)
2510	// return: sort array [[objectElement], [objectElement]] in sortDir direction
2511
2512	// example: BX.util.objectSort({'L1': {'name': 'Last'}, 'F1': {'name': 'First'}}, 'name', 'asc');
2513	// return: [{'name' : 'First'}, {'name' : 'Last'}]
2514	objectSort: function(object, sortBy, sortDir)
2515	{
2516		sortDir = sortDir == 'asc'? 'asc': 'desc';
2517
2518		var arItems = [], i;
2519		for (i in object)
2520		{
2521			if (object.hasOwnProperty(i) && object[i][sortBy])
2522			{
2523				arItems.push([i, object[i][sortBy]]);
2524			}
2525		}
2526
2527		if (sortDir == 'asc')
2528		{
2529			arItems.sort(function(i, ii) {
2530				var s1, s2;
2531				if (!isNaN(i[1]) && !isNaN(ii[1]))
2532				{
2533					s1 = parseInt(i[1]);
2534					s2 = parseInt(ii[1]);
2535				}
2536				else
2537				{
2538					s1 = i[1].toString().toLowerCase();
2539					s2 = ii[1].toString().toLowerCase();
2540				}
2541
2542				if (s1 > s2)
2543					return 1;
2544				else if (s1 < s2)
2545					return -1;
2546				else
2547					return 0;
2548			});
2549		}
2550		else
2551		{
2552			arItems.sort(function(i, ii) {
2553				var s1, s2;
2554				if (!isNaN(i[1]) && !isNaN(ii[1]))
2555				{
2556					s1 = parseInt(i[1]);
2557					s2 = parseInt(ii[1]);
2558				}
2559				else
2560				{
2561					s1 = i[1].toString().toLowerCase();
2562					s2 = ii[1].toString().toLowerCase();
2563				}
2564				if (s1 < s2)
2565					return 1;
2566				else if (s1 > s2)
2567					return -1;
2568				else
2569					return 0;
2570			});
2571		}
2572
2573		var arReturnArray = Array();
2574		for (i = 0; i < arItems.length; i++)
2575		{
2576			arReturnArray.push(object[arItems[i][0]]);
2577		}
2578
2579		return arReturnArray;
2580	},
2581
2582	// #fdf9e5 => {r=253, g=249, b=229}
2583	hex2rgb: function(color)
2584	{
2585		var rgb = color.replace(/[# ]/g,"").replace(/^(.)(.)(.)$/,'$1$1$2$2$3$3').match(/.{2}/g);
2586		for (var i=0;  i<3; i++)
2587		{
2588			rgb[i] = parseInt(rgb[i], 16);
2589		}
2590		return {'r':rgb[0],'g':rgb[1],'b':rgb[2]};
2591	},
2592
2593	remove_url_param: function(url, param)
2594	{
2595		if (BX.type.isArray(param))
2596		{
2597			for (var i=0; i<param.length; i++)
2598			{
2599				url = BX.util.remove_url_param(url, param[i]);
2600			}
2601		}
2602		else
2603		{
2604			var pos, params;
2605			if((pos = url.indexOf('?')) >= 0 && pos != url.length-1)
2606			{
2607				params = url.substr(pos + 1);
2608				url = url.substr(0, pos + 1);
2609
2610				params = params.replace(new RegExp('(^|&)'+param+'=[^&#]*', 'i'), '');
2611				params = params.replace(/^&/, '');
2612
2613				if(BX.type.isNotEmptyString(params))
2614				{
2615					url = url + params;
2616				}
2617				else
2618				{
2619					//remove trailing question character
2620					url = url.substr(0, url.length - 1);
2621				}
2622			}
2623		}
2624		return url;
2625	},
2626
2627	/*
2628	{'param1': 'value1', 'param2': 'value2'}
2629	 */
2630	add_url_param: function(url, params)
2631	{
2632		var param;
2633		var additional = '';
2634		var hash = '';
2635		var pos;
2636
2637		for(param in params)
2638		{
2639			url = this.remove_url_param(url, param);
2640			additional += (additional != ''? '&':'') + param + '=' + params[param];
2641		}
2642
2643		if((pos = url.indexOf('#')) >= 0)
2644		{
2645			hash = url.substr(pos);
2646			url = url.substr(0, pos);
2647		}
2648
2649		if((pos = url.indexOf('?')) >= 0)
2650		{
2651			url = url + (pos != url.length-1? '&' : '') + additional + hash;
2652		}
2653		else
2654		{
2655			url = url + '?' + additional + hash;
2656		}
2657
2658		return url;
2659	},
2660
2661	even: function(digit)
2662	{
2663		return (parseInt(digit) % 2 == 0);
2664	},
2665
2666	hashCode: function(str)
2667	{
2668		if(!BX.type.isNotEmptyString(str))
2669		{
2670			return 0;
2671		}
2672
2673		var hash = 0;
2674		for (var i = 0; i < str.length; i++)
2675		{
2676			var c = str.charCodeAt(i);
2677			hash = ((hash << 5) - hash) + c;
2678			hash = hash & hash;
2679		}
2680		return hash;
2681	},
2682
2683	getRandomString: function (length)
2684	{
2685		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
2686		var charQty = chars.length;
2687
2688		length = parseInt(length);
2689		if(isNaN(length) || length <= 0)
2690		{
2691			length = 8;
2692		}
2693
2694		var result = "";
2695		for (var i = 0; i < length; i++)
2696		{
2697			result += chars.charAt(Math.floor(Math.random() * charQty));
2698		}
2699		return result;
2700	},
2701
2702	number_format: function(number, decimals, dec_point, thousands_sep)
2703	{
2704		var i, j, kw, kd, km, sign = '';
2705		decimals = Math.abs(decimals);
2706		if (isNaN(decimals) || decimals < 0)
2707		{
2708			decimals = 2;
2709		}
2710		dec_point = dec_point || ',';
2711		if (typeof thousands_sep === 'undefined')
2712			thousands_sep = '.';
2713
2714		number = (+number || 0).toFixed(decimals);
2715		if (number < 0)
2716		{
2717			sign = '-';
2718			number = -number;
2719		}
2720
2721		i = parseInt(number, 10) + '';
2722		j = (i.length > 3 ? i.length % 3 : 0);
2723
2724		km = (j ? i.substr(0, j) + thousands_sep : '');
2725		kw = i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep);
2726		kd = (decimals ? dec_point + Math.abs(number - i).toFixed(decimals).replace(/-/, '0').slice(2) : '');
2727
2728		return sign + km + kw + kd;
2729	},
2730
2731	getExtension: function (url)
2732	{
2733		url = url || "";
2734		var items = url.split("?")[0].split(".");
2735		return items[items.length-1].toLowerCase();
2736	},
2737	addObjectToForm: function(object, form, prefix)
2738	{
2739		if(!BX.type.isString(prefix))
2740		{
2741			prefix = "";
2742		}
2743
2744		for(var key in object)
2745		{
2746			if(!object.hasOwnProperty(key))
2747			{
2748				continue;
2749			}
2750
2751			var value = object[key];
2752			var name = prefix !== "" ? (prefix + "[" + key + "]") : key;
2753			if(BX.type.isArray(value))
2754			{
2755				for(var i = 0; i < value.length; i++)
2756				{
2757					BX.util.addObjectToForm(value[i], form, (name + "[" + i.toString() + "]"));
2758				}
2759			}
2760			else if(BX.type.isPlainObject(value))
2761			{
2762				BX.util.addObjectToForm(value, form, name);
2763			}
2764			else
2765			{
2766				value = BX.type.isFunction(value.toString) ? value.toString() : "";
2767				if(value !== "")
2768				{
2769					form.appendChild(BX.create("INPUT", { attrs: { type: "hidden", name: name, value: value } }));
2770				}
2771			}
2772		}
2773	},
2774
2775	observe: function(object, enable)
2776	{
2777		if (!BX.browser.IsChrome() || typeof(object) != 'object')
2778			return false;
2779
2780		enable = enable !== false;
2781
2782		var observer = function(options)
2783		{
2784			options.forEach(function(option){
2785				var groupName = option.name + ' changed';
2786				console.groupCollapsed(groupName);
2787				console.log('Old value: ', option.oldValue);
2788				console.log('New value: ', option.object[option.name]);
2789				console.groupEnd(groupName);
2790			});
2791		}
2792		if (enable)
2793		{
2794			Object.observe(object, observer);
2795		}
2796		else
2797		{
2798			Object.unobserve(object, observer);
2799		}
2800
2801		return enable;
2802	},
2803	
2804	escapeRegExp: function(str) 
2805	{
2806		return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
2807	}
2808};
2809
2810BX.type = {
2811	isString: function(item) {
2812		return item === '' ? true : (item ? (typeof (item) == "string" || item instanceof String) : false);
2813	},
2814	isNotEmptyString: function(item) {
2815		return BX.type.isString(item) ? item.length > 0 : false;
2816	},
2817	isBoolean: function(item) {
2818		return item === true || item === false;
2819	},
2820	isNumber: function(item) {
2821		return item === 0 ? true : (item ? (typeof (item) == "number" || item instanceof Number) : false);
2822	},
2823	isFunction: function(item) {
2824		return item === null ? false : (typeof (item) == "function" || item instanceof Function);
2825	},
2826	isElementNode: function(item) {
2827		//document.body.ELEMENT_NODE;
2828		return item && typeof (item) == "object" && "nodeType" in item && item.nodeType == 1 && item.tagName && item.tagName.toUpperCase() != 'SCRIPT' && item.tagName.toUpperCase() != 'STYLE' && item.tagName.toUpperCase() != 'LINK';
2829	},
2830	isDomNode: function(item) {
2831		return item && typeof (item) == "object" && "nodeType" in item;
2832	},
2833	isArray: function(item) {
2834		return item && Object.prototype.toString.call(item) == "[object Array]";
2835	},
2836	isDate : function(item) {
2837		return item && Object.prototype.toString.call(item) == "[object Date]";
2838	},
2839	isPlainObject: function(item)
2840	{
2841		if(!item || typeof(item) !== "object" || item.nodeType)
2842		{
2843			return false;
2844		}
2845
2846		var hasProp = Object.prototype.hasOwnProperty;
2847		try
2848		{
2849			if (item.constructor && !hasProp.call(item, "constructor") && !hasProp.call(item.constructor.prototype, "isPrototypeOf") )
2850			{
2851				return false;
2852			}
2853		}
2854		catch (e)
2855		{
2856			return false;
2857		}
2858
2859		var key;
2860		for (key in item)
2861		{
2862		}
2863		return typeof(key) === "undefined" || hasProp.call(item, key);
2864	}
2865};
2866
2867BX.isNodeInDom = function(node, doc)
2868{
2869	return node === (doc || document) ? true :
2870		(node.parentNode ? BX.isNodeInDom(node.parentNode) : false);
2871};
2872
2873BX.isNodeHidden = function(node)
2874{
2875	if (node === document)
2876		return false;
2877	else if (BX.style(node, 'display') == 'none')
2878		return true;
2879	else
2880		return (node.parentNode ? BX.isNodeHidden(node.parentNode) : true);
2881};
2882
2883BX.evalPack = function(code)
2884{
2885	while (code.length > 0)
2886	{
2887		var c = code.shift();
2888
2889		if (c.TYPE == 'SCRIPT_EXT' || c.TYPE == 'SCRIPT_SRC')
2890		{
2891			BX.loadScript(c.DATA, function() {BX.evalPack(code)});
2892			return;
2893		}
2894		else if (c.TYPE == 'SCRIPT')
2895		{
2896			BX.evalGlobal(c.DATA);
2897		}
2898	}
2899};
2900
2901BX.evalGlobal = function(data)
2902{
2903	if (data)
2904	{
2905		var head = document.getElementsByTagName("head")[0] || document.documentElement,
2906			script = document.createElement("script");
2907
2908		script.type = "text/javascript";
2909
2910		if (!BX.browser.IsIE())
2911		{
2912			script.appendChild(document.createTextNode(data));
2913		}
2914		else
2915		{
2916			script.text = data;
2917		}
2918
2919		head.insertBefore(script, head.firstChild);
2920		head.removeChild(script);
2921	}
2922};
2923
2924BX.processHTML = function(data, scriptsRunFirst)
2925{
2926	var matchScript, matchStyle, matchSrc, matchHref, matchType, scripts = [], styles = [];
2927	var textIndexes = [];
2928	var lastIndex = r.script.lastIndex = r.script_end.lastIndex = 0;
2929
2930	while ((matchScript = r.script.exec(data)) !== null)
2931	{
2932		r.script_end.lastIndex = r.script.lastIndex;
2933		var matchScriptEnd = r.script_end.exec(data);
2934		if (matchScriptEnd === null)
2935		{
2936			break;
2937		}
2938
2939		// skip script tags of special types
2940		var skipTag = false;
2941		if ((matchType = matchScript[1].match(r.script_type)) !== null)
2942		{
2943			if(matchType[1] == 'text/html' || matchType[1] == 'text/template')
2944				skipTag = true;
2945		}
2946
2947		if(skipTag)
2948		{
2949			textIndexes.push([lastIndex, r.script_end.lastIndex - lastIndex]);
2950		}
2951		else
2952		{
2953			textIndexes.push([lastIndex, matchScript.index - lastIndex]);
2954
2955			var bRunFirst = scriptsRunFirst || (matchScript[1].indexOf('bxrunfirst') != '-1');
2956
2957			if ((matchSrc = matchScript[1].match(r.script_src)) !== null)
2958			{
2959				scripts.push({"bRunFirst": bRunFirst, "isInternal": false, "JS": matchSrc[1]});
2960			}
2961			else
2962			{
2963				var start = matchScript.index + matchScript[0].length;
2964				var js = data.substr(start, matchScriptEnd.index-start);
2965
2966				scripts.push({"bRunFirst": bRunFirst, "isInternal": true, "JS": js});
2967			}
2968		}
2969
2970		lastIndex = matchScriptEnd.index + 9;
2971		r.script.lastIndex = lastIndex;
2972	}
2973
2974	textIndexes.push([lastIndex, lastIndex === 0 ? data.length : data.length - lastIndex]);
2975	var pureData = "";
2976	for (var i = 0, length = textIndexes.length; i < length; i++)
2977	{
2978		pureData += data.substr(textIndexes[i][0], textIndexes[i][1]);
2979	}
2980
2981	while ((matchStyle = pureData.match(r.style)) !== null)
2982	{
2983		if ((matchHref = matchStyle[0].match(r.style_href)) !== null && matchStyle[0].indexOf('media="') < 0)
2984		{
2985			styles.push(matchHref[1]);
2986		}
2987
2988		pureData = pureData.replace(matchStyle[0], '');
2989	}
2990
2991	return {'HTML': pureData, 'SCRIPT': scripts, 'STYLE': styles};
2992};
2993
2994BX.garbage = function(call, thisObject)
2995{
2996	garbageCollectors.push({callback: call, context: thisObject});
2997};
2998
2999/* window pos functions */
3000
3001BX.GetDocElement = function (pDoc)
3002{
3003	pDoc = pDoc || document;
3004	return (BX.browser.IsDoctype(pDoc) ? pDoc.documentElement : pDoc.body);
3005};
3006
3007BX.GetContext = function(node)
3008{
3009	if (BX.type.isElementNode(node))
3010		return node.ownerDocument.parentWindow || node.ownerDocument.defaultView || window;
3011	else if (BX.type.isDomNode(node))
3012		return node.parentWindow || node.defaultView || window;
3013	else
3014		return window;
3015};
3016
3017BX.GetWindowInnerSize = function(pDoc)
3018{
3019	var width, height;
3020
3021	pDoc = pDoc || document;
3022
3023	if (window.innerHeight) // all except Explorer
3024	{
3025		width = BX.GetContext(pDoc).innerWidth;
3026		height = BX.GetContext(pDoc).innerHeight;
3027	}
3028	else if (pDoc.documentElement && (pDoc.documentElement.clientHeight || pDoc.documentElement.clientWidth)) // Explorer 6 Strict Mode
3029	{
3030		width = pDoc.documentElement.clientWidth;
3031		height = pDoc.documentElement.clientHeight;
3032	}
3033	else if (pDoc.body) // other Explorers
3034	{
3035		width = pDoc.body.clientWidth;
3036		height = pDoc.body.clientHeight;
3037	}
3038	return {innerWidth : width, innerHeight : height};
3039};
3040
3041BX.GetWindowScrollPos = function(pDoc)
3042{
3043	var left, top;
3044
3045	pDoc = pDoc || document;
3046
3047	if (window.pageYOffset) // all except Explorer
3048	{
3049		left = BX.GetContext(pDoc).pageXOffset;
3050		top = BX.GetContext(pDoc).pageYOffset;
3051	}
3052	else if (pDoc.documentElement && (pDoc.documentElement.scrollTop || pDoc.documentElement.scrollLeft)) // Explorer 6 Strict
3053	{
3054		left = pDoc.documentElement.scrollLeft;
3055		top = pDoc.documentElement.scrollTop;
3056	}
3057	else if (pDoc.body) // all other Explorers
3058	{
3059		left = pDoc.body.scrollLeft;
3060		top = pDoc.body.scrollTop;
3061	}
3062	return {scrollLeft : left, scrollTop : top};
3063};
3064
3065BX.GetWindowScrollSize = function(pDoc)
3066{
3067	var width, height;
3068	if (!pDoc)
3069		pDoc = document;
3070
3071	if ( (pDoc.compatMode && pDoc.compatMode == "CSS1Compat"))
3072	{
3073		width = pDoc.documentElement.scrollWidth;
3074		height = pDoc.documentElement.scrollHeight;
3075	}
3076	else
3077	{
3078		if (pDoc.body.scrollHeight > pDoc.body.offsetHeight)
3079			height = pDoc.body.scrollHeight;
3080		else
3081			height = pDoc.body.offsetHeight;
3082
3083		if (pDoc.body.scrollWidth > pDoc.body.offsetWidth ||
3084			(pDoc.compatMode && pDoc.compatMode == "BackCompat") ||
3085			(pDoc.documentElement && !pDoc.documentElement.clientWidth)
3086		)
3087			width = pDoc.body.scrollWidth;
3088		else
3089			width = pDoc.body.offsetWidth;
3090	}
3091	return {scrollWidth : width, scrollHeight : height};
3092};
3093
3094BX.GetWindowSize = function(pDoc)
3095{
3096	var innerSize = this.GetWindowInnerSize(pDoc);
3097	var scrollPos = this.GetWindowScrollPos(pDoc);
3098	var scrollSize = this.GetWindowScrollSize(pDoc);
3099
3100	return  {
3101		innerWidth : innerSize.innerWidth, innerHeight : innerSize.innerHeight,
3102		scrollLeft : scrollPos.scrollLeft, scrollTop : scrollPos.scrollTop,
3103		scrollWidth : scrollSize.scrollWidth, scrollHeight : scrollSize.scrollHeight
3104	};
3105};
3106
3107BX.scrollTop = function(node, val){
3108	if(typeof val != 'undefined'){
3109
3110		if(node == window){
3111			throw new Error('scrollTop() for window is not implemented');
3112		}else
3113			node.scrollTop = parseInt(val);
3114
3115	}else{
3116
3117		if(node == window)
3118			return BX.GetWindowScrollPos().scrollTop;
3119
3120		return node.scrollTop;
3121	}
3122}
3123
3124BX.scrollLeft = function(node, val){
3125	if(typeof val != 'undefined'){
3126
3127		if(node == window){
3128			throw new Error('scrollLeft() for window is not implemented');
3129		}else
3130			node.scrollLeft = parseInt(val);
3131
3132	}else{
3133
3134		if(node == window)
3135			return BX.GetWindowScrollPos().scrollLeft;
3136
3137		return node.scrollLeft;
3138	}
3139}
3140
3141BX.hide_object = function(ob)
3142{
3143	ob = BX(ob);
3144	ob.style.position = 'absolute';
3145	ob.style.top = '-1000px';
3146	ob.style.left = '-1000px';
3147	ob.style.height = '10px';
3148	ob.style.width = '10px';
3149};
3150
3151BX.is_relative = function(el)
3152{
3153	var p = BX.style(el, 'position');
3154	return p == 'relative' || p == 'absolute';
3155};
3156
3157BX.is_float = function(el)
3158{
3159	var p = BX.style(el, 'float');
3160	return p == 'right' || p == 'left';
3161};
3162
3163BX.is_fixed = function(el)
3164{
3165	var p = BX.style(el, 'position');
3166	return p == 'fixed';
3167};
3168
3169BX.pos = function(el, bRelative)
3170{
3171	var r = { top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 };
3172	bRelative = !!bRelative;
3173	if (!el)
3174		return r;
3175	if (typeof (el.getBoundingClientRect) != "undefined" && el.ownerDocument == document && !bRelative)
3176	{
3177		var clientRect = {};
3178
3179		// getBoundingClientRect can return undefined and generate exception in some cases in IE8.
3180		try
3181		{
3182			clientRect = el.getBoundingClientRect();
3183		}
3184		catch(e)
3185		{
3186			clientRect =
3187			{
3188				top: el.offsetTop,
3189				left: el.offsetLeft,
3190				width: el.offsetWidth,
3191				height: el.offsetHeight,
3192				right: el.offsetLeft + el.offsetWidth,
3193				bottom: el.offsetTop + el.offsetHeight
3194			};
3195		}
3196
3197		var root = document.documentElement;
3198		var body = document.body;
3199
3200		r.top = clientRect.top + (root.scrollTop || body.scrollTop);
3201		r.left = clientRect.left + (root.scrollLeft || body.scrollLeft);
3202		r.width = clientRect.right - clientRect.left;
3203		r.height = clientRect.bottom - clientRect.top;
3204		r.right = clientRect.right + (root.scrollLeft || body.scrollLeft);
3205		r.bottom = clientRect.bottom + (root.scrollTop || body.scrollTop);
3206	}
3207	else
3208	{
3209		var x = 0, y = 0, w = el.offsetWidth, h = el.offsetHeight;
3210		var first = true;
3211		for (; el != null; el = el.offsetParent)
3212		{
3213			if (!first && bRelative && BX.is_relative(el))
3214				break;
3215
3216			x += el.offsetLeft;
3217			y += el.offsetTop;
3218			if (first)
3219			{
3220				first = false;
3221				continue;
3222			}
3223
3224			var elBorderLeftWidth = parseInt(BX.style(el, 'border-left-width')),
3225				elBorderTopWidth = parseInt(BX.style(el, 'border-top-width'));
3226
3227			if (!isNaN(elBorderLeftWidth) && elBorderLeftWidth > 0)
3228				x += elBorderLeftWidth;
3229			if (!isNaN(elBorderTopWidth) && elBorderTopWidth > 0)
3230				y += elBorderTopWidth;
3231		}
3232
3233		r.top = y;
3234		r.left = x;
3235		r.width = w;
3236		r.height = h;
3237		r.right = r.left + w;
3238		r.bottom = r.top + h;
3239	}
3240
3241	for(var i in r)
3242	{
3243		if(r.hasOwnProperty(i))
3244		{
3245			r[i] = Math.round(r[i]);
3246		}
3247	}
3248
3249	return r;
3250};
3251
3252BX.width = function(node, val){
3253	if(typeof val != 'undefined')
3254		BX.style(node, 'width', parseInt(val)+'px');
3255	else{
3256
3257		if(node == window)
3258			return window.innerWidth;
3259
3260		//return parseInt(BX.style(node, 'width'));
3261		return BX.pos(node).width;
3262	}
3263}
3264
3265BX.height = function(node, val){
3266	if(typeof val != 'undefined')
3267		BX.style(node, 'height', parseInt(val)+'px');
3268	else{
3269
3270		if(node == window)
3271			return window.innerHeight;
3272
3273		//return parseInt(BX.style(node, 'height'));
3274		return BX.pos(node).height;
3275	}
3276}
3277
3278BX.align = function(pos, w, h, type)
3279{
3280	if (type)
3281		type = type.toLowerCase();
3282	else
3283		type = '';
3284
3285	var pDoc = document;
3286	if (BX.type.isElementNode(pos))
3287	{
3288		pDoc = pos.ownerDocument;
3289		pos = BX.pos(pos);
3290	}
3291
3292	var x = pos["left"], y = pos["bottom"];
3293
3294	var scroll = BX.GetWindowScrollPos(pDoc);
3295	var size = BX.GetWindowInnerSize(pDoc);
3296
3297	if((size.innerWidth + scroll.scrollLeft) - (pos["left"] + w) < 0)
3298	{
3299		if(pos["right"] - w >= 0 )
3300			x = pos["right"] - w;
3301		else
3302			x = scroll.scrollLeft;
3303	}
3304
3305	if(((size.innerHeight + scroll.scrollTop) - (pos["bottom"] + h) < 0) || ~type.indexOf('top'))
3306	{
3307		if(pos["top"] - h >= 0 || ~type.indexOf('top'))
3308			y = pos["top"] - h;
3309		else
3310			y = scroll.scrollTop;
3311	}
3312
3313	return {'left':x, 'top':y};
3314};
3315
3316BX.scrollToNode = function(node)
3317{
3318	var obNode = BX(node);
3319
3320	if (obNode.scrollIntoView)
3321		obNode.scrollIntoView(true);
3322	else
3323	{
3324		var arNodePos = BX.pos(obNode);
3325		window.scrollTo(arNodePos.left, arNodePos.top);
3326	}
3327};
3328
3329/* non-xhr loadings */
3330BX.showWait = function(node, msg)
3331{
3332	node = BX(node) || document.body || document.documentElement;
3333	msg = msg || BX.message('JS_CORE_LOADING');
3334
3335	var container_id = node.id || Math.random();
3336
3337	var obMsg = node.bxmsg = document.body.appendChild(BX.create('DIV', {
3338		props: {
3339			id: 'wait_' + container_id
3340		},
3341		style: {
3342			background: 'url("/bitrix/js/main/core/images/wait.gif") no-repeat scroll 10px center #fcf7d1',
3343			border: '1px solid #E1B52D',
3344			color: 'black',
3345			fontFamily: 'Verdana,Arial,sans-serif',
3346			fontSize: '11px',
3347			padding: '10px 30px 10px 37px',
3348			position: 'absolute',
3349			zIndex:'10000',
3350			textAlign:'center'
3351		},
3352		text: msg
3353	}));
3354
3355	setTimeout(BX.delegate(_adjustWait, node), 10);
3356
3357	lastWait[lastWait.length] = obMsg;
3358	return obMsg;
3359};
3360
3361BX.closeWait = function(node, obMsg)
3362{
3363	if(node && !obMsg)
3364		obMsg = node.bxmsg;
3365	if(node && !obMsg && BX.hasClass(node, 'bx-core-waitwindow'))
3366		obMsg = node;
3367	if(node && !obMsg)
3368		obMsg = BX('wait_' + node.id);
3369	if(!obMsg)
3370		obMsg = lastWait.pop();
3371
3372	if (obMsg && obMsg.parentNode)
3373	{
3374		for (var i=0,len=lastWait.length;i<len;i++)
3375		{
3376			if (obMsg == lastWait[i])
3377			{
3378				lastWait = BX.util.deleteFromArray(lastWait, i);
3379				break;
3380			}
3381		}
3382
3383		obMsg.parentNode.removeChild(obMsg);
3384		if (node) node.bxmsg = null;
3385		BX.cleanNode(obMsg, true);
3386	}
3387};
3388
3389BX.setJSList = function(scripts)
3390{
3391	if (BX.type.isArray(scripts))
3392	{
3393		jsList = scripts;
3394	}
3395};
3396
3397BX.getJSList = function()
3398{
3399	initJsList();
3400	return jsList;
3401};
3402
3403BX.setCSSList = function(scripts)
3404{
3405	if (BX.type.isArray(scripts))
3406	{
3407		cssList = scripts;
3408	}
3409};
3410
3411BX.getCSSList = function()
3412{
3413	initCssList();
3414	return cssList;
3415};
3416
3417BX.getJSPath = function(js)
3418{
3419	return js.replace(/^(http[s]*:)*\/\/[^\/]+/i, '');
3420};
3421
3422BX.getCSSPath = function(css)
3423{
3424	return css.replace(/^(http[s]*:)*\/\/[^\/]+/i, '');
3425};
3426
3427BX.getCDNPath = function(path)
3428{
3429	return path;
3430};
3431
3432BX.loadScript = function(script, callback, doc)
3433{
3434	if (BX.type.isString(script))
3435	{
3436		script = [script];
3437	}
3438
3439	return BX.load(script, callback, doc);
3440};
3441
3442BX.loadCSS = function(css, doc, win)
3443{
3444	if (BX.type.isString(css))
3445	{
3446		css = [css];
3447	}
3448
3449	if (BX.type.isArray(css))
3450	{
3451		css = css.map(function(url) {
3452			return { url: url, ext: "css" }
3453		});
3454
3455		BX.load(css, null, doc);
3456	}
3457};
3458
3459BX.load = function(items, callback, doc)
3460{
3461	if (!BX.isReady)
3462	{
3463		var _args = arguments;
3464		BX.ready(function() {
3465			BX.load.apply(this, _args);
3466		});
3467		return null;
3468	}
3469
3470	doc = doc || document;
3471	if (isAsync === null)
3472	{
3473		isAsync = "async" in doc.createElement("script") || "MozAppearance" in doc.documentElement.style || window.opera;
3474	}
3475
3476	return isAsync ? loadAsync(items, callback, doc) : loadAsyncEmulation(items, callback, doc);
3477};
3478
3479BX.convert =
3480{
3481	nodeListToArray: function(nodes)
3482	{
3483		try
3484		{
3485			return (Array.prototype.slice.call(nodes, 0));
3486		}
3487		catch (ex)
3488		{
3489			var ary = [];
3490			for(var i = 0, l = nodes.length; i < l; i++)
3491			{
3492				ary.push(nodes[i]);
3493			}
3494			return ary;
3495		}
3496	}
3497};
3498
3499function loadAsync(items, callback, doc)
3500{
3501	if (!BX.type.isArray(items))
3502	{
3503		return;
3504	}
3505
3506	function allLoaded(items)
3507	{
3508		items = items || assets;
3509		for (var name in items)
3510		{
3511			if (items.hasOwnProperty(name) && items[name].state !== LOADED)
3512			{
3513				return false;
3514			}
3515		}
3516
3517		return true;
3518	}
3519
3520	if (!BX.type.isFunction(callback))
3521	{
3522		callback = null;
3523	}
3524
3525	var itemSet = {}, item, i;
3526	for (i = 0; i < items.length; i++)
3527	{
3528		item = items[i];
3529		item = getAsset(item);
3530		itemSet[item.name] = item;
3531	}
3532
3533	var callbackWasCalled = false;
3534	for (i = 0; i < items.length; i++)
3535	{
3536		item = items[i];
3537		item = getAsset(item);
3538		load(item, function () {
3539			if (allLoaded(itemSet))
3540			{
3541				if (!callbackWasCalled)
3542				{
3543					callback && callback();
3544					callbackWasCalled = true;
3545				}
3546
3547			}
3548		}, doc);
3549	}
3550}
3551
3552function loadAsyncEmulation(items, callback, doc)
3553{
3554	function onPreload(asset)
3555	{
3556		asset.state = PRELOADED;
3557		if (BX.type.isArray(asset.onpreload) && asset.onpreload)
3558		{
3559			for (var i = 0; i < asset.onpreload.length; i++)
3560			{
3561				asset.onpreload[i].call();
3562			}
3563		}
3564	}
3565
3566	function preLoad(asset)
3567	{
3568		if (asset.state === undefined)
3569		{
3570			asset.state = PRELOADING;
3571			asset.onpreload = [];
3572
3573			loadAsset(
3574				{ url: asset.url, type: "cache", ext: asset.ext},
3575				function () { onPreload(asset); },
3576				doc
3577			);
3578		}
3579	}
3580
3581	if (!BX.type.isArray(items))
3582	{
3583		return;
3584	}
3585
3586	if (!BX.type.isFunction(callback))
3587	{
3588		callback = null;
3589	}
3590
3591	var rest = [].slice.call(items, 1);
3592	for (var i = 0; i < rest.length; i++)
3593	{
3594		preLoad(getAsset(rest[i]));
3595	}
3596
3597	load(getAsset(items[0]), items.length === 1 ? callback : function () {
3598		loadAsyncEmulation.apply(null, [rest, callback, doc]);
3599	}, doc);
3600}
3601
3602function load(asset, callback, doc)
3603{
3604	callback = callback || BX.DoNothing;
3605
3606	if (asset.state === LOADED)
3607	{
3608		callback();
3609		return;
3610	}
3611
3612	if (asset.state === PRELOADING)
3613	{
3614		asset.onpreload.push(function () {
3615			load(asset, callback, doc);
3616		});
3617		return;
3618	}
3619
3620	asset.state = LOADING;
3621
3622	loadAsset(
3623		asset,
3624		function () {
3625			asset.state = LOADED;
3626			callback();
3627		},
3628		doc
3629	);
3630}
3631
3632function loadAsset(asset, callback, doc)
3633{
3634	callback = callback || BX.DoNothing;
3635
3636	function error(event)
3637	{
3638		ele.onload = ele.onreadystatechange = ele.onerror = null;
3639		callback();
3640	}
3641
3642	function process(event)
3643	{
3644		event = event || window.event;
3645		if (event.type === "load" || (/loaded|complete/.test(ele.readyState) && (!doc.documentMode || doc.documentMode < 9)))
3646		{
3647			window.clearTimeout(asset.errorTimeout);
3648			window.clearTimeout(asset.cssTimeout);
3649			ele.onload = ele.onreadystatechange = ele.onerror = null;
3650			callback();
3651		}
3652	}
3653
3654	function isCssLoaded()
3655	{
3656		if (asset.state !== LOADED && asset.cssRetries <= 20)
3657		{
3658			for (var i = 0, l = doc.styleSheets.length; i < l; i++)
3659			{
3660				if (doc.styleSheets[i].href === ele.href)
3661				{
3662					process({"type": "load"});
3663					return;
3664				}
3665			}
3666
3667			asset.cssRetries++;
3668			asset.cssTimeout = window.setTimeout(isCssLoaded, 250);
3669		}
3670	}
3671
3672	var ele;
3673	var ext = BX.type.isNotEmptyString(asset.ext) ? asset.ext : BX.util.getExtension(asset.url);
3674
3675	if (ext === "css")
3676	{
3677		ele = doc.createElement("link");
3678		ele.type = "text/" + (asset.type || "css");
3679		ele.rel = "stylesheet";
3680		ele.href = asset.url;
3681
3682		asset.cssRetries = 0;
3683		asset.cssTimeout = window.setTimeout(isCssLoaded, 500);
3684	}
3685	else
3686	{
3687		ele = doc.createElement("script");
3688		ele.type = "text/" + (asset.type || "javascript");
3689		ele.src = asset.url;
3690	}
3691
3692	ele.onload = ele.onreadystatechange = process;
3693	ele.onerror = error;
3694
3695	ele.async = false;
3696	ele.defer = false;
3697
3698	asset.errorTimeout = window.setTimeout(function () {
3699		error({type: "timeout"});
3700	}, 7000);
3701
3702	if (ext === "css")
3703	{
3704		cssList.push(normalizeMinUrl(normalizeUrl(asset.url)));
3705	}
3706	else
3707	{
3708		jsList.push(normalizeMinUrl(normalizeUrl(asset.url)));
3709	}
3710
3711	var templateLink = null;
3712	var head = doc.head || doc.getElementsByTagName("head")[0];
3713	if (ext === "css" && (templateLink = getTemplateLink(head)) !== null)
3714	{
3715		templateLink.parentNode.insertBefore(ele, templateLink);
3716	}
3717	else
3718	{
3719		head.insertBefore(ele, head.lastChild);
3720	}
3721}
3722
3723function getAsset(item)
3724{
3725	var asset = {};
3726	if (typeof item === "object")
3727	{
3728		asset = item;
3729		asset.name = asset.name ? asset.name : BX.util.hashCode(item.url);
3730	}
3731	else
3732	{
3733		asset = { name: BX.util.hashCode(item), url : item };
3734	}
3735
3736	var ext = BX.type.isNotEmptyString(asset.ext) ? asset.ext : BX.util.getExtension(asset.url);
3737	if ((ext === "css" && isCssLoaded(asset.url)) || isScriptLoaded(asset.url))
3738	{
3739		asset.state = LOADED;
3740	}
3741
3742	var existing = assets[asset.name];
3743	if (existing && existing.url === asset.url)
3744	{
3745		return existing;
3746	}
3747
3748	assets[asset.name] = asset;
3749	return asset;
3750}
3751
3752function normalizeUrl(url)
3753{
3754	if (!BX.type.isNotEmptyString(url))
3755	{
3756		return "";
3757	}
3758
3759	url = BX.getJSPath(url);
3760	url = url.replace(/\?[0-9]*$/, "");
3761
3762	return url;
3763}
3764
3765function normalizeMinUrl(url)
3766{
3767	if (!BX.type.isNotEmptyString(url))
3768	{
3769		return "";
3770	}
3771
3772	var minPos = url.indexOf(".min");
3773	return minPos >= 0 ? url.substr(0, minPos) + url.substr(minPos + 4) : url;
3774}
3775
3776function isCssLoaded(fileSrc)
3777{
3778	initCssList();
3779
3780	fileSrc = normalizeUrl(fileSrc);
3781	var fileSrcMin = normalizeMinUrl(fileSrc);
3782
3783	return (fileSrc !== fileSrcMin && BX.util.in_array(fileSrcMin, cssList)) || BX.util.in_array(fileSrc, cssList);
3784}
3785
3786function initCssList()
3787{
3788	if(!cssInit)
3789	{
3790		var linksCol = document.getElementsByTagName('link');
3791
3792		if(!!linksCol && linksCol.length > 0)
3793		{
3794			for(var i = 0; i < linksCol.length; i++)
3795			{
3796				var href = linksCol[i].getAttribute('href');
3797				if (BX.type.isNotEmptyString(href))
3798				{
3799					href = normalizeMinUrl(normalizeUrl(href));
3800					cssList.push(href);
3801				}
3802			}
3803		}
3804		cssInit = true;
3805	}
3806}
3807
3808function getTemplateLink(head)
3809{
3810	var findLink = function(tag)
3811	{
3812		var links = head.getElementsByTagName(tag);
3813		for (var i = 0, length = links.length; i < length; i++)
3814		{
3815			var templateStyle = links[i].getAttribute("data-template-style");
3816			if (BX.type.isNotEmptyString(templateStyle) && templateStyle == "true")
3817			{
3818				return links[i];
3819			}
3820		}
3821
3822		return null;
3823	};
3824
3825	var link = findLink("link");
3826	if (link === null)
3827	{
3828		link = findLink("style");
3829	}
3830
3831	return link;
3832}
3833
3834function isScriptLoaded(fileSrc)
3835{
3836	initJsList();
3837
3838	fileSrc = normalizeUrl(fileSrc);
3839	var fileSrcMin = normalizeMinUrl(fileSrc);
3840
3841	return (fileSrc !== fileSrcMin && BX.util.in_array(fileSrcMin, jsList)) || BX.util.in_array(fileSrc, jsList);
3842}
3843
3844function initJsList()
3845{
3846	if(!jsInit)
3847	{
3848		var scriptCol = document.getElementsByTagName('script');
3849
3850		if(!!scriptCol && scriptCol.length > 0)
3851		{
3852			for(var i=0; i<scriptCol.length; i++)
3853			{
3854				var src = scriptCol[i].getAttribute('src');
3855
3856				if (BX.type.isNotEmptyString(src))
3857				{
3858					src = normalizeMinUrl(normalizeUrl(src));
3859					jsList.push(src);
3860				}
3861			}
3862		}
3863		jsInit = true;
3864	}
3865}
3866
3867BX.reload = function(back_url, bAddClearCache)
3868{
3869	if (back_url === true)
3870	{
3871		bAddClearCache = true;
3872		back_url = null;
3873	}
3874
3875	var new_href = back_url || top.location.href;
3876
3877	var hashpos = new_href.indexOf('#'), hash = '';
3878
3879	if (hashpos != -1)
3880	{
3881		hash = new_href.substr(hashpos);
3882		new_href = new_href.substr(0, hashpos);
3883	}
3884
3885	if (bAddClearCache && new_href.indexOf('clear_cache=Y') < 0)
3886		new_href += (new_href.indexOf('?') == -1 ? '?' : '&') + 'clear_cache=Y';
3887
3888	if (hash)
3889	{
3890		// hack for clearing cache in ajax mode components with history emulation
3891		if (bAddClearCache && (hash.substr(0, 5) == 'view/' || hash.substr(0, 6) == '#view/') && hash.indexOf('clear_cache%3DY') < 0)
3892			hash += (hash.indexOf('%3F') == -1 ? '%3F' : '%26') + 'clear_cache%3DY';
3893
3894		new_href = new_href.replace(/(\?|\&)_r=[\d]*/, '');
3895		new_href += (new_href.indexOf('?') == -1 ? '?' : '&') + '_r='+Math.round(Math.random()*10000) + hash;
3896	}
3897
3898	top.location.href = new_href;
3899};
3900
3901BX.clearCache = function()
3902{
3903	BX.showWait();
3904	BX.reload(true);
3905};
3906
3907BX.template = function(tpl, callback, bKillTpl)
3908{
3909	BX.ready(function() {
3910		_processTpl(BX(tpl), callback, bKillTpl);
3911	});
3912};
3913
3914BX.isAmPmMode = function()
3915{
3916	return (BX.message('FORMAT_DATETIME').match('T') != null);
3917};
3918
3919BX.formatDate = function(date, format)
3920{
3921	date = date || new Date();
3922
3923	var bTime = date.getHours() || date.getMinutes() || date.getSeconds(),
3924		str = !!format
3925			? format :
3926			(bTime ? BX.message('FORMAT_DATETIME') : BX.message('FORMAT_DATE')
3927		);
3928
3929	return str.replace(/YYYY/ig, date.getFullYear())
3930		.replace(/MMMM/ig, BX.util.str_pad_left((date.getMonth()+1).toString(), 2, '0'))
3931		.replace(/MM/ig, BX.util.str_pad_left((date.getMonth()+1).toString(), 2, '0'))
3932		.replace(/DD/ig, BX.util.str_pad_left(date.getDate().toString(), 2, '0'))
3933		.replace(/HH/ig, BX.util.str_pad_left(date.getHours().toString(), 2, '0'))
3934		.replace(/MI/ig, BX.util.str_pad_left(date.getMinutes().toString(), 2, '0'))
3935		.replace(/SS/ig, BX.util.str_pad_left(date.getSeconds().toString(), 2, '0'));
3936};
3937BX.formatName = function(user, template, login)
3938{
3939	user = user || {};
3940	template = (template || '');
3941	var replacement = {
3942		TITLE : (user["TITLE"] || ''),
3943		NAME : (user["NAME"] || ''),
3944		LAST_NAME : (user["LAST_NAME"] || ''),
3945		SECOND_NAME : (user["SECOND_NAME"] || ''),
3946		LOGIN : (user["LOGIN"] || ''),
3947		NAME_SHORT : user["NAME"] ? user["NAME"].substr(0, 1) + '.' : '',
3948		LAST_NAME_SHORT : user["LAST_NAME"] ? user["LAST_NAME"].substr(0, 1) + '.' : '',
3949		SECOND_NAME_SHORT : user["SECOND_NAME"] ? user["SECOND_NAME"].substr(0, 1) + '.' : '',
3950		EMAIL : (user["EMAIL"] || ''),
3951		ID : (user["ID"] || ''),
3952		NOBR : "",
3953		'/NOBR' : ""
3954	}, result = template;
3955	for (var ii in replacement)
3956	{
3957		if (replacement.hasOwnProperty(ii))
3958		{
3959			result = result.replace("#" + ii+ "#", replacement[ii])
3960		}
3961	}
3962	result = result.replace(/([\s]+)/gi, " ").trim();
3963	if (result == "")
3964	{
3965		result = (login == "Y" ? replacement["LOGIN"] : "");
3966		result = (result == "" ? "Noname" : result);
3967	}
3968	return result;
3969};
3970
3971BX.getNumMonth = function(month)
3972{
3973	var wordMonthCut = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
3974	var wordMonth = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
3975
3976	var q = month.toUpperCase();
3977	for (i = 1; i <= 12; i++)
3978	{
3979		if (q == BX.message('MON_'+i).toUpperCase() || q == BX.message('MONTH_'+i).toUpperCase() || q == wordMonthCut[i-1].toUpperCase() || q == wordMonth[i-1].toUpperCase())
3980		{
3981			return i;
3982		}
3983	}
3984	return month;
3985};
3986
3987BX.parseDate = function(str, bUTC, formatDate, formatDatetime)
3988{
3989	if (BX.type.isNotEmptyString(str))
3990	{
3991		if (!formatDate)
3992			formatDate = BX.message('FORMAT_DATE');
3993		if (!formatDatetime)
3994			formatDatetime = BX.message('FORMAT_DATETIME');
3995
3996		var regMonths = '';
3997		for (i = 1; i <= 12; i++)
3998		{
3999			regMonths = regMonths + '|' + BX.message('MON_'+i);
4000		}
4001
4002		var expr = new RegExp('([0-9]+|[a-z]+' + regMonths + ')', 'ig');
4003		var aDate = str.match(expr),
4004			aFormat = formatDate.match(/(DD|MI|MMMM|MM|M|YYYY)/ig),
4005			i, cnt,
4006			aDateArgs=[], aFormatArgs=[],
4007			aResult={};
4008
4009		if (!aDate)
4010			return null;
4011
4012		if(aDate.length > aFormat.length)
4013		{
4014			aFormat = formatDatetime.match(/(DD|MI|MMMM|MM|M|YYYY|HH|H|SS|TT|T|GG|G)/ig);
4015		}
4016
4017		for(i = 0, cnt = aDate.length; i < cnt; i++)
4018		{
4019			if(BX.util.trim(aDate[i]) != '')
4020			{
4021				aDateArgs[aDateArgs.length] = aDate[i];
4022			}
4023		}
4024
4025		for(i = 0, cnt = aFormat.length; i < cnt; i++)
4026		{
4027			if(BX.util.trim(aFormat[i]) != '')
4028			{
4029				aFormatArgs[aFormatArgs.length] = aFormat[i];
4030			}
4031		}
4032
4033
4034		var m = BX.util.array_search('MMMM', aFormatArgs);
4035		if (m > 0)
4036		{
4037			aDateArgs[m] = BX.getNumMonth(aDateArgs[m]);
4038			aFormatArgs[m] = "MM";
4039		}
4040		else
4041		{
4042			m = BX.util.array_search('M', aFormatArgs);
4043			if (m > 0)
4044			{
4045				aDateArgs[m] = BX.getNumMonth(aDateArgs[m]);
4046				aFormatArgs[m] = "MM";
4047			}
4048		}
4049
4050		for(i = 0, cnt = aFormatArgs.length; i < cnt; i++)
4051		{
4052			var k = aFormatArgs[i].toUpperCase();
4053			aResult[k] = k == 'T' || k == 'TT' ? aDateArgs[i] : parseInt(aDateArgs[i], 10);
4054		}
4055
4056		if(aResult['DD'] > 0 && aResult['MM'] > 0 && aResult['YYYY'] > 0)
4057		{
4058			var d = new Date();
4059
4060			if(bUTC)
4061			{
4062				d.setUTCDate(1);
4063				d.setUTCFullYear(aResult['YYYY']);
4064				d.setUTCMonth(aResult['MM'] - 1);
4065				d.setUTCDate(aResult['DD']);
4066				d.setUTCHours(0, 0, 0);
4067			}
4068			else
4069			{
4070				d.setDate(1);
4071				d.setFullYear(aResult['YYYY']);
4072				d.setMonth(aResult['MM'] - 1);
4073				d.setDate(aResult['DD']);
4074				d.setHours(0, 0, 0);
4075			}
4076
4077			if(
4078				(!isNaN(aResult['HH']) || !isNaN(aResult['GG']) || !isNaN(aResult['H']) || !isNaN(aResult['G']))
4079					&& !isNaN(aResult['MI'])
4080			)
4081			{
4082				if (!isNaN(aResult['H']) || !isNaN(aResult['G']))
4083				{
4084					var bPM = (aResult['T']||aResult['TT']||'am').toUpperCase()=='PM';
4085					var h = parseInt(aResult['H']||aResult['G']||0, 10);
4086					if(bPM)
4087					{
4088						aResult['HH'] = h + (h == 12 ? 0 : 12);
4089					}
4090					else
4091					{
4092						aResult['HH'] = h < 12 ? h : 0;
4093					}
4094				}
4095				else
4096				{
4097					aResult['HH'] = parseInt(aResult['HH']||aResult['GG']||0, 10);
4098				}
4099
4100				if (isNaN(aResult['SS']))
4101					aResult['SS'] = 0;
4102
4103				if(bUTC)
4104				{
4105					d.setUTCHours(aResult['HH'], aResult['MI'], aResult['SS']);
4106				}
4107				else
4108				{
4109					d.setHours(aResult['HH'], aResult['MI'], aResult['SS']);
4110				}
4111			}
4112
4113			return d;
4114		}
4115	}
4116
4117	return null;
4118};
4119
4120BX.selectUtils =
4121{
4122	addNewOption: function(oSelect, opt_value, opt_name, do_sort, check_unique)
4123	{
4124		oSelect = BX(oSelect);
4125		if(oSelect)
4126		{
4127			var n = oSelect.length;
4128			if(check_unique !== false)
4129			{
4130				for(var i=0;i<n;i++)
4131				{
4132					if(oSelect[i].value==opt_value)
4133					{
4134						return;
4135					}
4136				}
4137			}
4138
4139			oSelect.options[n] = new Option(opt_name, opt_value, false, false);
4140		}
4141
4142		if(do_sort === true)
4143		{
4144			this.sortSelect(oSelect);
4145		}
4146	},
4147
4148	deleteOption: function(oSelect, opt_value)
4149	{
4150		oSelect = BX(oSelect);
4151		if(oSelect)
4152		{
4153			for(var i=0;i<oSelect.length;i++)
4154			{
4155				if(oSelect[i].value==opt_value)
4156				{
4157					oSelect.remove(i);
4158					break;
4159				}
4160			}
4161		}
4162	},
4163
4164	deleteSelectedOptions: function(oSelect)
4165	{
4166		oSelect = BX(oSelect);
4167		if(oSelect)
4168		{
4169			var i=0;
4170			while(i<oSelect.length)
4171			{
4172				if(oSelect[i].selected)
4173				{
4174					oSelect[i].selected=false;
4175					oSelect.remove(i);
4176				}
4177				else
4178				{
4179					i++;
4180				}
4181			}
4182		}
4183	},
4184
4185	deleteAllOptions: function(oSelect)
4186	{
4187		oSelect = BX(oSelect);
4188		if(oSelect)
4189		{
4190			for(var i=oSelect.length-1; i>=0; i--)
4191			{
4192				oSelect.remove(i);
4193			}
4194		}
4195	},
4196
4197	optionCompare: function(record1, record2)
4198	{
4199		var value1 = record1.optText.toLowerCase();
4200		var value2 = record2.optText.toLowerCase();
4201		if (value1 > value2) return(1);
4202		if (value1 < value2) return(-1);
4203		return(0);
4204	},
4205
4206	sortSelect: function(oSelect)
4207	{
4208		oSelect = BX(oSelect);
4209		if(oSelect)
4210		{
4211			var myOptions = [];
4212			var n = oSelect.options.length;
4213			var i;
4214			for (i=0;i<n;i++)
4215			{
4216				myOptions[i] = {
4217					optText:oSelect[i].text,
4218					optValue:oSelect[i].value
4219				};
4220			}
4221			myOptions.sort(this.optionCompare);
4222			oSelect.length=0;
4223			n = myOptions.length;
4224			for(i=0;i<n;i++)
4225			{
4226				oSelect[i] = new Option(myOptions[i].optText, myOptions[i].optValue, false, false);
4227			}
4228		}
4229	},
4230
4231	selectAllOptions: function(oSelect)
4232	{
4233		oSelect = BX(oSelect);
4234		if(oSelect)
4235		{
4236			var n = oSelect.length;
4237			for(var i=0;i<n;i++)
4238			{
4239				oSelect[i].selected=true;
4240			}
4241		}
4242	},
4243
4244	selectOption: function(oSelect, opt_value)
4245	{
4246		oSelect = BX(oSelect);
4247		if(oSelect)
4248		{
4249			var n = oSelect.length;
4250			for(var i=0;i<n;i++)
4251			{
4252				oSelect[i].selected = (oSelect[i].value == opt_value);
4253			}
4254		}
4255	},
4256
4257	addSelectedOptions: function(oSelect, to_select_id, check_unique, do_sort)
4258	{
4259		oSelect = BX(oSelect);
4260		if(!oSelect)
4261			return;
4262		var n = oSelect.length;
4263		for(var i=0; i<n; i++)
4264			if(oSelect[i].selected)
4265				this.addNewOption(to_select_id, oSelect[i].value, oSelect[i].text, do_sort, check_unique);
4266	},
4267
4268	moveOptionsUp: function(oSelect)
4269	{
4270		oSelect = BX(oSelect);
4271		if(!oSelect)
4272			return;
4273		var n = oSelect.length;
4274		for(var i=0; i<n; i++)
4275		{
4276			if(oSelect[i].selected && i>0 && oSelect[i-1].selected == false)
4277			{
4278				var option = new Option(oSelect[i].text, oSelect[i].value);
4279				oSelect[i] = new Option(oSelect[i-1].text, oSelect[i-1].value);
4280				oSelect[i].selected = false;
4281				oSelect[i-1] = option;
4282				oSelect[i-1].selected = true;
4283			}
4284		}
4285	},
4286
4287	moveOptionsDown: function(oSelect)
4288	{
4289		oSelect = BX(oSelect);
4290		if(!oSelect)
4291			return;
4292		var n = oSelect.length;
4293		for(var i=n-1; i>=0; i--)
4294		{
4295			if(oSelect[i].selected && i<n-1 && oSelect[i+1].selected == false)
4296			{
4297				var option = new Option(oSelect[i].text, oSelect[i].value);
4298				oSelect[i] = new Option(oSelect[i+1].text, oSelect[i+1].value);
4299				oSelect[i].selected = false;
4300				oSelect[i+1] = option;
4301				oSelect[i+1].selected = true;
4302			}
4303		}
4304	}
4305};
4306
4307BX.getEventTarget = function(e)
4308{
4309	if(e.target)
4310	{
4311		return e.target;
4312	}
4313	else if(e.srcElement)
4314	{
4315		return e.srcElement;
4316	}
4317	return null;
4318};
4319
4320/******* HINT ***************/
4321// if function has 2 params - the 2nd one is hint html. otherwise hint_html is third and hint_title - 2nd;
4322// '<div onmouseover="BX.hint(this, 'This is &lt;b&gt;Hint&lt;/b&gt;')"'>;
4323// BX.hint(el, 'This is <b>Hint</b>') - this won't work, use constructor
4324BX.hint = function(el, hint_title, hint_html, hint_id)
4325{
4326	if (null == hint_html)
4327	{
4328		hint_html = hint_title;
4329		hint_title = '';
4330	}
4331
4332	if (null == el.BXHINT)
4333	{
4334		el.BXHINT = new BX.CHint({
4335			parent: el, hint: hint_html, title: hint_title, id: hint_id
4336		});
4337		el.BXHINT.Show();
4338	}
4339};
4340
4341BX.hint_replace = function(el, hint_title, hint_html)
4342{
4343	if (null == hint_html)
4344	{
4345		hint_html = hint_title;
4346		hint_title = '';
4347	}
4348
4349	if (!el || !el.parentNode || !hint_html)
4350			return null;
4351
4352	var obHint = new BX.CHint({
4353		hint: hint_html,
4354		title: hint_title
4355	});
4356
4357	obHint.CreateParent();
4358
4359	el.parentNode.insertBefore(obHint.PARENT, el);
4360	el.parentNode.removeChild(el);
4361
4362	obHint.PARENT.style.marginLeft = '5px';
4363
4364	return el;
4365};
4366
4367BX.CHint = function(params)
4368{
4369	this.PARENT = BX(params.parent);
4370
4371	this.HINT = params.hint;
4372	this.HINT_TITLE = params.title;
4373
4374	this.PARAMS = {};
4375	for (var i in this.defaultSettings)
4376	{
4377		if (null == params[i])
4378			this.PARAMS[i] = this.defaultSettings[i];
4379		else
4380			this.PARAMS[i] = params[i];
4381	}
4382
4383	if (null != params.id)
4384		this.ID = params.id;
4385
4386	this.timer = null;
4387	this.bInited = false;
4388	this.msover = true;
4389
4390	if (this.PARAMS.showOnce)
4391	{
4392		this.__show();
4393		this.msover = false;
4394		this.timer = setTimeout(BX.proxy(this.__hide, this), this.PARAMS.hide_timeout);
4395	}
4396	else if (this.PARENT)
4397	{
4398		BX.bind(this.PARENT, 'mouseover', BX.proxy(this.Show, this));
4399		BX.bind(this.PARENT, 'mouseout', BX.proxy(this.Hide, this));
4400	}
4401
4402	BX.addCustomEvent('onMenuOpen', BX.delegate(this.disable, this));
4403	BX.addCustomEvent('onMenuClose', BX.delegate(this.enable, this));
4404};
4405
4406BX.CHint.prototype.defaultSettings = {
4407	show_timeout: 1000,
4408	hide_timeout: 500,
4409	dx: 2,
4410	showOnce: false,
4411	preventHide: true,
4412	min_width: 250
4413};
4414
4415BX.CHint.prototype.CreateParent = function(element, params)
4416{
4417	if (this.PARENT)
4418	{
4419		BX.unbind(this.PARENT, 'mouseover', BX.proxy(this.Show, this));
4420		BX.unbind(this.PARENT, 'mouseout', BX.proxy(this.Hide, this));
4421	}
4422
4423	if (!params) params = {};
4424	var type = 'icon';
4425
4426	if (params.type && (params.type == "link" || params.type == "icon"))
4427		type = params.type;
4428
4429	if (element)
4430		type = "element";
4431
4432	if (type == "icon")
4433	{
4434		element = BX.create('IMG', {
4435			props: {
4436				src: params.iconSrc
4437					? params.iconSrc
4438					: "/bitrix/js/main/core/images/hint.gif"
4439			}
4440		});
4441	}
4442	else if (type == "link")
4443	{
4444		element = BX.create("A", {
4445			props: {href: 'javascript:void(0)'},
4446			html: '[?]'
4447		});
4448	}
4449
4450	this.PARENT = element;
4451
4452	BX.bind(this.PARENT, 'mouseover', BX.proxy(this.Show, this));
4453	BX.bind(this.PARENT, 'mouseout', BX.proxy(this.Hide, this));
4454
4455	return this.PARENT;
4456};
4457
4458BX.CHint.prototype.Show = function()
4459{
4460	this.msover = true;
4461
4462	if (null != this.timer)
4463		clearTimeout(this.timer);
4464
4465	this.timer = setTimeout(BX.proxy(this.__show, this), this.PARAMS.show_timeout);
4466};
4467
4468BX.CHint.prototype.Hide = function()
4469{
4470	this.msover = false;
4471
4472	if (null != this.timer)
4473		clearTimeout(this.timer);
4474
4475	this.timer = setTimeout(BX.proxy(this.__hide, this), this.PARAMS.hide_timeout);
4476};
4477
4478BX.CHint.prototype.__show = function()
4479{
4480	if (!this.msover || this.disabled) return;
4481	if (!this.bInited) this.Init();
4482
4483	if (this.prepareAdjustPos())
4484	{
4485		this.DIV.style.display = 'block';
4486		this.adjustPos();
4487
4488		BX.bind(window, 'scroll', BX.proxy(this.__onscroll, this));
4489
4490		if (this.PARAMS.showOnce)
4491		{
4492			this.timer = setTimeout(BX.proxy(this.__hide, this), this.PARAMS.hide_timeout);
4493		}
4494	}
4495};
4496
4497BX.CHint.prototype.__onscroll = function()
4498{
4499	if (!BX.admin || !BX.admin.panel || !BX.admin.panel.isFixed()) return;
4500
4501	if (this.scrollTimer) clearTimeout(this.scrollTimer);
4502
4503	this.DIV.style.display = 'none';
4504	this.scrollTimer = setTimeout(BX.proxy(this.Reopen, this), this.PARAMS.show_timeout);
4505};
4506
4507BX.CHint.prototype.Reopen = function()
4508{
4509	if (null != this.timer) clearTimeout(this.timer);
4510	this.timer = setTimeout(BX.proxy(this.__show, this), 50);
4511};
4512
4513BX.CHint.prototype.__hide = function()
4514{
4515	if (this.msover) return;
4516	if (!this.bInited) return;
4517
4518	BX.unbind(window, 'scroll', BX.proxy(this.Reopen, this));
4519
4520	if (this.PARAMS.showOnce)
4521	{
4522		this.Destroy();
4523	}
4524	else
4525	{
4526		this.DIV.style.display = 'none';
4527	}
4528};
4529
4530BX.CHint.prototype.__hide_immediately = function()
4531{
4532	this.msover = false;
4533	this.__hide();
4534};
4535
4536BX.CHint.prototype.Init = function()
4537{
4538	this.DIV = document.body.appendChild(BX.create('DIV', {
4539		props: {className: 'bx-panel-tooltip'},
4540		style: {display: 'none'},
4541		children: [
4542			BX.create('DIV', {
4543				props: {className: 'bx-panel-tooltip-top-border'},
4544				html: '<div class="bx-panel-tooltip-corner bx-panel-tooltip-left-corner"></div><div class="bx-panel-tooltip-border"></div><div class="bx-panel-tooltip-corner bx-panel-tooltip-right-corner"></div>'
4545			}),
4546			(this.CONTENT = BX.create('DIV', {
4547				props: {className: 'bx-panel-tooltip-content'},
4548				children: [
4549					BX.create('DIV', {
4550						props: {className: 'bx-panel-tooltip-underlay'},
4551						children: [
4552							BX.create('DIV', {props: {className: 'bx-panel-tooltip-underlay-bg'}})
4553						]
4554					})
4555				]
4556			})),
4557
4558			BX.create('DIV', {
4559				props: {className: 'bx-panel-tooltip-bottom-border'},
4560				html: '<div class="bx-panel-tooltip-corner bx-panel-tooltip-left-corner"></div><div class="bx-panel-tooltip-border"></div><div class="bx-panel-tooltip-corner bx-panel-tooltip-right-corner"></div>'
4561			})
4562		]
4563	}));
4564
4565	if (this.ID)
4566	{
4567		this.CONTENT.insertBefore(BX.create('A', {
4568			attrs: {href: 'javascript:void(0)'},
4569			props: {className: 'bx-panel-tooltip-close'},
4570			events: {click: BX.delegate(this.Close, this)}
4571		}), this.CONTENT.firstChild)
4572	}
4573
4574	if (this.HINT_TITLE)
4575	{
4576		this.CONTENT.appendChild(
4577			BX.create('DIV', {
4578				props: {className: 'bx-panel-tooltip-title'},
4579				text: this.HINT_TITLE
4580			})
4581		)
4582	}
4583
4584	if (this.HINT)
4585	{
4586		this.CONTENT_TEXT = this.CONTENT.appendChild(BX.create('DIV', {props: {className: 'bx-panel-tooltip-text'}})).appendChild(BX.create('SPAN', {html: this.HINT}));
4587	}
4588
4589	if (this.PARAMS.preventHide)
4590	{
4591		BX.bind(this.DIV, 'mouseout', BX.proxy(this.Hide, this));
4592		BX.bind(this.DIV, 'mouseover', BX.proxy(this.Show, this));
4593	}
4594
4595	this.bInited = true;
4596};
4597
4598BX.CHint.prototype.setContent = function(content)
4599{
4600	this.HINT = content;
4601
4602	if (this.CONTENT_TEXT)
4603		this.CONTENT_TEXT.innerHTML = this.HINT;
4604	else
4605		this.CONTENT_TEXT = this.CONTENT.appendChild(BX.create('DIV', {props: {className: 'bx-panel-tooltip-text'}})).appendChild(BX.create('SPAN', {html: this.HINT}));
4606};
4607
4608BX.CHint.prototype.prepareAdjustPos = function()
4609{
4610	this._wnd = {scrollPos: BX.GetWindowScrollPos(),scrollSize:BX.GetWindowScrollSize()};
4611	return BX.style(this.PARENT, 'display') != 'none';
4612};
4613
4614BX.CHint.prototype.getAdjustPos = function()
4615{
4616	var res = {}, pos = BX.pos(this.PARENT), min_top = 0;
4617
4618	res.top = pos.bottom + this.PARAMS.dx;
4619
4620	if (BX.admin && BX.admin.panel.DIV)
4621	{
4622		min_top = BX.admin.panel.DIV.offsetHeight + this.PARAMS.dx;
4623
4624		if (BX.admin.panel.isFixed())
4625		{
4626			min_top += this._wnd.scrollPos.scrollTop;
4627		}
4628	}
4629
4630	if (res.top < min_top)
4631		res.top = min_top;
4632	else
4633	{
4634		if (res.top + this.DIV.offsetHeight > this._wnd.scrollSize.scrollHeight)
4635			res.top = pos.top - this.PARAMS.dx - this.DIV.offsetHeight;
4636	}
4637
4638	res.left = pos.left;
4639	if (pos.left < this.PARAMS.dx)
4640		pos.left = this.PARAMS.dx;
4641	else
4642	{
4643		var floatWidth = this.DIV.offsetWidth;
4644
4645		var max_left = this._wnd.scrollSize.scrollWidth - floatWidth - this.PARAMS.dx;
4646
4647		if (res.left > max_left)
4648			res.left = max_left;
4649	}
4650
4651	return res;
4652};
4653
4654BX.CHint.prototype.adjustWidth = function()
4655{
4656	if (this.bWidthAdjusted) return;
4657
4658	var w = this.DIV.offsetWidth, h = this.DIV.offsetHeight;
4659
4660	if (w > this.PARAMS.min_width)
4661		w = Math.round(Math.sqrt(1.618*w*h));
4662
4663	if (w < this.PARAMS.min_width)
4664		w = this.PARAMS.min_width;
4665
4666	this.DIV.style.width = w + "px";
4667
4668	if (this._adjustWidthInt)
4669		clearInterval(this._adjustWidthInt);
4670	this._adjustWidthInt = setInterval(BX.delegate(this._adjustWidthInterval, this), 5);
4671
4672	this.bWidthAdjusted = true;
4673};
4674
4675BX.CHint.prototype._adjustWidthInterval = function()
4676{
4677	if (!this.DIV || this.DIV.style.display == 'none')
4678		clearInterval(this._adjustWidthInt);
4679
4680	var
4681		dW = 20,
4682		maxWidth = 1500,
4683		w = this.DIV.offsetWidth,
4684		w1 = this.CONTENT_TEXT.offsetWidth;
4685
4686	if (w > 0 && w1 > 0 && w - w1 < dW && w < maxWidth)
4687	{
4688		this.DIV.style.width = (w + dW) + "px";
4689		return;
4690	}
4691
4692	clearInterval(this._adjustWidthInt);
4693};
4694
4695BX.CHint.prototype.adjustPos = function()
4696{
4697	this.adjustWidth();
4698
4699	var pos = this.getAdjustPos();
4700
4701	this.DIV.style.top = pos.top + 'px';
4702	this.DIV.style.left = pos.left + 'px';
4703};
4704
4705BX.CHint.prototype.Close = function()
4706{
4707	if (this.ID && BX.WindowManager)
4708		BX.WindowManager.saveWindowOptions(this.ID, {display: 'off'});
4709	this.__hide_immediately();
4710	this.Destroy();
4711};
4712
4713BX.CHint.prototype.Destroy = function()
4714{
4715	if (this.PARENT)
4716	{
4717		BX.unbind(this.PARENT, 'mouseover', BX.proxy(this.Show, this));
4718		BX.unbind(this.PARENT, 'mouseout', BX.proxy(this.Hide, this));
4719	}
4720
4721	if (this.DIV)
4722	{
4723		BX.unbind(this.DIV, 'mouseover', BX.proxy(this.Show, this));
4724		BX.unbind(this.DIV, 'mouseout', BX.proxy(this.Hide, this));
4725
4726		BX.cleanNode(this.DIV, true);
4727	}
4728};
4729
4730BX.CHint.prototype.enable = function(){this.disabled = false;};
4731BX.CHint.prototype.disable = function(){this.__hide_immediately(); this.disabled = true;};
4732
4733/* ready */
4734if (document.addEventListener)
4735{
4736	__readyHandler = function()
4737	{
4738		document.removeEventListener("DOMContentLoaded", __readyHandler, false);
4739		runReady();
4740	}
4741}
4742else if (document.attachEvent)
4743{
4744	__readyHandler = function()
4745	{
4746		if (document.readyState === "complete")
4747		{
4748			document.detachEvent("onreadystatechange", __readyHandler);
4749			runReady();
4750		}
4751	}
4752}
4753
4754function bindReady()
4755{
4756	if (!readyBound)
4757	{
4758		readyBound = true;
4759
4760		if (document.readyState === "complete")
4761		{
4762			return runReady();
4763		}
4764
4765		if (document.addEventListener)
4766		{
4767			document.addEventListener("DOMContentLoaded", __readyHandler, false);
4768			window.addEventListener("load", runReady, false);
4769		}
4770		else if (document.attachEvent) // IE
4771		{
4772			document.attachEvent("onreadystatechange", __readyHandler);
4773			window.attachEvent("onload", runReady);
4774
4775			var toplevel = false;
4776			try {toplevel = (window.frameElement == null);} catch(e) {}
4777
4778			if (document.documentElement.doScroll && toplevel)
4779				doScrollCheck();
4780		}
4781	}
4782
4783	return null;
4784}
4785
4786
4787function runReady()
4788{
4789	if (!BX.isReady)
4790	{
4791		if (!document.body)
4792			return setTimeout(runReady, 15);
4793
4794		BX.isReady = true;
4795
4796		if (readyList && readyList.length > 0)
4797		{
4798			var fn, i = 0;
4799			while (readyList && (fn = readyList[i++]))
4800			{
4801				try{
4802					fn.call(document);
4803				}
4804				catch(e){
4805					BX.debug('BX.ready error: ', e);
4806				}
4807			}
4808
4809			readyList = null;
4810		}
4811
4812		// TODO: check ready handlers binded some other way;
4813	}
4814	return null;
4815}
4816
4817// hack for IE
4818function doScrollCheck()
4819{
4820	if (BX.isReady)
4821		return;
4822
4823	try {document.documentElement.doScroll("left");} catch( error ) {setTimeout(doScrollCheck, 1); return;}
4824
4825	runReady();
4826}
4827/* \ready */
4828
4829function _adjustWait()
4830{
4831	if (!this.bxmsg) return;
4832
4833	var arContainerPos = BX.pos(this),
4834		div_top = arContainerPos.top;
4835
4836	if (div_top < BX.GetDocElement().scrollTop)
4837		div_top = BX.GetDocElement().scrollTop + 5;
4838
4839	this.bxmsg.style.top = (div_top + 5) + 'px';
4840
4841	if (this == BX.GetDocElement())
4842	{
4843		this.bxmsg.style.right = '5px';
4844	}
4845	else
4846	{
4847		this.bxmsg.style.left = (arContainerPos.right - this.bxmsg.offsetWidth - 5) + 'px';
4848	}
4849}
4850
4851function _checkDisplay(ob, displayType)
4852{
4853	if (typeof displayType != 'undefined')
4854		ob.BXDISPLAY = displayType;
4855
4856	var d = ob.style.display || BX.style(ob, 'display');
4857	if (d != 'none')
4858	{
4859		ob.BXDISPLAY = ob.BXDISPLAY || d;
4860		return true;
4861	}
4862	else
4863	{
4864		ob.BXDISPLAY = ob.BXDISPLAY || 'block';
4865		return false;
4866	}
4867}
4868
4869function _processTpl(tplNode, cb, bKillTpl)
4870{
4871	if (tplNode)
4872	{
4873		if (bKillTpl)
4874			tplNode.parentNode.removeChild(tplNode);
4875
4876		var res = {}, nodes = BX.findChildren(tplNode, {attribute: 'data-role'}, true);
4877
4878		for (var i = 0, l = nodes.length; i < l; i++)
4879		{
4880			res[nodes[i].getAttribute('data-role')] = nodes[i];
4881		}
4882
4883		cb.apply(tplNode, [res]);
4884	}
4885}
4886
4887function _checkNode(obj, params)
4888{
4889	params = params || {};
4890
4891	if (BX.type.isFunction(params))
4892		return params.call(window, obj);
4893
4894	if (!params.allowTextNodes && !BX.type.isElementNode(obj))
4895		return false;
4896	var i,j,len;
4897	for (i in params)
4898	{
4899		if(params.hasOwnProperty(i))
4900		{
4901			switch(i)
4902			{
4903				case 'tag':
4904				case 'tagName':
4905					if (BX.type.isString(params[i]))
4906					{
4907						if (obj.tagName.toUpperCase() != params[i].toUpperCase())
4908							return false;
4909					}
4910					else if (params[i] instanceof RegExp)
4911					{
4912						if (!params[i].test(obj.tagName))
4913							return false;
4914					}
4915				break;
4916
4917				case 'class':
4918				case 'className':
4919					if (BX.type.isString(params[i]))
4920					{
4921						if (!BX.hasClass(obj, params[i]))
4922							return false;
4923					}
4924					else if (params[i] instanceof RegExp)
4925					{
4926						if (!BX.type.isString(obj.className) || !params[i].test(obj.className))
4927							return false;
4928					}
4929				break;
4930
4931				case 'attr':
4932				case 'attrs':
4933				case 'attribute':
4934					if (BX.type.isString(params[i]))
4935					{
4936						if (!obj.getAttribute(params[i]))
4937							return false;
4938					}
4939					else if (BX.type.isArray(params[i]))
4940					{
4941						for (j = 0, len = params[i].length; j < len; j++)
4942						{
4943							if (params[i] && !obj.getAttribute(params[i]))
4944								return false;
4945						}
4946					}
4947					else
4948					{
4949						for (j in params[i])
4950						{
4951							if(params[i].hasOwnProperty(j))
4952							{
4953								var q = obj.getAttribute(j);
4954								if (params[i][j] instanceof RegExp)
4955								{
4956									if (!BX.type.isString(q) || !params[i][j].test(q))
4957									{
4958										return false;
4959									}
4960								}
4961								else
4962								{
4963									if (q != '' + params[i][j])
4964									{
4965										return false;
4966									}
4967								}
4968							}
4969						}
4970					}
4971				break;
4972
4973				case 'property':
4974				case 'props':
4975					if (BX.type.isString(params[i]))
4976					{
4977						if (!obj[params[i]])
4978							return false;
4979					}
4980					else if (BX.type.isArray(params[i]))
4981					{
4982						for (j = 0, len = params[i].length; j < len; j++)
4983						{
4984							if (params[i] && !obj[params[i]])
4985								return false;
4986						}
4987					}
4988					else
4989					{
4990						for (j in params[i])
4991						{
4992							if (BX.type.isString(params[i][j]))
4993							{
4994								if (obj[j] != params[i][j])
4995									return false;
4996							}
4997							else if (params[i][j] instanceof RegExp)
4998							{
4999								if (!BX.type.isString(obj[j]) || !params[i][j].test(obj[j]))
5000									return false;
5001							}
5002						}
5003					}
5004				break;
5005
5006				case 'callback':
5007					return params[i](obj);
5008			}
5009		}
5010	}
5011
5012	return true;
5013}
5014
5015/* garbage collector */
5016function Trash()
5017{
5018	var i,len;
5019
5020	for (i = 0, len = garbageCollectors.length; i<len; i++)
5021	{
5022		try {
5023			garbageCollectors[i].callback.apply(garbageCollectors[i].context || window);
5024			delete garbageCollectors[i];
5025			garbageCollectors[i] = null;
5026		} catch (e) {}
5027	}
5028
5029	try {BX.unbindAll();} catch(e) {}
5030/*
5031	for (i = 0, len = proxyList.length; i < len; i++)
5032	{
5033		try {
5034			delete proxyList[i];
5035			proxyList[i] = null;
5036		} catch (e) {}
5037	}
5038*/
5039}
5040
5041if(window.attachEvent) // IE
5042	window.attachEvent("onunload", Trash);
5043else if(window.addEventListener) // Gecko / W3C
5044	//window.addEventListener('unload', Trash, false);
5045	window.addEventListener('pagehide', Trash, false);
5046else
5047	window.onunload = Trash;
5048/* \garbage collector */
5049
5050// set empty ready handler
5051BX(BX.DoNothing);
5052window.BX = BX;
5053BX.browser.addGlobalClass();
5054
5055/* data storage */
5056BX.data = function(node, key, value)
5057{
5058	if(typeof node == 'undefined')
5059		return undefined;
5060
5061	if(typeof key == 'undefined')
5062		return undefined;
5063
5064	if(typeof value != 'undefined')
5065	{
5066		// write to manager
5067		dataStorage.set(node, key, value);
5068	}
5069	else
5070	{
5071		var data;
5072
5073		// from manager
5074		if((data = dataStorage.get(node, key)) != undefined)
5075		{
5076			return data;
5077		}
5078		else
5079		{
5080			// from attribute data-*
5081			if('getAttribute' in node)
5082			{
5083				data = node.getAttribute('data-'+key.toString());
5084				if(data === null)
5085				{
5086					return undefined;
5087				}
5088				return data;
5089			}
5090		}
5091
5092		return undefined;
5093	}
5094};
5095
5096BX.DataStorage = function()
5097{
5098
5099	this.keyOffset = 1;
5100	this.data = {};
5101	this.uniqueTag = 'BX-'+Math.random();
5102
5103	this.resolve = function(owner, create){
5104		if(typeof owner[this.uniqueTag] == 'undefined')
5105			if(create)
5106			{
5107				try
5108				{
5109					Object.defineProperty(owner, this.uniqueTag, {
5110						value: this.keyOffset++
5111					});
5112				}
5113				catch(e)
5114				{
5115					owner[this.uniqueTag] = this.keyOffset++;
5116				}
5117			}
5118			else
5119				return undefined;
5120
5121		return owner[this.uniqueTag];
5122	};
5123	this.get = function(owner, key){
5124		if((owner != document && !BX.type.isElementNode(owner)) || typeof key == 'undefined')
5125			return undefined;
5126
5127		owner = this.resolve(owner, false);
5128
5129		if(typeof owner == 'undefined' || typeof this.data[owner] == 'undefined')
5130			return undefined;
5131
5132		return this.data[owner][key];
5133	};
5134	this.set = function(owner, key, value){
5135
5136		if((owner != document && !BX.type.isElementNode(owner)) || typeof value == 'undefined')
5137			return;
5138
5139		var o = this.resolve(owner, true);
5140
5141		if(typeof this.data[o] == 'undefined')
5142			this.data[o] = {};
5143
5144		this.data[o][key] = value;
5145	};
5146};
5147
5148// some internal variables for new logic
5149var dataStorage = new BX.DataStorage();	// manager which BX.data() uses to keep data
5150
5151BX.LazyLoad = {
5152	images: [],
5153	imageStatus: {
5154		hidden: -2,
5155		error: -1,
5156		"undefined": 0,
5157		inited: 1,
5158		loaded: 2
5159	},
5160	imageTypes: {
5161		image: 1,
5162		background: 2
5163	},
5164
5165	registerImage: function(id, isImageVisibleCallback)
5166	{
5167		if (BX.type.isNotEmptyString(id))
5168		{
5169			this.images.push({
5170				id: id,
5171				node: null,
5172				src: null,
5173				type: null,
5174				func: BX.type.isFunction(isImageVisibleCallback) ? isImageVisibleCallback : null,
5175				status: this.imageStatus.undefined
5176			});
5177		}
5178	},
5179
5180	registerImages: function(ids, isImageVisibleCallback)
5181	{
5182		if (BX.type.isArray(ids))
5183		{
5184			for (var i = 0, length = ids.length; i < length; i++)
5185			{
5186				this.registerImage(ids[i], isImageVisibleCallback);
5187			}
5188		}
5189	},
5190
5191	showImages: function(checkOwnVisibility)
5192	{
5193		var image = null;
5194		var isImageVisible = false;
5195
5196		checkOwnVisibility = (checkOwnVisibility !== false);
5197		for (var i = 0, length = this.images.length; i < length; i++)
5198		{
5199			image = this.images[i];
5200
5201			if (image.status == this.imageStatus.undefined)
5202			{
5203				this.initImage(image);
5204			}
5205
5206			if (image.status !== this.imageStatus.inited)
5207			{
5208				continue;
5209			}
5210
5211			if (
5212				!image.node
5213				|| !image.node.parentNode
5214			)
5215			{
5216				image.node = null;
5217				image.status = this.imageStatus.error;
5218				continue;
5219			}
5220
5221			isImageVisible = true;
5222			if (checkOwnVisibility && image.func)
5223			{
5224				isImageVisible = image.func(image);
5225			}
5226
5227			if (
5228				isImageVisible === true
5229				&& this.isElementVisibleOnScreen(image.node)
5230			)
5231			{
5232				if (image.type == this.imageTypes.image)
5233				{
5234					image.node.src = image.src;
5235				}
5236				else
5237				{
5238					image.node.style.backgroundImage = "url('" + image.src + "')";
5239				}
5240
5241				image.node.setAttribute("data-src", "");
5242				image.status = this.imageStatus.loaded;
5243			}
5244		}
5245	},
5246
5247	initImage: function(image)
5248	{
5249		image.status = this.imageStatus.error;
5250		var node = BX(image.id);
5251		if (node)
5252		{
5253			var src = node.getAttribute("data-src");
5254			if (BX.type.isNotEmptyString(src))
5255			{
5256				image.node = node;
5257				image.src = src;
5258				image.status = this.imageStatus.inited;
5259				image.type = (image.node.tagName.toLowerCase() == "img"
5260					? this.imageTypes.image
5261					: this.imageTypes.background
5262				);
5263			}
5264		}
5265	},
5266
5267	isElementVisibleOnScreen: function (element)
5268	{
5269		var coords = this.getElementCoords(element);
5270
5271		var windowTop = window.pageYOffset || document.documentElement.scrollTop;
5272		var windowBottom = windowTop + document.documentElement.clientHeight;
5273
5274		coords.bottom = coords.top + element.offsetHeight;
5275
5276		var topVisible = coords.top > windowTop && coords.top < windowBottom;
5277		var bottomVisible = coords.bottom < windowBottom && coords.bottom > windowTop;
5278
5279		return topVisible || bottomVisible;
5280	},
5281
5282	isElementVisibleOn2Screens: function(element)
5283	{
5284		var coords = this.getElementCoords(element);
5285
5286		var windowHeight = document.documentElement.clientHeight;
5287		var windowTop = window.pageYOffset || document.documentElement.scrollTop;
5288		var windowBottom = windowTop + windowHeight;
5289
5290		coords.bottom = coords.top + element.offsetHeight;
5291
5292		windowTop -= windowHeight;
5293		windowBottom += windowHeight;
5294
5295		var topVisible = coords.top > windowTop && coords.top < windowBottom;
5296		var bottomVisible = coords.bottom < windowBottom && coords.bottom > windowTop;
5297
5298		return topVisible || bottomVisible;
5299	},
5300
5301	getElementCoords: function(element)
5302	{
5303		var box = element.getBoundingClientRect();
5304
5305		return {
5306			originTop: box.top,
5307			originLeft: box.left,
5308			top: box.top + window.pageYOffset,
5309			left: box.left + window.pageXOffset
5310		};
5311	},
5312
5313	onScroll: function()
5314	{
5315		BX.LazyLoad.showImages();
5316	},
5317
5318	clearImages: function ()
5319	{
5320		this.images = [];
5321	}
5322
5323};
5324
5325BX.getCookie = function (name)
5326{
5327	var matches = document.cookie.match(new RegExp(
5328		"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
5329	));
5330
5331	return matches ? decodeURIComponent(matches[1]) : undefined;
5332};
5333
5334BX.setCookie = function (name, value, options)
5335{
5336	options = options || {};
5337
5338	var expires = options.expires;
5339	if (typeof(expires) == "number" && expires)
5340	{
5341		var currentDate = new Date();
5342		currentDate.setTime(currentDate.getTime() + expires * 1000);
5343		expires = options.expires = currentDate;
5344	}
5345
5346	if (expires && expires.toUTCString)
5347	{
5348		options.expires = expires.toUTCString();
5349	}
5350
5351	value = encodeURIComponent(value);
5352
5353	var updatedCookie = name + "=" + value;
5354
5355	for (var propertyName in options)
5356	{
5357		if (!options.hasOwnProperty(propertyName))
5358		{
5359			continue;
5360		}
5361		updatedCookie += "; " + propertyName;
5362		var propertyValue = options[propertyName];
5363		if (propertyValue !== true)
5364		{
5365			updatedCookie += "=" + propertyValue;
5366		}
5367	}
5368
5369	document.cookie = updatedCookie;
5370
5371	return true;
5372};
5373
5374BX.FixFontSize = function(params)
5375{
5376	var widthNode, computedStyles, width;
5377
5378	this.node = null;
5379	this.prevWindowSize = 0;
5380	this.prevWrapperSize = 0;
5381	this.mainWrapper = null;
5382	this.textWrapper = null;
5383	this.objList = params.objList;
5384	this.minFontSizeList = [];
5385	this.minFontSize = 0;
5386
5387	if (params.onresize)
5388	{
5389		this.prevWindowSize = window.innerWidth || document.documentElement.clientWidth;
5390		BX.bind(window, 'resize', BX.proxy(BX.throttle(this.onResize, 350),this));
5391	}
5392
5393	if (params.onAdaptiveResize)
5394	{
5395		widthNode = this.objList[0].scaleBy || this.objList[0].node;
5396		computedStyles = getComputedStyle(widthNode);
5397		this.prevWrapperSize = parseInt(computedStyles["width"]) - parseInt(computedStyles["paddingLeft"]) - parseInt(computedStyles["paddingRight"]);
5398		BX.bind(window, 'resize', BX.proxy(BX.throttle(this.onAdaptiveResize, 350),this));
5399	}
5400
5401	this.createTestNodes();
5402	this.decrease();
5403};
5404
5405BX.FixFontSize.prototype =
5406{
5407	createTestNodes: function()
5408	{
5409		this.textWrapper = BX.create('div',{
5410			style : {
5411				display : 'inline-block',
5412				whiteSpace : 'nowrap'
5413			}
5414		});
5415
5416		this.mainWrapper = BX.create('div',{
5417			style : {
5418				height : 0,
5419				overflow : 'hidden'
5420			},
5421			children : [this.textWrapper]
5422		});
5423
5424	},
5425	insertTestNodes: function()
5426	{
5427		document.body.appendChild(this.mainWrapper);
5428	},
5429	removeTestNodes: function()
5430	{
5431		document.body.removeChild(this.mainWrapper);
5432	},
5433	decrease: function()
5434	{
5435		var width,
5436			fontSize,
5437			widthNode,
5438			computedStyles;
5439
5440		this.insertTestNodes();
5441
5442		for(var i=this.objList.length-1; i>=0; i--)
5443		{
5444			widthNode = this.objList[i].scaleBy || this.objList[i].node;
5445			computedStyles = getComputedStyle(widthNode);
5446			width  = parseInt(computedStyles["width"]) - parseInt(computedStyles["paddingLeft"]) - parseInt(computedStyles["paddingRight"]);
5447			fontSize = parseInt(getComputedStyle(this.objList[i].node)["font-size"]);
5448
5449			this.textWrapperSetStyle(this.objList[i].node);
5450
5451			if(this.textWrapperInsertText(this.objList[i].node))
5452			{
5453				while(this.textWrapper.offsetWidth > width && fontSize > 0)
5454				{
5455					this.textWrapper.style.fontSize = --fontSize + 'px';
5456				}
5457
5458				if(this.objList[i].smallestValue)
5459				{
5460					this.minFontSize = this.minFontSize ? Math.min(this.minFontSize, fontSize) : fontSize;
5461
5462					this.minFontSizeList.push(this.objList[i].node)
5463				}
5464				else
5465				{
5466					this.objList[i].node.style.fontSize = fontSize + 'px';
5467				}
5468			}
5469		}
5470
5471		if(this.minFontSizeList.length > 0)
5472			this.setMinFont();
5473
5474		this.removeTestNodes();
5475
5476	},
5477	increase: function()
5478	{
5479		this.insertTestNodes();
5480		var width,
5481			fontSize,
5482			widthNode,
5483			computedStyles;
5484
5485		this.insertTestNodes();
5486
5487		for(var i=this.objList.length-1; i>=0; i--)
5488		{
5489			widthNode = this.objList[i].scaleBy || this.objList[i].node;
5490			computedStyles = getComputedStyle(widthNode);
5491			width  = parseInt(computedStyles["width"]) - parseInt(computedStyles["paddingLeft"]) - parseInt(computedStyles["paddingRight"]);
5492			fontSize = parseInt(getComputedStyle(this.objList[i].node)["font-size"]);
5493
5494			this.textWrapperSetStyle(this.objList[i].node);
5495
5496			if(this.textWrapperInsertText(this.objList[i].node))
5497			{
5498				while(this.textWrapper.offsetWidth < width && fontSize < this.objList[i].maxFontSize)
5499				{
5500					this.textWrapper.style.fontSize = ++fontSize + 'px';
5501				}
5502
5503				fontSize--;
5504
5505				if(this.objList[i].smallestValue)
5506				{
5507					this.minFontSize = this.minFontSize ? Math.min(this.minFontSize, fontSize) : fontSize;
5508
5509					this.minFontSizeList.push(this.objList[i].node)
5510				}
5511				else
5512				{
5513					this.objList[i].node.style.fontSize = fontSize + 'px';
5514				}
5515			}
5516		}
5517
5518		if(this.minFontSizeList.length > 0)
5519			this.setMinFont();
5520
5521		this.removeTestNodes();
5522	},
5523	setMinFont : function()
5524	{
5525		for(var i = this.minFontSizeList.length-1; i>=0; i--)
5526		{
5527			this.minFontSizeList[i].style.fontSize = this.minFontSize + 'px';
5528		}
5529
5530		this.minFontSize = 0;
5531	},
5532	onResize : function()
5533	{
5534		var width = window.innerWidth || document.documentElement.clientWidth;
5535
5536		if(this.prevWindowSize > width)
5537			this.decrease();
5538
5539		else if (this.prevWindowSize < width)
5540			this.increase();
5541
5542		this.prevWindowSize = width;
5543	},
5544	onAdaptiveResize : function()
5545	{
5546		var widthNode = this.objList[0].scaleBy || this.objList[0].node,
5547			computedStyles = getComputedStyle(widthNode),
5548			width = parseInt(computedStyles["width"]) - parseInt(computedStyles["paddingLeft"]) - parseInt(computedStyles["paddingRight"]);
5549
5550		if (this.prevWrapperSize > width)
5551			this.decrease();
5552		else if (this.prevWrapperSize < width)
5553			this.increase();
5554
5555		this.prevWrapperSize = width;
5556	},
5557	textWrapperInsertText : function(node)
5558	{
5559		if(node.textContent){
5560			this.textWrapper.textContent = node.textContent;
5561			return true;
5562		}
5563		else if(node.innerText)
5564		{
5565			this.textWrapper.innerText = node.innerText;
5566			return true;
5567		}
5568		else {
5569			return false;
5570		}
5571	},
5572	textWrapperSetStyle : function(node)
5573	{
5574		this.textWrapper.style.fontFamily = getComputedStyle(node)["font-family"];
5575		this.textWrapper.style.fontSize = getComputedStyle(node)["font-size"];
5576		this.textWrapper.style.fontStyle = getComputedStyle(node)["font-style"];
5577		this.textWrapper.style.fontWeight = getComputedStyle(node)["font-weight"];
5578		this.textWrapper.style.lineHeight = getComputedStyle(node)["line-height"];
5579	}
5580};
5581
5582BX.FixFontSize.init = function(params)
5583{
5584	return new BX.FixFontSize(params);
5585};
5586
5587if(typeof(BX.ParamBag) === "undefined")
5588{
5589	BX.ParamBag = function()
5590	{
5591		this._params = {};
5592	};
5593
5594	BX.ParamBag.prototype =
5595	{
5596		initialize: function(params)
5597		{
5598			this._params = params ? params : {};
5599		},
5600		getParam: function(name, defaultvalue)
5601		{
5602			var p = this._params;
5603			return typeof(p[name]) != "undefined" ? p[name] : defaultvalue;
5604		},
5605		setParam: function(name, value)
5606		{
5607			this._params[name] = value;
5608		},
5609		clear: function()
5610		{
5611			this._params = {};
5612		}
5613	};
5614
5615	BX.ParamBag.create = function(params)
5616	{
5617		var self = new BX.ParamBag();
5618		self.initialize(params);
5619		return self;
5620	}
5621}
5622
5623if(typeof(BX.Promise) === "undefined")
5624{
5625	BX.Promise = function(fn, ctx) // fn is future-reserved
5626	{
5627		this.state = null;
5628		this.value = null;
5629		this.reason = null;
5630		this.next = null;
5631		this.ctx = ctx || this;
5632
5633		this.onFulfilled = [];
5634		this.onRejected = [];
5635	};
5636	BX.Promise.prototype.fulfill = function(value)
5637	{
5638		this.checkState();
5639
5640		this.value = value;
5641		this.state = true;
5642		this.execute();
5643	};
5644	BX.Promise.prototype.reject = function(reason)
5645	{
5646		this.checkState();
5647
5648		this.reason = reason;
5649		this.state = false;
5650		this.execute();
5651	};
5652	BX.Promise.prototype.then = function(onFulfilled, onRejected)
5653	{
5654		if(BX.type.isFunction(onFulfilled))
5655		{
5656			this.onFulfilled.push(onFulfilled);
5657		}
5658		if(BX.type.isFunction(onRejected))
5659		{
5660			this.onRejected.push(onRejected);
5661		}
5662
5663		if(this.next === null)
5664		{
5665			this.next = new BX.Promise(null, this.ctx);
5666		}
5667
5668		if(this.state !== null) // if promise was already resolved, execute immediately
5669		{
5670			this.execute();
5671		}
5672
5673		return this.next;
5674	};
5675	
5676	BX.Promise.prototype.catch = function(onRejected)
5677	{
5678		if(BX.type.isFunction(onRejected))
5679		{
5680			this.onRejected.push(onRejected);
5681		}
5682
5683		if(this.next === null)
5684		{
5685			this.next = new BX.Promise(null, this.ctx);
5686		}
5687
5688		if(this.state !== null) // if promise was already resolved, execute immediately
5689		{
5690			this.execute();
5691		}
5692
5693		return this.next;
5694	};
5695	
5696	BX.Promise.prototype.setAutoResolve = function(way, ms)
5697	{
5698		this.timer = setTimeout(BX.delegate(function(){
5699			if(this.state === null)
5700			{
5701				this[way ? 'fulfill' : 'reject']();
5702			}
5703		}, this), ms || 15);
5704	};
5705	BX.Promise.prototype.cancelAutoResolve = function()
5706	{
5707		clearTimeout(this.timer);
5708	};
5709	/**
5710	 * Resolve function. This function allows promise chaining, like ..then().then()...
5711	 * Typical usage:
5712	 *
5713	 * var p = new Promise();
5714	 *
5715	 * p.then(function(value){
5716	 *  return someValue; // next promise in the chain will be fulfilled with someValue
5717	 * }).then(function(value){
5718	 *
5719	 *  var p1 = new Promise();
5720	 *  *** some async code here, that eventually resolves p1 ***
5721	 *
5722	 *  return p1; // chain will resume when p1 resolved (fulfilled or rejected)
5723	 * }).then(function(value){
5724	 *
5725	 *  // you can also do
5726	 *  var e = new Error();
5727	 *  throw e;
5728	 *  // it will cause next promise to be rejected with e
5729	 *
5730	 *  return someOtherValue;
5731	 * }).then(function(value){
5732	 *  ...
5733	 * }, function(reason){
5734	 *  // promise was rejected with reason
5735	 * })...;
5736	 *
5737	 * p.fulfill('let`s start this chain');
5738	 *
5739	 * @param x
5740	 */
5741	BX.Promise.prototype.resolve = function(x)
5742	{
5743		var this_ = this;
5744
5745		if(this === x)
5746		{
5747			this.reject(new TypeError('Promise cannot fulfill or reject itself')); // avoid recursion
5748		}
5749		// allow "pausing" promise chaining until promise x is fulfilled or rejected
5750		else if(x instanceof BX.Promise)
5751		{
5752			x.then(function(value){
5753				this_.fulfill(value);
5754			}, function(reason){
5755				this_.reject(reason);
5756			});
5757		}
5758		else // auto-fulfill this promise
5759		{
5760			this.fulfill(x);
5761		}
5762	};
5763	BX.Promise.prototype.execute = function()
5764	{
5765		if(this.state === null)
5766		{
5767			//then() must not be called before BX.Promise resolve() happens
5768			return;
5769		}
5770
5771		var value = undefined;
5772		var reason = undefined;
5773		var x = undefined;
5774		var k;
5775		if(this.state === true) // promise was fulfill()-ed
5776		{
5777			if(this.onFulfilled.length)
5778			{
5779				try
5780				{
5781					for(k = 0; k < this.onFulfilled.length; k++)
5782					{
5783						x = this.onFulfilled[k].apply(this.ctx, [this.value]);
5784						if(typeof x != 'undefined')
5785						{
5786							value = x;
5787						}
5788					}
5789				}
5790				catch(e)
5791				{
5792					if('console' in window)
5793					{
5794						console.dir(e);
5795					}
5796					BX.debug(e);
5797
5798					reason = e; // reject next
5799				}
5800			}
5801			else
5802			{
5803				value = this.value; // resolve next
5804			}
5805		}
5806		else if(this.state === false) // promise was reject()-ed
5807		{
5808			if(this.onRejected.length)
5809			{
5810				try
5811				{
5812					for(k = 0; k < this.onRejected.length; k++)
5813					{
5814						x = this.onRejected[k].apply(this.ctx, [this.reason]);
5815						if(typeof x != 'undefined')
5816						{
5817							value = x;
5818						}
5819					}
5820				}
5821				catch(e)
5822				{
5823					if('console' in window)
5824					{
5825						console.dir(e);
5826					}
5827					BX.debug(e);
5828
5829					reason = e; // reject next
5830				}
5831			}
5832			else
5833			{
5834				reason = this.reason; // reject next
5835			}
5836		}
5837
5838		if(this.next !== null)
5839		{
5840			if(typeof reason != 'undefined')
5841			{
5842				this.next.reject(reason);
5843			}
5844			else if(typeof value != 'undefined')
5845			{
5846				this.next.resolve(value);
5847			}
5848		}
5849	};
5850	BX.Promise.prototype.checkState = function()
5851	{
5852		if(this.state !== null)
5853		{
5854			throw new Error('You can not do fulfill() or reject() multiple times');
5855		}
5856	};
5857}
5858
5859})(window);
5860

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.