PageSourceSearch

https://www.mc-evromed.ru/bitrix/js/main/core/core.js

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

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.