PageSourceSearch

https://sushilnoedelo.ru/bitrix/js/main/core/core.js?1491773263117307

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

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.