/**
 * @author Vlad Yakovlev (red.scorpix@gmail.com)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @version 0.3 alpha 11
 * @date 2010-04-27
 * @requires jQuery 1.4.2
 *
 * @changelog
 * Version 0.3 alpha 11
 * а�аОаБаАаВаИаЛаИб�б� <code>$c.rad2Deg</code>, <code>$c.deg2Rad</code>, <code>$c.generateId</code>.
 *
 * @changelog
 * Version 0.3 alpha 10
 * аЂб�аГб� <code>html</code> аДаОаБаАаВаЛб�б�б�б�б� аКаЛаАб�б�б�, б�аОаДаЕб�аЖаАб�аИаЕ аИаНб�аОб�аМаАб�аИб� аО б�аИаПаЕ аИ аВаЕб�б�аИаИ аБб�аАб�аЗаЕб�аА.
 * <code>jCommon.popupBlock</code> аОаБаНаОаВаИаЛб�б� аДаО аВаЕб�б�аИаИ 2.1.8.
 * <code>jCommon.eventDispatcher</code> аОаБаНаОаВаИаЛб�б� аДаО аВаЕб�б�аИаИ 1.0.2.
 *
 * @changelog
 * Version 0.3 alpha 9
 * а�аОаБаАаВаЛаЕаН <code>jCommon.bezierCoords</code>.
 * а�аОб�аАаБаОб�аАаН <code>jCommon.attrSuffix</code>. а�аАаПаИб�аАаНб� б�аЕб�б�б�.
 * а�аОб�аАаБаОб�аАаН <code>jCommon.betweenNumber</code>. а�аАаПаИб�аАаНб� б�аЕб�б�б�.
 * а� <code>jCommon.popupWindow</code> б�аБб�аАаНаО аНаАаВаЕб�аИаВаАаНаИаЕ б�аОаБб�б�аИб� аНаА аВб�аЕ б�аЛаЕаМаЕаНб�б� б� аКаЛаАб�б�аОаМ <code>popup</code>.
 * <code>jCommon.popupBlock</code> аОаБаНаОаВаИаЛб�б� аДаО аВаЕб�б�аИаИ 2.1.6.
 * а�аМаЕб�б�аО аМаЕб�аОаДаА <code>dragDrop</code> аДаОаБаАаВаЛаЕаН <code>jCommon.draggable</code>.
 * <code>jCommon.extend</code> б�аЕаПаЕб�б� аВаОаЗаВб�аАб�аАаЕб� аОаБб�аЕаКб�.
 * а�аОаБаАаВаЛаЕаНб� аАаЛаИаАб�б� <code>plus</code> аИ <code>minus</code> аВ <code>jCommon.keyCode</code>.
 * а�аЕб�аОаДб� <code>jCommon.shortcuts</code> аВаОаЗаВб�аАб�аАаЕб� б�аАаМ аОаБб�аЕаКб� б�аЕаПаЕб�б�.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.supplant</code>.
 *
 * @changelog
 * Version 0.3 alpha 8
 * а�аПб�аИаМаИаЗаИб�аОаВаАаН <code>jCommon.cookie</code>.
 * а�аПб�аИаМаИаЗаИб�аОаВаАаН <code>jCommon.popupWindow</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.keyCode</code>.
 * а�аЗаМаЕаНаЕаН <code>jCommon.shortcuts</code>. а�аНаИб�аИаАаЛаИаЗаАб�аИб� б�б�б�аЛаОаК аПаО <code>link</code> аПб�аОаИаЗаВаОаДаИб�б�б� аВаНаЕ аОаБб�аЕаКб�аА.
 * а�аЗаМаЕаНаЕаН <code>jCommon.fixIePng</code>. а�аОаБаАаВаЛаЕаНб� аДаОаПаОаЛаНаИб�аЕаЛб�аНб�аЕ аНаАб�б�б�аОаЙаКаИ.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.extend</code>.
 * а�аОаБаАаВаЛаЕаНаА аВаОаЗаМаОаЖаНаОб�б�б� аНаАб�аЛаЕаДаОаВаАаНаИб� аКаЛаАб�б�аОаВ.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.abstract</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.loadImage</code>.
 * <code>jCommon.getSuffixClass</code> аПаЕб�аЕаИаМаЕаНаОаВаАаН аВ <code>jCommon.attrSuffix</code>.
 * <code>jCommon.getXml</code> аПаЕб�аЕаИаМаЕаНаОаВаАаН аВ <code>jCommon.xmlObject</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.betweenNumber</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.cleanToNumber</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.findInArray</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.formatNumber</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.inject</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.shuffleArray</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.sortNum</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.stripTags</code>.
 * а�аОаБаАаВаЛаЕаНб� аМаЕб�аОаДб� аМаАб�б�аИаВаОаВ, аКаОб�аОб�б�аЕ аПаОб�аВаИаЛаИб�б� аВ JavaScript 1.6 аДаЛб� б�аЕб� аБб�аАб�аЗаЕб�аОаВ, аКаОб�аОб�б�аЕ аНаЕ аПаОаДаДаЕб�аЖаИаВаАб�б� аИб� (аПаО аКб�аАаЙаНаЕаЙ аМаЕб�аЕ, IE lte 7): <code>every</code>, <code>filter</code>, <code>forEach</code>, <code>indexOf</code>, <code>lastIndexOf</code>, <code>map</code>, <code>some</code>.
 * а�аОаБаАаВаЛаЕаНб� аМаЕб�аОаДб� аДаЛб� б�аАаБаОб�б� б� SVG-б�аЛаЕаМаЕаНб�аАаМаИ.
 * а�аОаБаАаВаЛаЕаНб� <code>jCommon.hex2Rgb</code> аИ <code>jCommon.rgb2Hex</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.random</code>.
 * а�аОаБаАаВаЛаЕаНб� аМаЕб�аОаДб� аВ jQuery аДаЛб� аДб�аАаГ-аН-аДб�аОаПаА: <code>jQuery.drag</code>, <code>jQuery.releaseDrag</code>, <code>jQuery.undrag</code>.
 *
 * @changelog
 * Version 0.2.3.3
 * а�аОаБаАаВаЛаЕаН аПаАб�аАаМаЕб�б� <code>antialias</code> аДаЛб� VML-б�аЛаЕаМаЕаНб�аОаВ.
 *
 * @changelog
 * Version 0.2.3.2
 * а�б�аПб�аАаВаЛаЕаН аБаАаГ аВ <code>jCommon.webkitPlaceholder</code>.
 * <code>jCommon.eventDispatcher</code> б�аЕаПаЕб�б� аВаОаЗаВб�аАб�аАаЕб� аОаБб�аЕаКб�.
 * а�аОаБаАаВаЛаЕаНаА б�б�аНаКб�аИб� <code>jCommon.getSuffixClass()</code>.
 * аЂаЕаПаЕб�б� аМаОаЖаНаО аОаБб�аАб�аАб�б�б�б� аК <code>jCommon</code> б�аЕб�аЕаЗ аЗаНаАаК аДаОаЛаЛаАб�аА т�� <code>$c</code>.
 *
 * @changelog
 * Version 0.2.3.1
 * а�б�аПб�аАаВаЛаЕаН аБаАаГ аВ <code>jCommon.measurer</code>.
 * а�аОаБаАаВаЛаЕаНаА б�б�аНаКб�аИб� <code>jCommon.getXml</code>.
 *
 * @changelog
 * Version 0.2.3
 * <code>jCommon.popup</code> аПаЕб�аЕаИаМаЕаНаОаВаАаН аВ <code>jCommon.popupWindow</code>, аИб�аПб�аАаВаЛаЕаНб� аОб�аИаБаКаИ, аДаОаБаАаВаЛаЕаНб� аКаОаМаМаЕаНб�аАб�аИаИ.
 * <code>jCommon.keyNavigation</code> аПаЕб�аЕаИаМаЕаНаОаВаАаН аВ <code>jCommon.shortcuts</code>, аДаОаБаАаВаЛаЕаНб� аКаОаМаМаЕаНб�аАб�аИаИ.
 * <code>jCommon.popupBlock</code> аДаОб�аОб� аДаО аВаЕб�б�аИаИ 2.1.5.
 * <code>jCommon.labelPlaceholder</code> аДаОб�аОб� аДаО аВаЕб�б�аИаИ 0.1.2.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.eventDispatcher</code> аВаЕб�б�аИаИ 1.0.
 *
 * @changelog
 * Version 0.2.2
 * а�аОаБаАаВаЛаЕаН <code>jCommon.ns.ev</code>.
 *
 * @changelog
 * Version 0.2.1
 * а�аЕб�аАаНаИаЗаМ б�аИаКб�аА аПаОаЛб�аПб�аОаЗб�аАб�аНб�б� png аВ IE6 аПаЕб�аЕаНаЕб�аЕаН аВ б�б�аНаКб�аИб� <code>jCommon.fixIePng</code>.
 * а�аМаЕб�б�аО аПаЕб�аЕаМаЕаНаНаОаЙ <code>jCommon.isCanvas</code> б�аЕаПаЕб�б� <code>jCommon.support</code>, аКаОб�аОб�б�аЙ аИаМаЕаЕб� б�б�аИ б�аВаОаЙб�б�аВаА-б�аЛаАаГаА: <code>canvas</code>, <code>svg</code>, <code>vml</code>.
 * а�аЕб�аАаНаИаЗаМ б�аОаЗаДаАаНаИб� аПаЛаЕаЙб�б�аОаЛаДаЕб�аОаВ, аКаАаК аВ Webkit, аПаЕб�аЕаНаЕб�аЕаН аВ <code>jCommon.webkitPlaceholder</code>. а�аОаЖаНаО аДаОаБаАаВаЛб�б�б� аВб�б�б�аНб�б� б�аЕаКб�б�аОаВб�аЕ б�аЛаЕаМаЕаНб�б� б�аОб�аМб�.
 * <code>jCommon.utils</code> аПаЕб�аЕаНаЕб�аЕаН аВ <code>jCommon.keyNavigation</code> аИ <code>jCommon.poup</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.ns</code>, аКаОб�аОб�б�аЙ б�аОаДаЕб�аЖаИб� аНаЕаЙаМб�аПаЕаЙб�б� <code>svg</code> аИ <code>xlink</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.labelPlaceholder</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.browser</code>.
 * а�аОаБаАаВаЛаЕаН <code>jCommon.popupBlock</code>.
 * аЃаДаАаЛаЕаН <code>jCommon.object</code>.
 * а�б�аПб�аАаВаЛаЕаНаИаЕ аБаАаГаА т�� б�аЕаПаЕб�б� аНаЕ аДаОаБаАаВаЛб�б�б�б�б� аНаОаВб�аЕ html-б�аЛаЕаМаЕаНб�б� аВ <code>jCommon.measurer</code>.
 */

