/* ------------------------------------------------------------------------ *
 * SAS Institute, Inc.                                                      
 *                                                                          
 * Copyright (c) 2005 Institute, Inc.  All rights reserved.                 
 *                                                                          
 * Purpose: Contains common javascript functionality meant to be            
 *          reused in order to perform certain functions consistently       
 *          across CDD space.  
 *
 *          Ideally this common functionality should be compatible across
 *          major browsers.                                             
 *                                                                          
 * ------------------------------------------------------------------------ */
 
// Determine Browser
// xOp7 = Opera v7,  xOp5or6= Opera v5 or v6
// xIE = Internet Explorer, xNN4 = Netscape 4
xOp7=false,xOp5or6=false,xIE=false,xNN4=false;
var xUA=navigator.userAgent.toLowerCase();
if(window.opera){
  xOp7=(xUA.indexOf('opera 7')!=-1 || xUA.indexOf('opera/7')!=-1);
  if (!xOp7) xOp5or6=(xUA.indexOf('opera 5')!=-1 || xUA.indexOf('opera/5')!=-1 || xUA.indexOf('opera 6')!=-1 || xUA.indexOf('opera/6')!=-1);
}
else if(document.layers) xNN4=true;
else {xIE=document.all && xUA.indexOf('msie')!=-1 && parseInt(navigator.appVersion)>=4;}


/* ------------------------------------------------------------- *
 *  Get the current style for an element in browser
 *  independant fashion.  IE uses currentStyle while Mozilla
 *  currently uses window.getComputedStyle(...)
 * ------------------------------------------------------------- */
function sas_getCurrentStyle(element, style)
{
	var styleValue="";
	if(element!=null)
	{
		if (document.defaultView && document.defaultView.getComputedStyle)
	    {
	    	styleValue=document.defaultView.getComputedStyle(element,null).getPropertyValue(style);
		}
		else
		{
			if(element.currentStyle)
			{
				styleValue=element.currentStyle[style];
			}
		}
	}
	
	return styleValue;
}


/* ------------------------------------------------------------- *
 * --Begin createXMLHttpRequest--
 *
 *  Attempt to create an xmlhttprequest for communicating
 *  with server
 * ------------------------------------------------------------- */
function sas_createXMLHttpRequest()
{
	var xmlhttp;
	if(xIE)
	{
		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");    // IE
	}
	else
	{
		xmlhttp = new XMLHttpRequest();
	}
	return xmlhttp;
}




/* ------------------------------------------------------------- *
 * --Begin sas_registerEventHandler--
 *
 *  Attempt to register an event listener in cross browser
 *  fashion.
 *
 * Parm: element - object on which to register the handler.
 * Parm: eventType - event type to register this handler for. 
 *                   don't use 'on' prefix as this will be added
 *                   automatically.  'click' rather than 'onclick'.
 * Parm: listener - the function to register as the handler.
 * Parm: capture - specifies whether the handler should capture events.
 *
 * Example Useage...
 *  sas_registerEventHandler(document, 'click', handleClick, false);
 *
 * ------------------------------------------------------------- */
function sas_registerEventHandler ( element, eventType, listener, capture )
{
    if (element != null && eventType!=null && listener!=null) 
    {
      if( element.attachEvent != null) // IE way
      {
        element.attachEvent( "on" + eventType, listener);
      }
      else
      {
        element.addEventListener( eventType, listener, capture );
      }
    }
}

/* ------------------------------------------------------------- *
 * --Begin sas_unRegisterEventHandler--
 *
 *  Attempt to remove an event listener in cross browser
 *  fashion.
 *
 * Parm: element - object on which to unregister event handler
 * Parm: eventType - event type to unregister this handler for. 
 *                   don't use 'on' prefix as this will be added
 *                   automatically.  'click' rather than 'onclick'.
 * Parm: listener - the function to unregister as the handler.
 * Parm: capture - specifies whether the handler being removed 
 *                 captures events.
 *
 * Example Useage...
 *  sas_unRegisterEventHandler(document, 'click', handleClick, false);
 *
 * ------------------------------------------------------------- */
function sas_unRegisterEventHandler ( element, eventType, listener, capture )
{
    if (element != null && eventType!=null && listener!=null) 
    {
      if( element.attachEvent != null) // IE way
      {
        element.detachEvent( "on" + eventType, listener);
      }
      else
      {
        element.removeEventListener( eventType, listener, capture );
      }
    }
}


