var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var xhtmlNS = "http://www.w3.org/1999/xhtml";


if(!document.createElementNS){
	document.createElementNS = function(ns, name){
		prefix = null;
		if(ns==svgNS){
			prefix = 'svg';
		}
		var elem = document.createElement((prefix?prefix+':':'')+name);
		elem.setAttribute("xmlns", ns);
		return elem;
	}
}

var SVGVectorObject = function() {
	this.init();
};

SVGVectorObject.prototype = {
	init: function() {
		var svgElement = document.createElementNS(svgNS,"svg");
		if(typeof(svgElement.x)=="undefined"){
			this.svg_capable = false;
		}else{
			this.svg_capable = true;
		}
		svgElement = null;

		this.vml_capable = (document.all && !(navigator.userAgent.indexOf("Opera")>=0)) ? true : false;

		if ( this.vml_capable ) {
			try{
				document.namespaces.add("v","urn:schemas-microsoft-com:vml");
				document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML); position:absolute" );
			}catch(e){
				this.vml_capable = false;
			}
		}
	},

	createElementNS: function( ns, element ) {
		if ( this.svg_capable ) {
			var svgElement = document.createElementNS(ns, element);
			return svgElement;
		} else if ( this.vml_capable ) {
			element = element.toLowerCase();
			if ( element == "svg" ) {
				return createVMLSurface();
			} else if ( element == "g" ) {
				return createVMLGroup();
			} else if ( element == "circle") {
				return createVMLCircle();
			} else if ( element == "ellipse") {
				return createVMLEllipse();
			} else if ( element == "rect") {
				return createVMLRectangle();
			} else if ( element == "line") {
				return createVMLLine();
			} else if (element == "linearGradient") {
				return createVMLLinearGradient();
			} else if( element == "stop" ) {
				return createVMLStop();
			} else if( element == "defs" ) {
				return createVMLDefs();
			} else if( element == "image" ) {
				return createVMLImage();
			} else if( element == "text" ) {
				return createVMLTextbox();
			} else if( element == "path" ) {
				return createVMLPath();
			} else if( element == "a" ) {
				return createHTMLa();
			}
		} else {
			return null;
		}
	},

	createTextNode: function( string ) {
		return document.createTextNode(string);
	},

	getElementById: function( string ) {
		return document.getElementById(string);
	}
};