(function() {
	window.jCommon = window.$c = {

		/**
		 * а�аИаДаАаЕб� аИб�аКаЛб�б�аЕаНаИаЕ.
		 * @param {String} [message]
		 */
		'abstract': function(message) {
			throw('Abstract' + (message ? ': ' + message : ''));
		},


		/**
		 * а�аОаЗаВб�аАб�аАаЕб� б�б�б�б�аИаКб� аПаО аЗаАаДаАаНаНаОаМб� аПб�аЕб�аИаКб�б� б� аЗаНаАб�аЕаНаИб� аАб�б�аИаБб�б�аА б�аЛаЕаМаЕаНб�аА.
		 * @param {String|Element|jQuery} el
		 * @param {String} prefix
		 * @param {String} [attrName = 'class']
		 * @return {String}
		 *
		 * @example
		 * $c.attrSuffix($(<div class="block id_2"></div>), 'id_'); // 2
		 * $c.attrSuffix($(<div id="id_2"></div>), 'id_', 'id'); // 2
		 */
		attrSuffix: function(el, prefix, attrName) {
			var
				pattern = new RegExp('\\b(' + prefix + '\\w*)\\b'),
				parts = pattern.exec($(el).attr(attrName || 'class'));

			return parts && parts[1] ? parts[1].substr(prefix.length) : false;
		},


		/**
		 * а�аПб�аЕаДаЕаЛб�аЕб�, аНаАб�аОаДаИб�б�б� аЛаИ аЗаНаАб�аЕаНаИаЕ аПаЕб�аВаОаГаО аАб�аГб�аМаЕаНб�аА аВ аДаИаАаПаАаЗаОаНаЕ.
		 * @param {Number|String} source а�б�аОаВаЕб�б�аЕаМаОаЕ аЗаНаАб�аЕаНаИаЕ.
		 * @param {Number} a а�аЕб�аВаОаЕ аЗаНаАб�аЕаНаИаЕ аДаИаАаПаАаЗаОаНаА.
		 * @param {Number} b а�б�аОб�аОаЕ аЗаНаАб�аЕаНаИаЕ аДаИаАаПаАаЗаОаНаА.
		 * @param {Boolean} [strict = false] аЄаЛаАаГ б�б�б�аОаГаОаГаО б�аОаОб�аВаЕб�б�б�аВаИб�.
		 * @return {Boolean}
		 *
		 * @example
		 * $c.betweenNumber(101, 100, 200); // true
		 * $c.betweenNumber(101, 200, 100); // true
		 * $c.betweenNumber(100, 200, 100, true); // true
		 */
		betweenNumber: function(source, a, b, strict) {
			var
				min = Math.min(a, b),
				max = Math.max(a, b),
				value = source.valueOf();

			return strict ? min <= value && value <= max : min < value && value < max;
		},

		/**
		 * @author John Resig (http://jquery.com/), Vlad Yakovlev (red.scorpix@gmail.com)
		 * @version 1.0
		 */
		browser: function() {
			var userAgent = window.navigator.userAgent.toLowerCase();

			return {
				version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
				webkit: /webkit/.test(userAgent),
				opera: /opera/.test(userAgent),
				msie: /msie/.test(userAgent) && !/opera/.test(userAgent),
				mozilla: /mozilla/.test(userAgent ) && !/(compatible|webkit)/.test(userAgent),
				safari: /safari/.test(userAgent) && !/chrome/.test(userAgent),
				chrome: /chrome/.test(userAgent)
			};
		}(),


		bezierCoords: function(parents, t) {

			while (3 < parents.length) {
				var childs = [];

				for (var i = 0; i < parents.length - 2; i++) {
					childs.push(parents[i] + (parents[i + 2] - parents[i]) * t);
				}

				parents = childs;
			}

			return parents;
		},


		/**
		 * а�б�аИб�аАаЕб� б�б�б�аОаКб� аОб� аНаЕб�аИб�аЛаОаВб�б� б�аИаМаВаОаЛаОаВ, аПб�аИаВаОаДб� аЕаЕ аК б�аИб�аЛб�.
		 * @param {String} source
		 * @return {Number}
		 */
		cleanToNumber: function(source) {
			var mayBeNumber = source.valueOf().replace(/[^\d\.]/g, '');

			return '' === mayBeNumber || isNaN(mayBeNumber) ? NaN : new Number(mayBeNumber);
		},


		/**
		 * аЁаОаЗаДаАаЕб� аКб�аКаИ аИаЛаИ аВаОаЗаВб�аАб�аАаЕб� аЗаНаАб�аЕаНаИаЕ.
		 *
		 * @example $c.cookie('the_cookie', 'the_value');
		 * @desc а�аАаДаАаЕб� аКб�аКаИ аДаЛб� б�аЕб�б�аИаИ.
		 *
		 * @example $c.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'site.com', secure: true });
		 * @desc аЁаОаЗаДаАаЕб� аКб�аКаИ б� аОаПб�аИб�аМаИ.
		 *
		 * @example $c.cookie('the_cookie', null);
		 * @desc аЃаДаАаЛб�аЕб� аКб�аКаИ.
		 *
		 * @example $c.cookie('the_cookie');
		 * @desc а�аОаЗаВб�аАб�аАаЕб� аЗаНаАб�аЕаНаИаЕ аКб�аКаИ.
		 *
		 * @param {String} name а�аМб� аКб�аКаИ.
		 * @param {String} value а�аНаАб�аЕаНаИаЕ аКб�аКаИ.
		 * @param {Object} options а�аБб�аЕаКб� аОаПб�аИаЙ аКб�аКаИ.
		 * @option {Number|Date} expires Either an integer specifying the expiration date from now on in days or a Date object.
		 *                               If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
		 *                               If set to null or omitted, the cookie will be a session cookie and will not be retained
		 *                               when the the browser exits.
		 * @option {String} path The value of the path atribute of the cookie (default: path of page that created the cookie).
		 * @option {String} domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
		 * @option {Boolean} secure If true, the secure attribute of the cookie will be set and the cookie transmission will
		 *                          require a secure protocol (like HTTPS).
		 *
		 * @return {mixed|jCommon} а�аНаАб�аЕаНаИаЕ аКб�аКаИ аИаЛаИ аОаБб�аЕаКб� jCommon.
		 *
		 * @author Klaus Hartl (klaus.hartl@stilbuero.de), Vlad Yakovlev (red.scorpix@gmail.com)
		 * @version 1.0.1
		 * @date 2009-11-12
		 */
		cookie: function(name, value, options) {

			if ('undefined' != typeof value) {
				options = options || {};

				if (null === value) {
					value = '';
					options.expires = -1;
				}

				// CAUTION: Needed to parenthesize options.path and options.domain in the following expressions,
				// otherwise they evaluate to undefined in the packed version for some reasonт�І
				var
					path = options.path ? '; path=' + options.path : '',
					domain = options.domain ? '; domain=' + options.domain : '',
					secure = options.secure ? '; secure' : '',
					expires = '';

				if (options.expires && ('number' == typeof options.expires || options.expires.toUTCString)) {
					var date;

					if ('number' == typeof options.expires) {
						date = new Date();
						date.setTime(date.getTime() + (options.expires * 86400000/*24 * 60 * 60 * 1000*/));
					} else {
						date = options.expires;
					}

					expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
				}

				window.document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');

				return this;
			}

			var cookieValue = null;

			if (document.cookie && '' != document.cookie) {
				$.each(document.cookie.split(';'), function() {
					var cookie = $.trim(this);

					// Does this cookie string begin with the name we want?
					if (cookie.substring(0, name.length + 1) == (name + '=')) {
						cookieValue = decodeURIComponent(cookie.substring(name.length + 1));

						return false;
					}
				});
			}

			return cookieValue;
		},


		/**
		 * а�аОаЗаВаОаЛб�аЕб� б�аАб�б�аИб�б�б�б� аОаБб�аЕаКб�б�.
		 * @param {Object} destination а�аБб�аЕаКб�, аКаОб�аОб�аОаМб� аДаОаБаАаВаЛб�б�б�б�б� б�аВаОаЙб�б�аВаА.
		 * @param {Object} source а�б�б�аОб�аНаИаК б�аВаОаЙб�б�аВ.
		 * @param {Boolean} [replace = false] а�аАаМаЕаНб�б�б� аЛаИ б�аВаОаЙб�б�аВаО, аЕб�аЛаИ аОаНаО б�аЖаЕ аПб�аИб�б�б�б�б�аВб�аЕб� аВ аОаБб�аЕаКб�аЕ.
		 * @return {Object} а�аБб�аЕаКб� б�аО б�аВаОаЙб�б�аВаАаМаИ.
		 */
		extend: function(destination, source, replace) {
			if (!('object' === typeof destination || $.isFunction(destination))) {
				destination = {};
			}
			if (!('object' === typeof source || $.isFunction(source))) {
				source = {};
			}

			for (var i in source) {
				if (source.hasOwnProperty(i) && (replace || undefined === destination[i]) && undefined !== source[i]) {
					destination[i] = source[i];
				}
			}

			return destination;
		},


		/**
		 *
		 * @param {Array} source
		 * @param {mixed} searchStr
		 * @return {Array}
		 */
		findInArray: function(source, searchStr) {
			var returnArray = false;

			for (var i = 0; i < source.length; i++) {
				if ('function' == typeof(searchStr)) {
					if (searchStr.test(source[i])) {
						if (!returnArray) {
							returnArray = [];
						}

						returnArray.push(i);
					}
				} else {
					if (source[i] === searchStr) {
						if (!returnArray) {
							returnArray = [];
						}

						returnArray.push(i);
					}
				}
			}

			return returnArray;
		},


		/**
		 * аЄаИаКб� аПаОаЛб�аПб�аОаЗб�аАб�аНб�б� PNG аВ IE6.
		 * @param {String|Element|Array[Element]|jQuery} el а­аЛаЕаМаЕаНб�, б� аКаОб�аОб�аОаГаО аНб�аЖаНаО б�аДаЕаЛаАб�б� б�аИаКб�.
		 * @param {Object} [options]
		 * @option {Boolean} [allIe = false] аЄаЛаАаГ, аДаЛб� аВб�аЕб� аЛаИ аВаЕб�б�аИаЙ IE аПб�аИаМаЕаНб�б�б� б�аИаЛб�б�б�.
		 * @option {String} [scaleMode = 'crop'] а аЕаЖаИаМ аМаАб�б�б�аАаБаИб�аОаВаАаНаИб�.
		 * @option {String} [emptySrc] а�б�б�б� аК б�аАаЙаЛб� аПб�аОаЗб�аАб�аНаОаГаО аИаЗаОаБб�аАаЖаЕаНаИб�.
		 * @option {Boolean} [notReplaceImg = false] аЄаЛаАаГ ТЋаНаЕ аЗаАаМаЕаНб�б�б� src аИаЗаОаБб�аАаЖаЕаНаИб�ТЛ.
		 *
		 * @example
		 * .png {
		 * 	filter:expression($c.fixIePng(this));
		 * }
		 * @description а�аОаБаАаВаЛб�аЕаМ аДаЛб� аВб�аЕб� б�аЛаЕаМаЕаНб�аОаВ аВ IE 6 аИ б�б�аАб�б�аЕ аПб�аИаНб�аДаИб�аЕаЛб�аНб�аЙ б�аИаЛб�б�б�.
		 *
		 * @example $c.fixIePng('img', true, 'scale');
		 * @description а�аОаБаАаВаЛб�аЕаМ аДаЛб� аВб�аЕб� аИаЗаОаБб�аАаЖаЕаНаИаЙ аВаО аВб�аЕб� IE б�аИаЛб�б�б� б� б�аЕаЖаИаМаОаМ <code>scale</code>.
		 *
		 * @version 1.1
		 * @date 2009-11-13
		 */
		fixIePng: function() {

			var
				reScaleMode = /iesizing_(\w+)/,
				prefix = 'file:///',
				/** а�б�б�б� аК аПб�аОаЗб�аАб�аНаОаМб� аГаИб�б�. */
				gifPath = prefix == location.href.substr(0, prefix.length) ? './f/global/i/0.gif' : '/f/global/i/0.gif';

			/**
			 * а�аОаБаАаВаЛб�аЕб� б�аИаЛб�б�б�.
			 * @param {Element} el
			 * @param {Object} [options]
			 * @option {String} [scaleMode = 'crop'] а аЕаЖаИаМ аМаАб�б�б�аАаБаИб�аОаВаАаНаИб�.
			 * @option {String} [emptySrc] а�б�б�б� аК б�аАаЙаЛб� аПб�аОаЗб�аАб�аНаОаГаО аИаЗаОаБб�аАаЖаЕаНаИб�.
			 * @option {Boolean} [notReplaceImg = false] аЄаЛаАаГ ТЋаНаЕ аЗаАаМаЕаНб�б�б� src аИаЗаОаБб�аАаЖаЕаНаИб�ТЛ.
			 */
			function filter(el, options) {
				var scaleMode = options.scaleMode || 'crop';
				var emptySrc = options.emptySrc || gifPath;

				var src;

				if (('IMG' == el.tagName || ('INPUT' == el.tagName && 'image' == el.type)) && !options.notReplaceImg) {
					if (/\.png$/.test(el.src)) {
						src = el.src;
						el.src = emptySrc;
					}
				} else {
					src = el.currentStyle.backgroundImage.match(/url\("(.+\.png)"\)/i);

					if (src) {
						src = src[1];
						el.runtimeStyle.backgroundImage = 'none';
					}
				}

				var m = reScaleMode.exec(el.className);

				if (m) {
					scaleMode = m[1];
				}

				if (src) {
					el.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "',sizingMethod='" + scaleMode + "')";
				}
			}

			return function(el, options) {
				if (!$c.browser.msie) return;

				options = options || {};

				if (options.allIe || 6 >= parseInt($c.browser.version)) {
					$(el).each(function() {
						filter(this, options);
					});
				}
			};
		}(),


		/**
		 *
		 * @param {String|Number} source
		 * @param {String} [groupSeparator = ' ']
		 * @param {String} [fractionSeparator = ',']
		 * @return {String}
		 */
		formatNumber: function(source, groupSeparator, fractionSeparator) {
			source = source.toString();

			var
				groupSeparator = groupSeparator || ' ',
				fractionSeparator = fractionSeparator || ',',
				/** @type {Number} */
				fractionIndex = source.indexOf('.'),
				/** @type {String} */
				fraction = fractionIndex > -1 ? source.substring(fractionIndex + 1) : '',
				/** @type {String} */
				number = fractionIndex > -1 ? source.substring(0, fractionIndex) : source;

			if (5 > number.length) {
				return number + (fractionIndex > -1 ? fractionSeparator + fraction : '');
			}

			var result = '';

			while (3 < number.length) {
				result = number.substring(number.length - 3) + (result.length > 0 ? groupSeparator : '') + result;
				number = number.substring(0, number.length - 3);
			}

			result = number + groupSeparator + result + (-1 < fractionIndex ? fractionSeparator + fraction : '');

			return result;
		},


		/**
		 * аЈаАаБаЛаОаНаИаЗаИб�б�аЕб� б�аЕаКб�б�б�б� б�б�б�аОаКб�, аВаПб�б�б�аКаИаВаАб� аВ аНб�аЖаНб�аЕ аМаЕб�б�аА аЗаНаАб�аЕаНаИб� аИаЗ oData.
		 * @example "height:{hey}px{semi}".inject({ hey: 100, semi: ";" }) -> "height:100px;".
		 * @param {String} s
		 * @param {Object} data
		 * @return {String}
		 */
		inject: function(s, data){
			return s.replace(/{([^{}]*)}/g, function(match, itemKey) {
				var itemData = data[itemKey];

				return undefined !== itemData && ('string' === typeof itemData || 'number' === typeof itemData) ? new String(itemData) : match;
			});
		},


		/**
		 * а�аАаГб�б�аЖаАаЕб� аИаЗаОаБб�аАаЖаЕаНаИаЕ.
		 * @param {String} src а�б�б�б� аК б�аАаЙаЛб� аИаЗаОаБб�аАаЖаЕаНаИб�.
		 * @param {Function} [callback] аЄб�аНаКб�аИб�, аВб�аЗб�аВаАаЕаМаАб� аПаО аОаКаОаНб�аАаНаИаИ аЗаАаГб�б�аЗаКаИ.
		 */
		loadImage: function(src, callback) {
			var imgEl = new Image();
			$(imgEl).load(callback || $.noop);
			imgEl.src = src;
		},


		/**
		 * а�аОаПаАаПб� б� аОб�аКб�б�б�аИаЕаМ аНаОаВаОаГаО аОаКаНаА аБб�аАб�аЗаЕб�аА.
		 *
		 * а�аОб�аЛаЕ аЗаАаГб�б�аЗаКаИ аДаОаКб�аМаЕаНб�аА аАаВб�аОаМаАб�аИб�аЕб�аКаИ б�аОаЗаДаАб�б�б�б� б�б�аНаДаЛаЕб�б� аНаА б�аОаЗаДаАаНаИаЕ аПаОаПаАаПаОаВ б� б�аЛаЕаМаЕаНб�аОаВ б� аКаЛаАб�б�аОаМ <code>popup</code>.
		 * @param {String|Array[Element]|Element|jQuery} el а­аЛаЕаМаЕаНб�(б�) jQuery.
		 * @param {Object} options аЁаВаОаЙб�б�аВаА б�аОаЗаДаАаВаАаЕаМаОаГаО аОаКаНаА.
		 *
		 * @example $c.popupWindow.add('.popup_els', { menubar: 'yes' });
		 *
		 * @version 0.1.3
		 * @date 2010-02-15
		 */
		popupWindow: function() {

			/**
			 * а�аЛаАб�б� аДаЛб� б�аОаЗаДаАаНаИб� аПаОаПаАаПаОаВ.
			 * @param {String|Array[Element]|Element|jQuery} el а­аЛаЕаМаЕаНб�(б�) jQuery.
			 * @param {Object} options аЁаВаОаЙб�б�аВаА б�аОаЗаДаАаВаАаЕаМаОаГаО аОаКаНаА.
			 */
			function popup(el, options) {

				$(el).click(function() {
					bind($(this).attr('href'), '', undefined === options ? {} : options);

					return false;
				});

				/**
				 * аЁаОаЗаДаАаЕб� аПаОаПаАаП.
				 * @param {String} url а�аДб�аЕб�, аПаО аКаОб�аОб�аОаМб� аОб�аКб�аОаЕб�б�б� аПаОаПаАаП. а�б�аЛаИ б�аКаАаЗаАаНаО аИаЗаОаБб�аАаЖаЕаНаИаЕ, б�аО б�аОаЗаДаАаЕб�б�б� б�аЕаЛаО аДаОаКб�аМаЕаНб�аА б� аИаЗаОаБб�аАаЖаЕаНаИаЕаМ аВаНб�б�б�аИ.
				 * @param {String} name аЂаАаЙб�аЛ аОаКаНаА.
				 * @param {Object} options аЁаВаОаЙб�б�аВаА аОаКаНаА.
				 */
				function bind(url, name, options) {
					var popupDefaults = {
						height: 600,
						menubar: 'no',
						resizeable: 'yes',
						scrollbars: 'yes',
						status: 'yes',
						toolbar: 'no',
						width: 540
					};
					var optionsPlane = [];
					var empty = {};

					$c.extend(options, popupDefaults);
					options.left = Math.round((screen.availWidth - options.width) / 2);
					options.top = Math.round((screen.availHeight - options.height) / 2);

					$.each(options, function() {
						optionsPlane.push(id + '=' + this);
					});

					/** @type {Window} */
					var newWindow = window.open(url, '', optionsPlane.join(','));

					if (url.match(/\.(gif|jpe?g|png)$/i)) {
						newWindow.document.open();
						newWindow.document.write('<html><head>' + ('' != name ? '<title>' + name + '</title>' : '') + '</head><body style="background: #fff; margin: 0; padding: 0;">' +
							'<table cellpadding="0" cellspacing="0" border="0" width="100%" height="100%"><tr><td align="center">' +
							'<img src="' + url + '" />' + '</td></tr></table></body></html>');
						newWindow.document.close();
					}

					newWindow.focus();
				}
			}

			return function(el, options) {
				$(el).each(function() {
					popup(this, options);
				});
			};
		}(),


		/**
		 * а�аОаЗаВб�аАб�аАаЕб� б�аЛб�б�аАаЙаНаОаЕ б�аЕаЛаОаЕ б�аИб�аЛаО.
		 * @param {Number} min а�аИаНаИаМаАаЛб�аНаОаЕ аЗаНаАб�аЕаНаИаЕ.
		 * @param {Number} max а�аАаКб�аИаМаАаЛб�аНаОаЕ аЗаНаАб�аЕаНаИаЕ.
		 * @requires {Number}
		 */
		random: function(min, max) {
			min = parseInt(min);
			max = parseInt(max);

			return Math.floor(Math.random() * (max - min + 1)) + min;
		},


		/**
		 * а�аЕб�аЕаМаЕб�аИаВаАаЕб� аМаАб�б�аИаВ.
		 * @param {Array} source
		 */
		shuffleArray: function(source) {
			for (var rnd, tmp, i = source.length; i; rnd = parseInt(Math.random() * i), tmp = source[--i], source[i] = source[rnd], source[rnd] = tmp);
		},


		/**
		 * аЁаОб�б�аИб�б�аЕб� б�аИб�аЛаОаВаОаЙ аМаАб�б�аИаВ.
		 * @param {Array} source
		 * @return {Array}
		 */
		sortNum: function(source) {
			return source.sort(function (a, b) {
				return a - b;
			});
		},


		/**
		 * аЃаДаАаЛб�аЕб� б�б�аГаИ.
		 * @return {String} source
		 * @return {String}
		 */
		stripTags: function(source) {
			return source.replace(/<\/?[^>]+>/gi, '');
		},

		/**
		 * supplant() does variable substitution on the string. It scans
		 * through the string looking for expressions enclosed in {} braces.
		 * If an expression is found, use it as a key on the object,
		 * and if the key has a string value or number value, it is
		 * substituted for the bracket expression and it repeats.
		 */
		supplant: function(str, o) {
			return str.replace(/{([^{}]*)}/g,
				function(a, b) {
					var r = o[b];
					return 'string' === typeof r || 'number' === typeof r ? r : a;
				}
			);
		},


		/**
		 * а�б�аОаВаЕб�аКаА аПаОаДаДаЕб�аЖаКаИ SVG, Canvas аИ VML.
		 * а�аОаЗаВб�аАб�аАаЕб� аОаБб�аЕаКб� б� б�б�аЕаМб� б�аВаОаЙб�б�аВаАаМаИ-б�аЛаАаГаАаМаИ: <code>canvas</code>, <code>svg</code> аИ <code>vml</code>.
		 * а�б�аЛаИ VML аПаОаДаДаЕб�аЖаИаВаАаЕб�б�б�, б�аО аИаНаИб�аИаАаЛаИаЗаИб�б�б�б�б�б� аНаЕаЙаМб�аПаЕаЙб�б�.
		 *
		 * @version 1.0
		 */
		support: function() {
			var result = {
				canvas: false,
				svg: document.createElementNS ? true : false,
				vml: false
			};

			if ('undefined' == typeof(HTMLCanvasElement)) {
				// а� IE аДаЛб� VML аНаАаДаО аДаОаБаАаВаИб�б� б�б�аЕаМб� аИ б�б�аИаЛаИ.
				if (!document.namespaces['v']) {
					document.namespaces.add('v', 'urn:schemas-microsoft-com:vml');
					document.namespaces.add('o', 'urn:schemas-microsoft-com:office:office');

					var ss = document.createStyleSheet();
					ss.cssText = 'v\\:arc,v\\:curve,v\\:extrusion,v\\:fill,v\\:formulas,v\\:group,v\\:handles,v\\:image,v\\:imagedata,v\\:line,v\\:oval,v\\:path,v\\:polyline,v\\:rect,v\\:roundrect,v\\:shadow,v\\:shape,v\\:shapetype,v\\:stroke,v\\:textbox,v\\:textpath,v\\:vmlframe{behavior:url(#default#VML);display:block;} o\\:callout, o\\:locks, o\\:skew {behavior:url(#default#VML);antialias:true;}';
				}

				result.vml = true;
			} else {
				result.canvas = true;
			}

			return result;
		}(),


		/**
		 * а�аОаЗаВб�аАб�аАаЕб� XML аИаЗ б�б�б�аОаКаИ.
		 * @param {String} text XML аВ б�б�б�аОаКаЕ.
		 * @return {Element} XML аВ аОаБб�аЕаКб�аЕ.
		 *
		 * @version 1.0
		 * @date 2009-08-18
		 *
		 * @example
		 * $.ajax({
		 *   dataType: 'text', // а�аБб�аЗаАб�аЕаЛб�аНаО, аЕб�аЛаИ б�аОб�аЕб�б� аПаОаЛб�б�аИб�б� XML
		 *   success: function(data) {
		 *     var xmlData = $c.xmlObject(data);
		 *     xmlData = $('result', xmlData);
		 *   }
		 *   // а�б�б�аГаИаЕ аПаАб�аАаМаЕб�б�б�
		 * });
		 */
		xmlObject: function(text) {
			var xmlData = null;

			try {
				if (window.ActiveXObject) { // IE
					xmlData = new ActiveXObject('Microsoft.XMLDOM');
					xmlData.async = false;
					xmlData.loadXML(text);
				} else if (window.DOMParser) { // а�б�аЕ аОб�б�аАаЛб�аНб�аЕ
					var xmlData = (new DOMParser()).parseFromString(text, 'text/xml');
				}

				if (!xmlData || !xmlData.documentElement || 'parsererror' == xmlData.documentElement.nodeName
					|| xmlData.getElementsByTagName('parsererror').length) {
					return false;
				}
			} catch (error) {
				return false;
			}

			return xmlData;
		}

	};



	$c.extend(Function, {
		/**
		 * а аЕаАаЛаИаЗб�аЕб� аНаАб�аЛаЕаДаОаВаАаНаИаЕ аКаЛаАб�б�аОаВ.
		 * @param {Function} BaseClass а�аАаЗаОаВб�аЙ аКаЛаАб�б�, аОб� аКаОб�аОб�аОаГаО аНаАб�аЛаЕаДб�аЕб�б�б� б�аЕаКб�б�аИаЙ аКаЛаАб�б�.
		 * @param {Object} overrides а�аЕб�аЕаЗаАаПаИб�б�аВаАаЕаМб�аЕ б�аВаОаЙб�б�аВаА.
		 */
		inheritFrom: function(BaseClass, overrides){
			var Inheritance = function() {};
			Inheritance.prototype = BaseClass.prototype;
			this.prototype = new Inheritance();
			this.prototype.constructor = this;
			this.baseConstructor = BaseClass;
			this.superClass = BaseClass.prototype;

			if (overrides) {
				for(var i in overrides) {
					this.prototype[i] = overrides[i];
				}
			}
		}
	});

	/**
	 * а�аАаВаИаГаАб�аИб� аПаО б�б�б�аЛаКаАаМ аВ б�б�аГаАб� <code>link</code>.
	 */
	$(function() {
		var navigationLinks = {
			start: 'home',
			prev: 'left',
			up: 'up',
			next: 'right',
			down: 'down'
		};

		$('head link').each(function() {
			var rel = $(this).attr('rel');

			if (navigationLinks[rel]) {
				$c.shortcuts.bind({
					keyCode: $c.keyCode(navigationLinks[rel]),
					ctrlCode: true
				}, $(this).attr('href'));
			}
		});
	});


	/**
	 * аЄаИаКб� аКб�б�аИб�аОаВаАаНаИб� аКаАб�б�аИаНаОаК аНаА б�б�б�аАаНаИб�аЕ аВ IE6.
	 */
	if ($c.browser.msie && 6 >= parseInt($c.browser.version)) {
		try {
			document.execCommand('BackgroundImageCache', false, true);
		} catch(e) {}
	}


	$c.extend(Array.prototype, {

		every: function(fun /*, thisp*/) {
			var len = this.length;

			if ('function' != typeof fun) {
				throw new TypeError('Not Function');
			}

			var thisp = arguments[1];

			for (var i = 0; i < len; i++) {
				if (i in this && !fun.call(thisp, this[i], i, this)) {
					return false;
				}
			}

			return true;
		},

		filter: function(fun /*, thisp*/) {
			var len = this.length;

			if ('function' != typeof fun) {
				throw new TypeError('Not Function');
			}

			var res = new Array();
			var thisp = arguments[1];

			for (var i = 0; i < len; i++) {
				if (i in this) {
					var val = this[i]; // in case fun mutates this

					if (fun.call(thisp, val, i, this)) {
						res.push(val);
					}
				}
			}

			return res;
		},

		forEach: function(fun /*, thisp*/) {
			var len = this.length;

			if ('function' != typeof fun) {
				throw new TypeError('Not Function');
			}

			var thisp = arguments[1];

			for (var i = 0; i < len; i++) {
				if (i in this) {
					fun.call(thisp, this[i], i, this);
				}
			}
		},

		indexOf: function(elt /*, from*/) {
			var len = this.length;
			var from = Number(arguments[1]) || 0;

			from = 0 > from ? Math.ceil(from) : Math.floor(from);

			if (0 > from) {
				from += len;
			}

			for (; from < len; from++) {
				if (from in this && this[from] === elt) {
					return from;
				}
			}

			return -1;
		},

		lastIndexOf: function(elt /*, from*/) {
			var len = this.length;
			var from = Number(arguments[1]);

			if (isNaN(from)) {
				from = len - 1;
			} else {
				from = 0 > from ? Math.ceil(from) : Math.floor(from);

				if (0 > from) {
					from += len;
				} else if (from >= len) {
					from = len - 1;
				}
			}

			for (; from > -1; from--) {
				if (from in this && this[from] === elt) {
					return from;
				}
			}

			return -1;
		},

		map: function(fun /*, thisp*/) {
			var len = this.length;

			if ('function' != typeof fun) {
				throw new TypeError('Not Function');
			}

			var res = new Array(len);
			var thisp = arguments[1];

			for (var i = 0; i < len; i++) {
				if (i in this) {
					res[i] = fun.call(thisp, this[i], i, this);
				}
			}

			return res;
		},

		some: function(fun /*, thisp*/) {
			var len = this.length;

			if ('function' != typeof fun) {
				throw new TypeError('Not Function');
			}

			var thisp = arguments[1];

			for (var i = 0; i < len; i++) {
				if (i in this && fun.call(thisp, this[i], i, this)) {
					return true;
				}
			}

			return false;
		}

	});


	(function() {
		var classes = ['js'];

		if ($c.browser.msie) {

		} else if ($c.browser.mozilla) {
			classes.push('mozilla');

			var
				peaces = $c.browser.version.split('.'),
				version = parseInt(peaces[0]) * 100000000;

			if (peaces[1]) {
				version += parseInt(peaces[1]) * 10000;
			}
			if (peaces[2]) {
				version += parseInt(peaces[2]);
			}

			if (100090000 <= version) {
				// Firefox >= 3, Gecko >= 1.9
				// Features: EXSLT, APNG,
				classes.push('mozilla_gte_1_9');
			}
			if (100090001 <= version) {
				// Firefox >= 3.5, Gecko >= 1.9.1
				// Features: W3C Geolocation API, video and audio tag, text shadow, Canvas Text API, Native JSON
				// Multi-touch, CSS3 Transform
				classes.push('mozilla_gte_1_9_1');
			}
			if (100090002 <= version) {
				// Firefox >= 3.6, Gecko >= 1.9.2
				// Features: Linear gradient background
				classes.push('mozilla_gte_1_9_2');
			}
			if (100090003 <= version) {
				// Firefox >= 3.7, Gecko >= 1.9.3
				// Features: CSS3 Transitions
				classes.push('mozilla_gte_1_9_3');
			}
			if (100090004 <= version) {
				// Firefox >= 4, Gecko >= 1.9.4
				classes.push('mozilla_gte_1_9_4');
			}

		} else if ($c.browser.webkit) {
			classes.push('webkit');

			var
				peaces = $c.browser.version.split('.'),
				version = parseInt(peaces[0]) * 10000;

			if (peaces[1]) {
				version += parseInt(peaces[1]);
			}

			if (5230010 <= version) {
				// Safari >= 3.0.4, Webkit >= 523.10
				classes.push('webkit_gte_523_10');
			}
			if (5230013 <= version) {
				// Safari >= 3.1, Webkit >= 523.13
				// а�аОаДаДаЕб�аЖаКаА б�б�аИб�б�аОаВ CSS, HTML 5.
				classes.push('webkit_gte_523_13');
			}
			if (5300017 <= version) {
				// Safari >= 4.0, Webkit >= 530.17
				// Features: Linear gradient background
				classes.push('webkit_gte_530_17');
			}

		} else if ($c.browser.opera) {
			classes.push('opera');
		}

		$(document.documentElement || document.body).attr('class', classes.join(' '));
	})();
})();


