PageSourceSearch

https://shepkinskoe.ru/bitrix/js/main/core/core.js?1540923918121473

js shepkinskoe.ru collected 2026-10-02 11:07:19 UTC 121,473 bytes, 6,026 lines download raw bytes

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

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.