var createVMLSurface = function() {
	var domElement = document.createElement("div");
	domElement.style.position = "absolute";
	domElement.style.left = "0px";
	domElement.style.top = "0px";
	domElement.style.overflow = "hidden";
	domElement.onselectstart = function(){ return false; }
	domElement.ondrag = function(){ return false; }

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "width" ) {
			this.style.width = value;
		} else if ( key == "height" ) {
			this.style.height = value;
		} else if ( key == "x" ) {
			this.style.left = value;
		} else if ( key == "y" ) {
			this.style.top = value;
		} else if ( key == "overflow" ) {
			this.style.overflow = value;
		} else if ( key == "style" ) {
			if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText);
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {
		if ( key == "width" ) {
			return parseInt( this.style.width );
		} else if ( key == "height" ) {
			return parseInt( this.style.height );
		} else if ( key == "x" ) {
			return parseInt( this.style.left );
		} else if ( key == "y" ) {
			return parseInt( this.style.top );
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

var createVMLGroup = function() {
	//var domElement = document.createElement("v:group");
	//eventually try and use group here - mostly works, except for text items - possibly due to the nesting
	var domElement = document.createElement("div");
	domElement.style.position = "absolute";
	domElement.style.left = "0px";
	domElement.style.top = "0px";

	//domElement.style.width = '1';
	//domElement.style.height = '1';
	//domElement.coordsize = '1, 1';

	domElement['attribstroke'] = '';
	domElement['stylestroke'] = '';
	domElement['classstroke'] = '';
	domElement['parentstroke'] = '';

	domElement['attribstroke-width'] = '';
	domElement['stylestroke-width'] = '';
	domElement['classstroke-width'] = '';
	domElement['parentstroke-width'] = '';

	domElement['attribfill'] = '';
	domElement['stylefill'] = '';
	domElement['classfill'] = '';
	domElement['parentfill'] = '';

	domElement['attribopacity'] = '';
	domElement['styleopacity'] = '';
	domElement['classopacity'] = '';
	domElement['parentopacity'] = '';

	domElement.defs = {};

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "width" ) {
			this.style.width = value;
			//this.coordsize = this.style.width+', '+this.style.height;
		} else if ( key == "height" ) {
			this.style.height = value;
			//this.coordsize = this.style.width+', '+this.style.height;
		} else if ( key == "x" ) {
			this.style.left = value;
		} else if ( key == "y" ) {
			this.style.top = value;
		} else if ( key == "transform" ) {
			var reg = /scale\s*\(\s*(\d+\.\d+)\s*(\d+\.\d+)\s*\)/i;
			var ar = reg.exec(value);
			var xScale = 1;
			var yScale = 1;
			if( ar ){
				xScale = ar[1];
				yScale = ar[2];
			}
			for( var i=0; i<this.childNodes.length; i++ ){
				var child = this.childNodes[i];
				var width = parseInt(child.style.width);
				var height = parseInt(child.style.height);
				var left = parseInt(child.style.left);
				var top = parseInt(child.style.top);
				child.style.width = width * xScale + 'px';
				child.style.height = height * yScale + 'px';
				child.style.left = left * xScale + 'px';
				child.style.top = top * yScale + 'px';
			}
		} else if ( key == "stroke" || key == "stroke-width" || key == "fill" || key == "opacity" ) {
			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;

if(level=='parents'){
alert(
"passedVal          = '"+value+"'\n"+
"key         = '"+key+"'\n"+
"level              = '"+level+"'\n"+
"styleStrokeweight  = '"+this['style'+key]+"'\n"+
"classStrokeweight  = '"+this['class'+key]+"'\n"+
"attribStrokeweight = '"+this['attrib'+key]+"'\n"+
"parentStrokeweight = '"+this['parent'+key]+"'\n"
);
}	
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));

			for( var i=0; i<this.childNodes.length; i++ ){
				try{ //alert(this.childNodes[i].tagName);
					//childAttrVal = this.childNodes[i].getAttribute(key);
					//if(childAttrVal==''){
						this.childNodes[i].setAttribute(key,value,'parent');
					//}
				} catch (e) { }
			}
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			var level = 'style';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}

			this.style.visibility = "";
			this.setAttribute("stroke","",level);
			this.setAttribute("stroke-width","",level);
			this.setAttribute("fill","",level);
			this.setAttribute("opacity","",level);

			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'stroke' || key == 'stroke-width' || key == 'fill' || key == 'opacity' ) {
					this.setAttribute(key,value,level);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText,'class');
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}


	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {
		if ( key == "style" ) {
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

var createVMLCircle = function() {
	var domElement = document.createElement("v:oval");
	var strokeElement = document.createElement("v:stroke");
	domElement.appendChild(strokeElement);
	domElement.strokeElement = strokeElement;
	var fillElement = document.createElement("v:fill");
	domElement.appendChild(fillElement);
	domElement.fillElement = fillElement;

	domElement.leftPos = 0;
	domElement.topPos = 0;
	domElement.rVal = 0;
	domElement.setStyle = '';

	domElement['attribstroke'] = '';
	domElement['stylestroke'] = '';
	domElement['classstroke'] = '';
	domElement['parentstroke'] = '';

	domElement['attribstroke-width'] = '';
	domElement['stylestroke-width'] = '';
	domElement['classstroke-width'] = '';
	domElement['parentstroke-width'] = '';

	domElement.attribStrokedash = '';
	domElement.styleStrokedash = '';
	domElement.classStrokedash = '';
	domElement.parentStrokedash = '';

	domElement['attribfill'] = '';
	domElement['stylefill'] = '';
	domElement['classfill'] = '';
	domElement['parentfill'] = '';

	domElement['attribopacity'] = '';
	domElement['styleopacity'] = '';
	domElement['classopacity'] = '';
	domElement['parentopacity'] = '';

	domElement['attribfill-opacity'] = '';
	domElement['stylefill-opacity'] = '';
	domElement['classfill-opacity'] = '';
	domElement['parentfill-opacity'] = '';

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "cx" ) {
			this.leftPos = parseInt(value);
			this.style.left = (this.leftPos - this.rVal) + 'px';
		} else if ( key == "cy" ) {
			this.topPos = parseInt(value);
			this.style.top = (this.topPos - this.rVal) + 'px';
		} else if ( key == "stroke" ) {
			value = color2hex(value);
			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));

			this.strokecolor = value;
			this.style.stroke = value;
		} else if ( key == "stroke-width" ) {
			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));

			this.strokeweight = parseFloat(value)/1.2 + "pt";
			this.style['stroke-width'] = parseFloat(value);
		} else if ( key == "stroke-dasharray" ) {

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+'Strokedash'] = value;
			value = ((this.styleStrokedash!='')?this.styleStrokedash:((this.classStrokedash!='')?this.classStrokedash:((this.attribStrokedash!='')?this.attribStrokedash:((this.parentStrokedash!='')?this.parentStrokedash:''))));
			
			if(value==''){
				value = "1";
			}

			this.style['stroke-dasharray'] = value;

			// the dashstyle doesn't work very well, so we will use the built in names
			value = value.split(/[,\s]+/g);
			var minVal = parseFloat(value[0]);
			for(var x=1;x<value.length;x++){
				minVal = Math.min(minVal, parseFloat(value[x]));
			} if (minVal < 1) { minVal = 1; }
			
			if (value.length >= 6) {
				value = "longdashdotdot";
			} else if (value.length >= 4) {
				value = (1*value[0] >= 2*value[1]) ? "longdashdot" : "dashdot";
			} else if (value.length >= 2) {
				if (1*value[0] >= 2*value[1]) {
					value = "longdash";
				} else {
					value = (value[0]/minVal == 1 || value[1]/minVal == 1) ? "dot" : "dash";
				}
			} else {
				value = "solid";
			}

			this.strokeElement.dashstyle = value;

			return;
		} else if ( key == "fill" ) {
			if(this.fillElement.parentNode!=this){
				var foundFillElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='fill'){
						this.fillElement = this.childNodes[i];
						foundFillElement = true;
						break;
					}
				}
				if(!foundFillElement){
					var fillElement = document.createElement("v:fill");
					this.appendChild(fillElement);
					this.fillElement = fillElement;
				}
			}

			value = color2hex(value);
			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));

			if(value==''){
				value = "black";
			}
			if(value.toLowerCase()=='none'){
				this.fillElement.on = false;
			}else{
				this.fillElement.on = true;
			}
			this.fillElement.color = value;
			this.style.fill = value;
		} else if ( key == "r" ) {
			//save the last width
			this.rVal = parseInt(value);

			//set width and height to r*2
			this.style.width = this.rVal*2 + 'px';
			this.style.height = this.rVal*2 + 'px';

			this.style.left = (this.leftPos - this.rVal) + 'px';
			this.style.top = (this.topPos - this.rVal) + 'px';
		} else if ( key == "opacity" ) {
			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));
			if(value==''){
				value = "1";
			}

			this.setOpacity = parseFloat(value);
			if(this.setOpacity!=1){
				this.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+(this.setOpacity*100)+')';
			} else {
				// clear any old filters, leaving a filter when it's not needed messes things up
				this.style.filter='';
			}
			this.style.opacity = parseFloat(value);
			return;
		} else if ( key == "fill-opacity" ) {
			if(this.fillElement.parentNode!=this){
				var foundFillElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='fill'){
						this.fillElement = this.childNodes[i];
						foundFillElement = true;
						break;
					}
				}
				if(!foundFillElement){
					var fillElement = document.createElement("v:fill");
					this.appendChild(fillElement);
					this.fillElement = fillElement;
				}
			}

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));
			if(value==''){
				value = "1";
			}

			this.fillElement.setAttribute('opacity', parseFloat(value));
			this.style['fill-opacity'] = parseFloat(value);
			return;
		} else if ( key == "stroke-opacity" ) {
			if(this.strokeElement.parentNode!=this){
				var foundStrokeElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='stroke'){
						this.strokeElement = this.childNodes[i];
						foundStrokeElement = true;
						break;
					}
				}
				if(!foundStrokeElement){
					var strokeElement = document.createElement("v:stroke");
					this.appendChild(strokeElement);
					this.strokeElement = strokeElement;
				}
			}
		
			if(value==''){
				value = "1";
			}
			this.strokeElement.setAttribute('opacity', parseFloat(value));
			this.style['stroke-opacity'] = parseFloat(value);
			return;
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			var level = 'style';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			if(level=='style'){
				this.setStyle = value;
			}
			
			value = " "+value;
			
			if(value.search(/[; ]stroke\s*:/i)==-1){ 		this.setAttribute("stroke","",level); }
			if(value.search(/[; ]stroke-width\s*:/i)==-1){	 	this.setAttribute("stroke-width","",level); }
			if(value.search(/[; ]stroke-dasharray\s*:/i)==-1){ 	this.setAttribute("stroke-dasharray","",level); }
			if(value.search(/[; ]fill\s*:/i)==-1){ 			this.setAttribute("fill","",level); }
			if(value.search(/[; ]opacity\s*:/i)==-1){ 		this.setAttribute("opacity","",level); }
			if(value.search(/[; ]fill-opacity\s*:/i)==-1){ 		this.setAttribute("fill-opacity","",level); }
			if(value.search(/[; ]stroke-opacity\s*:/i)==-1){ 	this.setAttribute("stroke-opacity","",level); }
			if(value.search(/[; ]visibility\s*:/)==-1){ 		this.style.visibility = ""; }
			
			//if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'stroke' || key == 'stroke-width' || key == 'stroke-dasharray' || key == 'fill' || key == 'opacity' || key == 'fill-opacity' || key == 'stroke-opacity' ) {
					this.setAttribute(key,value,level);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText,'class');
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {

		if ( key == "cx" ) {
			return this.leftPos;
		} else if ( key == "cy" ) {
			return this.topPos;
		} else if ( key == "stroke" ) {
			return this.strokecolor;
		} else if ( key == "stroke-width" ) {
			return parseFloat( this.strokeweight ) * 1.2 + 'px';
		} else if ( key == "fill" ) {
			return this.fillcolor;
		} else if ( key == "opacity" ) {
			return this.setOpacity;
		} else if ( key == "r" ) {
			return this.rVal;
		} else if ( key == "style" ) {
			return this.setStyle;
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

var createVMLEllipse = function() {
	var domElement = document.createElement("v:oval");
	var strokeElement = document.createElement("v:stroke");
	domElement.appendChild(strokeElement);
	domElement.strokeElement = strokeElement;
	var fillElement = document.createElement("v:fill");
	domElement.appendChild(fillElement);
	domElement.fillElement = fillElement;

	domElement.leftPos = 0;
	domElement.topPos = 0;
	domElement.rxVal = 0;
	domElement.ryVal = 0;
	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "cx" ) {
			if( this.rxVal == 0 ) {
				this.leftPos = parseInt(value);
			} else {
				this.leftPos = parseInt(value) - parseInt(this.rxVal) + 'px';
				this.style.left = this.leftPos;
			}
		} else if ( key == "cy" ) {
			if( this.ryVal == 0 ) {
				this.topPos = parseInt(value);
			} else {
				this.topPos = parseInt(value) - parseInt(this.ryVal) + 'px';
				this.style.top = this.topPos;
			}
		} else if ( key == "stroke" ) {
			value = color2hex(value);
			this.strokecolor = value;
		} else if ( key == "stroke-width" ) {
			this.strokeweight = parseFloat(value)/1.2 + "pt";
		} else if ( key == "fill" ) {
			value = color2hex(value);
			this.fillcolor = value;
		} else if ( key == "rx" ) {
			this.rxVal = parseInt(value);
			var last = (this.style.width) ? parseInt( this.style.width ) : 0;
			this.style.width = this.rxVal*2 + 'px';

			//var left = (this.style.left) ? parseInt( this.style.left ) : 0;

			if( last == 0 ) {
				this.leftPos = this.leftPos - this.rxVal;
				this.style.left = this.leftPos + 'px';
			} else {
				this.style.left = this.leftPos + parseInt(last)/2 - this.rxVal;
			}
		} else if ( key == "ry" ) {
			this.ryVal = parseInt(value);
			var last = (this.style.height) ? parseInt( this.style.height ) : 0;
			this.style.height = this.ryVal*2 + 'px';

			//var top = (this.style.top) ? parseInt( this.style.top ) : 0;

			if( last == 0 ) {
				this.topPos = this.topPos - this.ryVal;
				this.style.top = this.topPos + 'px';
			} else {
				this.style.top = this.topPos + parseInt(last)/2 - this.ryVal;
			}
		} else if ( key == "opacity" ) {
			this.setOpacity = parseFloat(value);
			if(this.setOpacity!=1){
				this.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+(this.setOpacity*100)+')';
			} else {
				// clear any old filters, leaving a filter when it's not needed messes things up
				this.style.filter='';
			}
			return;
		} else if ( key == "fill-opacity" ) {
			if(this.fillElement.parentNode!=this){
				var foundFillElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='fill'){
						this.fillElement = this.childNodes[i];
						foundFillElement = true;
						break;
					}
				}
				if(!foundFillElement){
					var fillElement = document.createElement("v:fill");
					this.appendChild(fillElement);
					this.fillElement = fillElement;
				}
			}

			this.fillElement.setAttribute('opacity', parseFloat(value));
			return;
		} else if ( key == "stroke-opacity" ) {
			if(this.strokeElement.parentNode!=this){
				var foundStrokeElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='stroke'){
						this.strokeElement = this.childNodes[i];
						foundStrokeElement = true;
						break;
					}
				}
				if(!foundStrokeElement){
					var strokeElement = document.createElement("v:stroke");
					this.appendChild(strokeElement);
					this.strokeElement = strokeElement;
				}
			}
		
			this.strokeElement.setAttribute('opacity', parseFloat(value));
			return;
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'stroke' || key == 'stroke-width' || key == 'fill' || key == 'opacity' ) {
					this.setAttribute(key,value);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText);
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {

		if ( key == "cx" ) {
			var x = (parseInt(this.style.left) + parseInt(this.style.width)/2) ?
				(parseInt(this.style.left) + parseInt(this.style.width)/2) + 'px' : 0 + 'px';
			return x;
		} else if ( key == "cy" ) {
			var y = (parseInt(this.style.top) + parseInt(this.style.height)/2) ?
				(parseInt(this.style.top) + parseInt(this.style.height)/2) + 'px' : 0 + 'px';
			return y;
		} else if ( key == "stroke" ) {
			return this.strokecolor;
		} else if ( key == "stroke-width" ) {
			return parseFloat( this.strokeweight ) * 1.2 + 'px';
		} else if ( key == "fill" ) {
			return this.fillcolor;
		} else if ( key == "opacity" ) {
			return this.setOpacity;
		} else if ( key == "rx" ) {
			return parseInt( this.style.width )/2;
		} else if ( key == "ry" ) {
			return parseInt( this.style.height )/2;
		} else if ( key == "style" ) {
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

var LinearGradient = function( id, startColor, endColor, angle ) {
	this.init( id, startColor, endColor, angle );
};
LinearGradient.prototype = {
	init: function( id, startColor, endColor, angle ) {
		this.id = id;
		this.type = "LinearGradient";
		this.startColor = startColor;
		this.endColor = endColor;
		this.angle = angle;
	}
}


var createVMLRectangle = function() {
	var domElement = document.createElement("v:roundrect");
	var strokeElement = document.createElement("v:stroke");
	domElement.appendChild(strokeElement);
	domElement.strokeElement = strokeElement;
	var fillElement = document.createElement("v:fill");
	domElement.appendChild(fillElement);
	domElement.fillElement = fillElement;

	domElement.rxy = 0;
	domElement.arcSize = 0;

	domElement.applyGradient = function( gradient ) {
		if ( gradient.type == "LinearGradient" ) {
			this.fillcolor = gradient.startColor;
			var fill = document.createElement( "v:fill" );
			fill.type = "gradient";
			fill.color2 = gradient.endColor;
			fill.angle = gradient.angle;
			this.appendChild(fill);
		}
	}

	domElement.applyLinGradient = function( linGradient ) {
		var stop1 = linGradient.stops[0];
		var stop2 = linGradient.stops[linGradient.stops.length-1];
		this.fillcolor = stop1.stopColor;
		var fill = document.createElement( "v:fill" );
		fill.type = "gradient";
		fill.color2 = stop2.stopColor;

		if( linGradient.y1 == 0 ) {
			var rads = Math.atan((linGradient.x2-linGradient.x1)/linGradient.y2);
			var degs = rads * (180/Math.PI);
			fill.angle = (degs + 180) % 360;
		} else if( linGradient.y1 > 0 ) {
			var rads = Math.atan((linGradient.y2-linGradient.y1)/linGradient.x2);
			var degs = rads * (180/Math.PI);
			fill.angle = (degs + 180) % 360;
		}
		this.appendChild(fill);
	}

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "x" ) {
			this.style.left = parseInt(value) + 'px';
			return;
		} else if ( key == "y" ) {
			this.style.top = parseInt(value) + 'px';
			return;
		} else if ( key == "stroke" ) {
			value = color2hex(value);
			if(value==''){
				value = "none";
			}
			
			if(value.toLowerCase()=='none'){
				this.strokeElement.on = false;
			}else{
				this.strokeElement.on = true;
			}
			this.strokecolor = value;
			return;
		} else if ( key == "stroke-width" ) {
			this.strokeweight = parseFloat(value)/1.2 + "pt";
			return;
		} else if ( key == "fill" ) {
			if( value.substring(0,3) == "url" ) {
				//get id
				var gradId = value.substring(5,value.length-1);
				this.applyLinGradient(linearGradients[gradId]);
			} else {
				value = color2hex(value);
				if(value==''){
					value = "black";
				}
				if(value.toLowerCase()=='none'){
					this.fillElement.on = false;
				}else{
					this.fillElement.on = true;
				}
				this.fillcolor = value;
			}
			return;
		} else if ( key == "width" || key == "height" || key == "rx" || key == "ry") {
			if( key == "width" ) {
				this.style.width = parseInt(value) + 'px';
			} else if ( key == "height" ) {
				this.style.height = parseInt(value) + 'px';
			} else if ( key == "rx" || key == "ry" ) {
				if( parseInt(value) ){
					this.rxy = parseInt(value);
				}
			}
			/* compute the arc ratio */
			try {	// do a try - catch here because this was crashing in some cases for no reason
				// apparently it crashes here because arcSize can't be modified while the element is appended to the document
				if( this.rxy != 0  ){
					var dim = parseInt(this.style.width);
					var dimy = parseInt(this.style.height);
					if( !dim ){
						dim = 0;
					}
					if( !dimy ){
						dimy = 0;
					}
					if( dimy < dim ){
						dim = dimy;
					}
					if(dim==0) {
						this.arcSize = 0;
					}else{
						this.arcSize = this.rxy/dim;
					}
				} else {
					this.arcSize = 0;
				}
			} catch (e) { 
				//alert(e.name);
				//alert(e.message);
				//this.removeAttribute('arcsize');
				//this.arcsize = '0%';
			}
			return;
		} else if ( key == "opacity" ) {
			this.setOpacity = parseFloat(value);
			if(this.setOpacity!=1){
				this.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+(this.setOpacity*100)+')';
			} else {
				// clear any old filters, leaving a filter when it's not needed messes things up
				this.style.filter='';
			}
			return;
		} else if ( key == "fill-opacity" ) {
			if(this.fillElement.parentNode!=this){
				var foundFillElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='fill'){
						this.fillElement = this.childNodes[i];
						foundFillElement = true;
						break;
					}
				}
				if(!foundFillElement){
					var fillElement = document.createElement("v:fill");
					this.appendChild(fillElement);
					this.fillElement = fillElement;
				}
			}

			this.fillElement.setAttribute('opacity', parseFloat(value));
			return;
		} else if ( key == "stroke-opacity" ) {
			if(this.strokeElement.parentNode!=this){
				var foundStrokeElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='stroke'){
						this.strokeElement = this.childNodes[i];
						foundStrokeElement = true;
						break;
					}
				}
				if(!foundStrokeElement){
					var strokeElement = document.createElement("v:stroke");
					this.appendChild(strokeElement);
					this.strokeElement = strokeElement;
				}
			}
		
			this.strokeElement.setAttribute('opacity', parseFloat(value));
			return;
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'stroke' || key == 'stroke-width' || key == 'fill' || key == 'opacity' || key == 'fill-opacity' || key == 'stroke-opacity' ) {
					this.setAttribute(key,value);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText);
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {

		if ( key == "x" ) {
			var x = parseInt(this.style.left) ?	parseInt(this.style.left) + 'px' : 0 + 'px';
			return x;
		} else if ( key == "y" ) {
			var y = parseInt(this.style.top) ?	parseInt(this.style.top) + 'px' : 0 + 'px';
			return y;
		} else if ( key == "stroke" ) {
			return this.strokecolor;
		} else if ( key == "stroke-width" ) {
			return parseFloat( this.strokeweight ) * 1.2 + 'px';
		} else if ( key == "fill" ) {
			return this.fillcolor;
		} else if ( key == "opacity" ) {
			return this.setOpacity;
		} else if ( key == "width" ) {
			return parseInt( this.style.width );
		} else if ( key == "height" ) {
			return parseInt( this.style.height );
		} else if ( key == "style" ) {
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

var createVMLLine = function() {
	var domElement = document.createElement("v:line");

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "x1" ) {
			this.x1 = value;
			this.y1 = this.y1 ? this.y1 : 0;
			this.from = this.x1 + ' ' + this.y1;
			return;
		} else if ( key == "y1" ) {
			this.y1 = value;
			this.x1 = this.x1 ? this.x1 : 0;
			this.from = this.x1 + ' ' + this.y1;
			return;
		} else if ( key == "x2" ) {
			this.x2 = value;
			this.y2 = this.y2 ? this.y2 : 0;
			this.to = this.x2 + ' ' + this.y2;
			return;
		} else if ( key == "y2" ) {
			this.y2 = value;
			this.x2 = this.x2 ? this.x2 : 0;
			this.to = this.x2 + ' ' + this.y2;
			return;
		} else if ( key == "stroke" ) {
			value = color2hex(value);
			this.strokecolor = value;
			return;
		} else if ( key == "stroke-width" ) {
			this.strokeweight = parseFloat(value)/1.2 + "pt";
			return;
		} else if ( key == "fill" ) {
			value = color2hex(value);
			this.fillcolor = value;
			return;
		} else if ( key == "opacity" ) {
			this.setOpacity = parseFloat(value);
			if(this.setOpacity!=1){
				this.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+(this.setOpacity*100)+')';
			} else {
				// clear any old filters, leaving a filter when it's not needed messes things up
				this.style.filter='';
			}
			return;
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'stroke' || key == 'stroke-width' || key == 'fill' || key == 'opacity' ) {
					this.setAttribute(key,value);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText);
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {

		if ( key == "x1" ) {
			if ( !this.x1 ) { return 0; }
			return x1;
		} else if ( key == "y1" ) {
			if ( !this.y1 ) { return 0; }
			return y1;
		} else if ( key == "x2" ) {
			if ( !this.x2 ) { return 0; }
			return x2;
		} else if ( key == "y2" ) {
			if ( !this.y2 ) { return 0; }
			return y2;
		} else if ( key == "stroke" ) {
			return this.strokecolor;
		} else if ( key == "stroke-width" ) {
			return parseFloat( this.strokeweight ) * 1.2 + 'px';
		} else if ( key == "fill" ) {
			return this.fillcolor;
		} else if ( key == "opacity" ) {
			return this.setOpacity;
		} else if ( key == "width" ) {
			return parseInt( this.style.width );
		} else if ( key == "height" ) {
			return parseInt( this.style.height );
		} else if ( key == "style" ) {
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

var createVMLPath = function() {

	var domElement = document.createElement("v:shape");
	var strokeElement = document.createElement("v:stroke");
	domElement.appendChild(strokeElement);
	domElement.strokeElement = strokeElement;
	var fillElement = document.createElement("v:fill");
	domElement.appendChild(fillElement);
	domElement.fillElement = fillElement;

	domElement.attribStrokecolor = '';
	domElement.styleStrokecolor = '';
	domElement.classStrokecolor = '';
	domElement.parentStrokecolor = '';

	domElement.attribStrokeweight = '';
	domElement.styleStrokeweight = '';
	domElement.classStrokeweight = '';
	domElement.parentStrokeweight = '';

	domElement.attribStrokedash = '';
	domElement.styleStrokedash = '';
	domElement.classStrokedash = '';
	domElement.parentStrokedash = '';

	domElement.attribFillcolor = '';
	domElement.styleFillcolor = '';
	domElement.classFillcolor = '';
	domElement.parentFillcolor = '';

	domElement.attribOpacity = '';
	domElement.styleOpacity = '';
	domElement.classOpacity = '';
	domElement.parentOpacity = '';

	domElement['attribfill-opacity'] = '';
	domElement['stylefill-opacity'] = '';
	domElement['classfill-opacity'] = '';
	domElement['parentfill-opacity'] = '';

	domElement.style.width = '1';
	domElement.style.height = '1';
	domElement.coordsize = '100, 100'; // why use crazy 21600 sizes here? Use 100 to help compensate for lack of decimals - multiply all points by this number later...
	domElement.style.position = "absolute";
	domElement.x = '0';
	domElement.y = '0';
	domElement.strokeweight = (Math.round((1/1.333)*100)/100).toString();;
	domElement.strokecolor = 'black';
	domElement.fillcolor = 'black';
	domElement.setStyle = '';

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "d" ) {
			// sometimes the coordsize becomes undefined - why?  after cloneNode?
			if(typeof(this.coordsize)=="undefined"){ this.coordsize = '100, 100'; }

			// - SVG -
			// args: http://www.w3schools.com/svg/svg_path.asp

			// - VML -
			// args: m l x e v?

			// path attribute "d" needs to be able to handle at least:  m l a q t M L
			// m = t, l = r, a = ?, q = v, t = v (eventually), M = m, L = l

			this.origPath = value;
			 // make sure that any negative values have a space in front of them (helps with parsing individual points)
			value = value.replace(/[\-+]/g,' -');

			value = value.replace(/q([0-9.\-\s,]*)t/g,relQuadBShort); // change the shorthand 't' curves to 'q'
			value = value.replace(/q([0-9.\-\s,]*)/g,relQuadB); // change quadratic bezier curves to cubic 'v'

			value = value.replace(/c/g,'v');
			value = value.replace(/z/g,'x');
			value = value.replace(/l/g,'r');
			value = value.replace(/L/g,'l');
			value = value.replace(/m/g,'t');
			value = value.replace(/M/g,'m');
			value = value.replace(/([0-9.\-+]+)/g,doRounding); // VML does not like decimal places, so multiply by 100 and round off.

			this.path = value;
			return;

			var pathCommands = value.match( /([MLHVCSQTAZ].*?)(?=[MLHVCSQTAZ]|$)/gi );

			var newPath = "";

			for( var i=0; i<pathCommands.length; i++ ) {
				var command = pathCommands[i].substring(0,1);
				var params = pathCommands[i].substring(1,pathCommands[i].length);
				switch( command ) {
					case "M": // moveTo absolute
						command = 'm';
						break;

					case "A": // arc absolute:
					// SVG: rx ry x-axis-rotation large-arc-flag sweep-flag x y
					// VML: center (x,y) size(w,h) start-angle, end-angle

var command = "ae";
						var args = params.split(/[, ]+/);
						args[0] = parseInt(args[0]);
						args[1] = parseInt(args[1]);

						args[2] = parseInt(args[2]);
						args[3] = parseInt(args[3]);

						args[4] = parseInt(args[4]);
						args[5] = parseInt(args[5]);
//params = "2250 1590 791 791 -3538944 9437184";
						params = args[4] + " " + args[5] + " " + args[2]*2 + " " + args[3]*2 + " 0 360";

//alert( command + params );
						break;

					case "l": // lineTo relative
						command = 'r';
						break;

					default:
				}
				newPath += command + params;
			}

			this.path = newPath;
			return;
		} else if ( key == "transform" ) {
			setTransformation(this,value);
		} else if ( key == "stroke" ) {
			value = color2hex(value);

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+'Strokecolor'] = value;
			value = ((this.styleStrokecolor!='')?this.styleStrokecolor:((this.classStrokecolor!='')?this.classStrokecolor:((this.attribStrokecolor!='')?this.attribStrokecolor:((this.parentStrokecolor!='')?this.parentStrokecolor:''))));
			if(value==''){
				value = "black";
			}

			if(value.toLowerCase()=='none'){
				this.strokeElement.on = false;
			} else {
				this.strokeElement.on = true;
			}
			this.strokecolor = value;
			this.style.stroke = value;

			return;
		} else if ( key == "stroke-width" ) {
			//this.strokeweight = parseFloat(value)/1.2 + "pt";

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+'Strokeweight'] = value;
			value = ((this.styleStrokeweight!='')?this.styleStrokeweight:((this.classStrokeweight!='')?this.classStrokeweight:((this.attribStrokeweight!='')?this.attribStrokeweight:((this.parentStrokeweight!='')?this.parentStrokeweight:''))));

			if(value==''){
				value = "1px";
			}
			this.strokeweight = (Math.round((parseFloat(value)/1.333)*100)/100).toString();
			this.style['stroke-width'] = parseFloat(value);

			return;
		} else if ( key == "stroke-dasharray" ) {

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+'Strokedash'] = value;
			value = ((this.styleStrokedash!='')?this.styleStrokedash:((this.classStrokedash!='')?this.classStrokedash:((this.attribStrokedash!='')?this.attribStrokedash:((this.parentStrokedash!='')?this.parentStrokedash:''))));
			
			if(value==''){
				value = "1";
			}

			this.style['stroke-dasharray'] = value;

			/*
			value = value.split(/[,\s]+/g);
			for(var x=0;x<value.length;x++){
				value[x] = (parseFloat(value[x]) / (Math.round((parseFloat(this.strokeweight)*1.333)*100)/100));
			}
			value = value.join(' ');
			*/
			
			// the dashstyle doesn't work very well, so we will use the built in names
			value = value.split(/[,\s]+/g);
			var minVal = parseFloat(value[0]);
			for(var x=1;x<value.length;x++){
				minVal = Math.min(minVal, parseFloat(value[x]));
			} if (minVal < 1) { minVal = 1; }
			
			if (value.length >= 6) {
				value = "longdashdotdot";
			} else if (value.length >= 4) {
				value = (1*value[0] >= 2*value[1]) ? "longdashdot" : "dashdot";
			} else if (value.length >= 2) {
				if (1*value[0] >= 2*value[1]) {
					value = "longdash";
				} else {
					value = (value[0]/minVal == 1 || value[1]/minVal == 1) ? "dot" : "dash";
				}
			} else {
				value = "solid";
			}

			this.strokeElement.dashstyle = value;

			return;
		} else if ( key == "fill" ) {
			value = color2hex(value);
			//this.fillcolor = value;

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+'Fillcolor'] = value;
			value = ((this.styleFillcolor!='')?this.styleFillcolor:((this.classFillcolor!='')?this.classFillcolor:((this.attribFillcolor!='')?this.attribFillcolor:((this.parentFillcolor!='')?this.parentFillcolor:''))));
			if(value==''){
				value = "black";
			}
			
			if(value.toLowerCase()=='none'){
				this.fillElement.on = false;
			} else {
				this.fillElement.on = true;
			}
			this.fillcolor = value;
			this.style.fill = value;

			return;
		} else if ( key == "opacity" ) {
			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+'Opacity'] = value;
			value = ((this.styleOpacity!='')?this.styleOpacity:((this.classOpacity!='')?this.classOpacity:((this.attribOpacity!='')?this.attribOpacity:((this.parentOpacity!='')?this.parentOpacity:''))));

			if(value==''){
				value = "1";
			}
			this.setOpacity = parseFloat(value);
			this.strokeElement.setAttribute(key,value);
			this.fillElement.setAttribute(key,value);
			this.style.opacity = parseFloat(value);

			return;
		} else if ( key == "fill-opacity" ) {
			if(this.fillElement.parentNode!=this){
				var foundFillElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='fill'){
						this.fillElement = this.childNodes[i];
						foundFillElement = true;
						break;
					}
				}
				if(!foundFillElement){
					var fillElement = document.createElement("v:fill");
					this.appendChild(fillElement);
					this.fillElement = fillElement;
				}
			}

			var level = 'attrib';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			this[level+key] = value;
			value = ((this['style'+key]!='')?this['style'+key]:((this['class'+key]!='')?this['class'+key]:((this['attrib'+key]!='')?this['attrib'+key]:((this['parent'+key]!='')?this['parent'+key]:''))));
			if(value==''){
				value = "1";
			}
			this.fillElement.setAttribute('opacity', parseFloat(value));
			this.style['fill-opacity'] = parseFloat(value);
			return;
		} else if ( key == "stroke-opacity" ) {
			if(this.strokeElement.parentNode!=this){
				var foundStrokeElement = false;
				for( var i=0; i<this.childNodes.length; i++ ){
					if(this.childNodes[i].tagName.toLowerCase()=='stroke'){
						this.strokeElement = this.childNodes[i];
						foundStrokeElement = true;
						break;
					}
				}
				if(!foundStrokeElement){
					var strokeElement = document.createElement("v:stroke");
					this.appendChild(strokeElement);
					this.strokeElement = strokeElement;
				}
			}
			if(value==''){
				value = "1";
			}
		
			this.strokeElement.setAttribute('opacity', parseFloat(value));
			this.style['stroke-opacity'] = parseFloat(value);
			return;
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			var level = 'style';
			if(this.setAttribute.arguments.length>2){
				var level = this.setAttribute.arguments[2];
			}
			if(level=='style'){
				this.setStyle = value;
			}
			
			value = " "+value;
			
			if(value.search(/[; ]stroke\s*:/i)==-1){ 		this.setAttribute("stroke","",level); }
			if(value.search(/[; ]stroke-width\s*:/i)==-1){	 	this.setAttribute("stroke-width","",level); }
			if(value.search(/[; ]stroke-dasharray\s*:/i)==-1){ 	this.setAttribute("stroke-dasharray","",level); }
			if(value.search(/[; ]fill\s*:/i)==-1){ 			this.setAttribute("fill","",level); }
			if(value.search(/[; ]opacity\s*:/i)==-1){ 		this.setAttribute("opacity","",level); }
			if(value.search(/[; ]fill-opacity\s*:/i)==-1){ 		this.setAttribute("fill-opacity","",level); }
			if(value.search(/[; ]stroke-opacity\s*:/i)==-1){ 	this.setAttribute("stroke-opacity","",level); }
			if(value.search(/[; ]visibility\s*:/)==-1){ 		this.style.visibility = ""; }
			
			
			//if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'stroke' || key == 'stroke-width' || key == 'stroke-dasharray' || key == 'fill' || key == 'opacity' || key == 'fill-opacity' || key == 'stroke-opacity' ) {
					this.setAttribute(key,value,level);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText,'class');
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {
		key = key.toLowerCase();
		if ( key == "d" ) {
			return this.origPath;
			return;
		} else if ( key == "transform" ) {
			removeTransformation(this);
		} else if ( key == "stroke" ) {
			return this.strokecolor;
			return;
		} else if ( key == "stroke-width" ) {
			return (Math.round((parseFloat(this.strokeweight)*1.333)*100)/100) + 'px';
			return;
		} else if ( key == "fill" ) {
			return this.fillcolor;
		} else if ( key == "opacity" ) {
			return this.setOpacity;
		} else if ( key == "style" ) {
			return this.setStyle;
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}

	return domElement;
};