/**
 * а аАб�б�аИб�аЕаНаИб�
 */

/**
 * а�аОаЗаВб�аАб�аАаЕб� аКаОаД аКаЛаАаВаИб�аИ аПаО аЕаЕ аИаДаЕаНб�аИб�аИаКаАб�аОб�б�.
 * а аЕаГаИб�б�б� аИ аПб�аОаБаЕаЛб� аНаЕ б�б�аИб�б�аВаАб�б�б�б�.
 * а�б�аЛаИ аИаДаЕаНб�аИб�аИаКаАб�аОб� аНаЕ аИаЗаВаЕб�б�аЕаН, аВаОаЗаВб�аАб�аАаЕб� <code>undefined</code>.
 *
 * @example $c.keyCode(1)
 * @description а�аОаЗаВб�аАб�аИб� 49
 *
 * @example $c.keyCode('Caps Lock')
 * @example $c.keyCode('CApsLock')
 * @description а�аОаЗаВб�аАб�аИб� 20
 *
 * @param String|Number key а�аДаЕаНб�аИб�аИаКаАб�аОб� аКаЛаАаВаИб�аИ.
 * @return Number а�аОаД б�аИаМаВаОаЛаА.
 *
 * @version 0.1.1
 * @date 2009-12-08
 *
 * @changelog
 * Version 0.1.1
 * а�аОаБаАаВаЛаЕаН аКаОаД аДаЛб� Tab.
 */
