var rocon=(function(){/**
 * Общие методы и свойства для rocon
 * @author Sergey Chikuyonok (sc@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 */

var re_rule = /\.rc(\d+)\b/,
	re_class = /\brc(\d+)\b/,
	re_shape_flag = /\brc-shape\b/,

	/** Префиск для создаваемых CSS-правил */
	rule_prefix = 'rocon__',

	/** Базовый класс для создаваемых элементов */
	base_class = 'rocon',
	
	/** Привязанные к определенным классам фоны */
	binded_props = [],

	/** Результат, возвращаемый в объект <code>rocon</code> */
	result = {
		/**
		 * Добавление/обновление уголков для динамически созданных элементов.
		 * Может принимать неограниченное количество элементов либо массивов
		 * элементов, у которых нужно обновить уголки  
		 */
		update: function(){},
		bindProperties: function(){
			var id = 1;
			return function(rule, bg, border_width) {
				binded_props.push({
					'id': id++,
					'rule': rule, 
					'bg': mapArray(expandProperty(bg), function(val){
						if (val.charAt(0) != '#')
							val = '#' + val;
						return convertColorToHex(val);
					}),
					'border_width': border_width || 0
				});
			}
		}(),
		
		process: function(context) {
			processRoundedElements(context);
		}
	},

	/** @type {CSSStyleSheet} Таблица стилей для уголков */
	corners_ss = null,

	/** Кэш для уголков */
	_corner_cache = {},
	
	/** Классы элементов, которым нужно добавить скругленные уголки */
	elem_classes = [],
	
	/** Список функций, которые нужно выполнить при загрузке DOM-дерева */
	dom_ready_list = [],
	
	/** Загрузился ли DOM? */
	is_ready = false,
	
	/** Привязано ли событие, ожидающее загрузку DOM? */
	readyBound = false,

	userAgent = navigator.userAgent.toLowerCase(),
	
	/** 
	 * CSS-селекторы, которые уже были добавлены в стили. 
	 * Используется для того, чтобы не создавать одинаковые правила
	 */
	processed_rules = {},

	/** Тип и версия браузера пользователя. Взято с jQuery */
	browser = {
		version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
		safari: /webkit/.test( userAgent ),
		opera: /opera/.test( userAgent ),
		msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
		mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
	};

/**
 * Выполняет все функции, добавленные на событие onDomContentLoaded.
 * Взято с jQuery
 */
function fireReady() {
	//Make sure that the DOM is not already loaded
	if (!is_ready) {
		// Remember that the DOM is ready
		is_ready = true;

		// If there are functions bound, to execute
		if ( dom_ready_list.length ) {
			
			for (var i = 0; i < dom_ready_list.length; i++) {
				dom_ready_list[i].call(document);
			}
			
//			walkArray(dom_ready_list, function(){
//				this.call(document);
//			});

			// Reset the list of functions
			dom_ready_list = null;
		}
	}
}

/**
 * Добавляет слушателя на событие onDomContentLoaded
 * @type {Function} fn Слушатель
 */
function addDomReady(fn) {
	dom_ready_list.push(fn);
}

/**
 * Проверка на наступление события onDomContentLoaded. 
 * Взято с jQuery
 */
function bindReady(){
	if ( readyBound ) return;
	readyBound = true;

	// Mozilla, Opera and webkit nightlies currently support this event
	if ( document.addEventListener ) {
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", function(){
			document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
			fireReady();
		}, false );

	// If IE event model is used
	} else if ( document.attachEvent ) {
		// ensure firing before onload,
		// maybe late but safe also for iframes
		document.attachEvent("onreadystatechange", function(){
			if ( document.readyState === "complete" ) {
				document.detachEvent( "onreadystatechange", arguments.callee );
				fireReady();
			}
		});

		// If IE and not an iframe
		// continually check to see if the document is ready
		if ( document.documentElement.doScroll && !window.frameElement ) (function(){
			if ( is_ready ) return;

			try {
				// If IE is used, use the trick by Diego Perini
				// http://javascript.nwbox.com/IEContentLoaded/
				document.documentElement.doScroll("left");
			} catch( error ) {
				setTimeout( arguments.callee, 0 );
				return;
			}

			// and execute any waiting functions
			fireReady();
		})();
	}
}

