PageSourceSearch

https://www.iqconsultancy.ru/bitrix/js/main/core/core.js

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

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.