$c.keyCode = function() {
	var codes = {
		alt: 18,
		backspace: 8,
		capslock: 20,
		control: 17,
		ctrl: 17,
		'delete': 46,
		del: 46,
		down: 40,
		end: 35,
		enter: 13,
		escape: 27,
		home: 36,
		insert: 45,
		left: 37,
		minus: 109,
		pagedown: 34,
		pageup: 33,
		plus: 61,
		right: 39,
		shift: 16,
		space: 32,
		tab: 9,
		up: 38
	};

	if (window.jCommon.browser.webkit) {
		codes.plus = 187;
		codes.minus = 189;
	}

	return function(key) {
		return codes[key.toString().replace(' ', '').toLowerCase()];
	};
}();


/**
 * а�аБб�аЕаКб� аДаЛб� б�аАаБаОб�б� б� аКаЛаАаВаИаАб�б�б�аНб�аМаИ б�аОаКб�аАб�аЕаНаИб�аМаИ.
 *
 * @example $c.shortcuts.unbind($c.keyCode('Enter'));
 * @description аЃаДаАаЛб�аЕб� аДаЕаЙб�б�аВаИаЕ аПб�аИ аНаАаЖаАб�аИаИ аКаЛаАаВаИб�аИ Enter.
 *
 * @example
 * $c.shortcuts.bind($c.keyCode('Right'), function(evt) {
 * 	alert(evt.keyCode);
 * });
 * аИаЛаИ
 * $c.shortcuts.bind('Right', function(evt) {
 * 	alert(evt.keyCode);
 * });
 * @description а�б�аИаВб�аЗб�аВаАаЕб� аК ТЋб�б�б�аЕаЛаКаА аВаПб�аАаВаОТЛ б�б�аНаКб�аИб�.
 *
 * @example
 * $c.shortcuts.bind('left right', function(evt) {
 * 	alert(evt.keyCode);
 * });
 * @description а�б�аИаВб�аЗб�аВаАаЕб� аК ТЋб�б�б�аЕаЛаКаА аВаПб�аАаВаОТЛ аИаЛаИ ТЋб�б�б�аЕаЛаКаА аВаЛаЕаВаОТЛ б�б�аНаКб�аИб�.
 *
 * @example
 * $c.shortcuts.bind({
 * 	keyCode: $c.keyCode('Right'),
 * 	ctrlKey: true
 * }, 'http://ya.ru');
 * @description а�б�аИаВб�аЗб�аВаАаЕб� аК Ctrl + ТЋб�б�б�аЕаЛаКаА аВаПб�аАаВаОТЛ аПаЕб�аЕб�аОаД аНаА аЏаНаДаЕаКб�.
 *
 * @example $c.shortcuts.unbindAll();
 * @description аЃаДаАаЛб�аЕб� аВб�аЕ аДаЕаЙб�б�аВаИб�.
 *
 * @version 1.1.1
 * @date 2009-12-27
 */
