 /****************************************************************************
  * Code from comp.lang.javascript and (c) Michael Winter:
  * http://groups-beta.google.com/group/comp.lang.javascript/msg/3f287a2f20de1b10
  ***************************************************************************/

var fade = (function() {
	var global = this,
	    objects = new Hashtable(),
	    /* If it's determined that the host supports the application of an
	     * opacity value either through opacity, or a proprietary property, this
	     * variable will hold that property name.
	     *
	     * This should be left undefined. If it's not set when setOpacity is
	     * called, hosts that implement DOM 2 Style, but not opacity, won't
	     * attempt to modify the value.
	     */
	    property;

	function getOpacity(object) {var style;
		if(object.filters) {
			getOpacity = function(object) {
				return object.filters['DXImageTransform.Microsoft.Alpha'].Opacity;
			};
		} else if(global.getComputedStyle
		 && (style = global.getComputedStyle(object, null))
		 && style.getPropertyValue
		 && (style.getPropertyValue(property = 'opacity')
		 || style.getPropertyValue(property = '-moz-opacity')
		 || style.getPropertyValue(property = '-khtml-opacity')))
		{
			getOpacity = function(object) {
				return parseFloat(
					global.getComputedStyle(object, null).getPropertyValue(property)
				) * 100;
			};
			style = null;
		} else {
			getOpacity = function() {return 100;};
		}
		return getOpacity(object);
	}

	function setOpacity(object, opacity) {
		if(object.filters) {
			setOpacity = function(object, opacity) {
				object.filters['DXImageTransform.Microsoft.Alpha'].Opacity = opacity;
			};
		/* If the property variable hasn't been set, an earlier call to getOpacity
		 * determined that CSS opacity values aren't supported by the host.
		 */
		} else if(property && object.style && object.style.setProperty) {
			setOpacity = function(object, opacity) {
				object.style.setProperty(property, opacity / 100, '');
			};
		} else {
			setOpacity = function() {};
		}
		setOpacity(object, opacity);
	}

	return function(object, targetOpacity, rate, delta) {
		var opacity = getOpacity(object);

		function stepFade() {var onTarget;
			opacity += delta;
			onTarget = (0 < delta) ?
				opacity >= targetOpacity
			: opacity <= targetOpacity;
			if(onTarget) {
				opacity = targetOpacity;
				objects.remove(object);
			}
			setOpacity(object, opacity);
			if(!onTarget) {objects.put(object, setTimeout(stepFade, rate));}
		}
		/* This function relies on the closure produced by the inner function
		 * above. Though the closure could be preserved by exposing the inner
		 * function publicly, it would cause clashes should the effect be active
		 * on more than one element simultaneously. As such, any host that is
		 * unable to accept a function argument to the setTimeout method will
		 * silently fail.
		 */
		stepFade.toString = function() {return ';';};

		/* If the element is already fading, stop the effect. */
		if(objects.containsKey(object)) {clearTimeout(objects.get(object));}
		/* This line prevents a bug in Gecko-based browsers where artifacts
		 * appear when the opacity reaches 100%.
		 */
		if(100 == targetOpacity) {--targetOpacity;}
		if(opacity > targetOpacity) {delta = -delta;}
		if(delta && rate) {objects.put(object, setTimeout(stepFade, rate));}
	}
})();
