
	function DoLater ( Script, Timeout )
	{
		setTimeout ( Script, Timeout );
	}

	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////

	var m_OnUpdate = null;

	function UpdatePending ()
	{
		if
			( m_OnUpdate != null )
		{
			return true;
		}

		return false;
	}

	function OnUpdate ( Script )
	{
		if
			( UpdatePending () )
		{
			alert ( "UPDATE REQUEST WHILE UPDATE PENDING" );
		}

		m_OnUpdate = Script;
	}

	function DoAction ( source, target, action )
	{
		
		if
			( action == "ReplaceOuter" )
		{
			if
				( source.innerHTML == null )
			{
				target.outerHTML = "";
			}
			else
			{
				target.outerHTML = source.innerHTML;
			}
		}
		else 
		if
			( action =="ReplaceInner" )
		{
			if
				( source.innerHTML == null )
			{
				target.innerHTML = "";
			}
			else
			{
				target.innerHTML = source.innerHTML;
			}
		}
		else 
		if
			( action == "InsertAfterBegin" )
		{
			target.insertAdjacentHTML ( "afterBegin", source.outerHTML );

			var c = target.children;
			var l = c.length;

			if
				( l != null )
			{
				var e = c [ 0 ];

				AddBindings ( e.all );
			}
		}
		else 
		if
			( action == "InsertBeforeEnd" )
		{
			target.insertAdjacentHTML ( "beforeEnd", source.outerHTML );

			var c = target.children;
			var l = c.length;

			if
				( l != null )
			{
				var e = c [ l - 1 ];
				AddBindings ( e.all );
			}
		}
		else
		{
			alert ( "UNKNOWN UPDATE ACTION: '" + action + "'." );
		}

		/*
			while
				( target != null )
			{
				if
					( target.tagName == "TABLE" )
				{
					target.outerHTML = target.outerHTML;

					target = null;
				}
				else
				{
					target = target.parentElement;
				}
			}
		*/
	}

	function DeltaAction ( e )
	{
		var target = e [ "target-id" ];
		var action = e [ "action" ];
	
		if
			( target == null )
		{
			return;
		}

		if
			( action == null )
		{
			alert ( "No action for delta " + elem.outerHTML );
			return;
		}

		var targetElem = document.all.item ( target );

		if
			( targetElem == null )
		{
			return;
		}

		if
			( targetElem.length != null )
		{
			// Collection

			for
				( var i = 0; i < targetElem.length; i++ )
			{
				DoAction ( e, targetElem [ i ], action );
			} 
		}
		else
		{
			DoAction ( e, targetElem, action );
		}
	}

	function DeltaReady ( d )
	{
		if
			( ! UpdatePending () )
		{
			alert ( "UNEXPECTED UPDATE" );
		}
		else
		{
			var col = d.all.item ( "delta" );

			if
				( col == null )
			{
				return;
			}

			if
				( col.length == null )
			{
				DeltaAction ( col );
			}
			else
			{
				for
					( var i = 0; i < col.length; i++ )
				{
					DeltaAction ( col [ i ] );
				} 
			}
		}
	}

	var last_id;
	function DeltaReadyCheckDup ( d )
	{
		if
			( ! UpdatePending () )
		{
			alert ( "UNEXPECTED UPDATE" );
		}
		else
		{
			var col = d.all.item ( "delta" );

			if
				( col == null )
			{
				return;
			}

			if
				(col.list_id == null )
			{
				alert("Expected Change list id in delta");
			}

			if
				(col.list_id == last_id )
			{
				return;
			}
			else
			{
				last_id = col.list_id;
			}

			if
				( col.length == null )
			{
				DeltaAction ( col );
			}
			else
			{
				for
					( var i = 0; i < col.length; i++ )
				{
					DeltaAction ( col [ i ] );
				} 
			}
		}
	}

	function DeltaDone ()
	{
		var script = m_OnUpdate;
		m_OnUpdate = null;
		window.eval ( script );
	}

	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////

	var m_pressed = null;
	var m_waiting = false;

	function AfterScrollUpdate () {
		EnableAll ( "Scroll" );
		
		SetScrollButtons ();
	}

	function CanGetMoreUp ( Target )
	{
		object = document.all ( Target );

		if
			( object [ "scroll-more-up" ] != null )
		{
			if
				( window.eval ( object [ "scroll-more-up" ] ) )
			{
				return true;
			}
		}

		return false;
	}

	function CanGetMoreDown ( Target )
	{
		object = document.all ( Target );

		if
			( object [ "scroll-more-down" ] != null )
		{
			if
				( window.eval ( object [ "scroll-more-down" ] ) )
			{
				return true;
			}
		}

		return false;
	}

	function Reposition ( Target, OldHeight )
	{
		var object = document.all ( Target );

		var new_height = object.scrollHeight;

		var delta = new_height - OldHeight;

		object.scrollTop += delta;
	}

	function DoGetMoreUp ( Target )
	{
		if
			( CanGetMoreUp ( Target ) )
		{
			object = document.all ( Target );

			if
				( object [ "scroll-get-more-up" ] != null )
			{
				var old_height = object.scrollHeight;

				DisableAll ( "Scroll" );

				OnUpdate ( "Reposition ( '" + Target + "', " + old_height + " ); AfterScrollUpdate ();" );

				window.eval ( object [ "scroll-get-more-up" ] );
			}
		}
	}

	function DoGetMoreDown ( Target )
	{
		if
			( CanGetMoreDown ( Target ) )
		{
			object = document.all ( Target );

			if
				( object [ "scroll-get-more-down" ] != null )
			{
				DisableAll ( "Scroll" );
				OnUpdate ( "AfterScrollUpdate ();" );

				window.eval ( object [ "scroll-get-more-down" ] );
			}
		}
	}

	function SetScrollButtons ( Target )
	{
		var scrollers = m_ElementTypes.Scroll;

		if
			( scrollers != null )
		{
			for
				( var i in scrollers )
			{
				var e = scrollers [ i ];
				var target = null;

				if
					( Target == null )
				{
					target = e [ "scroll-target" ];
				}
				else
				if
					( e [ "scroll-target" ] == Target )
				{
					target = Target;
				}

				if
					( target != null )
				{
					var object = document.all ( target );
					var type = e [ "scroll-type" ];
					var enable = true;
					var enabled = true;

					if
						( e [ "logical-enabled" ] == 0 )
					{
						enabled = false;
					}

					if
						( type == "up" )
					{
						if
							( object.scrollTop == 0 )
						{
							if
								( ! CanGetMoreUp ( target ) )
							{
								enable = false;
							}
						}
					}
					else
					if
						( type == "down" )
					{
						var windowHeight = object.offsetHeight;

						if
							( object.scrollTop >= ( object.scrollHeight - object.offsetHeight ) )
						{
							if
								( ! CanGetMoreDown ( target ) )
							{
								enable = false;
							}
							else
							{
								if
									( ! UpdatePending () )
								{
									DoGetMoreDown ( target );
								}

								return;
							}
						}
					}

					if
						( enable != enabled )
					{
						if
							( enable )
						{
							e [ "logical-enabled" ] = 1;

							ElementEnable ( e );
						}
						else
						{
							e [ "logical-enabled" ] = 0;

							ElementDisable ( e );
						}
					}
				}
			}
		}
	}

	function ElementStartScroll ( e )
	{
		if
			( e [ "state-enabled" ] )
		{
			var target = "";
			var up = true;

			if
				( e [ "scroll-target" ] != null )
			{
				target = e [ "scroll-target" ];

				if
					( e [ "scroll-type" ] == "down" )
				{
					up = false;
				}
			}
			else
			{
				return;
			}

			m_pressed = e;

			if
				( up )
			{
				DoScroll ( -5, 0, target );
			}
			else
			{
				DoScroll ( 5, 0, target );
			}
		}
	}

	function ElementStopScroll ( e )
	{
		m_pressed = null;
	}

	function DoScroll ( delta, target_delta, target ) {

		var stop = false;

		if
			( ! UpdatePending () )
		{
			var object = document.all ( target );

			var old_top = object.scrollTop;

			object.scrollTop += delta;

			if
				( m_pressed )
			{
				if
					( Math.abs ( delta ) < 30 )
				{
					var delta_delta = 1;

					if
						( delta < 0 )
					{
						delta -= delta_delta;
					}
					else
					{
						delta += delta_delta;
					}
				}
			}

			if
				( old_top == object.scrollTop )
			{
				if
					( delta < 0 )
				{
					// alert ( "At the top" );

					if
						( ! UpdatePending () )
					{
						if
							( CanGetMoreUp ( target ) )
						{
							DoGetMoreUp ( target );
						}
						else
						{
							stop = true;
						}
					}
				}
				else
				{
					// alert ( "At the bottom" );

					if
						( ! UpdatePending () )
					{
						if
							( CanGetMoreDown ( target ) )
						{
							DoGetMoreDown ( target );
						}
						else
						{
							stop = true;
						}
					}
				}
			}

			if
				( ! m_pressed )
			{
				stop = true;
			}
		}

		if
			( stop )
		{
			SetScrollButtons ( target );

			m_pressed = null;
		}
		else
		{
			if
				( ! m_waiting )
			{
				m_waiting = true;

				DoLater ( "m_waiting = false; DoScroll ( " + delta + ", " + target_delta + ", '" + target + "' );", 10 );
			}
		}
	}

	function TopOfList ( Target )
	{
		var object = document.all ( Target );
		var collection = object.all;

		if
			( collection != null )
		{
			if
				( collection.length != null )
			{
				var object_top = object.scrollTop;
				var window_height = object.offsetHeight;
				var best_element = null;
				var best_top;

				for
					( var i = 0; i < collection.length; i++ )
				{
					var element = collection [ i ];

					if
						( element [ "item-number" ] != null )
					{
						var top = element.offsetTop - object_top;
						var bottom = top + element.offsetHeight;

						if
							( ( bottom > 0 ) && ( top <= window_height ) )
						{
							if
								( best_element != null )
							{
								if
									( top < best_top )
								{
									best_element = null;
								}
							}

							if
								( best_element == null )
							{
								best_element = element;
								best_top = top;
							}
						}
					}
				}

				if
					( best_element != null )
				{
					return best_element [ "item-number" ];
				}
			}
		}

		return "";
	}

	var m_flash_state = 1;

	function Flash ()
	{
		
		var flashers = m_ElementTypes.Flash;

		if
			( flashers != null )
		{
			if
				( m_flash_state )
			{
				m_flash_state = 0;
			}
			else
			{
				m_flash_state = 1;
			}

			for
				( var i in flashers )
			{
				var e = flashers [ i ];

				if
					( e [ "state-enabled" ] )
				{
					if
						( m_flash_state )
					{
						SetElementClass ( e, "class-hover", true );

					}
					else
					{
						SetElementClass ( e, "class-hover", false );
					}
				}
			}

			if
				( m_flash_state )
			{
				DoLater ( "Flash();", 500 );
			}
			else
			{
				DoLater ( "Flash();", 5000 );
			}
		}
	}

	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////

	function SetDefaultClasses ( Element )
	{
		if
			( Element [ "default-class" ] == null )
		{
			Element [ "default-class" ] = Element.className;
		}

		if
			( Element [ "default-onclick" ] == null )
		{
			Element [ "default-onclick" ] = Element.onclick;
		}

		var coll = Element.children;

		if
			( coll != null )
		{
			if
				( coll.length == null )
			{
				if
					( coll [ "register" ] == null )
				{
					SetDefaultClasses ( coll );
				}
			}
			else
			{
				var i;

				for
					( i = 0; i < coll.length; i++ )
				{
					var e = coll [ i ];

					if
						( e [ "register" ] == null )
					{
						SetDefaultClasses ( e );
					}
				}
			}
		}
	}

	function SetClass ( Element, Class, Set )
	{
		if
			( Element [ Class ] != null )
		{
			if
				( Set )
			{
				Element.className = Element [ Class ];
			}
			else
			{
				Element.className = Element [ "default-class" ];
			}
		}

		var coll = Element.children;

		if
			( coll != null )
		{
			if
				( coll.length == null )
			{
				if
					( coll [ "register" ] == null )
				{
					SetClass ( coll, Class, Set );
				}
			}
			else
			{
				var i;

				for
					( i = 0; i < coll.length; i++ )
				{
					var e = coll [ i ];

					if
						( e [ "register" ] == null )
					{
						SetClass ( e, Class, Set );
					}
				}
			}
		}
	}

	/*
		All this 'selectedElement' and 'SetElementClassOuter' stuff is a work around to prevent
		IE4 giving a protection violation.
	*/

	var selectedElement;
	var hoveredOnElement;

	function SetElementClassOuter ( Class, Set )
	{
		SetClass ( selectedElement, Class, Set );
	}

	function SetElementClass ( Element, Class, Set )
	{
		
	//	Util.TRACE( "Set Element Class "+Class+"="+Set+"\r\n");
	//	Util.TRACE( Element.innerText );
	//	Util.Trace("\r\n----------------------\r\n");

		var c = "SetElementClassOuter ( '" + Class + "', " + Set + " );";

		selectedElement = Element;

		window.eval ( c );
	}

	

	function PerformElementHover ( elem )
	{
	//	Util.TRACE( "Element Hover\r\n");
		if
			(hoveredOnElement != null )
		{
			// Util.TRACE( "element needs unhovering\r\n");

			if (!hoveredOnElement.contains( elem ))
			{
				// Util.TRACE( "forced unhover\r\n");
				SetElementClass ( hoveredOnElement, "class-hover", false );
				SetElementClass ( hoveredOnElement, "class-down", false );
			}
		}
		
		
		if
			( elem [ "state-enabled" ] )
		{
			if
				( (event == null ) || (! elem.contains ( event.fromElement )) )
			{
				SetElementClass ( elem, "class-hover", true );
				hoveredOnElement = elem;
			}
		}
	}

	function PerformElementUnHover (elem)
	{
		//Util.TRACE( "Element UnHover\r\n");

		if
			( elem [ "state-enabled" ] )
		{
			if
				( ! elem.contains ( event.toElement ) )
			{
				
				if
					(hoveredOnElement == elem)
				{
					hoveredOnElement == null;
				}
				SetElementClass ( elem, "class-hover", false );
				SetElementClass ( elem, "class-down", false );
			}
		}

		if
			( elem [ "scroll-target" ] != null )
		{
			ElementStopScroll ( elem );
		}
	}
	
	function ElementUnHover()
	{
		PerformElementUnHover( this );
	}
	
	function ElementHover ()
	{
		PerformElementHover( this );
	}


	function SearchForwardForAttribute( collection, element, attribute )
	{
		// search forward with the collection for an element with the given 
		// attribute.

		var foundCurrent = 0;
		if
			(element == null)
		{
			// find the first in the collection
			for (var i = 0; i< collection.length; i++ )
			{
				var item = collection.item(i);
				if
					(item.getAttribute( attribute ) != null )
				{
					return item;
				}
			}
			return null;
		}

		for (var i = 0; i< collection.length; i++ )
		{
			var item = collection.item(i);
			if
				(item == element) 
			{
				foundCurrent = 1;
			}
			else if
				(foundCurrent==1)
			{
				if
					(item.getAttribute( attribute ) != null )
				{
					return item;
				}
			}
		}
		return null;
	}

	function SearchBackForAttribute( collection, element, attribute )
	{

		var result = null;
		for (var i = 0; i< collection.length; i++ )
		{
			var item = collection.item(i);
			if
				(item == element )
			{
				return result;
			}
			else if
				(item.getAttribute( attribute ) != null )
			{
				result = item;
			}
		};

		return null;
	}

	function onScreen(e) {
	   // Test whether the supplied element is visible.
	   var rp = e.offsetParent;
	   if (rp == null)
		  return false;
	   var pleft = e.offsetLeft;
	   var ptop = e.offsetTop;
	   while (true) {
		  if (!((pleft >= rp.scrollLeft) &&
				(pleft <= rp.scrollLeft + rp.clientWidth) &&
				(ptop >= rp.scrollTop) &&
				(ptop <= rp.scrollTop + rp.clientHeight)))
			 return false;
		  pleft += rp.offsetLeft - rp.scrollLeft ;
		  ptop += rp.offsetTop - rp.scrollTop;
		  rp = rp.offsetParent;
		  if (rp == null)
			 return true;
	   }
	}

	function BottomOnScreen(e) {
	   // Test whether the supplied element is visible.
	   var rp = e.offsetParent;
	   if (rp == null)
		  return false;
	   var pleft = e.offsetLeft;
	   var ptop = e.offsetTop;
	   ptop += e.offsetHeight;
	   while (true) {
		  if (!((pleft >= rp.scrollLeft) &&
				(pleft <= rp.scrollLeft + rp.clientWidth) &&
				(ptop >= rp.scrollTop) &&
				(ptop <= rp.scrollTop + rp.clientHeight)))
			 return false;
		  pleft += rp.offsetLeft - rp.scrollLeft ;
		  ptop += rp.offsetTop - rp.scrollTop;
		  rp = rp.offsetParent;
		  if (rp == null)
			 return true;
	   }
	}

	var LeftRightActive = 1;
	var TabKeyUsed      = 0;

	function BrowseListKeyHandler( code, collection, attribute )
	{
	//	Util.TRACE(" Code is "+code );
		if
			(code == 40 )
		{
			LeftRightActive = 1;
			
			var NewElem = SearchForwardForAttribute( collection, hoveredOnElement, attribute )
			
			if
				(NewElem != null)
			{
				PerformElementHover( NewElem );
				if (!BottomOnScreen(NewElem))
				{
					NewElem.scrollIntoView(false);
				}
			}
			else
			{

				if
					(!UpdatePending())
				{
					DoGetMoreDown("InnerDiv");
				}

			}	
			event.returnValue = false;
			event.cancelBubble = true;
			
		}
		else if
			(code == 38)
		{

			LeftRightActive = 1;
			var NewElem = null;
			if
				( hoveredOnElement!=null)
			{
				NewElem = SearchBackForAttribute( collection, hoveredOnElement, attribute )
			}
			else
			{
				NewElem = SearchForwardForAttribute( collection, null, attribute )
			}
			if
				(NewElem != null)
			{
				PerformElementHover( NewElem );
				if (!onScreen(NewElem))
				{
					NewElem.scrollIntoView();
				}
				event.returnValue = false;
				event.cancelBubble = true;

			}
			else
			{
				if
					(!UpdatePending())
				{
					DoGetMoreUp("InnerDiv");
				}
				event.returnValue = false;
				event.cancelBubble = true;
				
			}
		}
		else if
			(code == 37)
		{
			if (LeftRightActive) GlobalGoBack();
		}
		else if
			(
				((code == 39) && (LeftRightActive)) ||
				((code == 13) && (TabKeyUsed == 0))
			) 
		{
			if
				(hoveredOnElement != null)
			{
				if
					(hoveredOnElement.onclick != null )
				{
					var elInput = document.all [ "Stem" ];
					if ( elInput != null ) {
						if ( document.activeElement == elInput ) {
							return true;
						}
					}
					hoveredOnElement.click();
				}
				else
				{
					var NewElem = SearchForwardForAttribute( hoveredOnElement.all, null, "IsListClick" );
					if
						(NewElem != null)
					{
						NewElem.click();
					}
				}
			}

			if ( code != 13 ) {
				event.returnValue = false;
				event.cancelBubble = true;
			}
		}
		else if
			(code == 9)
		{
			TabKeyUsed = 1;
		}
		else
		{
			LeftRightActive = 0;
		}
	}

	function ElementDown ()
	{
		if
			( this [ "state-enabled" ] )
		{
			SetElementClass ( this, "class-down", true );

			if
				( this [ "scroll-target" ] != null )
			{
				if
					( this [ "onclick" ] == null )
				{
					ElementStartScroll ( this );
				}
			}
		}
	}

	function ElementUnDown ()
	{
		if
			( this [ "state-enabled" ] )
		{
			if
				( this [ "register" ] != "item" )
			{
				SetElementClass ( this, "class-down", false );
			}
		}

		if
			( this [ "scroll-target" ] != null )
		{
			ElementStopScroll ( this );
		}

		if
			( this [ "toggle" ] != null )
		{
			var t = this [ "toggle" ];

			if
				( t == 1 )
			{
				this [ "toggle" ] = 0;

				SetElementClass ( this, "class-toggle", false );

				SetScrollButtons ();
			}
			else
			{
				this [ "toggle" ] = 1;

				SetElementClass ( this, "class-toggle", true );

				SetScrollButtons ();
			}
		}
	}

	function ElementSelectStart ()
	{
		return false;
	}

	function ElementDisable ( e )
	{
		e [ "state-enabled" ] = 0;
		e.onclick = null;

		SetElementClass ( e, "class-disabled", true );
	}

	function ElementEnable ( e )
	{
		SetElementClass ( e, "class-disabled", false );

		e [ "state-enabled" ] = 1;
		e.onclick = e [ "default-onclick" ];
	}

	function SetElementTypeStatus ( Type, Set )
	{
		if
			( m_ElementTypes [ Type ] != null )
		{
			var elements = m_ElementTypes [ Type ];

			for
				( var n in elements )
			{
				var e = elements [ n ];

				if
					( Set )
				{
					e [ "logical-enabled" ] = 1;

					ElementEnable ( e );
				}
				else
				{
					e [ "logical-enabled" ] = 0;

					ElementDisable ( e );
				}
			}
		}
	}

	function DisableAll ( Type )
	{
		for
			( var type in m_ElementTypes )
		{
			if
				( ( Type == null ) || ( Type == type ) )
			{
				var elements = m_ElementTypes [ type ];

				for
					( var n in elements )
				{
					ElementDisable ( elements [ n ] );
				}
			}
		}
	}

	function EnableAll ( Type )
	{
		for
			( var type in m_ElementTypes )
		{	
			if
				( ( Type == null ) || ( Type == type ) )
			{
				var elements = m_ElementTypes [ type ];

				for
					( var n in elements )
				{
					var e = elements [ n ];

					if
						( e [ "logical-enabled" ] == null )
					{
						ElementEnable ( e );
					}
					else
					{
						if
							( e [ "logical-enabled" ] )
						{
							ElementEnable ( e );
						}
					}
				}
			}
		}
	}

	function EnableType ( Type ) { SetElementTypeStatus ( Type, true ); }
	function DisableType ( Type ) { SetElementTypeStatus ( Type, false ); }

	var m_ElementTypes = new Array();

	function AddBindings ( coll )
	{	
		var i;
		var n = 0;

		for
			( i = 0; i < coll.length; i++ )
		{
			var e = coll [ i ];

			if
				( e.register != null )
			{
				var types = e.register.split ( ';' );

				for
					( var j in types )
				{
					var type = types [ j ];

					if
						( m_ElementTypes [ type ] == null )
					{
						m_ElementTypes [ type ] = new Array ();
					}

					var n = m_ElementTypes [ type ].length;

					m_ElementTypes [ type ] [ n++ ] = e;
				}

				SetDefaultClasses ( e );

				if
					( e [ "state-enabled" ] == null )
				{
					e [ "state-enabled" ] = 1;
				}

				e.onmouseover = ElementHover;
				e.onmouseout = ElementUnHover;
				e.onselectstart = ElementSelectStart;
				e.onmousedown = ElementDown;
				e.onmouseup = ElementUnDown;
			}
		}

		/*

		var s = "";

		for
			( var type in m_ElementTypes )
		{
			s += "TYPE:" + type + " [";

			s += m_ElementTypes [ type ].length;

			s += "]\r";
		}

		alert ( s );

		*/
	}