$c.shortcuts = function() {
	var
		binded = {},
		that = {};

	$(document).keydown(dispatch);

	function dispatch(evt) {
		var links = binded;

		for (var id in binded) {
			if (binded[id].keyCode == evt.keyCode && binded[id].ctrlKey == evt.ctrlKey && binded[id].altKey == evt.altKey && binded[id].shiftKey == evt.shiftKey) {
				if ('string' == typeof links[id].href && '' != binded[id].href) {
					document.location = links[id].href;
					return;
				} else if ($.isFunction(binded[id].href)) {
					return binded[id].href(evt);
				}
			}
		}
	}

	/**
	 * а�аОаЗаВб�аАб�аАаЕб� аИаДаЕаНб�аИб�аИаКаАб�аОб� б� б�б�аЕб�аОаМ б�аПаЕб�. аКаЛаАаВаИб�.
	 */
	function keyCodeId(keyCode) {
		if ('number' == typeof keyCode) return keyCode.toString();

		var parts = [ keyCode.keyCode.toString() ];
		keyCode.ctrlCode && parts.push('ctrl');
		keyCode.altCode && parts.push('alt');
		keyCode.shiftCode && parts.push('shift');

		return parts.join('_');
	}

	/**
	 * а�б�аИаВб�аЗб�аВаАаЕб� аК б�аОб�б�аКаАб�б� аКаЛаАаВаИаАб�б�б�б� аДаЕаЙб�б�аВаИаЕ.
	 *
	 * @param {Number|String|Object} keyCode а�аОаД аКаЛаАаВаИб�аИ. а�б�аЛаИ б�аИб�аЛаО, б�аО б�аОаЛб�аКаО аКаОаД аКаЛаАаВаИб�аИ.
	 *                                а�б�аЛаИ аОаБб�аЕаКб�, б�аО аКаОаД аКаЛаАаВаИб�аИ аИ б�аПаЕб�. аКаЛаАаВаИб�аИ.
	 * @option {Number} [keyCode] а�аОаД аКаЛаАаВаИб�аИ.
	 * @option {Boolean} [ctrlKey] а�аАаЖаАб� аЛаИ <code>Ctrl</code>.
	 * @option {Boolean} [altKey] а�аАаЖаАб� аЛаИ <code>Alt</code>.
	 * @option {Boolean} [shiftKey] а�аАаЖаАб� аЛаИ <code>Shift</code>.
	 *
	 * @param {String|Function} href а�б�аЛаИ б�б�б�аОаКаА, б�аО аОб�б�б�аЕб�б�аВаЛб�б�б� аПаЕб�аЕб�аОаД аПаО аАаДб�аЕб�б�, аЕб�аЛаИ б�б�аНаКб�аИб�, б�аО аВб�аПаОаЛаНаИб�б� б�б�аНаКб�аИб� (аПаЕб�аВб�аЙ аПаАб�аАаМаЕб�б� т�� аОаБб�аЕаКб� Event).
	 */
	that.bind = function(keyCode, href) {
		var
			code,
			options = {
				href: '',
				keyCode: '',
				ctrlKey: false,
				altKey: false,
				shiftKey: false
			};

		if ('string' == typeof keyCode) {
			$.each(keyCode.split(' '), function() {
				$c.extend(options, {
					href: href,
					keyCode: $c.keyCode(this)
				}, true);
				binded[keyCodeId($c.keyCode(this))] = options;
			});
		} else if ('number' == typeof keyCode) {
			$c.extend(options, {
				href: href,
				keyCode: keyCode
			}, true);
			binded[keyCodeId($c.keyCode(this))] = options;
		} else {
			binded[keyCodeId(keyCode)] = {
				href: href,
				keyCode: keyCode.keyCode,
				ctrlKey: !!keyCode.ctrlCode,
				altKey: !!keyCode.altCode,
				shiftKey: !!keyCode.shiftCode
			};
		}

		return that;
	};

	/**
	 * аЃаДаАаЛб�аЕб� аДаЕаЙб�б�аВаИаЕ аДаЛб� б�аОб�б�аКаАб�аА.
	 * @param {Number|String|Object} keyCode а�аОаД аКаЛаАаВаИб�аИ. а�б�аЛаИ б�аИб�аЛаО, б�аО б�аОаЛб�аКаО аКаОаД аКаЛаАаВаИб�аИ.
	 *                                а�б�аЛаИ аОаБб�аЕаКб�, б�аО аКаОаД аКаЛаАаВаИб�аИ аИ б�аПаЕб�. аКаЛаАаВаИб�аИ.
	 * @option {Number} [keyCode] а�аОаД аКаЛаАаВаИб�аИ.
	 * @option {Boolean} [ctrlKey] а�аАаЖаАб� аЛаИ <code>Ctrl</code>.
	 * @option {Boolean} [altKey] а�аАаЖаАб� аЛаИ <code>Alt</code>.
	 * @option {Boolean} [shiftKey] а�аАаЖаАб� аЛаИ <code>Shift</code>.
	 */
	that.unbind = function(keyCode) {
		if ('string' == typeof keyCode) {
			$.each(keyCode.split(' '), function() {
				delete binded[keyCodeId($c.keyCode(this))];
			});
		} else {
			delete binded[keyCodeId(keyCode)];
		}

		return that;
	};

	/**
	 * аЃаДаАаЛб�аЕб� аВб�аЕ б�аОб�б�аКаАб�б�.
	 */
	that.unbindAll = function() {
		binded = {};

		return that;
	};

	return that;
}();


/**
 * а�б�б�аЛаЕаЖаИаВаАаЕб� аИаЗаМаЕаНаЕаНаИаЕ б�аАаЗаМаЕб�аОаВ аОаКаНаА аБб�аАб�аЗаЕб�аА аИ аМаАб�б�б�аАаБаИб�аОаВаАаНаИаЕ б�аЕаКб�б�аА.
 * а�б�б�аЛаЕаЖаИаВаАаНаИаЕ аЗаАаПб�б�аКаАаЕб�б�б� б�аОаЛб�аКаО аПб�аИ аДаОаБаАаВаЛаЕаНаИаИ аПаЕб�аВаОаГаО б�б�аНаДаЛаЕб�аА.
 *
 * @example
 * function funcBind() { alert('yoop'); }
 * $c.measurer.bind(funcBind);
 * @description аЂаЕаПаЕб�б� б�б�аНаКб�аИб� аБб�аДаЕб� аВб�аПаОаЛаНб�б�б�б�б� аВб�б�аКаИаЙ б�аАаЗ, аКаОаГаДаА аИаЗаМаЕаНаИб�б�б� б�аАаЗаМаЕб� аОаКаНаА аБб�аАб�аЗаЕб�аА аИаЛаИ б�аАаЗаМаЕб� б�аЕаКб�б�аА.
 * $c.measurer.unbind(funcBind);
 * @description а� б�аЕаПаЕб�б� т�� аНаЕб�.
 *
 * @version 1.0
 */
$c.measurer = function() {

	var
		callbacks = [],
		interval = 500,
		curHeight,
		el,
		isInit = false,
		isDocReady = false;

	$(function() {
		isDocReady = true;
		isInit && initBlock();
	});

	function initBlock() {
		el = $('<div></div>').css({
			height: '1em',
			left: 0,
			lineHeight: '1em',
			margin: 0,
			position: 'absolute',
			padding: 0,
			top: '-1em',
			visibility: 'hidden',
			//width: '100%'
			width: '1em'
		}).appendTo('body');

		/**
		 * а� IE б�аОаБб�б�аИаЕ <code>onresize</code> б�б�аАаБаАб�б�аВаАаЕб� аИ аНаА б�аЛаЕаМаЕаНб�аАб�.
		 */
		if ($c.browser.msie) {
			el.resize(callFuncs);
			return;
		}

		/**
		 * а�аЛб� аОб�б�аАаЛб�аНб�б� аБб�аАб�аЗаЕб�аОаВ аПаЕб�аИаОаДаИб�аЕб�аКаИ аПб�аОаВаЕб�б�аЕаМ аИаЗаМаЕаНаЕаНаИаЕ б�аАаЗаМаЕб�аА б�аЕаКб�б�аА.
		 */
		curHeight = el.height();
		setInterval(function() {
			var newHeight = el.height();

			if (newHeight != curHeight) {
				curHeight = newHeight;
				callFuncs();
			}
		}, interval);
		$(window).resize(callFuncs);
	}

	function callFuncs() {
		for(var i = 0; i < callbacks.length; i++) {
			callbacks[i]();
		}
	}

	return {
		/**
		 * а б�б�аНаАб� аИаНаИб�аИаАаЛаИаЗаАб�аИб� б�аОаБб�б�аИб� аИаЗаМаЕаНаЕаНаИб� б�аАаЗаМаЕб�аОаВ б�аЛаЕаМаЕаНб�аОаВ аНаА б�б�б�аАаНаИб�аЕ.
		 */
		resize: callFuncs,

		/**
		 * а�аОаБаАаВаЛб�аЕб� аОаБб�аАаБаОб�б�аИаК б�аОаБб�б�аИб�.
		 * @param {Function} func аЁб�б�аЛаКаА аНаА б�б�аНаКб�аИб�, аКаОб�аОб�б�б� аНб�аЖаНаО аВб�аПаОаЛаНаИб�б�.
		 */
		bind: function(func) {
			if (!el) {
				isInit = true;
				isDocReady && initBlock();
			}

			callbacks.push(func);
		},

		/**
		 * аЃаДаАаЛб�аЕб� аОаБб�аАаБаОб�б�аИаК б�аОаБб�б�аИб�.
		 */
		unbind: function(func) {
			for(var i = 0; i < callbacks.length; i++) {
				callbacks[i] == func && callbacks.splice(i, 1);
			}
		}
	};
}();

/**
 * а­аМб�аЛаИб�б�аЕб� аПаОаВаЕаДаЕаНаИаЕ <input type="search" />, аКаАаК аВ Webkit.
 * @version 1.0
 */
$c.webkitPlaceholder = function() {

	if ($c.browser.webkit) return { bind: $.noop };

	$(function() {
		$('input[placeholder]').each(function () {
			bind(this);
		});
	});

	/**
	 * а�аОаБаАаВаЛб�аЕб� б�б�аНаКб�аИб� аПаЛаЕаЙб�б�аОаЛаДаЕб�аА б�аЛаЕаМаЕаНб�б�.
	 * @param {String|Array[Element]|Element|jQuery} els а�аОаЛб� аВаВаОаДаА
	 * @param {String} [class_empty = 'empty'] а�аЛаАб�б� аДаЛб� аПб�б�б�аОаГаО аПаОаЛб� аВаВаОаДаА
	 */
	function bind(els, classEmpty) {
		els = $(els);
		classEmpty = ('string' === typeof classEmpty) ? classEmpty : 'empty';

		els.focus(function () {
			if (this.value === $(this).attr('placeholder')) {
				this.value = '';
			}

			$(this).removeClass(classEmpty);
		});

		els.blur(function () {
			if (!this.value.length) {
				this.value = $(this).attr('placeholder');
				$(this).addClass(classEmpty);
			}
		});

		els.each(function() {
			$(this).val().length || $(this).blur();
		});
	}

	return {
		/**
		 * а�б�б�б�аНб�б� аДаОаБаАаВаЛб�аЕб� б�б�аНаКб�аИб� аПаЛаЕаЙб�б�аОаЛаДаЕб�аА б�аЛаЕаМаЕаНб�б�.
		 * @param {String|Array[Element]|Element|jQuery} elem а�аОаЛаЕ аВаВаОаДаА.
		 * @param {String} [class_empty] а�аЛаАб�б� аДаЛб� аПб�б�б�аОаГаО аПаОаЛб� аВаВаОаДаА.
		 */
		bind: bind
	};
}();


/**
 * а�аЕб�аКаИ аКаАаК аПаЛаЕаЙб�б�аОаЛаДаЕб�б�.
 *
 * @author Sergey Chikuyonok (serge.che@gmail.com), Vlad Yakovlev (red.scorpix@gmail.com)
 * @version 0.1.2
 * @date 2009-08-12
 *
 * @changelog
 * Version 0.1.2
 * а�аЕб�аЕаИаМаЕаНаОаВаАаНб� б�б�аНаКб�аИаИ аВ <code>bind</code> аИ <code>unbind</code>.
 *
 * @changelog
 * Version 0.1.1
 * аЂаЕаПаЕб�б� аМаОаЖаНаО аДаОаБаАаВаЛб�б�б� аИ б�аДаАаЛб�б�б� аПаЛаЕаЙб�б�аОаЛаДаЕб�б�, аНаО б�аОаЛб�аКаО аПаОб�аЛаЕ аЗаАаГб�б�аЗаКаИ аДаОаКб�аМаЕаНб�аА.
 */