/**
 * Вспомогательная функция, которая пробегается по всем элементам массива
 * <code>ar</code> и выполняет на каждом элементе его элементе функцию
 * <code>fn</code>. <code>this</code> внутри этой функции указывает на 
 * элемент массива
 * @param {Array} ar Массив, по которому нужно пробежаться
 * @param {Function} fn Функция, которую нужно выполнить на каждом элементе массива
 * @param {Boolean} forward Перебирать значения от начала массива (п умолчанию: с конца)
 */
function walkArray(ar, fn, forward) {
	if (forward) {
		for (var i = 0, len = ar.length; i < len; i++)
			if (fn.call(ar[i], i) === false)
				break;
	} else {
		for (var i = ar.length - 1, result; i >= 0; i--)
			if (fn.call(ar[i], i) === false)
				break;
	}
}

/**
 * Преобразует один массив элементов в другой с помощью функции callback.
 * Взято в jQuery
 * @param {Array} elems
 * @param {Function} callback
 * @return {Array}
 */
function mapArray(elems, callback) {
	var ret = [];

	// Go through the array, translating each of the items to their
	// new value (or values).
	for ( var i = 0, length = elems.length; i < length; i++ ) {
		var value = callback( elems[ i ], i );

		if ( value != null )
			ret[ ret.length ] = value;
	}

	return ret.concat.apply( [], ret );
}

/**
 * Функция добавления скругленных уголков элементу. Для каждого браузера 
 * будет своя функция
 */
function addCorners(){
	return;
};

// TODO Добавить исключение при правильной работе border-radius

/**
 * Преобразует цвет из RGB-предствления в hex
 * @param {String} color
 * @return {String}
 */
function convertColorToHex(color) {
	var result;
	function s(num) {
		var n = parseInt(num, 10).toString(16);
		return (n.length == 1) ? n + n : n;
	}
	
	function p(num) {
		return s(Math.round(num * 2.55));
	}
	
	if (result = /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/.exec(color))
		return '#' + s(result[1]) + s(result[2]) + s(result[3]);

	// Look for rgb(num%,num%,num%)
	if (result = /rgb\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*\)/.exec(color))
		return '#' + p(result[1]) + p(result[2]) + p(result[3]); 

	// Look for #a0b1c2
	if (result = /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/i.exec(color))
		return '#' + result[1] + result[2] + result[3];
		
	if (result = /#([a-f0-9])([a-f0-9])([a-f0-9])/i.exec(color))
		return '#' + result[1] + result[1] + result[2] + result[2] + result[3] + result[3];
	
	s = null;
	p = null;
		
	return color;
}

/**
 * Создает HTML-элемент <code>name</code> с классом <code>class_name</code>
 * @param {String} name Название элемента
 * @param {String} class_name Класс элемента
 * @return {Element}
 */
function createElement(name, class_name) {
	var elem = document.createElement(name);
	if (class_name) {
		elem.className = class_name;
	}
	return elem;
}

/**
 * Простая проверка наличия определенного класса у элемента
 * @param {HTMLElement} elem
 * @param {String} class_name
 * @return {Boolean}
 */
function hasClass(elem, class_name) {
	var re = new RegExp('\\b' + class_name + '\\b');
	return elem.nodeType == 1 && re.test(elem.className || '');
}

/**
 * Возвращает значение CSS-свойства <b>name</b> элемента <b>elem</b>
 * @author John Resig (http://ejohn.org)
 * @param {Element} elem Элемент, у которого нужно получить значение CSS-свойства
 * @param {String|Array} name Название CSS-свойства
 * @return {String|Object}
 */