/* ------------------------------------------------------------- *
 * --Begin sas_autoPosition--
 *
 *  Attempt to automatically do an absolute positioning on an html
 *  element relative to some other element.  Will attempt several
 *  predefined relative positions until it finds one that doesn't
 *  cause the element to be clipped.  If none of the predefined
 *  positions work without clipping then we just dump the element
 *  anywhere.
 *
 * Example Useage...
 *  relativeToElement = document.getElementById("MyImageId");
 *  DivToPosition = document.getELementById("MyPopupMenu");
 *  sas_autoPosition(DivToPosition, relativeToELement);
 *
 * ------------------------------------------------------------- */
function sas_autoPosition(elementToPosition, relativeToElement)
{
	var relativeToCoordinates = new sas_Coordinates(relativeToElement);
	relativeToCoordinates.setRelativeToSharedBreakoutBox(elementToPosition);

	// lets try several positions which we would consider ideal and
	// if none of them work without clipping then we'll have to resort to 
	// just dumping it somewhere even though it does clip
	
//sas_log_println('-----Start sas_autoPosition-------');
	// 1. try positioning elementToPosition left edge aligned with left edge
		// of relativeToElement and top edge aligned with bottomtop edge of relativeToElement.
		proposedLeft = relativeToCoordinates.getX();
		proposedTop = relativeToCoordinates.getY() + relativeToCoordinates.getHeight();
//sas_log_println('-----Attempt #1-------');
	if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
	{
		// 2.  try positioning element right edge aligned with right edge
		// of relativeToElement and top edge aligned with bottom edge of relativeToElement
		proposedLeft = relativeToCoordinates.getX() - (elementToPosition.offsetWidth - relativeToCoordinates.getWidth());
		proposedTop = relativeToCoordinates.getY() + relativeToCoordinates.getHeight();
//sas_log_println('-----Attempt #2-------');		
		if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
		{
			// 3. try positioning elementToPosition left edge aligned with left edge of
			// relativeToElement area and bottom edge aligned with top edge of relativeToElement
			proposedLeft = relativeToCoordinates.getX();
			proposedTop = relativeToCoordinates.getY() - elementToPosition.offsetHeight;
//sas_log_println('-----Attempt #3-------');
			if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
			{
				// 3. try positioning elementToPosition right edge aligned with right edge
				// of relativeToElement image and bottom edge aligned with top edge of relativeToElement
				proposedLeft = relativeToCoordinates.getX() - (elementToPosition.offsetWidth - relativeToCoordinates.getWidth());
				proposedTop = relativeToCoordinates.getY() - elementToPosition.offsetHeight;
//sas_log_println('-----Attempt #4-------');
				if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
				{
					// 5. try positioning elementToPosition right edge aligned with left edge
					// of relativeToElement and center aligned with center of relativeToElement
					proposedLeft = relativeToCoordinates.getX() - elementToPosition.offsetWidth;
					proposedTop = relativeToCoordinates.getY() - (elementToPosition.offsetHeight/2) + (relativeToCoordinates.getWidth()/2);
//sas_log_println('-----Attempt #5-------');
					if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
					{
						// 6. try positioning elementToPosition left edge aligned with right edge
						// of relativeToElement and center aligned with center of relativeToElement
						proposedLeft = relativeToCoordinates.getX() + relativeToCoordinates.getWidth();
						proposedTop = relativeToCoordinates.getY() - (elementToPosition.offsetHeight/2) + (relativeToCoordinates.getWidth()/2);
//sas_log_println('-----Attempt #6-------');
						if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
						{
							// 7. last ditch effort... Could probably write another attempt that tries to figure out how much space is available
							// on each side of the relativeToELement and optimize where the elementToPosition goes for the last try. 
							// Just dump it at our ideal spot (#1) even though it will clip
							proposedLeft = relativeToCoordinates.getX();
							proposedTop = relativeToCoordinates.getY() + relativeToCoordinates.getHeight();
//sas_log_println('-----Attempt #7 (Last Ditch)-------');							
						}
					}					
				
				}
				
			}
		}
		
	}			

    elementToPosition.style.left = proposedLeft;
    elementToPosition.style.top = proposedTop;
//sas_log_println('-----End sas_autoPosition-------');

}
/* ------------------------------------------------------------- *
 * --End sas_autoPosition--
 * ------------------------------------------------------------- */


