function neRoundCorners() {
	// finds all elements in the document that contain the class "rounded".  It then rounds those elements.
	// Other classes assigned to the same element control the rounding function as follows:
	// rounded-notop means don't round the top of the div
	// rounded-nobot means don't rounde the bottom of the div
	// rounded-bigcorners means use a 15 pixel radius instead of the default 10
	// rounded-adjustvpos means set a negative margin on the divs that this code creates so that stuff inside the elements can more fully fill them after rounding
	// this function should be called after the last element that will be rounded
	// if JavaScript is not enabled, the function will not be called, the classes will be ignored, and the elements will be displayed normally
	
	// check browser versions and return if not supported
	if (navigator.appVersion.indexOf("Safari") > -1)
		return;
		
	// find all elements with class "rounded"
	var elementNumber;
	var elements=find_elements_to_round(document.body);
	
	for (elementNumber in elements) {
		// for each element that we're rounding
		var element=elements[elementNumber];

		// default values
		var radius=10;
		var roundTop=true;
		var roundBot=true;
		var adjustVPos=false;
		
		// look through all classnames for this element to see if any default values are overridden
		var classes=element.className.split(" ");
		for (classIndex in classes){
			switch (classes[classIndex]){
				case "rounded-notop":
				roundTop=false;
				break;
				
				case "rounded-nobot":
				roundBot=false;
				break;
				
				case "rounded-bigcorners":
				radius=15;
				break;
				
				case "rounded-adjustvpos":
				adjustVPos=true;
				
				default:
				
			} // end switch
		} // end for all class names of this element
		
		// get color of element and background (either parent element or body)
		elementColor=get_background_color(element);
		parentColor=get_background_color(element.parentNode);
		if (!parentColor)parentColor=get_background_color(document.body);
		
		// create divs for rounding areas
		// There is a top div and a bottom div.  Each covers the area of the element that will be rounded, so each is "radius" pixels high
		newTopDiv=document.createElement("div");
		newBotDiv=document.createElement("div");
		newTopDiv.style.backgroundColor=newBotDiv.style.backgroundColor=parentColor;
		newTopDiv.style.height=newBotDiv.style.height=radius+"px";
newTopDiv.style.display=newBotDiv.style.display="block";
newTopDiv.style.overflow=newBotDiv.style.overflow="hidden";
newTopDiv.style.margin=newBotDiv.style.margin="0px 0px 0px 0px";
newTopDiv.style.padding=newBotDiv.style.padding="0px 0px 0px 0px";

		if (adjustVPos){
			newTopDiv.style.marginBottom=newBotDiv.style.marginTop="-"+radius+"px";
		}
			
		// In these divs, we will create a series of spans that are stripes of element color.
		// The stripes also have a border that implements antialiasing
		// Create one top and one bottom span for each step
		for(i=0;i<radius;i++)
			{
			newTopSpan=document.createElement("span");
			newBotSpan=document.createElement("span");
			newTopSpan.style.display=newBotSpan.style.display="block";
			newTopSpan.style.overflow=newBotSpan.style.overflow="hidden";
			newTopSpan.style.height=newBotSpan.style.height="1px";
			newTopSpan.style.backgroundColor=newBotSpan.style.backgroundColor=elementColor;
			newTopSpan.style.margin=newBotSpan.style.margin="0px 0px 0px 0px";
			newTopSpan.style.fontSize=newBotSpan.style.fontSize="1px";
			newTopSpan.style.lineHeight=newBotSpan.style.lineHeight="1px";
			newTopSpan.style.borderStyle=newBotSpan.style.borderStyle="solid";
newTopSpan.style.padding=newBotSpan.style.padding="0px 0px 0px 0px";
				
			// calculate angle between horizontal and the radius that intersects with the rounding circle at this horizontal line
			angle=Math.asin(i/radius); // angle is arcsin of opposite over hypotenuse
			// calculate the width of the segment using cosine (adjacent over hypotenuse = width over radius)
			segmentWidth=radius-(radius*Math.cos(angle));
			// set the margin for the span to this width
			newTopSpan.style.margin=newBotSpan.style.margin="0 "+Math.round(segmentWidth)+"px 0 "+Math.round(segmentWidth)+"px";
			// calculate and set span border width by checking the difference between this segment width and the previous one
			borderWidth=Math.ceil(radius*Math.cos(Math.asin((i-1)/radius))-radius*Math.cos(angle));
			newTopSpan.style.borderWidth=newBotSpan.style.borderWidth="0 "+borderWidth+"px 0 "+borderWidth+"px";
			// calculate antialiasing color by mixing the element and parent colors based on the rounding error in segmentWidth times one over the borderwidth.
			// the wider the border width, the closer we want to be to the parent color
			newTopSpan.style.borderColor=newBotSpan.style.borderColor= antialias(elementColor,parentColor,(0.5-(Math.round(segmentWidth)-segmentWidth))*(borderWidth?1/borderWidth:1));

			// insert the spans into the DOM.
			if (roundTop){
				// top spans go before any existing child elements
				if (newTopDiv.firstChild){
					newTopDiv.insertBefore(newTopSpan.cloneNode(true),newTopDiv.firstChild);
				}
				else newTopDiv.appendChild(newTopSpan.cloneNode(true));
			}
			if (roundBot){
				// bottom spans go after any existing child elements
				newBotDiv.appendChild(newBotSpan.cloneNode(true));
			}
			// clean up spans
			delete newTopSpan;
			delete newBotSpan;
		} // end creation of spans for each step
		
		// insert the divs into the DOM
		if (roundTop){
			if(element.firstChild){
				// top div goes before any child elements
				element.insertBefore(newTopDiv.cloneNode(true),element.firstChild);
			}
			else element.appendChild(newTopDiv.cloneNode(true));
		} // end if rounding top, insert top div
		if (roundBot){
			// bottom div goes after any child elements
			element.appendChild(newBotDiv.cloneNode(true));
		}
		// clean up divs
		delete newTopDiv;
		delete newBotDiv;
	}  // end for each element to be rounded
} // end function
		
	
function find_elements_to_round(element,elementList,start){
	// find all elements with the "rounded" class by searching iteratively and recursively.  Return a list of the elements
	
  var exp=new RegExp("(^| )(rounded)( |$)");
  if(!start){
  	start=element;
  	elementList=new Array();
  }
  if (element.nodeType==1 && exp.test(element.className)) elementList[elementList.length]=element;
  if (element.hasChildNodes()) elementList=find_elements_to_round(element.firstChild,elementList,start);
  if (element!=start && element.nextSibling) elementList=find_elements_to_round(element.nextSibling,elementList,start);
  return elementList;
}