function getStyle(elem, name) {
	var cs, 
		result = {},
		camel = function(str, p1){return p1.toUpperCase();};
	
	walkArray(name instanceof Array ? name : [name], function(){
		var n = this, 
			name_camel = n.replace(/\-(\w)/g, camel);
		
		// If the property exists in style[], then it's been set
		// recently (and is current)
		if (elem.style[name_camel]) {
			result[name_camel] = elem.style[name_camel];
		}
		//Otherwise, try to use IE's method
		else if (browser.msie) {
			result[name_camel] = elem.currentStyle[name_camel];
		}
		// Or the W3C's method, if it exists
		else if (document.defaultView && document.defaultView.getComputedStyle) {
			if (!cs)
				cs = document.defaultView.getComputedStyle(elem, "");
			result[name_camel] = cs && cs.getPropertyValue(n);
		}
	});
	
	return name instanceof Array ? result : result[name.replace(/\-(\w)/g, camel)];
		
}

/**
 * Разворачивает краткую запись четырехзначного свойства в полную:<br>
 * 	— a      -&gt; a,a,a,a<br>
 *	— a_b    -&gt; a,b,a,b<br>
 *	— a_b_с  -&gt; a,b,с,b<br>
 * 
 * @param {String} prop Значение, которое нужно раскрыть
 * @return {Array} Массив с 4 значениями
 */
function expandProperty(prop) {
	var chunks = (prop || '').split('_');
		
	switch (chunks.length) {
		case 1:
			return [chunks[0], chunks[0], chunks[0], chunks[0]];
		case 2:
			return [chunks[0], chunks[1], chunks[0], chunks[1]];
		case 3:
			return [chunks[0], chunks[1], chunks[2], chunks[1]];
		case 4:
			return chunks;
	}
	
	return null;
}

/**
 * Возвращает цвет фона элемента
 * @type {Function}
 * @param {Element} elem Элемент, для которого нужно достать цвет фона
 * @param {Boolean} use_shape Для элемента создаются уголки в виде формы
 * @return {Array} Массив из 4 элементов фона
 */
var getBg = (function() {

	var session_elems = [], 
		default_color = '#ffffff';
	
	/**
	 * Основной цикл с использованием кэширования
	 */
	function mainLoopCache(elem) {
		var c;
		do {
			if (elem.nodeType != 1)
				break;
			
			if (elem.rocon_bg) { // цвет был найден ранее
				return elem.rocon_bg;
			} else { // цвет еще не найден
				session_elems.push(elem);
				c = getStyle(elem, 'background-color');
				if (c != 'transparent')
					return convertColorToHex(c);
			}
				
		} while (elem = elem.parentNode);
		
		return default_color;
	}
	
	/**
	 * Основной цикл без кэширования
	 */
	function mainLoopNoCache(elem) {
		var c;
		do {
			if (elem.nodeType != 1)
				break;
				
			c = getStyle(elem, 'background-color');
			if (c != 'transparent')
				return convertColorToHex(c);
				
		} while (elem = elem.parentNode);
		
		return default_color;
	}
	
	return function(elem, use_shape){
		var cl = /* String */elem.className, 
			bg = null;
		
		// сначала посмотрим, указан ли фон в классе элемента
		var bg_props = /\brcbg([a-f0-9_]+)\b/i.exec(cl);
		
		if (bg_props) {
			
			bg =  mapArray(expandProperty(bg_props[1]), function(el){
				return convertColorToHex('#' + el);
			});
			
			return bg;
		}
		
		// Теперь проверяем, есть ли привязанный через rocon.bindBg() к классу фон
		var elem_props = getBindedProperties(elem);
		if (elem_props) {
			return elem_props.bg;
		}
		
		if (!use_shape) 
			elem = elem.parentNode;
		
		if (getBg.use_cache) {
			session_elems = [];
			bg = mainLoopCache(elem);
			// закэшируем цвет фона у всех элементов, по которым проходились
			walkArray(session_elems, function(){
				this.rocon_bg = bg;
				getBg.processed_elems.push(this);
			});
			
			session_elems = null;
		} else {
			bg = mainLoopNoCache(elem);
		}
		
		return expandProperty(bg);
	}
})();