$c.labelPlaceholder = function() {
	var dataKey = 'labelPlaceholder';
	var fieldsKey = 'bindedFields';

	/**
	 * а�аНаИб�аИаАаЛаИаЗаИб�б�аЕб� аПаОаЛб� б�аОб�аМб�, аДаЛб� аКаОб�аОб�б�б� аЕб�б�б� аЗаАаПаОаЛаНаИб�аЕаЛб� (placeholder).
	 */
	$(function() {
		$('label.placeholder').each(function(){
			linkPlaceholderWithField(this, '#' + $(this).attr('for'));
		});
	});

	/**
	 * аЁаВб�аЗб�аВаАаЕб� аВаМаЕб�б�аЕ аПаОаДаПаИб�б�-аЗаАаПаОаЛаНаИб�аЕаЛб� аИ аПаОаЛаЕ, аК аКаОб�аОб�аОаМб� аОаНаА аОб�аНаОб�аИб�б�б�.
	 * @param {String|Array[Element]|Element|jQuery} label а�аОаДаПаИб�б�-аЗаАаПаОаЛаНаИб�аЕаЛб�
	 * @param {String|Array[Element]|Element|jQuery} input а�аОаЛаЕ
	 */
	function linkPlaceholderWithField(label, field) {
		label = $(label);
		field = $(field);

		/** @type {Array} */
		var bindedFields = label.data(fieldsKey);

		if (!bindedFields) {
			bindedFields = [];
			label
				.data(fieldsKey, bindedFields)
				.click(focusOnField);
		}

		bindedFields.push(field[0]);
		field.data(dataKey, label)
			.bind('focus blur', placeholderSwitcher)
			.blur();
	}

	/**
	 * аЁб�аАаВаИб� б�аОаКб�б� аНаА аПаОаЛаЕ, аК аКаОб�аОб�аОаМб� аПб�аИаВб�аЗаАаН б�аЕаКб�б�аАб� аПаОаДаПаИб�б�-аЗаАаПаОаЛаНаИб�аЕаЛб�.
	 * а�аОаЛаЕаЗаНаО аИб�аПаОаЛб�аЗаОаВаАб�б� аВ б�аЛб�б�аАб�б�, аКаОаГаДаА аОаДаИаН аЗаАаПаОаЛаНаИб�аЕаЛб� аПб�аИаВб�аЗаАаН
	 * аК аНаЕб�аКаОаЛб�аКаИаМ аПаОаЛб�аМ.
	 * @param {Event} evt
	 */
	function focusOnField(evt) {
		var bindedFields = $(this).data(fieldsKey);

		if (bindedFields) {
			$(bindedFields).filter(':visible:first').focus();
			evt.preventDefault();
		}
	}

	/**
	 * аЄб�аНаКб�аИб�, аОб�аВаЕб�аАб�б�аАб� аЗаА аПаЕб�аЕаКаЛб�б�аЕаНаИаЕ аОб�аОаБб�аАаЖаЕаНаИб� аЗаАаПаОаЛаНаИб�аЕаЛб�.
	 * аЁб�аАаБаАб�б�аВаАаЕб� аАаВб�аОаМаАб�аИб�аЕб�аКаИ аПб�аИ б�аОаКб�б�аЕ/аБаЛб�б�аЕ б� б�аЛаЕаМаЕаНб�аА аВаВаОаДаА.
	 * @param {Event} evt
	 */
	function placeholderSwitcher(evt) {
		var
			input = $(this),
			label = input.data(dataKey);

		!$.trim(input.val()) && 'blur' == evt.type ? label.show() : label.hide();
	}

	function bind(label) {
		linkPlaceholderWithField(label, '#' + $(label).attr('for'));
	}

	function unbind(label) {
		label = $(label);
		var field = $('#' + label.attr('for'));

		label
			.data(fieldsKey, '')
			.unbind('click', focusOnField);
		field
			.data(dataKey, '')
			.unbind('focus blur', placeholderSwitcher);
	}

	return {

		/**
		 * а�аОаБаАаВаЛб�аЕб� аОаБб�аАаБаОб�б�аИаК.
		 * @param {String|Element|Array[Element]|jQuery} label а­аЛаЕаМаЕаНб� аМаЕб�аКаИ.
		 */
		bind: bind,

		/**
		 * аЃаДаАаЛб�аЕб� аОаБб�аАаБаОб�б�аИаКаИ б� б�аЛаЕаМаЕаНб�аОаВ.
		 * @param {String|Element|Array[Element]|jQuery} label а­аЛаЕаМаЕаНб� аМаЕб�аКаИ, б� аКаОб�аОб�аОаГаО аНб�аЖаНаО б�аДаАаЛаИб�б� аОаБб�аАаБаОб�б�аИаК.
		 */
		unbind: unbind
	};
}();


/**
 * а�аОаПаАаПб�-аБаЛаОаКаИ аВаНб�б�б�аИ аОаКаНаА аБб�аАб�аЗаЕб�аА.
 *
 * @param {String|Element|jQuery} container а�аОаНб�аЕаЙаНаЕб� аПаОаПаАаПаА.
 * @param {Object} options а�аАб�б�б�аОаЙаКаИ:
 * @option {String|Element|jQuery} fader а�аЛаОаК б�аЕаНаИ.
 * @option {String|Element|Array[Element]|jQuery} link а�аЛаОаКаИ аДаЛб� аПаОаКаАаЗаА/б�аКб�б�б�аИб� аПаОаПаАаПаА.
 * @option {String|Element|Array[Element]|jQuery} close а�аЛаОаКаИ аДаЛб� аЗаАаКб�б�б�аИб� аПаОаПаАаПаА.
 * @option {Function} beforeShow аЄб�аНаКб�аИб�, аВб�аПаОаЛаНб�аЕаМаАб� аПаЕб�аЕаД аОб�аКб�б�б�аИаЕаМ.
 * @option {Function} afterShow аЄб�аНаКб�аИб�, аВб�аПаОаЛаНб�аЕаМаАб� аПаОб�аЛаЕ аОб�аКб�б�б�аИб�.
 * @option {Function} beforeHide аЄб�аНаКб�аИб�, аВб�аПаОаЛаНб�аЕаМаАб� аПаЕб�аЕаД аЗаАаКб�б�б�аИаЕаМ.
 * @option {Function} afterHide аЄб�аНаКб�аИб�, аВб�аПаОаЛаНб�аЕаМаАб� аПаОб�аЛаЕ аЗаАаКб�б�б�аИб�.
 * @option {Boolean|Function} show = true аЄаЛаАаГ аАаНаИаМаАб�аИаИ аПаОаКаАаЗаА аПаОаПаАаПаА, б�аВаОб� б�б�аНаКб�аИб� (б�аОаГаДаА <code>afterShow</code> аНаЕ аВб�аПаОаЛаНб�аЕб�б�б�) аИаЛаИ аБаЕаЗ б�б�б�аЕаКб�аОаВ (false).
 * @option {Boolean|Function} hide = false аЄаЛаАаГ аАаНаИаМаАб�аИаИ б�аКб�б�б�аИб� аПаОаПаАаПаА, б�аВаОб� б�б�аНаКб�аИб� (б�аОаГаДаА <code>afterHide</code> аНаЕ аВб�аПаОаЛаНб�аЕб�б�б�) аИаЛаИ аБаЕаЗ б�б�б�аЕаКб�аОаВ (false).
 * @option {Boolean} escapeKey = true а�аАаКб�б�аВаАб�б� аЛаИ аПаОаПаАаП аПб�аИ аНаАаЖаАб�аИаИ аКаЛаАаВаИб�аИ Esc.
 * @option {Booleen} documentClick = true а�аАаКб�б�аВаАб�б� аЛаИ аПаОаПаАаП аПб�аИ аКаЛаИаКаЕ аВаНаЕ аПаОаПаАаПаА.
 *
 * @return {Object} аЄб�аНаКб�аИаИ:
 * <ul>
 *   <li>hide</li>
 *   <li>cancel</li>
 *   <li>show</li>
 *   <li>toggle</li>
 *   <li>unbind</li>
 * </ul>
 *
 * @author Stepan Reznikov [stepan.reznikov@gmail.com], Vladislav Yakovlev [red.scorpix@gmail.com]
 * @version 2.1.7
 * @date 2010-03-18
 *
 * @changelog
 * Version 2.1.8
 * а�аОаБаАаВаЛаЕаНаА аОаПб�аИб� <code>documentClick</code>.
 *
 * @changelog
 * Version 2.1.7
 * а�аОаБаАаВаЛаЕаН аМаЕб�аОаД <code>unbind</code>.
 *
 * @changelog
 * Version 2.1.6
 * а�аОаБаАаВаЛаЕаНб� аНаОаВб�аЕ аОаПб�аИаИ: <code>show</code>, <code>hide</code>, <code>escapeKey</code>.
 * а�б�аПб�аАаВаЛаЕаНаА аОб�аИаБаКаА, аКаОаГаДаА аЗаАаКб�б�аВаАаЛб�б� аПаОаПаАаП аПб�аИ аНаАаЖаАб�аИаИ аПб�аАаВаОаЙ аКаНаОаПаКаИ аМб�б�аИ.
 *
 * @changelog
 * Version 2.1.5
 * а�б�аПб�аАаВаЛаЕаНаА аОб�аИаБаКаИ, аПаО аКаОб�аОб�аОаЙ аБб�аЛаИ аПб�аОаБаЛаЕаМб� б� аМаНаОаЖаЕб�б�аВаЕаНаНб�аМ б�аОаЗаДаАаНаИаЕаМ аПаОаПаАаПаОаВ.
 * а�аПб�аИаМаИаЗаИб�аОаВаАаН аКаОаД.
 * а�аБб�аЗаАб�аЕаЛб�аНаАб� аОаПб�аИб� аБаЛаОаКаА аВб�аНаЕб�аЕаНаА аВ аОб�аДаЕаЛб�аНб�аЙ аПаАб�аАаМаЕб�б� <code>container</code>.
 *
 * @changelog
 * Version 2.1.4
 * а�аПб�аИаМаИаЗаИб�аОаВаАаН аКаОаД.
 *
 * @changelog
 * Version 2.1.3
 * а�аОаБаАаВаЛаЕаНб� аКаОаМаМаЕаНб�аАб�аИаИ.</li>
 * а�аАб�аАаМаЕб�б� <code>showFunction</code> б�аДаАаЛаЕаН.</li>
 * а�аОаБаАаВаЛаЕаНб� аПаАб�аАаМаЕб�б�б� <code>beforeShow</code>, <code>afterShow</code>, <code>beforeHide</code>, <code>afterHide</code>.</li>
 *
 * @changelog
 * Version 2.1
 * аЄаЛаАаГ <code>keep</code> аЗаАаМаЕаНаЕаН аНаА <code>event.stopPropagation().</code>
 * аЄаОб�аМаА аПаОб�аВаЛб�аЕб�б�б� аИ аИб�б�аЕаЗаАаЕб� аПаЛаАаВаНаО (аПаОаД IE аПаОб�аВаЛб�аЕб�б�б�/аИб�б�аЕаЗаАаЕб� аМаГаНаОаВаЕаНаНаО аВ аВаИаДб� аПб�аОаБаЛаЕаМ б� <code>filter</code>).
 * а�аОаБаАаВаЛаЕаН аПаАб�аАаМаЕб�б� <code>showFunction</code> - б�б�аНаКб�аИб�, аВб�аПаОаЛаНб�аЕаМаАб� аПаОб�аЛаЕ аПаОаКаАаЗаА popup'аА.
 */
$c.popupBlock = function(container, options) {

	container = $(container);
	options = $c.extend(options, {
		show: true,
		hide: false,
		escapeKey: true,
		documentClick: true
	});

	container.mousedown(containerStop);

	if (options.fader) {
		options.fader = $(options.fader);
	}

	if (options.link) {
		options.link = $(options.link);
		options.link.mousedown(toggle);
	}

	if (options.close) {
		options.close = $(options.close);
		options.close.mousedown(toggle);
	}

	var
		documentClickHandler,
		documentKeyDownHandler,
		docEl = $(document);

	function containerStop(event) {
		event.stopPropagation();
	}

	function cancel(event) {
		var code = event.keyCode ? event.keyCode : event.which ? event.which : null;

		if (27 === code) {
			hide(event);
		}
	}

	/**
	 * @param {Event} event
	 */
	function hide(event) {
		// а�б�аОаВаЕб�аКаА аНаА аНаАаЖаАб�аИаЕ аПб�аАаВаОаЙ аКаЛаАаВаИб�аИ аМб�б�аИ.
		if (event && 3 === event.which && $(event.target).parents().filter(container).length) {
			return;
		}

		if (options.documentClick) {
			docEl.unbind('mousedown', documentClickHandler);
		}

		if (options.escapeKey) {
			docEl.unbind('keydown', documentKeyDownHandler);
		}

		if (options.beforeHide) {
			options.beforeHide(event);
		}
		if (options.fader) {
			options.fader.addClass('hidden');
		}

		if (!options.hide || (true === options.hide && $c.browser.msie)) {
			container.addClass('hidden');

			if (options.afterHide) {
				options.afterHide(event);
			}
		} else if (true === options.hide) {
			container
				.css('opacity', 1)
				.animate({ opacity: 0 }, {
					duration: 300,
					complete: function() {
						container.addClass('hidden').css('opacity', '');

						if (options.afterHide) {
							options.afterHide(event);
						}
					}
				});
		} else {
			options.hide();
		}

		return false;
	}

	function show(event) {

		if (options.documentClick) {
			documentClickHandler = hide;
			docEl.mousedown(documentClickHandler);
		}

		if (options.escapeKey) {
			documentKeyDownHandler = cancel;
			docEl.keydown(documentKeyDownHandler);
		}

		if (options.beforeShow) {
			options.beforeShow(event);
		}
		if (options.fader) {
			options.fader.removeClass('hidden');
		}

		if (!options.show || (true === options.show && $c.browser.msie)) {
			container.removeClass('hidden');

			if (options.afterShow) {
				options.afterShow(event);
			}
		} else if (true === options.show) {
			container.css('opacity', 0)
				.removeClass('hidden')
				.animate({ opacity: 1 }, {
					duration: 300,
					complete: function() {
						container.css('opacity', '');

						if (options.afterShow) {
							options.afterShow(event);
						}
					}
				});
		} else {
			options.show();
		}

		return false;
	}

	function toggle(event) {
		return container.hasClass('hidden') ? show(event) : hide(event);
	}

	function unbind() {
		container.unbind('mousedown', containerStop);

		if (options.link) {
			options.link.unbind('mousedown', toggle);
		}

		if (options.close) {
			options.close.unbind('mousedown', toggle);
		}
	}

	return {

		/**
		 * а�б�аЗб�аВаАаЕб� б�аОаБб�б�аИаЕ б�аКб�б�б�аИб� аПаОаПаАаПаА.
		 * @param {Event} [event]
		 */
		hide: hide,

		/**
		 * а�б�аЗб�аВаАаЕб� б�аОаБб�б�аИаЕ аПаОаКаАаЗаА аПаОаПаАаПаА.
		 * @param {Event} [event]
		 */
		show: show,

		/**
		 * а�б�аЗб�аВаАаЕб� б�аОаБб�б�аИаЕ аПаЕб�аЕаКаЛб�б�аЕаНаИб� б�аОб�б�аОб�аНаИб� аПаОаПаАаПаА.
		 * @param {Event} [event]
		 */
		toggle: toggle,

		/**
		 * а�б�аПаИб�б�аВаАаЕб� аОб� б�аОаБб�б�аИаЙ.
		 */
		unbind: unbind
	};
};


