jQuery.noConflict();
	function dumpProps(obj, parent) {
		// Go through all the properties of the passed-in object
		for (var i in obj) {
			// if a parent (2nd parameter) was passed in, then use that to
			// build the message. Message includes i (the object's property name)
			// then the object's property value on a new line
			if (parent) { var msg = parent + "." + i + "\n" + obj[i]; } else { var msg = i + "\n" + obj[i]; }
			// Display the message. If the user clicks "OK", then continue. If they
			// click "CANCEL" then quit this level of recursion
			if (!confirm(msg)) { return; }
			// If this property (i) is an object, then recursively process the object
			if (typeof obj[i] == "object") {
				if (parent) { dumpProps(obj[i], parent + "." + i); } else { dumpProps(obj[i], i); }
			}
		}
	}
	
	function  printProps(obj, objName) {
		var output = "" ;
		for (var prop in obj) {
			output += objName + "." + prop + " = " + obj[prop] + "\n" ;
		}
		return output ;
	}


            
	var TIME_INTERVAL = 8000;
	var TIME_REMAINING = 8000;
	var TIME_STARTED = new Date();
	var ANIMATING = false;
	var scrollState = {
		sliderInitValue: 0,
		sliderMinHeight: 15,
		sliderHeight: 5,
		sliderMin: 0,
		sliderMax: 0,
		sliderHasMinHeight: 0
	};
	function resumeScroller() {
		if (!ANIMATING)
			return;
		TIME_STARTED = new Date();
		//console?console.log('resume ' + TIME_REMAINING):void(0);
		setupScroll(false);
	}
	function pauseScroller() {
		//console?console.log('pause ' + TIME_REMAINING):void(0);
		jQuery('#scroller').stop(true);
		if (TIME_REMAINING>0) {
			var curtime = new Date();
			TIME_REMAINING = TIME_REMAINING - (curtime.getTime() - TIME_STARTED.getTime());
			//TIME_STARTED = curtime;
		}
	}

	function setupScroll(atbottom) {
		var scroller = jQuery('#scroller');
		var sbh = jQuery('#scrollbox').height();
		var srh = jQuery('#scroller').height();
		if (atbottom) {
			scroller.css('top', sbh);
		}
		//scroller.slideDown();
		scroller.animate({
			top: '0px',
			easing: false
		},
		TIME_REMAINING,
		function() {
			ANIMATING = false;
			//setTimeout('startScroller()', 1000);
		});
		ANIMATING = true;
	}

	function startScroller() {
//                console!=undefined?console.log('start ' + TIME_REMAINING):void(0);
		TIME_STARTED = new Date();
		
		TIME_REMAINING = TIME_INTERVAL;
		setupScroll(true);
	}

	function slideHandler(event, ui, move) {
		ANIMATING = false;
		pauseScroller();
		var pos = jQuery('#scrollhandle').position();
		var handleh = jQuery('#scrollhandle').height();
		
		var sbh = jQuery('#scrollbar').height();
		var sbtop = jQuery('#scrollbar').position().top;
		var value = pos.top - sbtop; 
		//dumpProps(jQuery('#history_scroll').position());
		//dumpProps(jQuery.browser);
		if (jQuery.browser.opera) {
			//var correction = jQuery('#history_scroll').position().top;
			sbh = document.getElementById('scrollbar').scrollHeight;
			handleh =  document.getElementById('scrollhandle').scrollHeight;
		}
		var handlefix = 0;
		if (scrollState.sliderHasMinHeight) {
			// slider can't reach bottom because of slider handle, compensate for it's height
			handlefix = (value/(scrollState.sliderMax)) * handleh;
		}
		//value += handlefix;
		
		if (move != undefined && move != 0) {
			value += move;
			// check if within bounds
			if (value < 0) {
				value = 0;
			} else if (value > sbh - handleh) {
				value = sbh - handleh;
			}
			// update handle position
			jQuery('#scrollhandle').css('top', value + 'px');
		}

		var percent = (value + handlefix) / sbh  ;
		var dbginfo = 'scrollhandle.top=' + pos.top + '  val=' + value + ' scrollbarheight=' + sbh + '--' + sbtop + ' sliderMax=' + scrollState.sliderMax + ' % = ' +(-(percent)*100);
		//console.log(dbginfo);
		//alert(dbginfo);
		jQuery('#scroller').css('top', -(percent)*jQuery('#scroller').height() + 'px');

	}

	function handleMouseWheel(event, delta) {
		if (delta>0) {
			// scroll up
			slideHandler(null, null, -5);
		} else {
			//scroll down
			slideHandler(null, null, 5);
		}
		return false;
	}

	jQuery(document).ready(function(){
		jQuery('#scrollhandle').draggable(
			{
				axis: 'y',
				containment: 'parent',
				drag: slideHandler,
				start: function() {
					ANIMATING = false;
					pauseScroller();
				},
				stop: function() {
					slideHandler(null, null);                          
					//setTimeout('startScroller()', TIME_INTERVAL);
				}
			}
		);
		//
		// calculate proper height of slider handle
		var sbh = jQuery('#scrollbox').height();
		var srh = jQuery('#scroller').height();
		var sbarh = jQuery('#scrollbar').height();
		// the above don't work in Opera
		if (jQuery.browser.opera) {
			sbh = document.getElementById('history_scroll').scrollHeight;
			srh = document.getElementById('scroller').scrollHeight;
			sbarh = document.getElementById('scrollbar').scrollHeight;
		}

		//alert(srh + ' - ' + sbh); 
		if (srh <= sbh + 20) {
			scrollState.sliderHeight = sbarh;
			//scrollState.sliderMax = 0;
			//jQuery('#scrollbardiv').hide();
		} else {
			scrollState.sliderHeight = sbh * (sbh/srh);
			scrollState.sliderMax = 100 - ((sbh)/srh)*100;
			if (scrollState.sliderHeight < scrollState.sliderMinHeight) {
				scrollState.sliderHeight = scrollState.sliderMinHeight;
				scrollState.sliderHasMinHeight = 1;
				scrollState.sliderMax = 100 - ((sbh-scrollState.sliderMinHeight)/srh)*100;

			}
			//scrollState.sliderMax = ((srh)/sbh)*100;
			//scrollState.sliderInitValue = sbh / (srh - sbh);
		}
		////now initialize mouse wheel support
		jQuery('#scrollbar').bind('mousewheel', handleMouseWheel);
		jQuery('#scrollbox').bind('mousewheel', handleMouseWheel);
		
		jQuery('#scrollhandle').css('height', scrollState.sliderHeight);
		startScroller();
	});