getBg.use_cache = true;
getBg.processed_elems = [];

function getBindedProperties(elem) {
	var cl = elem.className, result = null;
	walkArray(binded_props, function(){
		if (
			// проверка наличия подстроки
			(typeof(this.rule) == 'string' && cl.indexOf(this.rule) != -1) ||
			// проверка по регулярке
			cl.search(this.rule) != -1
		) {
			result = this;
			return false;
		}
	}, true);
	
	return result;
}

/**
 * Добавляет CSS-правило в стиль
 * @param {String} selector CSS-селектор, для которого нужно добавить правила
 * @param {String} rules CSS-правила
 */
function addRule(selector, rules) {
	corners_ss.insertRule(selector + ' {' + rules + '}', corners_ss.cssRules.length);
}

/**
 * Функция поиска правил для скругленных уголков
 * @param {Function} addFunc Функция добавления уголков
 */
function findRules(addFunc) {
	/** @type {String[]}  */
	var match;
	
	walkArray(document.styleSheets, function(){
		walkArray(this.cssRules || this.rules, function(){
			if (match = re_rule.exec(this.selectorText))
				addFunc(this, parseInt(match[1], 10));
		});
	});
}

/**
 * Очищает элемент от предыдущих вставок скругленных уголков
 * @param {Element} elem
 * @param {String} [add_class] Классы, которые нужно добавить
 * @return {Element} Переданный элемент
 */
function cleanUp(elem, add_class) {
	var	cl = (elem.className || '').replace(new RegExp('\\s*' + base_class + '[\-_].+?\\b', 'ig'), '');
	if (add_class) {
		cl += ' ' + add_class;
	}
	
	elem.className = cl;
	return elem;
}

	
/**
 * Функция добавления правил для скругленных уголков
 */
function addRoundedProperties(/* CSSStyleRule */ rule, /* Number */ radius) {
	elem_classes.push(rule.selectorText.substr(1));
}

/**
 * Создает новую таблицу стилей на странице, куда будут добавляться правила
 * для описания скругленных уголков
 * @return {CSSStyleSheet}
 */
function createStylesheet() {
	if (!corners_ss) {
		if (document.createStyleSheet) {
			corners_ss = document.createStyleSheet();
		} else {
			var style = createElement('style');
			style.rel = 'rocon';
			document.getElementsByTagName('head')[0].appendChild(style);
			
			/*
			 * Просто получить самый последний стиль не получится: иногда стили
			 * добавляются внутрь <body> (так делает счетчик Яндекса, например),
			 * в этом случае мы не можем быть уверены, что только что 
			 * добавленная таблица стилей — последняя. Поэтому пробегаетмся 
			 * по всем таблицам в поисках нашей  
			 */ 
			walkArray(document.styleSheets, function(){
				if (this.ownerNode.rel == 'rocon') {
					corners_ss = this;
					return false;
				}
			});
		}
	}
	
	return corners_ss;
}

/**
 * Возвращает массив элементов, которым нужно добавить скругленные уголки.
 * Элементом массива является объект со свойствами <code>node</code> 
 * и <code>radius</code>
 * @param {Element} [context] Откуда брать элементы
 * @return {Array}
 */
function getElementsToProcess(context) {
	var elems = [], m;
	
	walkArray((context || document).getElementsByTagName('*'), function(){
		if (m = re_class.exec(this.className || '')) {
			elems.push({node: this, radius: parseInt(m[1], 10)});
		}
	});
	
	return elems;
}

/**
 * Обрабатывает все элементы на странице, которым нужно добавить скругленные
 * уголки
 */