/**
 * а�аИб�аПаЕб�б�аЕб� аЛб�аБб�б� б�аОаБб�б�аИаЙ.
 * @author Matthew Foster, Vlad Yakovlev (red.scorpix@gmail.com)
 * @version 1.0.2
 * @date 2010-03-19
 *
 * @changelog
 * Version 1.0.2
 * а�б�аПб�аАаВаЛаЕаНаА аОб�аИаБаКаА аПб�аИ б�аДаАаЛаЕаНаИаИ аПаОаДаПаИб�б�аИаКаА (аНаА б�аАаМаОаМ аДаЕаЛаЕ аНаЕ б�аДаАаЛб�аЛб�б�).
 * а�аЕб�аОаДб�, аКб�аОаМаЕ <code>hasBinds</code>, аВаОаЗаВб�аАб�аАб�б� аОаБб�аЕаКб�-аДаИб�аПаЕб�б�аЕб�.
 * аЃ аМаЕб�аОаДаА <code>unbind</code> аАб�аГб�аМаЕаНб�б� б�б�аАаЛаИ аНаЕ аОаБб�аЗаАб�аЕаЛб�аНб�аМаИ.
 * а�аЕб�аОаД <code>dispatch</code> аПаЕб�аЕаИаМаЕаНаОаВаАаН аВ <code>trigger</code>.
 * а�аЕб�аОаД <code>hasBinds</code> аПаЕб�аЕаИаМаЕаНаОаВаАаН аВ <code>bound</code.
 *
 * Version 1.0.1
 * аЂаЕаПаЕб�б� аВаОаЗаВб�аАб�аАаЕб� аОаБб�аЕаКб�. а�аОаЖаНаО аДаЕаЛаАб�б� аНаЕб�аКаОаЛб�аКаО аОаБб�аЕаКб�аОаВ-аДаИб�аПаЕб�б�аЕб�аОаВ.
 */
$c.eventDispatcher = function() {

	function eventDispatcher() {
		var
			listenerChain = {},
			onlyOnceChain = {},
			that = {};

		/**
		 * а�аОаБаАаВаЛб�аЕб� б�аЛб�б�аАб�аЕаЛб� б�аОаБб�б�аИб�.
		 * @param {String|Array} type а�аАаЗаВаАаНаИаЕ б�аОаБб�б�аИб� аИаЛаИ б�аОаБб�б�аИаЙ б�аЕб�аЕаЗ аПб�аОаБаЕаЛ аИаЛаИ аМаАб�б�аИаВаОаМ.
		 * @param {Function} listener аЁаЛб�б�аАб�аЕаЛб�.
		 * @param {Boolean} [onlyOnce] а�аОаДаПаИб�аАб�б�б�б� аНаА б�аОаБб�б�аИаЕ б�аОаЛб�аКаО аОаДаИаН б�аАаЗ.
		 */
		that.bind = function(type, listener, onlyOnce) {
			if (!listener instanceof Function) {
				throw new Error("Listener isn't a function");
			}

			var chain = onlyOnce ? onlyOnceChain : listenerChain;

			type = 'string' == typeof(type) ? type.split(' ') : type;

			$.each(type, function() {
				if (chain[this]) {
					chain[this].push(listener);
				} else {
					chain[this] = [listener];
				}
			});

			return that;
		};

		/**
		 * а�б�аОаВаЕб�б�аЕб�, аЕб�б�б� аЛаИ б� б�аАаКаОаГаО б�аОаБб�б�аИб� б�аЛб�б�аАб�аЕаЛаИ.
		 * @param {String} type а�аАаЗаВаАаНаИаЕ б�аОаБб�б�аИб�.
		 * @return {Boolean}
		 */
		that.bound = function(type) {
			return (listenerChain[type] || onlyOnceChain[type]);
		};

		/**
		 * аЃаДаАаЛб�аЕб� б�аЛб�б�аАб�аЕаЛб� б�аОаБб�б�аИб�.
		 * @param {String} [type] а�аАаЗаВаАаНаИаЕ б�аОаБб�б�аИб�. а�б�аЛаИ аНаЕ б�аКаАаЗаАаНаО, б�аО аВб�аЕ б�аОаБб�б�аИб�.
		 * @param {Function} [listener] аЁаЛб�б�аАб�аЕаЛб�, аКаОб�аОб�аОаГаО аНб�аЖаНаО б�аДаАаЛаИб�б�. а�б�аЛаИ аНаЕ б�аКаАаЗаАаН, б�аО аВб�аЕб� б�аЛб�б�аАб�аЕаЛаЕаЙ.
		 */
		that.unbind = function(type, listener) {
			if (!that.bound(type)) {
				return that;
			}

			if (listener) {
				if (listenerChain[type]) {
					/** @type Array */
					var lst = listenerChain[type];

					for (var j = 0; j < lst.length; j++) {
						if (lst[j] === listener) {
							lst.splice(j, 1);
						}
					}
				}

				if (onlyOnceChain[type]) {
					/** @type Array */
					var lst = onlyOnceChain[type];

					for (var j = 0; j < lst.length; j++) {
						if (lst[j] === listener) {
							lst.splice(j, 1);
						}
					}
				}
			} else if (type) {
				if (listenerChain[type]) {
					delete listenerChain[type];
				}
				if (onlyOnceChain[type]) {
					delete onlyOnceChain[type];
				}
			} else {
				listenerChain = {};
				onlyOnceChain = {};
			}

			return that;
		};

		/**
		 * а�аНаИб�аИаИб�б�аЕб� б�аОаБб�б�аИаЕ.
		 * @param {String} type а�аАаЗаВаАаНаИаЕ б�аОаБб�б�аИб�.
		 * @param {Object} [args] а�аОаПаОаЛаНаИб�аЕаЛб�аНб�аЕ аДаАаНаНб�аЕ, аКаОб�аОб�б�аЕ аНб�аЖаНаО аПаЕб�аЕаДаАб�б� б�аЛб�б�аАб�аЕаЛб�.
		 * @return {Boolean}
		 */
		that.trigger = function(type, args) {

			if (!that.bound(type)) {
				return that;
			}

			var
				chains = [listenerChain, onlyOnceChain],
				evt = new CustomEvent(type, this, args);

			$.each(chains, function() {
				if (this[type]) {
					$.each(this[type], function() {
						this(evt);
					});
				}
			});

			if (onlyOnceChain[type]) {
				delete onlyOnceChain[type];
			}

			return that;
		};

		return that;
	}

	/**
	 * а�аБб�аЕаКб� б�аОаБб�б�аИб�.
	 * @param {String} type аЂаИаП б�аОаБб�б�аИб�.
	 * @param {Object} target а�аБб�аЕаКб�, аКаОб�аОб�б�аЕ аИаНаИб�аИаИб�аОаВаАаЛ б�аОаБб�б�аИаЕ.
	 * @param {Object} [data] а�аОаПаОаЛаНаИб�аЕаЛб�аНб�аЕ аДаАаНаНб�аЕ.
	 */
	function CustomEvent(type, target, data) {
		this.type = type;
		this.target = target;

		if (data) {
			this.data = data;
		}
	}

	return function() {
		return eventDispatcher();
	}
}();




/**
 * SVG Package
 */