/* ------------------------------------------------------------- *
 * --Begin sas_autoPositionHorizontally--
 *
 *  Attempt to automatically do an absolute positioning on an html
 *  element relative to some other element.  This version
 *  is meant for items which have a preference of positioning 
 *  horizontally relative to an item.  Such items include
 *  submenus or popups off of vertical menus.
 *  If we can't find suitable horizontal alignment then we just
 *  run through as if it weren't a horizontal preference until
 *  we hit a good position or give up.
 *
 * Example Useage...
 *  relativeToElement = document.getElementById("MyImageId");
 *  DivToPosition = document.getELementById("MyPopupMenu");
 *  sas_autoPositionHorizontally(DivToPosition, relativeToELement);
 *
 * ------------------------------------------------------------- */
function sas_autoPositionHorizontally(elementToPosition, relativeToElement)
{
	var relativeToCoordinates = new sas_Coordinates(relativeToElement);
	relativeToCoordinates.setRelativeToSharedBreakoutBox(elementToPosition);	

	// lets try several positions which we would consider ideal and
	// if none of them work without clipping then we'll have to resort to 
	// just dumping it somewhere (0,0)??
	

	// 1. try positioning elementToPosition left edge indented from right edge
	// of relativeToElement and top edge aligned with top edge of relativeToElement.
	proposedLeft = relativeToCoordinates.getX() + relativeToCoordinates.getWidth();
	proposedTop = relativeToCoordinates.getY();

	if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
	{
		// 2.  try positioning element right edge indented from left edge
		// of relativeToElement and top edge aligned with top edge of relativeToElement
		proposedLeft = relativeToCoordinates.getX() - elementToPosition.offsetWidth;
		proposedTop = relativeToCoordinates.getY();
		
		if(sas_checkClipping(elementToPosition, proposedLeft, proposedTop)==true)
		{
			// if the preferred submenu alignments didn't work go through
			// the position posibilities for non submenus. 

			sas_autoPosition(elementToPosition, relativeToElement);
			return;
		}
		
	}			

    elementToPosition.style.left = proposedLeft;
    elementToPosition.style.top = proposedTop;


}
/* ------------------------------------------------------------- *
 * --End sas_autoPositionHorizontal--
 * ------------------------------------------------------------- */


/* ------------------------------------------------------------- *
 * --Begin sas_checkClipping--
 *
 *  js function to try and determine whether placing a given html element
 *  at a specified set of absolute coordinates would cause the element
 *  to be clipped.
 *
 * Example Useage...
 *  if(sas_checkClipping(palette, proposedLeft, proposedTop)==true)
 *    this would clip so figure out somewhere else to place it.
 *
 * ------------------------------------------------------------- */