function processRoundedElements(context){
	var elems = getElementsToProcess(context);
	if (elems.length) {
		createStylesheet();
		walkArray(elems, function(){
			addCorners(this.node, this.radius);
		});
	}
}
/**
 * Проверяет, был ли добавлен CSS-selector в таблицу стилей
 * @param {String} selector
 * @return {Boolean}
 */
function isProcessed(selector) {
	return processed_rules[selector] ? true : false;
}

/**
 * Возвращает параметры уголка элемента
 * @param {Element} elem Элемент, у которого нужно получить параметры уголка
 * @param {Number} [radius] Радиус скругления
 */
function getCornerParams(elem, radius) {
	var cl = elem.className || '';
	radius = radius || parseInt(cl.match(re_class)[1], 10);
	var use_shape = re_shape_flag.test(cl),
		props = getBindedProperties(elem);
	
	var border_color = '';
	var border_width = props ? props.border_width : (parseInt(getStyle(elem, 'border-left-width')) || 0);
	if (border_width) {
		// нужно отрисовать бордюр
		border_color = convertColorToHex(getStyle(elem, 'border-left-color') || '#000');
	}
	
	return {
		'radius': radius,
		'bg_color': getBg(elem, use_shape),
		
		// толщина бордюра не может быть больше радиуса скругления
		// (так по CSS3 спецификации)
		'border_width': (border_width > radius) ? radius : border_width,
		'real_border_width': border_width,
		'border_color': border_color,
		'use_shape': use_shape
	};
}

/**
 * Применяет уголки к элементам, переданным в массиве. В основном вызывается из
 * <code>rocon.update()</code>
 * @param {arguments} args Аргументы функции
 * @param {Function} fn Функция, которую нужно выполнить на каждом элементе
 */
function applyCornersToArgs(args, fn) {
	walkArray(args, function(){
		walkArray((this instanceof Array) ? this : [this], fn);
	});
}

/**
 * Делает копию объекта
 * @param {Object} obj
 * @return {Object}
 */
function copyObj(obj) {
	var result = {};
	for (var p in obj) 
		if (obj.hasOwnProperty(p))
			result[p] = obj[p];
	
	return result;
}

/**
 * Корректирует CSS-свойства элемента для правильного рисования уголков в виде
 * формы
 * @param {HTMLElement} elem Элемент, который нужно подкорректировать
 * @param {String} class_name Имя создаваемого класса
 * @param {getCornerParams()} options параметры рисования уголка
 */
function adjustBox(elem, class_name, options) {
	var elem_styles = getStyle(elem, ['padding-top', 'padding-bottom', 'margin-top', 'margin-bottom']);
	function getProp(prop) {
		return parseInt(elem_styles[prop], 10) || 0;
	}
	
	/*
	 * Используем форму, поэтому у блока снижаем верхние и нижние
	 * бордюры, а также на величину радиуса снижаем верхний 
	 * и нижний паддинг 
	 */
	
	var padding_top = Math.max(getProp('paddingTop') - options.radius + options.border_width, 0),
		padding_bottom = Math.max(getProp('paddingBottom') - options.radius + options.border_width, 0),
		margin_top = getProp('marginTop') + options.radius,
		margin_bottom = getProp('marginBottom') + options.radius,
		border_width = options.real_border_width - options.border_width;
	
	addRule('.' + class_name, 
			'border-top-width:' + border_width + 'px;' +
			'border-bottom-width:' + border_width + 'px;' +
			'padding-top:' + padding_top + 'px;' +
			'padding-bottom:' + padding_bottom + 'px;' +
			'margin-top:' + margin_top + 'px;' +
			'margin-bottom:' + margin_bottom + 'px' );
}

addDomReady(processRoundedElements);
// после того, как добавили уголки, необходимо очистить кэш фона,
// иначе будут проблемы с динамическим обновлением блоков
addDomReady(function(){
	walkArray(getBg.processed_elems, function(){
		this.removeAttribute('rocon_bg');
	});
	getBg.use_cache = false;
});

