/*! * Copyright (c) 2008 Simo Kinnunen. * Licensed under the MIT license. */var Cufon = (function() {		var api = function() {			return api.replace.apply(null, arguments);	};		var DOM = api.DOM = {					ready: (function() {					var complete = false, readyStatus = { loaded: 1, complete: 1 };					var queue = [], perform = function() {				if (complete) return;				complete = true;				for (var fn; fn = queue.shift(); fn());			};						// Gecko, Opera, WebKit r26101+						if (document.addEventListener) {				document.addEventListener('DOMContentLoaded', perform, false);				window.addEventListener('pageshow', perform, false); // For cached Gecko pages			}						// Old WebKit, Internet Explorer						if (!window.opera && document.readyState) (function() {				readyStatus[document.readyState] ? perform() : setTimeout(arguments.callee, 10);			})();						// Internet Explorer						if (document.readyState && document.createStyleSheet) (function() {				try {					document.body.doScroll('left');					perform();				}				catch (e) {					setTimeout(arguments.callee, 1);				}			})();						addEvent(window, 'load', perform); // Fallback						return function(listener) {				if (!arguments.length) perform();				else complete ? listener() : queue.push(listener);			};					})()			};	var CSS = api.CSS = {			Size: function(value, base) {					this.value = parseFloat(value);			this.unit = String(value).match(/[a-z%]*$/)[0] || 'px';					this.convert = function(value) {				return value / base * this.value;			};						this.convertFrom = function(value) {				return value / this.value * base;			};						this.toString = function() {				return this.value + this.unit;			};		},			getStyle: function(el) {			var view = document.defaultView;			if (view && view.getComputedStyle) return new Style(view.getComputedStyle(el, null));			if (el.currentStyle) return new Style(el.currentStyle);			return new Style(el.style);		},				ready: (function() {						var complete = false;						var queue = [], perform = function() {				complete = true;				for (var fn; fn = queue.shift(); fn());			};						// Safari 2 does not include <style> elements in document.styleSheets.			// Safari 2 also does not support Object.prototype.propertyIsEnumerable.						var styleElements = Object.prototype.propertyIsEnumerable ? elementsByTagName('style') : { length: 0 };			var linkElements = elementsByTagName('link');						DOM.ready(function() {				// These checks are actually only needed for WebKit-based browsers, but don't really hurt other browsers.				var linkStyles = 0, link;				for (var i = 0, l = linkElements.length; link = linkElements[i], i < l; ++i) {					// WebKit does not load alternate stylesheets.					if (!link.disabled && link.rel.toLowerCase() == 'stylesheet') ++linkStyles;				}				if (document.styleSheets.length >= styleElements.length + linkStyles) perform();				else setTimeout(arguments.callee, 10);			});						return function(listener) {				if (complete) listener();				else queue.push(listener);			};					})(),		supports: function(property, value) {			var checker = document.createElement('span').style;			if (checker[property] === undefined) return false;			checker[property] = value;			return checker[property] === value;		},				textAlign: function(word, style, position, wordCount) {			if (style.get('textAlign') == 'right') {				if (position > 0) word = ' ' + word;			}			else if (position < wordCount - 1) word += ' ';			return word;		},				textDecoration: function(el, style) {			if (!style) style = this.getStyle(el);			var types = {				underline: null,				overline: null,				'line-through': null			};			for (var search = el; search.parentNode && search.parentNode.nodeType == 1; ) {				var foundAll = true;				for (var type in types) {					if (types[type]) continue;					if (style.get('textDecoration').indexOf(type) != -1) types[type] = style.get('color');					foundAll = false;				}				if (foundAll) break; // this is rather unlikely to happen				style = this.getStyle(search = search.parentNode);			}			return types;		},				textShadow: cached(function(value) {			if (value == 'none') return null;			var shadows = [], currentShadow = {}, result, offCount = 0;			var re = /(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)|(-?[\d.]+[a-z%]*)|,/ig;			while (result = re.exec(value)) {				if (result[0] == ',') {					shadows.push(currentShadow);					currentShadow = {}, offCount = 0;				}				else if (result[1]) {					currentShadow.color = result[1];				}				else {					currentShadow[[ 'offX', 'offY', 'blur' ][offCount++]] = result[2];				}			}			shadows.push(currentShadow);			return shadows;		}),				color: cached(function(value) {			var parsed = {};			parsed.color = value.replace(/^rgba\((.*?),\s*([\d.]+)\)/, function($0, $1, $2) {				parsed.opacity = parseFloat($2);				return 'rgb(' + $1 + ')';			});			return parsed;		}),				textTransform: function(text, style) {			return text[{				uppercase: 'toUpperCase',				lowercase: 'toLowerCase'			}[style.get('textTransform')] || 'toString']();		}			};		api.VML = {			parsePath: function(path) {			var cmds = [], re = /([mrvxe])([^a-z]*)/g, match;			while (match = re.exec(path)) {				cmds.push({					type: match[1],					coords: match[2].split(',')				});			}			return cmds;		}				};		function Font(data) {				var face = this.face = data.face;		this.glyphs = data.glyphs;		this.w = data.w;		this.baseSize = parseInt(face['units-per-em'], 10);				this.family = face['font-family'].toLowerCase();		this.weight = face['font-weight'];		this.style = face['font-style'] || 'normal';				this.viewBox = (function () {			var parts = face.bbox.split(/\s+/);			return {				minX: parseInt(parts[0], 10),				minY: parseInt(parts[1], 10),				width: parseInt(parts[2], 10) - parseInt(parts[0], 10),				height: parseInt(parts[3], 10) - parseInt(parts[1], 10),				toString: function() {					return [ this.minX, this.minY, this.width, this.height ].join(' ');				}			};		})();				this.ascent = -parseInt(face.ascent, 10);		this.descent = -parseInt(face.descent, 10);				this.height = -this.ascent + this.descent;			}		function FontFamily() {		var styles = {}, mapping = {			oblique: 'italic',			italic: 'oblique'		};				this.add = function(font) {			(styles[font.style] || (styles[font.style] = {}))[font.weight] = font;		};				this.get = function(style, weight) {			var weights = styles[style] || styles[mapping[style]] || styles.normal;			if (!weights) return null;			// we don't have to worry about "bolder" and "lighter"			// because IE's currentStyle returns a numeric value for it,			// and other browsers use the computed value anyway			weight = {				normal: 400,				bold: 700			}[weight] || parseInt(weight, 10);			if (weights[weight]) return weights[weight];			// http://www.w3.org/TR/CSS21/fonts.html#propdef-font-weight			// Gecko uses x99/x01 for lighter/bolder			var up = {				1: 1,				99: 0			}[weight % 100], alts = [], min, max;			if (up === undefined) up = weight > 400;			if (weight == 500) weight = 400;			for (var alt in weights) {				alt = parseInt(alt, 10);				if (!min || alt < min) min = alt;				if (!max || alt > max) max = alt;				alts.push(alt);			}			if (weight < min) weight = min;			if (weight > max) weight = max;			alts.sort(function(a, b) {				return (up					? (a > weight && b > weight) ? a < b : a > b					: (a < weight && b < weight) ? a > b : a < b) ? -1 : 1;			});			return weights[alts[0]];		};		}		function Storage() {				var map = {}, at = 0;				function identify(el) {			return el.cufid || (el.cufid = ++at);		}				this.get = function(el) {			var id = identify(el);			return map[id] || (map[id] = {});		};			}		function Style(style) {				var custom = {}, sizes = {};				this.get = function(property) {			return custom[property] != undefined ? custom[property] : style[property];		};				this.getSize = function(property, base) {			return sizes[property] || (sizes[property] = new CSS.Size(this.get(property), base));		};				this.extend = function(styles) {			for (var property in styles) custom[property] = styles[property];			return this;		};			}		function addEvent(el, type, listener) {		if (el.addEventListener) {			el.addEventListener(type, listener, false);		}		else if (el.attachEvent) {			el.attachEvent('on' + type, function() {				return listener.apply(el, arguments);			});		}	}		function cached(fun) {		var cache = {};		return function(key) {			if (!cache.hasOwnProperty(key)) cache[key] = fun.apply(null, arguments);			return cache[key];		};		}		function getFont(el, style) {		if (!style) style = CSS.getStyle(el);		var families = style.get('fontFamily').split(/\s*,\s*/), family;		for (var i = 0, l = families.length; i < l; ++i) {			family = families[i].replace(/^(["'])(.*?)\1$/, '$2').toLowerCase();			if (fonts[family]) return fonts[family].get(style.get('fontStyle'), style.get('fontWeight'));		}		return null;	}		function elementsByTagName(query) {		return document.getElementsByTagName(query);	}		function merge() {		var merged = {}, key;		for (var i = 0, l = arguments.length; i < l; ++i) {			for (key in arguments[i]) merged[key] = arguments[i][key];		}		return merged;	}		function process(font, text, style, options, node, el) {		var separate = options.separate;		if (separate == 'none') return engines[options.engine].apply(null, arguments);		var fragment = document.createDocumentFragment(), processed;		var parts = text.split(separators[separate]), needsAligning = (separate == 'words');		if (needsAligning && HAS_BROKEN_REGEXP) {			// @todo figure out a better way to do this			if (/^\s/.test(text)) parts.unshift('');			if (/\s$/.test(text)) parts.push('');		}		for (var i = 0, l = parts.length; i < l; ++i) {			processed = engines[options.engine](font,				needsAligning ? CSS.textAlign(parts[i], style, i, l) : parts[i],				style, options, node, el, i < l - 1);			if (processed) fragment.appendChild(processed);		}		return fragment;	}		function replaceElement(el, options) {		var storage = sharedStorage.get(el);		if (!options) options = storage.options;		var font, style, nextNode;		for (var node = el.firstChild; node; node = nextNode) {			nextNode = node.nextSibling;			if (node.nodeType == 1) {				if (!node.firstChild) continue;				if (!/cufon/.test(node.className)) {					arguments.callee(node, options);					continue;				}			}			var text = node.nodeType == 3 ? node.data : node.alt;			if (text.trim() == '') continue;			if (!style) style = CSS.getStyle(el).extend(options);			if (!font) font = getFont(el, style);			if (!font) continue;			var processed = process(font, text, style, options, node, el);			if (processed) node.parentNode.replaceChild(processed, node);			else node.parentNode.removeChild(node);		}		if (!storage.options) {			storage.options = options;		}	}		var HAS_BROKEN_REGEXP = ' '.split(/\s+/).length == 0;		var sharedStorage = new Storage();	var replaceHistory = [];		var engines = {}, fonts = {}, defaultOptions = {		enableTextDecoration: false,		engine: null,		//fontScale: 1,		//fontScaling: false,		//hover: false,		printable: true,		//rotation: 0,		//selectable: false,		selector: (				window.Sizzle			||	(window.dojo && dojo.query)			||	(window.$$ && function(query) { return $$(query); })			||	window.$			||	(document.querySelectorAll && function(query) { return document.querySelectorAll(query); })			||	elementsByTagName		),		separate: 'words', // 'none' and 'characters' are also accepted		textShadow: 'none'	};		var separators = {		words: /\s+/,		characters: ''	};		api.now = function() {		DOM.ready();		return api;	};		api.refresh = function() {		var currentHistory = replaceHistory.splice(0, replaceHistory.length);		for (var i = 0, l = currentHistory.length; i < l; ++i) {			api.replace.apply(null, currentHistory[i]);		}		return api;	};		api.registerEngine = function(id, engine) {		if (!engine) return api;		engines[id] = engine;		return api.set('engine', id);	};		api.registerFont = function(data) {		var font = new Font(data), family = font.family;		if (!fonts[family]) fonts[family] = new FontFamily();		fonts[family].add(font);		return api.set('fontFamily', family);	};		api.replace = function(elements, options, ignoreHistory) {		options = merge(defaultOptions, options);		if (!options.engine) return api; // there's no browser support so we'll just stop here		if (typeof options.textShadow == 'string')			options.textShadow = CSS.textShadow(options.textShadow);		if (!ignoreHistory) replaceHistory.push(arguments);		if (elements.nodeType || typeof elements == 'string') elements = [ elements ];		CSS.ready(function() {			for (var i = 0, l = elements.length; i < l; ++i) {				var el = elements[i];				if (typeof el == 'string') api.replace(options.selector(el), options, true);				else replaceElement(el, options);			}		});		return api;	};		api.set = function(option, value) {		defaultOptions[option] = value;		return api;	};		return api;	})();Cufon.registerEngine('canvas', (function() {	// Safari 2 doesn't support .apply() on native methods		var check = document.createElement('canvas');	if (!check || !check.getContext || !check.getContext.apply) return null;	check = null;		var HAS_INLINE_BLOCK = Cufon.CSS.supports('display', 'inline-block');		// Firefox 2 w/ non-strict doctype (almost standards mode)	var HAS_BROKEN_LINEHEIGHT = !HAS_INLINE_BLOCK && (document.compatMode == 'BackCompat' || /frameset|transitional/i.test(document.doctype.publicId));		var styleSheet = document.createElement('style');	styleSheet.type = 'text/css';	styleSheet.appendChild(document.createTextNode(		'@media screen,projection{' +			'.cufon-canvas{display:inline;display:inline-block;position:relative;vertical-align:middle' + 			(HAS_BROKEN_LINEHEIGHT				? ''				: ';font-size:1px;line-height:1px') +			'}.cufon-canvas .cufon-alt{display:none}' +			(HAS_INLINE_BLOCK				? '.cufon-canvas canvas{position:relative}'				: '.cufon-canvas canvas{position:absolute}') +		'}' +		'@media print{' +			'.cufon-canvas{padding:0 !important}' +			'.cufon-canvas canvas{display:none}' +			'.cufon-canvas .cufon-alt{display:inline}' +		'}'	));	document.getElementsByTagName('head')[0].appendChild(styleSheet);	function generateFromVML(path, context) {		var atX = 0, atY = 0;		var cmds = Cufon.VML.parsePath(path);		var code = new Array(cmds.length - 1);		generate: for (var i = 0, l = cmds.length; i < l; ++i) {			var c = cmds[i].coords;			switch (cmds[i].type) {				case 'v':					code[i] = { m: 'bezierCurveTo', a: [ atX + Number(c[0]), atY + Number(c[1]), atX + Number(c[2]), atY + Number(c[3]), atX += Number(c[4]), atY += Number(c[5]) ] };					break;				case 'r':					code[i] = { m: 'lineTo', a: [ atX += Number(c[0]), atY += Number(c[1]) ] };					break;				case 'm':					code[i] = { m: 'moveTo', a: [ atX = Number(c[0]), atY = Number(c[1]) ] };					break;				case 'x':					code[i] = { m: 'closePath' };					break;				case 'e':					break generate;			}			context[code[i].m].apply(context, code[i].a);		}		return code;	}		function interpret(code, context) {		for (var i = 0, l = code.length; i < l; ++i) {			var line = code[i];			context[line.m].apply(context, line.a);		}	}		return function(font, text, style, options, node, el) {				var viewBox = font.viewBox;				var size = style.getSize('fontSize', font.baseSize);				var letterSpacing = style.get('letterSpacing');		letterSpacing = (letterSpacing == 'normal') ? 0 : size.convertFrom(parseInt(letterSpacing, 10));				var expandTop = 0, expandRight = 0, expandBottom = 0, expandLeft = 0;		var shadows = options.textShadow, shadowOffsets = [];		if (shadows) {			for (var i = 0, l = shadows.length; i < l; ++i) {				var shadow = shadows[i];				var x = size.convertFrom(parseFloat(shadow.offX));				var y = size.convertFrom(parseFloat(shadow.offY));				shadowOffsets[i] = [ x, y ];				if (y < expandTop) expandTop = y;				if (x > expandRight) expandRight = x;				if (y > expandBottom) expandBottom = y;				if (x < expandLeft) expandLeft = x;			}		}				var chars = Cufon.CSS.textTransform(text, style).split('');				var width = 0, lastWidth = null;				for (var i = 0, l = chars.length; i < l; ++i) {			var glyph = font.glyphs[chars[i]] || font.missingGlyph;			if (!glyph) continue;			width += lastWidth = Number(glyph.w || font.w) + letterSpacing;		}				if (lastWidth === null) return null; // there's nothing to render				expandRight += (viewBox.width - lastWidth);		expandLeft += viewBox.minX;				var wrapper = document.createElement('span');		wrapper.className = 'cufon cufon-canvas';		wrapper.alt = text;				var canvas = document.createElement('canvas');				var wStyle = wrapper.style;		var cStyle = canvas.style;				var height = size.convert(viewBox.height - expandTop + expandBottom);		var roundedHeight = Math.ceil(height);		var roundingFactor = roundedHeight / height;				canvas.width = Math.ceil(size.convert(width + expandRight - expandLeft) * roundingFactor);		canvas.height = roundedHeight;				// minY has no part in canvas.height		expandTop += viewBox.minY;				cStyle.top = Math.round(size.convert(expandTop - font.ascent)) + 'px';		cStyle.left = Math.round(size.convert(expandLeft)) + 'px';				var wrapperWidth = Math.ceil(size.convert(width * roundingFactor)) + 'px';				if (HAS_INLINE_BLOCK) {			wStyle.width = wrapperWidth;			wStyle.height = size.convert(font.height) + 'px';		}		else {			wStyle.paddingLeft = wrapperWidth;			wStyle.paddingBottom = (size.convert(font.height) - 1) + 'px';		}				var g = canvas.getContext('2d'), scale = roundedHeight / viewBox.height;				g.scale(scale, scale);		g.translate(-expandLeft, -expandTop);				g.lineWidth = font.face['underline-thickness'];				g.save();				function line(y, color) {			g.strokeStyle = color;						g.beginPath();						g.moveTo(0, y);			g.lineTo(width, y);						g.stroke();		}				var textDecoration = options.enableTextDecoration ? Cufon.CSS.textDecoration(el, style) : {};				if (textDecoration.underline) line(-font.face['underline-position'], textDecoration.underline);		if (textDecoration.overline) line(font.ascent, textDecoration.overline);				g.fillStyle = style.get('color');				function renderText() {			for (var i = 0, l = chars.length; i < l; ++i) {				var glyph = font.glyphs[chars[i]] || font.missingGlyph;				if (!glyph) continue;				g.beginPath();				if (glyph.d) {					if (glyph.code) interpret(glyph.code, g);					else glyph.code = generateFromVML('m' + glyph.d, g);				}				g.fill();				g.translate(Number(glyph.w || font.w) + letterSpacing, 0);			}		}				if (shadows) {			for (var i = 0, l = shadows.length; i < l; ++i) {				var shadow = shadows[i];				g.save();				g.fillStyle = shadow.color;				g.translate.apply(g, shadowOffsets[i]);				renderText();				g.restore();			}		}				renderText();				g.restore();				if (textDecoration['line-through']) line(-font.descent, textDecoration['line-through']);				wrapper.appendChild(canvas);				if (options.printable) {			var print = document.createElement('span');			print.className = 'cufon-alt';			print.appendChild(document.createTextNode(text));			wrapper.appendChild(print);		}				return wrapper;				};	})());Cufon.registerEngine('vml', (function() {	if (!document.namespaces) return;	// isn't undocumented stuff great?	document.write('<!--[if vml]><script type="text/javascript">Cufon.vmlEnabled=true;</script><![endif]-->');	if (!Cufon.vmlEnabled) return;		if (document.namespaces['cvml'] == null) {		document.namespaces.add('cvml', 'urn:schemas-microsoft-com:vml');		document.write('<style type="text/css">' +			'@media screen{' + 				'cvml\\:shape,cvml\\:group,cvml\\:shapetype,cvml\\:fill{behavior:url(#default#VML);display:inline-block;antialias:true;position:absolute}' +				'.cufon-vml{display:inline-block;position:relative;vertical-align:middle}' +				'.cufon-vml .cufon-alt{display:none}' +				'a .cufon-vml{cursor:pointer}' +			'}' +			'@media print{' + 				'.cufon-vml *{display:none}' +				'.cufon-vml .cufon-alt{display:inline}' +			'}' +		'</style>');	}	var typeIndex = 0; // this is used to reference VML ShapeTypes	function getFontSizeInPixels(el, value) {		return getSizeInPixels(el, /(?:em|ex|%)$/i.test(value) ? '1em' : value);	}		// Original by Dead Edwards.	// Combined with getFontSizeInPixels it also works with relative units.	function getSizeInPixels(el, value) {		if (/px$/i.test(value)) return parseFloat(value);		var style = el.style.left, runtimeStyle = el.runtimeStyle.left;		el.runtimeStyle.left = el.currentStyle.left;		el.style.left = value;		var result = el.style.pixelLeft;		el.style.left = style;		el.runtimeStyle.left = runtimeStyle;		return result;	}		function createType(glyph, viewBox) {		var shapeType = document.createElement('cvml:shapetype');		shapeType.id = 'cufon-glyph-' + typeIndex++;		glyph.typeRef = '#' + shapeType.id;		shapeType.stroked = 'f';		shapeType.coordsize = viewBox.width + ',' + viewBox.height;		shapeType.coordorigin = viewBox.minX + ',' + viewBox.minY;		var ensureSize = 'm' + viewBox.minX + ',' + viewBox.minY + ' r' + viewBox.width + ',' + viewBox.height;		shapeType.path = (glyph.d ? 'm' + glyph.d + 'x' : '') + ensureSize;		document.body.insertBefore(shapeType, document.body.firstChild);	}		return function(font, text, style, options, node, el, hasNext) {			// @todo word-spacing, text-decoration			var viewBox = font.viewBox;				var size = style.computedFontSize || (style.computedFontSize = new Cufon.CSS.Size(getFontSizeInPixels(el, style.get('fontSize')) + 'px', font.baseSize));				var letterSpacing = style.computedLSpacing;				if (letterSpacing == undefined) {			letterSpacing = style.get('letterSpacing');			style.computedLSpacing = letterSpacing = (letterSpacing == 'normal') ? 0 : size.convertFrom(getSizeInPixels(el, letterSpacing));		}				var wrapper = document.createElement('span');		wrapper.className = 'cufon cufon-vml';		wrapper.alt = text;				var canvas = document.createElement('cvml:group');				var wStyle = wrapper.runtimeStyle;		var cStyle = canvas.runtimeStyle;				var height = size.convert(viewBox.height);				cStyle.height = Math.ceil(height);		cStyle.top = Math.round(size.convert(viewBox.minY - font.ascent));		cStyle.left = Math.round(size.convert(viewBox.minX));				var roundingFactor = parseInt(cStyle.height, 10) / height;				wStyle.height = size.convert(-font.ascent + font.descent) + 'px';				var textDecoration = options.enableTextDecoration ? Cufon.CSS.textDecoration(el, style) : {};				var color = style.get('color');		var chars = Cufon.CSS.textTransform(text, style).split('');				var width = 0, offsetX = 0, advance = null;				var shadows = options.textShadow;				for (var i = 0, l = chars.length; i < l; ++i) {					var glyph = font.glyphs[chars[i]] || font.missingGlyph;			if (!glyph) continue;						if (!glyph.typeRef) createType(glyph, viewBox);						var shape = document.createElement('cvml:shape');			shape.type = glyph.typeRef;			var sStyle = shape.runtimeStyle;			sStyle.width = viewBox.width;			sStyle.height = viewBox.height;			sStyle.top = 0;			sStyle.left = offsetX;			sStyle.zIndex = 1;			shape.fillcolor = color;			canvas.appendChild(shape);						if (shadows) {				// the VML shadow element is not used because it can only support				// up to 2 shadows. and it breaks text selection.				for (var z = 0, p = shadows.length; z < p; ++z) {					var shadow = shadows[z];					var shadowColor = Cufon.CSS.color(shadow.color);					var shadowNode = shape.cloneNode(false), zStyle = shadowNode.runtimeStyle;					zStyle.top = size.convertFrom(parseFloat(shadow.offY));					zStyle.left = offsetX + size.convertFrom(parseFloat(shadow.offX));					zStyle.zIndex = 0;					shadowNode.fillcolor = shadowColor.color;					if (shadowColor.opacity) {						var shadowFill = document.createElement('cvml:fill');						shadowFill.opacity = shadowColor.opacity;						shadowNode.appendChild(shadowFill);					}					canvas.appendChild(shadowNode);				}			}						advance = Number(glyph.w || font.w) + letterSpacing;						width += advance;			offsetX += advance;					}				if (advance === null) return null;				var fullWidth = -viewBox.minX + width + (viewBox.width - advance);				canvas.coordsize = fullWidth + ',' + viewBox.height;				cStyle.width = size.convert(fullWidth * roundingFactor);				wStyle.width = Math.max(Math.ceil(size.convert(width * roundingFactor)), 0);				wrapper.appendChild(canvas);			if (options.printable) {			var print = document.createElement('span');			print.className = 'cufon-alt';			print.innerText = text;			wrapper.appendChild(print);		}				// ie6, for some reason, has trouble rendering the last VML element in the document.		// we can work around this by injecting a dummy element where needed.		// @todo find a better solution		if (!hasNext) wrapper.appendChild(document.createElement('cvml:group'));				return wrapper;			};	})());