function sas_checkClipping(element, proposedLeft, proposedTop)
{
	var clip=false;
    
    elementWidth = element.offsetWidth;
    elementHeight = element.offsetHeight;

	windowWidth = document.body.clientWidth;
	windowHeight = document.body.clientHeight;

	// proposedLeft and proposedTop coming in are likely relative
	// to elements breaking box. For clipping check we need to 
	// convert proposedLeft and proposedTop to be relative to the
	// entire page.  so.. Get breaking box of element. and then
	// get that breaking boxes coordinates relative to the entire
	// document.  add that height and width to proposedTop and proposedLeft
	breakoutBox = sas_getBreakoutBox(element);
	if(breakoutBox!=null)
	{
		// Note: the above statement about clipping should be checked
		// relative to entire page is generally true unless element
		// lives in a breaking box that can itself cut off content such
		// as overflows of clip, scroll, etc... so need to not adjust
		// to entire page if this is the case.
		if(sas_getCurrentStyle(breakoutBox,'overflowY')!='auto')
//		if(breakoutBox.currentStyle.overflowY!='auto')
		{
			breakoutBoxCoordinates = new sas_Coordinates(breakoutBox);
			breakoutBoxCoordinates.setRelativeToPage();
			
			proposedLeft += breakoutBoxCoordinates.getX();
			proposedTop += breakoutBoxCoordinates.getY();
		}
	}
	
	// if element lives in scrollable overflow area then 
	// proposedLeft and proposedTop are likely relative
	// to the virtual area (included nonvisible scroll areas)
	// in checking clipping it needs to be going against
	// the physical area instead so adjust them as needed.
    if (element != null)
    {
	    parentComponent = element;            
	    while(parentComponent!=null)
	    {
	    
			//*** Note:  the check for scrollTop>0, scrollLeft>0 deals with any scrollable area
			// that is currently scrolled including the main browser window itself.
			//  The subsequent check for overflow settings specifically catches scroll areas OTHER
			// than the main browser window itself.

	    
			// alter proposedTop and proposedLeft to take into account scrolling space.
				// this will treat the proposed top relative to the physical
				// top/left of the overflow area instead of relative to the virtual
				// top/left of the overflow area
			if(parentComponent.scrollTop>0 || parentComponent.scrollLeft>0)
			{
					proposedTop = proposedTop - parentComponent.scrollTop;
				proposedLeft = proposedLeft - parentComponent.scrollLeft;
			}

				// if the scrollable area is something other than body then
				// we need to alter the window width and height used as
				// clipping checks to be the internal scrollable area 
				// instead of the entire window.
				// settings other than auto creating scrollable areas?
				if(sas_getCurrentStyle(parentComponent,'overflowY')=='auto' ||
				   sas_getCurrentStyle(parentComponent,'overflowX')=='auto')
				{
		        	windowWidth=parentComponent.offsetWidth;
		        	windowHeight=parentComponent.offsetHeight;
	        	
	        	break;
        	}
	        parentComponent = parentComponent.offsetParent;
	    }
	}

	// will it clip on left?
	if(proposedLeft<0)
		clip = true;

	// will it clip on top?
	if(proposedTop<0)
		clip = true;
		
	// will it clip on right side?
	if(proposedLeft+elementWidth>windowWidth)
		clip = true;

	// will it clip on bottom
	if(proposedTop+elementHeight>windowHeight)
		clip = true;

//if(clip)
//	sas_log_println('INVALID!! Proposed=[' +proposedLeft + ', ' + proposedTop + '], Dimensions=['+elementWidth+', '+elementHeight+'], WindowDimensions=[' + windowWidth + ', ' + windowHeight + ']');
//else
//	sas_log_println('Valid Proposed=[' +proposedLeft + ', ' + proposedTop + '], Dimensions=['+elementWidth+', '+elementHeight+'], WindowDimensions=[' + windowWidth + ', ' + windowHeight + ']');	


	return clip;
}
/* ------------------------------------------------------------- *
 * --End sas_checkClipping--
 * ------------------------------------------------------------- */


/* ------------------------------------------------------------- *
 * --Begin sas_Coordinates--
 *
 *  js object for determining absolute coordinates of an
 * html element.  Useful for positioning one element relative
 * to another with absolute position such as popup menus,
 * Calendar popup, Color Picker popup, etc...
 *
 *
 *
 * NOTE:
 * Depending on what you plan on doing with the coordinates of a given element you may want either 
 * coordinates relative to the top/left of the page OR coordinates relative to the top/left of the
 * nearest relatively positioned containing box(breakout box).
 * 
 * This is because an absolutely positioned element withing a breakoutbox (SPAN, DIV, etc..) that
 * has a position of relative or absolute uses coordinates relative to that breakoutbox rather than to the the page.
 * breakoutbox html elements that this is true for seem to differ based on browser.  In IE it appears to
 * be supported fairly widely across the board.  In Mozilla it seems more restricted to things like Spans, Divs
 * and not supported for things like Table, TH, TD, etc...  
 *
 * Adding third case where you want coordinates of element relative to a breakoutbox for a different 
 * element. Take a popup div(p) which you want to position relative to an image (i).  If p lives inside of 
 * different breakoutbox than i then the coordinates of i relative to page or its own breakoutbox do
 * you know good.  In this case you really need to the coordinates of i relative to the first breakoutbox
 * that both i and p have in common.
 *
 *
 * default coordinates will be relative to parent breakoutbox.
 *
 * Example Useage getting coordinates relative to parent breakoutbox.
 *	var coords = new sas_Coordinates(document.getElementById("someelement"));
 *  coords.getX()
 *  coords.getY()
 *  coords.getWidth()
 *  coords.getHeight()
 *
 * Example Useage getting coordinates relative to page.
 *	var coords = new sas_Coordinates(document.getElementById("someelement"));
 *  coords.setRelativeToPage();
 *
 * Example Useage getting coordinates relative to first breakoutbox shared with
 * some other element.
 *	var coords = new sas_Coordinates(document.getElementById("someimage"));
 *  coords.setRelativeToSharedBreakoutBox("menudiv");
 *
 *  Parameters:
 *     element - the html element you want to get coordinates for
 *
 * ------------------------------------------------------------- */