function doRounding(str,match)
{	if(isNaN(parseFloat(match)) == false){
		return Math.round(match*100);
	}
}
function relQuadB(str,match){
	// taken from excanvas who "lifted" it from http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes#Firefox_1.5_quadraticCurveTo.28.29_bug_workaround
	var matchP = match.split(/[, ]+/);
	var aCPx = matchP[0];
	var aCPy = matchP[1];
	var aX = matchP[2];
	var aY = matchP[3];

	var cp1x = 2.0 / 3.0 * (aCPx);
	var cp1y = 2.0 / 3.0 * (aCPy);
	var cp2x = cp1x + (aX) / 3.0;
	var cp2y = cp1y + (aY) / 3.0;
	var returnVal= 'v'+cp1x+','+cp1y+' '+cp2x+','+cp2y+' '+aX+','+aY;
	return returnVal;
}
function relQuadBShort(str,match){
	// we need to calculate the reflection of the previous control point relative to the current point
	// this lets us change it from a shorthand quadradic bezier to a complete one
	matchP1 = match.split(/[, ]+/);
	if(matchP1.length==4){
		var aCPx = matchP1[2]-matchP1[0];
		var aCPy = matchP1[3]-matchP1[1];
	}else{
		var aCPx = 0;
		var aCPy = 0;
	}

	var returnVal= 'q'+match+'q'+aCPx+','+aCPy+' ';
	return returnVal;
}

