PageSourceSearch

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

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

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.