function sas_Coordinates(element)
{
	this.element=element;
	
	// determine absolute coordinates of the element
	elementLeft=0;
	elementTop=0;

    if (element != null)
    {
	    parentComponent = element;            
	    while(parentComponent!=null)
	    {
			// need to deal with horizontal overflows as well and
			// also deal with anytime it creates a separate container box. 
			// Settings other than auto could trigger this such as "scroll".
		if(sas_getCurrentStyle(parentComponent,'overflowY')=='auto')
//	        if(parentComponent.currentStyle.overflowY=="auto")
	        	break;

			// as we walk up the chain if we find an appropriate item with relative positioning then
			// don't count it and stop immediately so that we return coordinates relative
			// to this relative containing box
			if(sas_getCurrentStyle(parentComponent,'position')=='relative' || sas_getCurrentStyle(parentComponent,'position')=='absolute')
			{
				// IE elements which honor 'relative' position
				if(xIE)
					break;
					
				// Mozilla elements which honor 'relative' position
				if(parentComponent.tagName=='SPAN' || parentComponent.tagName=='DIV')
					break;
			}
			
	        elementLeft = elementLeft + parentComponent.offsetLeft;
	        elementTop = elementTop + parentComponent.offsetTop;
	        parentComponent = parentComponent.offsetParent;
	        
	        
	    }
	}

	this.x=elementLeft;
	this.y=elementTop;
	this.init();

	return this;
}	

function sas_Coordinates_init()
{
	if(xIE)
	{
		this.width=this.element.offsetWidth;
		this.height=this.element.offsetHeight;
	}
	else
	{
		this.width=this.element.offsetWidth;
		this.height=this.element.offsetHeight;
	}
}

function sas_Coordinates_getX()
{
	return this.x;
}

function sas_Coordinates_getY()
{
	return this.y;
}
function sas_Coordinates_getWidth()
{
	return this.width;
}
function sas_Coordinates_getHeight()
{
	return this.height;
}

// comment the caveaut
function sas_Coordinates_setRelativeToSharedBreakoutBox(breakoutBoxChild)
{
	// determine absolute coordinates of the element
	elementLeft=0;
	elementTop=0;

	breakoutBox = sas_getBreakoutBox(breakoutBoxChild);

    if (this.element != null)
    {
	    parentComponent = this.element;            
	    while(parentComponent!=null && parentComponent!=breakoutBox)
	    {
	        elementLeft = elementLeft + parentComponent.offsetLeft;
	        elementTop = elementTop + parentComponent.offsetTop;
	        parentComponent = parentComponent.offsetParent;
	    }
	}

	this.x=elementLeft;
	this.y=elementTop;

	this.init();
}	

function sas_Coordinates_setRelativeToPage()
{
	// determine absolute coordinates of the element
	elementLeft=0;
	elementTop=0;


    if (this.element != null)
    {
	    parentComponent = this.element;            
	    while(parentComponent!=null)
	    {
	        elementLeft = elementLeft + parentComponent.offsetLeft;
	        elementTop = elementTop + parentComponent.offsetTop;
	        parentComponent = parentComponent.offsetParent;
	    }
	}

	this.x=elementLeft;
	this.y=elementTop;

	this.init();
}	

sas_Coordinates.prototype.getX=sas_Coordinates_getX;
sas_Coordinates.prototype.getY=sas_Coordinates_getY;
sas_Coordinates.prototype.getWidth=sas_Coordinates_getWidth;
sas_Coordinates.prototype.getHeight=sas_Coordinates_getHeight;
sas_Coordinates.prototype.setRelativeToSharedBreakoutBox=sas_Coordinates_setRelativeToSharedBreakoutBox;
sas_Coordinates.prototype.setRelativeToPage=sas_Coordinates_setRelativeToPage;
sas_Coordinates.prototype.init=sas_Coordinates_init;

/* ------------------------------------------------------------- *
 * --End sas_Coordinates--
 * ------------------------------------------------------------- */



/* ------------------------------------------------------------- *
 *  find the container box (breakout box) for this element.
 *  This will walk up the dom tree until it finds an ancestor
 *  which causes absolute child coordinates to be relative to 
 *  the box.  This could walk all the way back up to the root
 *  document.
 * ------------------------------------------------------------- */