var deg2radians = Math.PI * 2 / 360;
function setTransformation(oObj, transformText)
{
	// get the various parts of supported transformations
	var rotate = transformText.match(/rotate\s*\([^)]*\)/gi);
	var scale = transformText.match(/scale\s*\([^)]*\)/gi);
	var translate = transformText.match(/translate\s*\([^)]*\)/gi);
	
	// put in default values if they were not found, otherwise parse the needed values
	if (rotate === null) {
		rotate = 0;
	} else {
		rotate = parseFloat(rotate[0].replace(/rotate\s*\(/i,'').replace(/\)/,''));
		if (isNaN(rotate)) { rotate = 0; }
	}

	if (scale === null) {
		scale = '1';
	} else {
		scale = parseFloat(scale[0].replace(/scale\s*\(/i,'').replace(/\)/,''));
		if (isNaN(scale)) { scale = 1; }
	}

	if (translate === null) {
		translate[0] = 0;
		translate[0] = 1;
	} else {
		translate = translate[0].replace(/translate\s*\(/i,'').replace(/\)/,'').split(/,/g,2);
		translate[0] = parseInt(translate[0]);
		translate[1] = parseInt(translate[1]);
		if (isNaN(translate[0])) { translate[0] = 0; }
		if (isNaN(translate[1])) { translate[1] = 0; }
	}
	//alert(rotate+', '+scale+', '+translate);
	
	// adjust for translate
	oObj.style.left = parseInt(oObj.x) + (translate[0]);
	oObj.style.top = parseInt(oObj.y) + (translate[1]);
	
	//alert(rotate+', '+scale+', '+translate);

	// get any currently applied filters
	var currFilters = oObj.style.filter;

	// remove the Matrix filter, if found
	currFilters = currFilters.replace(/progid:DXImageTransform\.Microsoft\.Matrix\s*\([^)]*\)/gi,'');

	if (rotate!==0) {
		// do the calculations we need,
		var rad = rotate * deg2radians;
		var costheta = Math.cos(rad);
		var sintheta = Math.sin(rad);

		// add the Matrix filter, adjusting for rotate and scale
		currFilters += 'progid:DXImageTransform.Microsoft.Matrix( sizingMethod="auto expand", M11='+(costheta)+
			', M12='+((-sintheta))+
			', M21='+(sintheta)+
			', M22='+(costheta)+
			' )';
	}
	// apply the filter
	oObj.style.filter = currFilters;
	oObj.coordsize = ''+Math.round(100/scale)+', '+Math.round(100/scale);

	//alert(rotate+', '+scale+', '+translate);
}
function removeTransformation(oObj, transformText)
{
	// get any currently applied filters
	var currFilters = oObj.style.filter;

	// remove the Matrix filter, if found
	currFilters = currFilters.replace(/progid:DXImageTransform\.Microsoft\.Matrix\s*\([^)]*\)/gi,'');

	// apply the remaining filters
	oObj.style.filter = currFilters;

	// reset pos to 0adjust for translate
	oObj.style.left = parseInt(oObj.x);
	oObj.style.top = parseInt(oObj.y);

	oObj.coordsize = '100, 100';
}