function get_background_color(element){
	// get the background color for an element
  var value = "";
	if(document.defaultView && document.defaultView.getComputedStyle){
		// non-IE:
    value = document.defaultView.getComputedStyle(element, "").getPropertyValue("background-color");
  }
  else if(element.currentStyle){
  	// IE:
    value = element.currentStyle["backgroundColor"];
  }
  // if transparent or not valid, and there is a parent, try that
  if ((value==null || value=="transparent" || value=="undefined")&& element.parentNode)value=get_background_color(element.parentNode);
  return value;
}


function color_to_array(color)
// return an array of red, green, and blue values from a hex or RGB color
	{
	if(color.substr(0,1)=="#")
		// color is hex (#RRGGBB)
		return new Array(parseInt(color.substr(1,2),16),parseInt(color.substr(3,2),16),parseInt(color.substr(5,2),16));
	else if(color.substr(0,3)=="rgb"){
		// color is rgb (rgb(R,G,B))
		var pos=color.indexOf("(")+1;
		var len=color.indexOf(",")-pos;
		var arr=new Array();
		arr[0]=parseInt(color.substr(pos,len));
		pos=pos+len+1;
		len=color.indexOf(",",pos)-pos;
		arr[1]=parseInt(color.substr(pos,len));
		pos=pos+len+1;
		len=color.indexOf(")")-pos;
		arr[2]=parseInt(color.substr(pos,len));
		return arr;
	}
	else return false;
}

	
function antialias(color1, color2, fraction){
	// mix two colors based on the percentage weight of the second
	var aacolor=new Array();
	var c1array=color_to_array(color1);
	var c2array=color_to_array(color2);
	aacolor[0]=c1array[0]+Math.round(fraction*(c2array[0]-c1array[0]));
	aacolor[1]=c1array[1]+Math.round(fraction*(c2array[1]-c1array[1]));
	aacolor[2]=c1array[2]+Math.round(fraction*(c2array[2]-c1array[2]));
	// assemble an rgb color and return
	return "rgb("+aacolor[0]+","+aacolor[1]+","+aacolor[2]+")";
}
		