function sas_getBreakoutBox(element)
{
    if (element != null)
    {
	    parentComponent = element;            
	    while(parentComponent.offsetParent!=null)
	    {
	        parentComponent = parentComponent.offsetParent;	    
			if(sas_getCurrentStyle(parentComponent,'overflowY')=='auto')
//	        if(parentComponent.currentStyle.overflowY=="auto")
	        	break;

			if(sas_getCurrentStyle(parentComponent,'position')=='relative' || sas_getCurrentStyle(parentComponent,'position')=='absolute')
			{
				// IE elements which honor 'relative' position
				if(xIE)
					break;
					
				// Mozilla elements which honor 'relative' position
				if(parentComponent.tagName=='SPAN' || parentComponent.tagName=='DIV')
					break;
			}
	    }
	}
	
	return parentComponent;
}


/* ------------------------------------------------------------- *
 * --Begin Javascript logging helpers--
 *
 * js functions for helping log from javascript without using
 * alerts.  This will open a separate window and dump all log
 * messages to this window instead of opening alert dialog.
 *
 * Example Useage:
 *
 * // print a simple debug message
 * sas_log_println("Hey I'm logging a message");
 *
 * // print all the elements and their values for a form.
 * sas_log_printFormElements(someform);
 *
 * // print all the properties for a given element.
 * sas_log_printObjectProperties(somediv, "Popup_Div");
 *
 * ------------------------------------------------------------- */
var sas_log = null;		    	//handle to log window
var sas_logging_enabled=true;  //to log or not to log... that is the question!

function sas_log_enable(enable)
{
	if (sas_logging_enabled != enable)
	{
		sas_logging_enabled = enable;
	}
}

function sas_log_println(msg) 
{
	if(sas_logging_enabled==true)
	{
			sas_log_getLog().document.write(msg, "<br>");
		    sas_log_getLog().scrollBy(0,1000000);	//scroll to the end
			window.status = msg;
	}
}

function sas_log_printFormElements(form) 
{
	if(sas_logging_enabled==true)
	{
		var text = "Form["+form.name+"] Elements:<BR>\n";
		
		if (form != null && form.elements == null) 
		{
			//must be the ID for the form try to find the real form object
			form = document.getElementById(form);
		}
		
		if (form != null && form.elements != null) 
		{
			var elText;
			for (i=0; i<form.elements.length; i++) 
			{
				elText = "  " + form.elements[i].name + " = " + form.elements[i].value;
				text = text + elText + "<BR>\n";
			}
		}
		
		if (text.length > 0) 
		{
			sas_log_println(text);
		}
	}
}

function sas_log_printObjectProperties(obj, obj_name) 
{
	if(sas_logging_enabled==true)
	{
	
		var result = "Object["+obj_name+"] Properties:<br>\n";
		var props = new Array();
		for (var i in obj) 
		{
			props[props.length] = i;
		}
		props.sort();
	
		for (var i =0; i<props.length; i++ ) 
		{
			var p = props[i];
			result += obj_name + "." + p + " = ";
			try 
			{
				var v = obj[p];
				if (v == null)
					result += "<i>null</i><br>\n";
				else

					if (v.replace)
					{
						v = v.replace("<", "&lt;");
						v = v.replace(">", "&gt;");
					}

					result += v + "<br>\n";
			} catch (e) 
			{
				result += "<font color=\"RED\"><b>ERROR:</b> "+e.message+"</font><br>\n";
			}
		}
		sas_log_println(result);
	}
}



function sas_log_getLog()
{
	if (sas_log == null || sas_log.closed == true) 
	{
		sas_log = window.open("", "sas_log", "width=600,height=500,left=0px,top=0px,resizable,scrollbars=yes,status=0");
//		sas_log.document.open("text/plain");	//set document type to plain text?
		sas_log.document.bgcolor = "#FFCC00";
		sas_log.document.title = "SAS JavaScript Log";
	}
	return sas_log;
}
/* ------------------------------------------------------------- *
 * --End Javascript logging helpers--
 * ------------------------------------------------------------- */

/* ------------------------------------------------------------- *
 * emulate parent.contains(child)
 * ------------------------------------------------------------- */
function sas_DOMContains( parent, child )
{
    if (parent.contains) return parent.contains(child);
    if (parent==child) return false;
    while (child !=null && child != parent)
        child = child.parentNode;
    return child != null;
}
