{
    new Ruby(); // JS 1.1 does not create prototype, until function is used once as constructor
    var p = Ruby.prototype;

    p.setBreadcrumb = RubySetBreadcrumb;
    p.setBreadcrumbOnLoad = RubySetBreadcrumbOnLoad;
    p.newWnd = RubyNewWindow;
    p.closeAllWnds = RubyCloseAllWindows;
    p.goTo = RubyGoTo;
    p.setupEvents = RubySetupEvents;
    p.addEvent = RubyAddEvent;
    p.addEventHandler = RubyAddEventHandler;
    p.setTimeout = RubySetTimeout;
    p.include = RubyInclude;
    p.complete = RubyComplete;
    p.isLoaded = RubyIsLoaded;
    p.setPagerStart = RubySetPagerStart;
}

// Global ruby variable
var ruby = new Ruby();
ruby.setupEvents();
ruby.addEventHandler( 'unload', ruby, ruby.closeAllWnds );

// Other global namespaces
var Widgets = new Object();
Widgets.OnChange = new Object();

function Ruby()
{
    this.open_wnds = new Array();
    this.handlers = new Array();
    this.timeouts = new Array();
    this.includes = new Array();
    this.isIE = (document.all) ? true : false;
} // Ruby Constructor

function RubyNewWindow( url, width, height, scroll )
{
    x = (screen.availWidth - width)/2 + 50;
    y = (screen.availHeight - height)/2 + 50;

    var new_wnd = window.open( url, '_blank', 
			       'width=' + width + 'px, height=' + 
			       height + 'px, left=' + 
			       x + ',top=' + 
			       y + ', scrollbars=' + 
			       scroll );    
    if( new_wnd.blur ) new_wnd.focus();
    this.open_wnds.push( new_wnd );
} // RubyNewWindow

function RubyCloseAllWindows()
{
    for( var i = 0; i < this.open_wnds.length; i++ ) {
	var open_wnd = this.open_wnds[i];
	if( open_wnd && !open_wnd.closed )
	    open_wnd.close();
    } // foreach window
} // RubyCloseAllWindows

function RubySetBreadcrumb( bc )
{
    if( top.frm_header && top.frm_header.newBreadcrumb ) {
	top.frm_header.newBreadcrumb( bc );
    }
} // RubySetBreadcrumb

function RubySetBreadcrumbOnLoad( bc )
{
    ruby.addEventHandler( 'load',
			  null,
			  function () { ruby.setBreadcrumb( bc ); } );
} // RubySetBreadcrumbOnLoad

function RubyGoTo( url, heading, headingWithSlash )
{
    var section, subsection, tmpURL;
    
    // Set the section to the first 2 dirs
    tmpURL = url.substring( 1 );
    var slash1 = tmpURL.indexOf( '/' );
    var slash2 = slash1 + tmpURL.substring( slash1 + 1 ).indexOf( '/' ) + 1;

    if( heading != null && heading != '' ) {
	section          = heading;
	sectionWithSlash = headingWithSlash;
    }
    else {
	section = tmpURL.substring( 0, slash1 ) 
	        + "__" 
	        + tmpURL.substring( slash1 + 1, slash2 )
	        ;

	sectionWithSlash = tmpURL.substring( 0, slash1 ) 
	                 + "/" 
	                 + tmpURL.substring( slash1 + 1, slash2 )
	                 ;
    }
    
    subsection = null;

    // Set the subsection to the second dir
    tmpURL = tmpURL.substring( slash2 + 1 );
    var slash3 = tmpURL.indexOf( '/' );
    if( slash3 > 0 ) {
	subsection = tmpURL.substring( 0, slash3 );
    }

    var td = parent.frm_header.getTDElement( "td_" + section );
    var imgName = "image_" + section;
    var urlSide = "/elements/sidebar.html?topName=" + sectionWithSlash;
	
    if( subsection != null ) {
	urlSide += "&openSection=" + subsection;
    }

    
    parent.frm_header.navMouseClick( td, url, urlSide );
}

function RubySetPagerStart( formName, count, numPages, useThisNumber, url )
{
    if( useThisNumber != '-1' ) {
	document.forms[formName].start.value = useThisNumber;
	return;
    }

    var val = parseInt( document.forms[formName].page.value );
    if( val > numPages || val < 1 || isFinite( document.forms[formName].page.value ) == false ) {
	document.forms[formName].start.value = 1;
    }
    else {
	document.forms[formName].start.value = val;
    }

    document.forms[formName].start.value = ( ( parseInt( document.forms[formName].start.value ) - 1 ) * count ) + 1;

    if( url != null ) {
	location.href = url + document.forms[formName].start.value;
    }
} // RubySetPagerStart