bindReady();/**
 * Добавление уголков для Safari
 * @author Sergey Chikuyonok (sc@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @include "common.js"
 */

if (browser.safari) {
	addCorners = function(elem, radius) {
		var selector = '.rc' + radius;
		if (!isProcessed(selector)) {
			addRule(selector, '-webkit-border-radius:' + radius + 'px; -khtml-border-radius:' + radius);
			processed_rules[selector] = true;
		}
	}
	
	result.update = function() {
		applyCornersToArgs(arguments, function(){
			var m = re_class.exec(this.className || '');
			if (m) 
				addCorners(this, parseInt(m[1]));
		});
	}
}/**
 * Добавление уголков для Firefox
 * @author Sergey Chikuyonok (sc@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @include "common.js"
 */

if (browser.mozilla) {
	addCorners = function(elem, radius) {
		var selector = '.rc' + radius;
		if (!isProcessed(selector)) {
			addRule(selector, '-moz-border-radius:' + radius + 'px');
			processed_rules[selector] = true;
		}
	}
	
	result.update = function() {
		applyCornersToArgs(arguments, function(){
			var m = re_class.exec(this.className || '');
			if (m) 
				addCorners(this, parseInt(m[1]));
		});
	}
}/**
 * Добавление уголков для Opera
 * @author Sergey Chikuyonok (sc@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @include "common.js"
 * @include "/js-libs/canvas-doc.js"
 */
 
if (browser.opera) {
  addCorners = function(elem, radius) {
		var selector = '.rc' + radius;
		if (!isProcessed(selector)) {
			addRule(selector, 'border-radius:' + radius + 'px');
			processed_rules[selector] = true;
		}
	}
	
	result.update = function() {
		applyCornersToArgs(arguments, function(){
			var m = re_class.exec(this.className || '');
			if (m) 
				addCorners(this, parseInt(m[1]));
		});
	}
}/**
 * Добавление уголков для IE
 * @author Sergey Chikuyonok (sc@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @include "common.js"
 */

