PageSourceSearch

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

js intervalwatch.ru collected 2026-10-08 16:26:22 UTC 124,952 bytes, 6,254 lines download raw bytes

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

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.