var createVMLLinearGradient = function(){
	return new LinGradient();
};

var createVMLStop = function() {
	var myStop = new Object();

	myStop.setAttribute = function( key, value ) {
		if( key == 'offset' ) {
			this.offset = value;
		} else if( key == 'stop-color' ) {
			this.stopColor = value;
		}
	}

	return myStop;
};

var createVMLDefs = function() {
	var myDef = new Object();
	myDef = document.createElement("defs");
	myDef.appendChild = function(child){};
	return myDef;
}

var createVMLImage = function() {
	//var domElement = document.createElement("v:image");
	
	// consider changing to an HTML image (or similar) since the VML get fuzzy edges when enlarged - dragging an issue
	var domElement = document.createElement("div");
	domElement.style.position = "absolute";
	var imgElement = document.createElement("img");
	imgElement.setAttributeOrig = imgElement.setAttribute;
	imgElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "cursor" ) {
			this.style.cursor = value;
		} else {
			this.setAttributeOrig( key, value );
		}
	}
	domElement.imgElement = imgElement;
	domElement.imgElement.border = 0;
	
	domElement.setOpacity = 1;
	domElement.setVisibility = "";

	domElement.imageLoadVisibility = function () {
		if(this.isLoaded){
			this.style.visibility = this.setVisibility;
		}
	}
	domElement.isLoaded = true;


	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		if(this.imgElement.parentNode!=this){
			var foundImgElement = false;
			for( var i=0; i<this.childNodes.length; i++ ){
				if(this.childNodes[i].tagName.toLowerCase()=='img'){
					this.imgElement = this.childNodes[i];
					foundImgElement = true;
					break;
				}
			}
			if(!foundImgElement){
				var imgElement = document.createElement("img");
				imgElement.setAttributeOrig = imgElement.setAttribute;
				imgElement.setAttribute = function( key, value ) {
					key = key.toLowerCase();
					if ( key == "cursor" ) {
						this.style.cursor = value;
					} else {
						this.setAttributeOrig( key, value );
					}
				}
				this.appendChild(imgElement);
				this.imgElement = imgElement;
				this.imgElement.border = 0;
			}
		}

		key = key.toLowerCase();
		if ( key == "x" ) {
			this.style.left = parseInt(value) + 'px';
			return;
		} else if ( key == "y" ) {
			this.style.top = parseInt(value) + 'px';
			return;
		} else if ( key == "width" ) {
			this.style.width = parseInt(value) + 'px';
			this.imgElement.style.width = parseInt(value) + 'px';
			return;
		} else if ( key == "height" ) {
			this.style.height = parseInt(value) + 'px';
			this.imgElement.style.height = parseInt(value) + 'px';
			return;
		} else if ( key == "preserveaspectratio" ) {
			// at some point, add support for the different aspect ratio options
			return;
		} else if ( key == "opacity" ) {
			this.setOpacity = parseFloat(value);
			if(this.setOpacity!=1){
				this.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+(this.setOpacity*100)+')';
				// basicImage does the same thing.
				//this.style.filter='progid:DXImageTransform.Microsoft.BasicImage(opacity='+(this.setOpacity)+')';
			} else {
				// clear any old filters, leaving a filter when it's not needed messes things up
				this.style.filter='';
			}
			return;
		} else if ( key == "cursor" ) {
			this.style.cursor = value;
		} else if ( key == "style" ) {
			if(value.replace(/^\s*|\s*$/g,"")==""){ this.setVisibility = ""; this.imageLoadVisibility(); }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'opacity' ) {
					this.setAttribute(key,value);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.setVisibility = value;
					this.imageLoadVisibility();
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText);
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.setAttributeNSOrig = domElement.setAttributeNS;
	domElement.setAttributeNS = function( ns, key, value ) {
		if(this.imgElement.parentNode!=this){
			var foundImgElement = false;
			for( var i=0; i<this.childNodes.length; i++ ){
				if(this.childNodes[i].tagName.toLowerCase()=='img'){
					this.imgElement = this.childNodes[i];
					foundImgElement = true;
					break;
				}
			}
			if(!foundImgElement){
				var imgElement = document.createElement("img");
				imgElement.setAttributeOrig = imgElement.setAttribute;
				imgElement.setAttribute = function( key, value ) {
					key = key.toLowerCase();
					if ( key == "cursor" ) {
						this.style.cursor = value;
					} else {
						this.setAttributeOrig( key, value );
					}
				}
				this.appendChild(imgElement);
				this.imgElement = imgElement;
				this.imgElement.border = 0;
			}
		}

		key = key.toLowerCase();
		if ( key == "xlink:href" || key == "href") {
			this.src = value;
			this.style.visibility = "hidden";
			this.isLoaded = false;
			this.imgElement.style.filter = '';

			this.imgElement.onload = function () {
				this.parentNode.isLoaded = true;
				this.parentNode.imageLoadVisibility();
			}

			// test for png
			if (/\.png$/i.test(value) || /FORMAT=image\/png/i.test(value) || /FORMAT=png/i.test(value)) {
				// if it's a png, we need to load it in the alphaloader, but not until after the initial load (no more hangs)

				this.imgElement.src = 'spacer.gif'; // set blank image (so the alpha loader does not put the image on top of itself)
				
				// create a second temp image for loading the PNG in the background
				tmpImg = document.createElement("img");
				tmpImg.setAttributeOrig = tmpImg.setAttribute;
				tmpImg.setAttribute = function( key, value ) {
					key = key.toLowerCase();
					if ( key == "cursor" ) {
						this.style.cursor = value;
					} else {
						this.setAttributeOrig( key, value );
					}
				}
				this.appendChild(tmpImg);
				tmpImg.onload = function () {
					// set filter
					this.parentNode.imgElement.style.filter = " progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.parentNode.src + "',sizingMethod='scale') ";
					
					this.parentNode.removeChild(this);
					this.onload = null;
					this.src = null;
				}
				tmpImg.src = value; 
			} else {
				this.imgElement.src = value;
			}
		} else {
			this.setAttributeNSOrig( ns, key, value );
		}
	}

	domElement.removeAttributeNSOrig = domElement.setAttributeNS;
	domElement.removeAttributeNS = function( ns, key ) {
		key = key.toLowerCase();
		if ( key == "xlink:href" || key == "href") {
			this.src = '';
			this.imgElement.src = '';
			this.imgElement.style.filter = '';
		} else {
			this.removeAttributeNSOrig( ns, key );
		}
	}

	domElement.getAttributeNSOrig = domElement.setAttributeNS;
	domElement.getAttributeNS = function( ns, key ) {
		key = key.toLowerCase();
		if ( key == "xlink:href" || key == "href") {
			return this.src;
		} else {
			this.getAttributeNSOrig( ns, key );
		}
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {
		if ( key == "width" ) {
			return parseInt( this.style.width );
		} else if ( key == "height" ) {
			return parseInt( this.style.height );
		} else if ( key == "x" ) {
			return parseInt( this.style.left );
		} else if ( key == "y" ) {
			return parseInt( this.style.top );
		} else if ( key == "opacity" ) {
			return this.setOpacity;
		} else if ( key == "style" ) {
			if ( this.setVisibility ) {
				return "visibility:"+this.setVisibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}


	return domElement;
};

var createHTMLa = function() {
	var domElement = document.createElement("a");

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "target" ) {
			this.target = value;
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}

	domElement.setAttributeNSOrig = domElement.setAttributeNS;
	domElement.setAttributeNS = function( ns, key, value ) {
		key = key.toLowerCase();
		if ( key == "xlink:href" || key == "href") {
			this.href = value;
		} else {
			this.setAttributeNSOrig( ns, key, value );
		}
	}

	return domElement;
};

var createVMLTextbox = function() {
	var domElement = document.createElement("v:textbox");
	domElement.x = 0;
	domElement.y = 0;
	domElement.anch = 'l';
	domElement.fontSize = 12;
	domElement.style.fontSize = '12px';
	domElement.style.whiteSpace = 'nowrap';

	domElement.setAttributeOrig = domElement.setAttribute;
	domElement.setAttribute = function( key, value ) {
		key = key.toLowerCase();
		if ( key == "x" ) {
			this.x = parseInt(value);
			if(this.anch=='m'){
				this.style.left = (this.x-(this.scrollWidth/2)) + 'px';
			}else if(this.anch=='r'){
				this.style.left = (this.x-this.scrollWidth) + 'px';
			}else{
				this.style.left = this.x + 'px';
			}
			return;
		} else if ( key == "y" ) {
			this.y = parseInt(value);
			this.style.top = (this.y - this.fontSize) + 'px';
			return;
		} else if ( key == "fill" ) {
			value = color2hex(value);
			this.style.color = value;
			return;
		} else if ( key == "font-family" ) {
			this.style.fontFamily = value;
			return;
		} else if ( key == "font-size" ) {
			this.fontSize = parseInt(value);
			this.style.fontSize = this.fontSize + 'px';
			this.style.top = (this.y - this.fontSize) + 'px';
			return;
		} else if ( key == "font-weight" ) {
			this.style.fontWeight = value;
			return;
		} else if ( key == "text-anchor" ) {
			if(value.toLowerCase()=="middle"){
				this.anch = 'm';
			}else if(value.toLowerCase()=="right"){
				this.anch = 'r';
			}else{//left
				this.anch = 'l';
			}
			
			// note that scrollWidth will only return the proper value AFTER the object is appended to the page
			if(this.anch=='m'){
				this.style.left = (this.x-(this.scrollWidth/2)) + 'px';
			}else if(this.anch=='r'){
				this.style.left = (this.x-this.scrollWidth) + 'px';
			}else{
				this.style.left = this.x + 'px';
			}
			return;
		} else if ( key == "opacity" ) {
			this.setOpacity = parseFloat(value);
			if(this.setOpacity!=1){
				this.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+(this.setOpacity*100)+')';
			} else {
				// clear any old filters, leaving a filter when it's not needed messes things up
				this.style.filter='';
			}
			return;
		} else if ( key == "style" ) {
			if(value.replace(/^\s*|\s*$/g,"")==""){ this.style.visibility = ""; }
			var styles = value.split(/;/);
			for(var x=0;x<styles.length;x++){
				currStyle = styles[x].split(/:/);
				key = currStyle[0].replace(/^\s*|\s*$/g,"").toLowerCase();
				value = ((typeof(currStyle[1])=='undefined')? '' : currStyle[1].replace(/^\s*|\s*$/g,"") );
				if ( key == 'fill' || key == 'opacity' || key == 'font-family' || key == 'font-size' || key == 'font-weight' || key == 'text-anchor' ) {
					this.setAttribute(key,value);
				} else if ( key == "cursor" ) {
					this.style.cursor = value;
				} else if ( key == "visibility" ) {
					this.style.visibility = value;
				}
			}
			return;
		} else if ( key == "class" ) {
			this.setAttributeOrig( key, value );
			for (var i=0;i<document.styleSheets.length;i++){
				for (var j=0;j<document.styleSheets[i].rules.length;j++) {
					if (document.styleSheets[i].rules[j].selectorText == '.'+value){
						if(document.styleSheets[i].rules[j].style.cssText!=''){
							this.setAttribute('style',document.styleSheets[i].rules[j].style.cssText);
						}
					}
				}
			}
			return;
		} else if ( key == "onmouseover" ) {
			this.onmouseover = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousedown" ) {
			this.onmousedown = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseout" ) {
			this.onmouseout = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmouseup" ) {
			this.onmouseup = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onmousemove" ) {
			this.onmousemove = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else if ( key == "onclick" ) {
			this.onclick = new Function('var evt=(typeof(evt)!="undefined")?evt:((typeof(event)!="undefined")?event:null); evt.target=(typeof(evt.target)!="undefined")?evt.target:((typeof(evt.srcElement)!="undefined")?evt.srcElement:null);'+value);
		} else {
			this.setAttributeOrig( key, value );
		}
	}
	
	domElement.getComputedTextLength = function( ) {
		return this.scrollWidth;
	}

	domElement.getAttributeOrig = domElement.getAttribute;
	domElement.getAttribute = function( key ) {
		if ( key == "style" ) {
			if ( this.style.visibility ) {
				return "visibility:"+this.style.visibility;
			} else {
				return "";
			}
		} else {
			return this.getAttributeOrig( key );
		}
	}


	return domElement;
};


var LinGradient = function( ) {
	this.init( );
};
LinGradient.prototype = {
	init: function( ) {
		this.stops = new Array();
	},

	setAttribute: function( key, value ) {
		if( key == "id" ){
			this.id = value;
			linearGradients[this.id] = this;
		} else if( key == "x1" ) {
			this.x1 = value.substring(0,value.length-1);
		} else if( key == "y1" ) {
			this.y1 = value.substring(0,value.length-1);
		} else if( key == "x2" ) {
			this.x2 = value.substring(0,value.length-1);
		} else if( key == "y2" ) {
			this.y2 = value.substring(0,value.length-1);
		}
	},

	appendChild: function( stop ) {
		this.stops.push(stop);
	}
}


function color2hex(color) 
{
	// get rid of any spaces
	color = color.replace(/ /g,'').toLowerCase();
	switch (color) {
		case 'aliceblue':
			return '#f0f8ff';
		case 'antiquewhite':
			return '#faebd7';
		case 'aqua':
			return '#00ffff';
		case 'aquamarine':
			return '#7fffd4';
		case 'azure':
			return '#f0ffff';
		case 'beige':
			return '#f5f5dc';
		case 'bisque':
			return '#ffe4c4';
		case 'black':
			return '#000000';
		case 'blanchedalmond':
			return '#ffebcd';
		case 'blue':
			return '#0000ff';
		case 'blueviolet':
			return '#8a2be2';
		case 'brown':
			return '#a52a2a';
		case 'burlywood':
			return '#deb887';
		case 'cadetblue':
			return '#5f9ea0';
		case 'chartreuse':
			return '#7fff00';
		case 'chocolate':
			return '#d2691e';
		case 'coral':
			return '#ff7f50';
		case 'cornflowerblue':
			return '#6495ed';
		case 'cornsilk':
			return '#fff8dc';
		case 'crimson':
			return '#dc143c';
		case 'cyan':
			return '#00ffff';
		case 'darkblue':
			return '#00008b';
		case 'darkcyan':
			return '#008b8b';
		case 'darkgoldenrod':
			return '#b8860b';
		case 'darkgray':
			return '#a9a9a9';
		case 'darkgrey':
			return '#a9a9a9';
		case 'darkgreen':
			return '#006400';
		case 'darkkhaki':
			return '#bdb76b';
		case 'darkmagenta':
			return '#8b008b';
		case 'darkolivegreen':
			return '#556b2f';
		case 'darkorange':
			return '#ff8c00';
		case 'darkorchid':
			return '#9932cc';
		case 'darkred':
			return '#8b0000';
		case 'darksalmon':
			return '#e9967a';
		case 'darkseagreen':
			return '#8fbc8f';
		case 'darkslateblue':
			return '#483d8b';
		case 'darkslategray':
			return '#2f4f4f';
		case 'darkslategrey':
			return '#2f4f4f';
		case 'darkturquoise':
			return '#00ced1';
		case 'darkviolet':
			return '#9400d3';
		case 'deeppink':
			return '#ff1493';
		case 'deepskyblue':
			return '#00bfff';
		case 'dimgray':
			return '#696969';
		case 'dimgrey':
			return '#696969';
		case 'dodgerblue':
			return '#1e90ff';
		case 'firebrick':
			return '#b22222';
		case 'floralwhite':
			return '#fffaf0';
		case 'forestgreen':
			return '#228b22';
		case 'fuchsia':
			return '#ff00ff';
		case 'gainsboro':
			return '#dcdcdc';
		case 'ghostwhite':
			return '#f8f8ff';
		case 'gold':
			return '#ffd700';
		case 'goldenrod':
			return '#daa520';
		case 'gray':
			return '#808080';
		case 'grey':
			return '#808080';
		case 'green':
			return '#008000';
		case 'greenyellow':
			return '#adff2f';
		case 'honeydew':
			return '#f0fff0';
		case 'hotpink':
			return '#ff69b4';
		case 'indianred':
			return '#cd5c5c';
		case 'indigo':
			return '#4b0082';
		case 'ivory':
			return '#fffff0';
		case 'khaki':
			return '#f0e68c';
		case 'lavender':
			return '#e6e6fa';
		case 'lavenderblush':
			return '#fff0f5';
		case 'lawngreen':
			return '#7cfc00';
		case 'lemonchiffon':
			return '#fffacd';
		case 'lightblue':
			return '#add8e6';
		case 'lightcoral':
			return '#f08080';
		case 'lightcyan':
			return '#e0ffff';
		case 'lightgoldenrodyellow':
			return '#fafad2';
		case 'lightgray':
			return '#d3d3d3';
		case 'lightgrey':
			return '#d3d3d3';
		case 'lightgreen':
			return '#90ee90';
		case 'lightpink':
			return '#ffb6c1';
		case 'lightsalmon':
			return '#ffa07a';
		case 'lightseagreen':
			return '#20b2aa';
		case 'lightskyblue':
			return '#87cefa';
		case 'lightslategray':
			return '#778899';
		case 'lightslategrey':
			return '#778899';
		case 'lightsteelblue':
			return '#b0c4de';
		case 'lightyellow':
			return '#ffffe0';
		case 'lime':
			return '#00ff00';
		case 'limegreen':
			return '#32cd32';
		case 'linen':
			return '#faf0e6';
		case 'magenta':
			return '#ff00ff';
		case 'maroon':
			return '#800000';
		case 'mediumaquamarine':
			return '#66cdaa';
		case 'mediumblue':
			return '#0000cd';
		case 'mediumorchid':
			return '#ba55d3';
		case 'mediumpurple':
			return '#9370d8';
		case 'mediumseagreen':
			return '#3cb371';
		case 'mediumslateblue':
			return '#7b68ee';
		case 'mediumspringgreen':
			return '#00fa9a';
		case 'mediumturquoise':
			return '#48d1cc';
		case 'mediumvioletred':
			return '#c71585';
		case 'midnightblue':
			return '#191970';
		case 'mintcream':
			return '#f5fffa';
		case 'mistyrose':
			return '#ffe4e1';
		case 'moccasin':
			return '#ffe4b5';
		case 'navajowhite':
			return '#ffdead';
		case 'navy':
			return '#000080';
		case 'oldlace':
			return '#fdf5e6';
		case 'olive':
			return '#808000';
		case 'olivedrab':
			return '#6b8e23';
		case 'orange':
			return '#ffa500';
		case 'orangered':
			return '#ff4500';
		case 'orchid':
			return '#da70d6';
		case 'palegoldenrod':
			return '#eee8aa';
		case 'palegreen':
			return '#98fb98';
		case 'paleturquoise':
			return '#afeeee';
		case 'palevioletred':
			return '#d87093';
		case 'papayawhip':
			return '#ffefd5';
		case 'peachpuff':
			return '#ffdab9';
		case 'peru':
			return '#cd853f';
		case 'pink':
			return '#ffc0cb';
		case 'plum':
			return '#dda0dd';
		case 'powderblue':
			return '#b0e0e6';
		case 'purple':
			return '#800080';
		case 'red':
			return '#ff0000';
		case 'rosybrown':
			return '#bc8f8f';
		case 'royalblue':
			return '#4169e1';
		case 'saddlebrown':
			return '#8b4513';
		case 'salmon':
			return '#fa8072';
		case 'sandybrown':
			return '#f4a460';
		case 'seagreen':
			return '#2e8b57';
		case 'seashell':
			return '#fff5ee';
		case 'sienna':
			return '#a0522d';
		case 'silver':
			return '#c0c0c0';
		case 'skyblue':
			return '#87ceeb';
		case 'slateblue':
			return '#6a5acd';
		case 'slategray':
			return '#708090';
		case 'slategrey':
			return '#708090';
		case 'snow':
			return '#fffafa';
		case 'springgreen':
			return '#00ff7f';
		case 'steelblue':
			return '#4682b4';
		case 'tan':
			return '#d2b48c';
		case 'teal':
			return '#008080';
		case 'thistle':
			return '#d8bfd8';
		case 'tomato':
			return '#ff6347';
		case 'turquoise':
			return '#40e0d0';
		case 'violet':
			return '#ee82ee';
		case 'wheat':
			return '#f5deb3';
		case 'white':
			return '#ffffff';
		case 'whitesmoke':
			return '#f5f5f5';
		case 'yellow':
			return '#ffff00';
		case 'yellowgreen':
			return '#9acd32';
		case 'none':
			return 'none';
		case '':
			return '';
	}
	// not a supported named color, check some other things
	
	if(color.search(/rgb/)==0){ // if it's an RGB color
		// get rid of RGB()
		color = color.replace(/rgb|\(|\)/g,'');

		// break into 3 parts
		var rgb = color.split(',',3);

		// verify the RGB by trying to parse them to decimal values
		rgb[0] = Math.abs(parseInt(rgb[0]));
		rgb[1] = Math.abs(parseInt(rgb[1]));
		rgb[2] = Math.abs(parseInt(rgb[2]));
		
		// if they are not valid, default to 0
		if (isNaN(rgb[0]) || rgb[0]>255) { rgb[0] = 0; }
		if (isNaN(rgb[1]) || rgb[1]>255) { rgb[1] = 0; }
		if (isNaN(rgb[2]) || rgb[2]>255) { rgb[2] = 0; }
		
		// convert them to hex
		rgb[0] = rgb[0].toString(16);
		rgb[1] = rgb[1].toString(16);
		rgb[2] = rgb[2].toString(16);
		
		// check to make sure these are 2 digix hexes
		if (rgb[0].length == 1) { rgb[0] = '0' + rgb[0]; }
		if (rgb[1].length == 1) { rgb[1] = '0' + rgb[1]; }
		if (rgb[2].length == 1) { rgb[2] = '0' + rgb[2]; }
		
    		// all done, return the value
    		return ('#' + rgb[0] + rgb[1] + rgb[2]).toUpperCase();		
	}else{ // treat it as a hex color
		// strip off any leading #
		if (color.search(/#/)==0) { 
		    color = color.substr(1,6);
		} else if (color.search(/&h/)==0) {
		    color = color.substr(2,7);
		}

		var r;
		var g;
		var b;
		
		// get the RGB hex values
		if (color.length == 3) {
			r = color.substr(0, 1);
			r += r;
			g = color.substr(1, 1);
			g += g;
			b = color.substr(2, 1);
			b += b;
		} else {
			r = color.substr(0, 2);
			g = color.substr(2, 2);
			b = color.substr(4, 2);
		}
		
		// verify the hex by trying to parse them to decimal values
		r = parseInt(r, 16);
		g = parseInt(g, 16);
		b = parseInt(b, 16);
		
		// if they are not valid, default to 0
		if (isNaN(r)) { r = 0; }
		if (isNaN(g)) { g = 0; }
		if (isNaN(b)) { b = 0; }
		
		// convert them back to hex
		r = r.toString(16);
		g = g.toString(16);
		b = b.toString(16);
		
		// check to make sure these are 2 digix hexes
		if (r.length == 1) { r = '0' + r; }
		if (g.length == 1) { g = '0' + g; }
		if (b.length == 1) { b = '0' + b; }
		
    		// all done, return the value
    		return ('#' + r + g + b).toUpperCase();		
	}
}