if (browser.msie) {
	/*
	 * Уголки для IE создаем через VML.
	 * 
	 * У IE в этом скрипте есть одно очень узкое место: динамическое добавление
	 * CSS-правил в таблицу стилей (функция addRule()). Для увеличения 
	 * производительности был применен следующий трюк: сначала, при первичной 
	 * инициализации, весь CSS накапливается в переменной css_text, и после того,
	 * как все необходимые правила для существующих блоков были созданы, 
	 * накопленный CSS применяется к созданной таблице стилей. После этого 
	 * функция addRule() уже указывает на метод corners_ss.addRule()  
	 */
	
	_corner_cache.ix = 0;
	_corner_cache.created = {};
	
	var css_text = '',
		corner_types = {
			tl: 0,
			tr: 1,
			br: 2,
			bl: 3
		};
	
	var vml_class = 'vml-' + base_class; //использую именно класс, чтобы работало в IE8
	
	try {
		if (!document.namespaces["v"])
			document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
	} catch(e) { }
	
	createStylesheet();
	var dot_class = '.' + base_class;
	corners_ss.cssText = "." + vml_class + " {behavior:url(#default#VML);display:inline-block;position:absolute}" +
		dot_class + "-init {position:relative;zoom:1;}" +
		dot_class + " {position:absolute; display:inline-block; zoom: 1; overflow:hidden}" +
		dot_class + "-tl ." + vml_class + "{flip: 'y'}" +
		dot_class + "-tr ." + vml_class + "{rotation: 180;right:1px;}" +
		dot_class + "-br ." + vml_class + "{flip: 'x'; right:1px;}";
		
	if (browser.version < 7) {
		corners_ss.cssText += dot_class + '-tr, ' + dot_class + '-br {margin-left: 100%;}';
//				dot_class + ' .' + vml_class + '{position:absolute}' +
//				dot_class + '-tr .' + vml_class + '{right: 0}';
	}
	
	addRule = function(selector, rules){
		css_text += selector + '{' + rules + '}';
	};
	
	/**
	 * Создает элемент со скругленным уголком. В функции используется
	 * кэширование, то есть ранее созданный уголок дублируется, 
	 * а не создается заново
	 * @param {getCornerParams()} options Параметры рисования уголка 
	 * @return {HTMLElement}
	 */
	function createCornerElementIE(options) {
		var radius = options.radius,
			border_width = options.border_width,
			cache_key = radius + ':' + border_width + ':' + options.use_shape;
		
		if (!createCornerElementIE._cache[cache_key]) { // элемент еще не создан
			
			var multiplier = 10;
			
			var cv = createElement('v:shape');
			cv.className = vml_class;
			cv.strokeweight = border_width + 'px';
			cv.stroked = (border_width) ? true : false;
			var stroke = createElement('v:stroke');
			stroke.className = vml_class;
			stroke.joinstyle = 'miter';
			cv.appendChild(stroke);
			
			var w = radius, h = w;
			
			cv.style.width = w + 'px';
			cv.style.height = h + 'px';
			
			radius -= border_width / 2;
			radius *= multiplier;
			var bo = border_width / 2 * multiplier;
			var px = Math.round((radius + bo) / w);
			var rbo = radius + bo;
			
			cv.coordorigin = Math.round(px / 2) + ' ' + Math.round(px / 2);
			cv.coordsize = rbo + ' ' + rbo;
			
			var path = '';
			var max_width = rbo + px;
			
			if (options.use_shape) {
				max_width = 2000 * multiplier;
				path = 'm' + max_width + ',0 ns l' + bo +',0  qy' + rbo + ',' + radius + ' l' + max_width + ',' + radius + ' e ';
			} else {
				path = 'm0,0 ns l' + bo +',0  qy' + rbo + ',' + radius + ' l' + rbo + ',' + rbo + ' l0,' + rbo + ' e ';
			}
			
			
			// stroke
			path += 'm' + bo + ',' + (-px) + ' nf l' + bo + ',0 qy' + rbo + ',' + radius + ' l ' + (max_width) +','+ radius +' e x';
			
			cv.path = path;
				
			createCornerElementIE._cache[cache_key] = cv;
		}
		
		return createCornerElementIE._cache[cache_key].cloneNode(true);
	}
	
	createCornerElementIE._cache = {};
	
	/**
	 * Создает скругленный уголок
	 * @param {getCornerParams()} cparams параметры уголка
	 * @param {String} type Тип уголка (tl, tr, bl, br)
	 */
	function drawCornerIE(cparams, type){
		var cv = createCornerElementIE(cparams);
		cv.fillcolor = cparams.bg_color[corner_types[type]] || '#000';
		cv.strokecolor = cparams.border_color || '#000';
		
		var elem = createElement('span', base_class + ' ' + base_class + '-' + type);
		elem.appendChild(cv);
		
		return elem;
	}
	
	/**
	 * Удаляет у элемента старые уголки
	 * @param {HTMLElement} elem Элемент, у которого нужно удалить уголки 
	 */
	function removeOldCorners(elem) {
		walkArray(elem.childNodes, function(){
			if (hasClass(this, base_class)) {
				elem.removeChild(this);
			}
		});
		
		cleanUp(elem);
	}
	
	/**
	 * Возвращает имя класса для переданных параметров. Используется для 
	 * того, чтобы не плодить много разных классов для одних и тех же правил
	 * @param {getCornerParams()} options Параметры рисования уголка
	 * @return {String}
	 */
	function getClassName(options) {
		var key = options.radius + ':' + (options.real_border_width || 0) + ':' + options.use_shape;
		if (!_corner_cache[key]) {
			_corner_cache[key] = rule_prefix + _corner_cache.ix++;
		}
		
		return _corner_cache[key];
	}
	
	/**
	 * Создает CSS-правила для скругленных уголков
	 * @param {getCornerParams()} options Параметры рисования уголка
	 * @param {HTMLElement} elem Элемент, которому добавляются уголки
	 * @param {Number} border_width Толщина бордюра
	 */
	function createCSSRules(options, elem) {
		var radius = options.radius,
			border_width = options.real_border_width || 0,
			diff = (options.use_shape) ? options.real_border_width - options.border_width : 0;
//		border_width += 10;
		
//		corners_ss.disabled = true;
			
		var class_name = getClassName(options);
		if (!_corner_cache.created[class_name]) {
			// такое правило еще не создано в CSS, создадим его
			var prefix = (browser.version < 7) 
							? '.' + class_name + ' .' + base_class  // IE6 
							: '.' + class_name + '>.' + base_class; // IE7+
			
			var offset_x = -border_width, 
				offset_y = -1 -border_width;
			
				
			addRule(prefix, 'width:' + (radius + border_width + 1) + 'px;height:' + (radius + 1) + 'px');
			
			if (options.use_shape) {
				offset_y = -radius - 1 - diff;
				var left_adjust = radius + options.border_width * 2 + diff;
				adjustBox(elem, class_name, options);
				var clip_size = Math.max(radius - border_width * 2, 0),
					pad_size = Math.min(radius - border_width * 2, 0) * -1;
				
				if (browser.version < 7) {
					pad_size += parseInt(getStyle(elem, 'padding-left') || 0) + parseInt(getStyle(elem, 'padding-right') || 0);
				}
				
				var css_rules = 'width:100%;clip:rect(auto auto auto ' + clip_size + 'px);padding-right:' + pad_size + 'px;left:' + (-border_width - clip_size) + 'px;';
				addRule(prefix + '-tl', css_rules + 'top:' + offset_y + 'px;');
				addRule(prefix + '-tl .' + vml_class, 'left:' + clip_size + 'px');
				
				addRule(prefix + '-bl', css_rules +'bottom:' + offset_y + 'px;');
				addRule(prefix + '-bl .' + vml_class, 'left:' + clip_size + 'px');
			} else {
				addRule(prefix + '-tl', 'left:' + offset_x + 'px;top:' + offset_y + 'px;');
				addRule(prefix + '-bl', 'left:' + offset_x + 'px;bottom:' + offset_y + 'px;');
			}
			
			if (browser.version < 7) {
				offset_x = -radius + (border_width ? radius % 2 - border_width % 2 : -radius % 2);
				
				addRule(prefix + '-tr', 'left:' + offset_x + 'px;top:' + offset_y + 'px;');
				addRule(prefix + '-br', 'left:' + offset_x + 'px;bottom:' + offset_y + 'px;');
			} else {
				addRule(prefix + '-tr', 'right:' + offset_x + 'px;top:' + offset_y + 'px;');
				addRule(prefix + '-br', 'right:' + offset_x + 'px;bottom:' + offset_y + 'px;');
			}
			
			_corner_cache.created[class_name] = true;
		}
	}
	
	addCorners = function(elem, radius) {
		var cparams = getCornerParams(elem, radius);
		
		createCSSRules(cparams, elem);
		
		// теперь добавляем сами уголки в элемент
		walkArray(['tl', 'tr', 'bl', 'br'], function(){
			elem.appendChild(drawCornerIE(cparams, this));
		});
		
		
		// говорим, что все добавилось
		elem.className += ' ' + getClassName(cparams) + ' ' + base_class + '-init';
		
	};
	
	result.update = function() {
		applyCornersToArgs(arguments, function(){
			removeOldCorners(this);
			addCorners(this);
		});
	};
	
	addDomReady(function(){
		corners_ss.cssText += css_text;
		css_text = '';
		addRule = corners_ss.addRule;
	});
};return result;})();