(function() {
	var xlinkAttrs = ['actuate', 'arcrole', 'href', 'role', 'show', 'title', 'type'];
	var xmlAttrs = ['base', 'lang', 'space'];
	var attrNames = {
		accentHeight: 'accent-height', alignmentBaseline: 'alignment-baseline', arabicForm: 'arabic-form',
		baselineShift: 'baseline-shift',
		capHeight: 'cap-height', clipPath: 'clip-path', clipRule: 'clip-rule', colorInterpolation: 'color-interpolation', colorInterpolationFilters: 'color-interpolation-filters', colorProfile: 'color-profile', colorRendering: 'color-rendering',
		dominantBaseline: 'dominant-baseline',
		enableBackground: 'enable-background',
		fillOpacity: 'fill-opacity', fillRule: 'fill-rule', floodColor: 'flood-color', floodOpacity: 'flood-opacity', fontFamily: 'font-family', fontSize: 'font-size', fontSizeAdjust: 'font-size-adjust', fontStretch: 'font-stretch', fontStyle: 'font-style', fontVariant: 'font-variant', fontWeight: 'font-weight',
		glyphName: 'glyph-name', glyphOrientationHorizontal: 'glyph-orientation-horizontal', glyphOrientationVertical: 'glyph-orientation-vertical',
		horizAdvX: 'horiz-adv-x', horizOriginX: 'horiz-origin-x', horizOriginY: 'horiz-origin-y',
		imageRendering: 'image-rendering',
		letterSpacing: 'letter-spacing', lightingColor: 'lighting-color',
		markerEnd: 'marker-end', markerMid: 'marker-mid', markerStart: 'marker-start',
		overlinePosition: 'overline-position', overlineThickness: 'overline-thickness',
		panose1: 'panose-1', pointerEvents: 'pointer-events',
		renderingIntent: 'rendering-intent',
		shapeRendering: 'shape-rendering', stopColor: 'stop-color', stopOpacity: 'stop-opacity', strikethroughPosition: 'strikethrough-position', strikethroughThickness: 'strikethrough-thickness', strokeDashArray: 'stroke-dasharray', strokeDasharray: 'stroke-dasharray', strokeDashoffset: 'stroke-dashoffset', strokeDashOffset: 'stroke-dashoffset', strokeLineCap: 'stroke-linecap', strokeLinecap: 'stroke-linecap', strokeLinejoin: 'stroke-linejoin', strokeLineJoin: 'stroke-linejoin', strokeMiterlimit: 'stroke-miterlimit', strokeMiterLimit: 'stroke-miterlimit', strokeOpacity: 'stroke-opacity', strokeWidth: 'stroke-width',
		textAnchor: 'text-anchor', textDecoration: 'text-decoration', textRendering: 'text-rendering',
		underlinePosition: 'underline-position', underlineThickness: 'underline-thickness', unicodeBidi: 'unicode-bidi', unicodeRange: 'unicode-range', unitsPerEm: 'units-per-em',
		vAlphabetic: 'v-alphabetic', vHanging: 'v-hanging', vIdeographic: 'v-ideographic', vMathematical: 'v-mathematical', vertAdvY: 'vert-adv-y', vertOriginX: 'vert-origin-x', vertOriginY: 'vert-origin-y',
		wordSpacing: 'word-spacing', writingMode: 'writing-mode',
		xHeight: 'x-height'
	};
	var	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;

	function getAttrName(name) {
		if (attrNames[name]) {
			name = attrNames[name];
		}

		if (-1 < $.inArray(name, xlinkAttrs)) {
			return [$c.ns.xlink, name];
		} else if (-1 < $.inArray(name, xmlAttrs)) {
			return [$c.ns.xml, name];
		} else {
			return [null, name];
		}
	}

	function attr(el, name, value) {
		if ('string' == typeof name && undefined !== value) {
			var attrName = getAttrName(name);
			el.setAttributeNS(attrName[0], attrName[1], value.valueOf());
		} else if ('string' == typeof name && undefined === value) {
			var attrName = getAttrName(name);
			return el.getAttributeNS(attrName[0], attrName[1]);
		} else {
			$.each(name, function(prop) {
				var attrName = getAttrName(prop);
				el.setAttributeNS(attrName[0], attrName[1], this);
			});
		}
	}

	function removeAttr(el, name) {
		var attrName = getAttrName(name);
		el.removeAttributeNS(attrName[0], attrName[1]);
	}

	function getStyleName(style) {
		return style.replace(/-([a-z])/ig, function(all, letter){
			return letter.toUpperCase();
		})
	}

	/**
	 * а�аЗ б�б�б�аОаКаИ аДаЕаЛаАаЕб� SVG-б�аЛаЕаМаЕаНб�.
	 * @param {String} data
	 */
	function loadSvg(data) {
		data = $.trim(data);

		var index = data.indexOf(' ');

		if (-1 < index) {
			var namespaces = '';

			$.each($c.ns, function(name) {
				if ('xml' != name && -1 == data.indexOf(this)) {
					namespaces += ' xmlns' + ('svg' == name ? '' : ':' + name) + '="' + this + '"';
				}
			});

			if (namespaces) {
				data = data.substr(0, index) + namespaces + data.substr(index);
			}
		}

		var
			xmlData = new DOMParser().parseFromString(data, 'text/xml'),
			svgEl = document.createElementNS($c.ns.svg, 'svg'),
			attrs = { version: '1.1' };

		for (var i = 0; i < xmlData.documentElement.attributes.length; i++) {
			var xmlAttr = xmlData.documentElement.attributes.item(i);

			if (!('version' == xmlAttr.nodeName || 'xmlns' == xmlAttr.nodeName.substring(0, 5))) {
				attrs[xmlAttr.nodeName] = xmlAttr.nodeValue;
			}
		}

		attr(svgEl, attrs);

		$.each(xmlData.documentElement.childNodes, function() {
			svgEl.appendChild(this.cloneNode(true));
		});

		return svgEl;
	}

	/**
	 * а�аЕаЙаМб�аПаЕаЙб�б� аДаЛб� SVG.
	 */
	$c.ns = {
		/* SVG namespace. */
		svg: 'http://www.w3.org/2000/svg',
		/* XLink namespace. */
		xlink: 'http://www.w3.org/1999/xlink',
		/* XML Events namespace. */
		ev: 'http://www.w3.org/2001/xml-events',
		/* XML namespace. */
		'xml': 'http://www.w3.org/XML/1998/namespace'
	};

	$.fn.extend({
		/**
		 * аЃб�б�аАаНаАаВаЛаИаВаАаЕб� аИаЛаИ аВаОаЗаВб�аАб�аАаЕб� аАб�б�аИаБб�б� SVG-б�аЛаЕаМаЕаНб�аА.
		 * @param {String|Object} name а�аАаЗаВаАаНаИаЕ аАб�б�аИаБб�б�аА аИаЛаИ аОаБб�аЕаКб� аНаАаЗаВаАаНаИаЙ-аЗаНаАб�аЕаНаИаЙ.
		 * @param {String|Number} [value] а�аНаАб�аЕаНаИаЕ аАб�б�аИаБб�б�аА.
		 * @return {String} а�б�аЛаИ getter, б�аО аЗаНаАб�аЕаНаИаЕ аАб�б�аИаБб�б�аА.
		 */
		svgAttr: function(name, value) {
			if (!document.createElementNS) {
				return this.attr(name, value);
			}

			if ('string' == typeof name && undefined === value) {
				return this.length ? attr(this[0], name) : undefined;
			}

			this.each(function() {
				attr(this, name, value);
			});

			return this;
		},


		/**
		 * а аАаБаОб�аА б�аО б�б�аИаЛб�аМаИ SVG-б�аЛаЕаМаЕаНб�аОаВ.
		 * @param {String|Object} name а�аАаЗаВаАаНаИаЕ б�б�аИаЛб� аИаЛаИ аОаБб�аЕаКб� аНаАаЗаВаАаНаИаЙ-аЗаНаАб�аЕаНаИаЙ.
		 * @param {String|Number} [value] а�аНаАб�аЕаНаИаЕ аАб�б�аИаБб�б�аА
		 * @return {String} а�б�аЛаИ getter, б�аО аЗаНаАб�аЕаНаИаЕ аАб�б�аИаБб�б�аА.
		 */
		svgCss: function(name, value) {
			if (!document.createElementNS) {
				return this.css(name, value);
			}

			if ('string' == typeof name && undefined === value) {
				return this.length ? window.getComputedStyle(this[0], null).getPropertyValue(name) : undefined;
			}

			var styles = {};

			if ('string' == typeof name) {
				styles[name] = value;
			} else {
				styles = name;
			}

			this.each(function() {
				for (var index in styles) {
					this.style[getStyleName(index)] = 'number' === typeof styles[index] && !exclude.test(styles[index]) ? styles[index] + 'px' : styles[index];
				}
			});

			return this;
		},


		/**
		 * аЃаДаАаЛб�аЕб� аАб�б�аИаБб�б� б� SVG-б�аЛаЕаМаЕаНб�аОаВ.
		 * @param {String} name
		 */
		svgRemoveAttr: function(name) {
			if (document.createElementNS) {
				this.each(function() {
					removeAttr(this, name);
				});

				return this;
			}

			return this.removeAttr(name);
		}
	});


	/**
	 * аЁаОаЗаДаАаЕб� SVG-б�аЛаЕаМаЕаНб� аИ аВаОаЗаВб�аАб�аАаЕб� аЕаГаО аВ аОаБаЕб�б�аКаЕ jQuery.
	 * @param {String|Element} selector а�аАаЗаВаАаНаИаЕ б�аЛаЕаМаЕаНб�аА, б�б�б�аОаКаА XML аИаЛаИ б�аЛаЕаМаЕаНб�.
	 * @return {jQuery}
	 */
	$c.svg = function(selector) {

		if ('string' == typeof selector) {
			if ('<' == selector.substr(0, 1)) {
				// а�б�аОаДаНаОаЙ аПаАб�аАаМаЕб�б� т�� б�б�б�аОаКаА XML.
				selector = loadSvg(selector);
			} else {
				// а�б�аОаДаНаОаЙ аПаАб�аАаМаЕб�б� т�� аНаАаЗаВаАаНаИаЕ SVG-б�аЛаЕаМаЕаНб�аА.
				var name = selector;
				selector = document.createElementNS($c.ns.svg, selector);
				'svg' == name && attr(selector, 'version', '1.1');
			}
		}

		return $(selector);
	}
})();


/**
 * а�б�аЕаОаБб�аАаЗб�аЕб� HEX-аПб�аЕаДб�б�аАаВаЛаЕаНаИаЕ б�аВаЕб�аА аВ RGB.
 * @param {String} hex
 * @return {Array}
 */
$c.hex2Rgb = function(hex) {
	if ('#' == hex.substr(0, 1)) {
		hex = hex.substr(1);
	}
	if (3 == hex.length) {
		hex = hex.substr(0, 1) + hex.substr(0, 1) + hex.substr(1, 1) + hex.substr(1, 1) + hex.substr(2, 1) + hex.substr(2, 1);
	}

	return [parseInt(hex.substr(0, 2), 16), parseInt(hex.substr(2, 2), 16), parseInt(hex.substr(4, 2), 16)];
};

/**
 * а�б�аЕаОаБб�аАаЗб�аЕб� RGB-аПб�аЕаДб�б�аАаВаЛаЕаНаИаЕ б�аВаЕб�аА аВ HEX.
 * @param {Array} rgb
 * @return {String}
 */
$c.rgb2Hex = function(rgb) {
	var s = '0123456789abcdef';

	return '#' + s.charAt(parseInt(rgb[0] / 16)) + s.charAt(rgb[0] % 16) + s.charAt(parseInt(rgb[1] / 16)) +
		s.charAt(rgb[1] % 16) + s.charAt(parseInt(rgb[2] / 16)) + s.charAt(rgb[2] % 16);
};

/**
 * а�б�аЕаОаБб�аАаЗб�аЕб� б�аАаДаИаАаНб� аВ аГб�аАаДб�б�б�.
 * @param {Number} rad
 * @return {Number}
 */
$c.rad2Deg = function(rad) {
	return rad * 180 / Math.PI;
};

/**
 * а�б�аЕаОаБб�аАаЗб�аЕб� аГб�аАаДб�б�б� аВ б�аАаДаИаАаНб�.
 * @param {Number} deg
 * @return {Number}
 */
$c.deg2Rad = function(deg) {
	return deg * Math.PI / 180;
};

$c.generateId = function() {
	var ids = {};

	function getId() {
		return 'id' + Math.round($c.random(0, 10000000));
	}

	return function() {
		var id;

		do {
			id = getId();
		} while (undefined !== ids[id]);

		ids[id] = 1;

		return id;
	};
}();


/**
 * Drag and Drop
 *
 * @param {String|Element|jQuery} el
 * @param {Function} start аЄб�аНаКб�аИб�, аВб�аЗб�аВаАаЕаМаАб� аПб�аИ б�б�аАб�б�аЕ. а�аМаЕаЕб� аПаАб�аАаМаЕб�б� т�� аОаБб�аЕаКб� Event.
 * @param {Function} drag аЄб�аНаКб�аИб�, аВб�аЗб�аВаАаЕаМб�б� аПб�аИ аПаЕб�аЕаМаЕб�аЕаНаИаИ. а�аМаЕаЕб� аПаАб�аАаМаЕб�б� т�� аОаБб�аЕаКб� jQuery.Event
 *                        (<code>data</code> б�аОаДаЕб�аЖаИб� startX, startY,
 *                        аА б�аАаКаЖаЕ moveX, moveY т�� аПаЕб�аЕаМаЕб�аЕаНаИаЕ б� аНаАб�аАаЛаА аДб�аАаГ-аН-аДб�аОаПаА).
 * @param {Function} stop аЄб�аНаКб�аИб�, аВб�аЗб�аВаАаЕаМаАб� аПаО аОаКаОаНб�аАаНаИаИ аПаЕб�аЕаМаЕб�аЕаНаИб�.
 *
 * @version 0.1.1
 * @date 2010-02-16
 */
$c.draggable = function(el) {
	el = $(el).first();

	var
		isDrag = false,
		isBind = false,
		startX,
		startY,
		lastX,
		lastY,
		that = {},
		startFunc,
		dropFunc,
		endFunc;

	bind();

	function bind(start, drop, end) {
		if (!el.length) return;

		if (isBind) {
			unbind();
		}

		isBind = true;

		startFunc = start;
		dropFunc = drop;
		endFunc = end;

		el.mousedown(startDnd);
	}

	function startDnd(evt) {
		if (!(el.length && isBind && !isDrag)) return;

		isDrag = true;
		startX = parseInt(evt.pageX);
		startY = parseInt(evt.pageY);
		lastX = startX;
		lastY = startY;

		$(document).mousemove(dnd).mouseup(endDnd);

		return startFunc ? startFunc(evt) : false;
	}

	function dnd(evt) {
		if (!el.length) return;

		var
			pageX = parseInt(evt.pageX),
			pageY = parseInt(evt.pageY),
			stepX = pageX - lastX,
			stepY = pageY - lastY;

		lastX = pageX;
		lastY = pageY;

		return dropFunc ? dropFunc(evt, {
			startX: startX,
			startY: startY,
			moveX: pageX - startX,
			moveY: pageY - startY,
			stepX: stepX,
			stepY: stepY
		}) : false;
	}

	function endDnd(evt) {
		if (!(el.length && isBind && isDrag)) return;

		isDrag = false;
		$(document).unbind('mousemove', dnd).unbind('mouseup', endDnd);

		return endFunc ? endFunc(evt, {
			startX: startX,
			startY: startY,
			moveX: parseInt(evt.pageX) - startX,
			moveY: parseInt(evt.pageY) - startY
		}) : false;
	}

	/**
	 * а�б�аЕаКб�аАб�аАаЕб� аОб�б�аЛаЕаЖаИаВаАаНаИаЕ аДб�аАаГ-аН-аДб�аОаПаА.
	 */
	function unbind() {
		if (!(el.length && isBind)) return;

		endDnd();

		startFunc = null;
		dropFunc = null;
		endFunc = null;
		isBind = false;
		el.unbind('mousedown', startDnd);
	}

	that.bind = function(start, drop, end) {
		bind(start, drop, end);
		return that;
	};

	that.unbind = function() {
		unbind();
		return that;
	};

	/**
	 * а�б�аИаНб�аДаИб�аЕаЛб�аНаО аЗаАаВаЕб�б�аАаЕб� аДб�аАаГ-аН-аДб�аОаП.
	 */
	that.release = function(evt) {
		endDnd(evt);
		return that;
	};

	that.start = function(evt) {
		startDnd(evt);
		return that;
	};

	return that;
};