function RubyAddEvent( elm, eventName, func, capt ) // Copied from dhtml.js so that ruby.js does not rely on any other js file
{
    if( elm.attachEvent ) {
	elm.attachEvent( "on"+eventName, func );
    }
    else if( elm.addEventListener ) {
	elm.addEventListener( eventName, func, capt );
	return true;
    }
    else {
	return true;
    }
} // RubyAddEvent

function RubySetupEvents()
{    
    DHTML.createListener( window, 'load' );
/*    this.addEvent( window, 'load', _handle_ruby_event, false );
    this.addEvent( window, 'unload', _handle_ruby_event, false );
    this.addEvent( document, 'submit', _handle_ruby_event, false );
    this.addEvent( document, 'mouseover', _handle_ruby_event, false );
    this.addEvent( document, 'mousemove', _handle_ruby_event, false );
    this.addEvent( document, 'mouseout', _handle_ruby_event, false );
*/
    
} // RubySetupEvents

function RubyAddEventHandler( event_name, cbObj, cbFunc, cbArgs )
{
    if( cbFunc ) {
	
	if( !this.handlers[event_name] ) {
	    this.handlers[event_name] = new Array();
	}
	
	this.handlers[event_name][this.handlers[event_name].length] = { call_back_obj : cbObj,
									call_back_func : cbFunc,
									call_back_args : cbArgs };
    }
} // RubyAddEventHandler

function RubySetTimeout( cbObj, cbFunc, timeout, args )
{
    this.timeouts[this.timeouts.length] = { call_back_obj : cbObj,
					    call_back_func : cbFunc,
					    call_back_args : args
                                          };
    
    setTimeout( "_handle_ruby_timeout( " + (this.timeouts.length-1) + " )", timeout );
} // RubySetTimeout

function RubyIsLoaded( uri )
{
    if( !this.includes[uri] ) {
	return -1;
    } else {
	if( this.includes[uri]["loaded"] ) {
	    return 1;
	} else {
	    return 0;
	}
    }
} // RubyIsLoaded

function RubyComplete( uri )
{
    if( !this.includes[uri] ) {
	this.includes[uri] = { loaded : true };
    }
    else {
	this.includes[uri]["loaded"] = true;
    }
} // RubyComplete

function RubyInclude( uri )
{
    if( !this.includes[uri] ) {

	this.includes[uri] = { loaded : false };
	
	var script_node = document.createElement("script");
	script_node.setAttribute( "src", uri );
	script_node.src = uri;
	script_node.setAttribute( "type","text/javascript" );
	document.getElementsByTagName("head")[0].appendChild( script_node );

	return true;
    }
    
    return false;
} // RubyInclude

function _handle_ruby_timeout( timeout_idx )
{
    if( ruby.timeouts.length > timeout_idx &&
	ruby.timeouts[timeout_idx] ) {
	
	var cbObj = ruby.timeouts[timeout_idx].call_back_obj;
	var cbFunc = ruby.timeouts[timeout_idx].call_back_func;
	var cbArgs = ruby.timeouts[timeout_idx].call_back_args;

	// TODO: Add support for when cbfunc is string
        //tt_debug( 'Obj = ' + cbObj + ' func = ' + cbFunc + ' args = ' + cbArgs );
	if( cbObj ) {
	    cbFunc.call( cbObj, cbArgs );
	}
	else {
	    cbFunc( cbArgs );
	}
    } 
} // _handle_ruby_timeout

function _handle_ruby_event( evt )
{
    if( !evt ) {
	evt = event;
    }
    
    var event_name = evt.type;
    if( ruby.handlers[event_name] ) {
	for( var i = 0; i < ruby.handlers[event_name].length; i++ ) {
	    
	    var cbObj = ruby.handlers[event_name][i].call_back_obj;
	    var cbFunc = ruby.handlers[event_name][i].call_back_func;
	    var cbArgs = ruby.handlers[event_name][i].call_back_args;

	    // TODO: Add support for when cbfunc is string
	    if( cbObj ) {
		cbFunc.call( cbObj, evt, cbArgs );
	    }
	    else {
		cbFunc( evt, cbArgs );
	    }
	}
    }
} // _handle_ruby_event
