function ImageFlow ()
{
	/* Setting option defaults */
	this.defaults =
	{
		ImageFlowID:        'imageflow',    /* Default id of the ImageFlow container */
		preloadImages:      true,           /* Toggles loading bar (false: requires img attributes height and width) */
		reflections:        true,           /* Toggle reflections */
		reflectionP:        0.5,            /* Height of the reflection in % of the source image */
		reflectionPNG:      false,          /* Toggle reflect2.php or reflect3.php */
		reflectionGET:      '',             /* Pass variables via the GET method to the reflect_.php script */
		imageFocusMax:      4,              /* Max number of images on each side of the focussed one */
		imageFocusM:        1.0,            /* Multiplicator for the focussed image size in percent */
		imageCursor:        'default',      /* Cursor type for all images - default is 'default' */
		startID:            16,              /* Glide to this image ID on startup */
		startAnimation:     false,          /* Animate images moving in from the right on startup */
		slider:             true,           /* Toggle slider */
		sliderCursor:       'e-resize',     /* Slider cursor type - default is 'default' */
		sliderWidth:        14,             /* Width of the slider in px */
		xStep:              150,            /* Step width on the x-axis in px */
		captions:           true,           /* Toggle captions */
		opacity:            false,          /* Toggle image opacity */
		opacityArray:       [10,8,6,4,2],   /* Image opacity (range: 0 to 10) first value is for the focussed image */
		onClick:            function() { document.location = this.url; }   /* Onclick behaviour */
	};

	/* Closure for this */
	var thisObject = this;

	/* Initiate ImageFlow */
	this.init = function (options)
	{
		/* Evaluate options */
		var optionsArray = new Array('ImageFlowID', 'preloadImages', 'reflections', 'reflectionP', 'reflectionPNG', 'reflectionGET', 'imageFocusMax', 'imageFocusM', 'imageCursor', 'startID', 'startAnimation', 'slider', 'sliderCursor', 'sliderWidth', 'xStep', 'captions', 'opacity', 'opacityArray', 'onClick');
		var max = optionsArray.length;
		for (var i = 0; i < max; i++)
		{
			var name = optionsArray[i];
			this[name] = (options !== undefined && options[name] !== undefined) ? options[name] : thisObject.defaults[name];
		}

		/* Try to get ImageFlow div element */
		var ImageFlowDiv = document.getElementById(thisObject.ImageFlowID);
		if(ImageFlowDiv)
		{
			/* Set it global within the ImageFlow scope */
			ImageFlowDiv.style.visibility = 'visible';
			this.ImageFlowDiv = ImageFlowDiv;

			/* Try to create XHTML structure */
			if(this.createStructure())
			{
				this.imagesDiv = document.getElementById(thisObject.ImageFlowID+'_images');
				this.captionDiv = document.getElementById(thisObject.ImageFlowID+'_caption');
				this.scrollbarDiv = document.getElementById(thisObject.ImageFlowID+'_scrollbar');
				this.sliderDiv = document.getElementById(thisObject.ImageFlowID+'_slider');
			
				this.indexArray = [];
				this.current = 0;
				this.imageID = 0;
				this.target = 0;
				this.memTarget = 0;
				this.firstRefresh = true;
				this.firstCheck = true;
				this.busy = false;

				/* Toggle Slider */
				if(this.slider === false)
				{
					this.scrollbarDiv.style.display = 'none';
				}

				/* Set height of the ImageFlow container and center the loading bar */
				var width = this.ImageFlowDiv.offsetWidth;
				var height = Math.round(width * 0.5085);
				document.getElementById(thisObject.ImageFlowID+'_loading_txt').style.paddingTop = ((height * 0.5) -22) + 'px';
				ImageFlowDiv.style.height = height + 'px';

				/* Init loading progress */
				this.loadingProgress();
			}
		}
	};

	/* Create HTML Structure */
	this.createStructure = function()
	{
		/* Create images div container */
		var imagesDiv = document.createElement('div');		
		imagesDiv.setAttribute('id',thisObject.ImageFlowID+'_images');
		imagesDiv.setAttribute('class','images');
		imagesDiv.setAttribute('className','images');

		/* Shift all images into the images div */
		var node = null;
		var max = this.ImageFlowDiv.childNodes.length;
		for(var index = 0; index < max; index++)
		{ 
			node = this.ImageFlowDiv.childNodes[index];
			if (node && node.nodeType == 1 && node.nodeName == 'IMG')
			{
				/* Add 'reflect.php?img=' */
				if(thisObject.reflections === true)
				{
					var version = '2';
					if(thisObject.reflectionPNG === true)
					{
						version = '3';
					}
					var src = node.getAttribute('src',2);
					src =  '/reflect'+version+'.php?img='+src+thisObject.reflectionGET;
					node.setAttribute('src',src);
				}

				var imageNode = node.cloneNode(true);
				imagesDiv.appendChild(imageNode);
			}
		}
					
		/* Create loading text container */
		var loadingP = document.createElement('p');
		var loadingText = document.createTextNode(' ');
		loadingP.setAttribute('id',thisObject.ImageFlowID+'_loading_txt');
		loadingP.appendChild(loadingText);
		
		/* Create loading div container */
		var loadingDiv = document.createElement('div');
		loadingDiv.setAttribute('id',thisObject.ImageFlowID+'_loading');
		loadingDiv.setAttribute('class','loading');
		loadingDiv.setAttribute('className','loading');
			
		/* Create loading bar div container inside the loading div */
		var loadingBarDiv = document.createElement('div');
		loadingBarDiv.setAttribute('id',thisObject.ImageFlowID+'_loading_bar');
		loadingBarDiv.setAttribute('class','loading_bar');
		loadingBarDiv.setAttribute('className','loading_bar');
		loadingDiv.appendChild(loadingBarDiv);

		/* Create captions div container */
		var captionDiv = document.createElement('div');
		captionDiv.setAttribute('id',thisObject.ImageFlowID+'_caption');
		captionDiv.setAttribute('class','caption');
		captionDiv.setAttribute('className','caption');

		/* Create slider div container inside the scrollbar div */
		var scrollbarDiv = document.createElement('div');
		scrollbarDiv.setAttribute('id',thisObject.ImageFlowID+'_scrollbar');
		scrollbarDiv.setAttribute('class','scrollbar');
		scrollbarDiv.setAttribute('className','scrollbar');
		var sliderDiv = document.createElement('div');
		sliderDiv.setAttribute('id',thisObject.ImageFlowID+'_slider');
		sliderDiv.setAttribute('class','slider');
		sliderDiv.setAttribute('className','slider');
		scrollbarDiv.appendChild(sliderDiv);
		
		/* Update document structure and return true on success */
		var success = false;
		if (thisObject.ImageFlowDiv.appendChild(imagesDiv) && 
			thisObject.ImageFlowDiv.appendChild(loadingP) && 
			thisObject.ImageFlowDiv.appendChild(loadingDiv) && 
			thisObject.ImageFlowDiv.appendChild(captionDiv) && 
			thisObject.ImageFlowDiv.appendChild(scrollbarDiv))
		{
			/* Remove image nodes outside the images div */
			for(index = 0; index < max; index++)
			{ 
				node = this.ImageFlowDiv.childNodes[index];
				if (node && node.nodeType == 1 && node.nodeName == 'IMG')
				{
					this.ImageFlowDiv.removeChild(node);
				}				
			}
			success = true;
		}
		return success;
	};


	/* Manages loading progress and calls the refresh function */
	this.loadingProgress = function()
	{
		var p = thisObject.loadingStatus();
		if(p < 100 || thisObject.firstCheck === true && thisObject.preloadImages === true)
		{
			/* Insert a short delay if the browser loads rapidly from its cache */
			if(thisObject.firstCheck === true && p == 100)
			{
				thisObject.firstCheck = false;
				window.setTimeout(thisObject.loadingProgress, 100);
			}
			else
			{
				window.setTimeout(thisObject.loadingProgress, 40);
			}
		}
		else
		{
			/* Hide loading elements */
			document.getElementById(thisObject.ImageFlowID+'_loading_txt').style.display = 'none';
			document.getElementById(thisObject.ImageFlowID+'_loading').style.display = 'none';

			/* Refresh ImageFlow on window resize - delay adding this event for the IE */
			window.setTimeout(thisObject.addResizeEvent, 1000);
						
			/* Fixes the back button issue */
			window.onunload = function()
			{
				document = null;
			};

			/* Initialize Mouse and key support */
			thisObject.initMouseWheel();
			thisObject.MouseDrag.init();
			thisObject.Key.init();

			/* Call refresh function */
			thisObject.refresh(true);

			/* Unhide scrollbar elements */
			document.getElementById(thisObject.ImageFlowID+'_scrollbar').style.visibility = 'visible';

			/* Glide to start image */
			var startID = thisObject.startID-1;
			if (startID < 0 )
			{
				startID = 0;
			}
			if (startID > thisObject.max)
			{
				startID = thisObject.max -1;
			}
			thisObject.glideTo(startID);

			/* Animate images moving in from the right */
			if(thisObject.startAnimation === true)
			{
				thisObject.moveTo(5000);
			}
		}
	};

	
	/* Returns loaded images in percent, sets loading bar width and loading text */
	this.loadingStatus = function()
	{
		var max = thisObject.imagesDiv.childNodes.length;
		var i = 0, completed = 0;
		var image = null;
		for(var index = 0; index < max; index++)
		{
			image = thisObject.imagesDiv.childNodes[index];
			if (image && image.nodeType == 1 && image.nodeName == 'IMG')
			{
				if (image.complete === true)
				{
					completed++;
				}
				i++;
			}
		}
		var finished = Math.round((completed/i)*100);
		var loadingBar = document.getElementById(thisObject.ImageFlowID+'_loading_bar');
		loadingBar.style.width = finished+'%';

		var loadingP = document.getElementById(thisObject.ImageFlowID+'_loading_txt');
		var loadingTxt = document.createTextNode('Загрузка изображений '+completed+'/'+i);
		loadingP.replaceChild(loadingTxt,loadingP.firstChild);
		return finished;
	};


	/* Cache EVERYTHING that only changes on refresh or resize of the window */
	this.refresh = function()
	{
		/* Cache global variables */
		this.iWidth = thisObject.imagesDiv.offsetWidth;
		this.maxHeight = Math.round(thisObject.iWidth * 0.51);
		this.maxFocus = thisObject.imageFocusMax * thisObject.xStep;
		this.size = thisObject.iWidth * 0.5;
		this.scrollbarWidth = Math.round(thisObject.iWidth * 0.6);
		this.sliderWidth = thisObject.sliderWidth * 0.5;
		
		/* Change imageflow div properties */
		thisObject.ImageFlowDiv.style.height = thisObject.maxHeight + 'px';
		
		/* Change images div properties */
		thisObject.imagesDiv.style.height = Math.round(thisObject.iWidth * 0.338) + 'px';

		/* Change captions div properties */
		thisObject.captionDiv.style.width = thisObject.iWidth + 'px';
		thisObject.captionDiv.style.marginTop = Math.round(thisObject.iWidth * 0.03) + 'px';

		/* Change scrollbar div properties */
		thisObject.scrollbarDiv.style.width = thisObject.scrollbarWidth + 'px';
		thisObject.scrollbarDiv.style.marginTop = Math.round(thisObject.iWidth * 0.02) + 'px';
		thisObject.scrollbarDiv.style.marginLeft = Math.round(thisObject.iWidth * 0.2) + 'px';
		
		/* Set slider attributes */
		thisObject.sliderDiv.style.cursor = thisObject.sliderCursor;
		thisObject.sliderDiv.onmousedown = function () { thisObject.MouseDrag.start(this); return false;};
		
		/* Set the reflection multiplicator */
		var multi = (thisObject.reflections === true) ? thisObject.reflectionP + 1 : 1;
		
		/* Set image attributes */
		var max = thisObject.imagesDiv.childNodes.length;
		var i = 0;
		var image = null;
		for (var index = 0; index < max; index++)
		{ 
			image = thisObject.imagesDiv.childNodes[index];
			if(image !== null && image.nodeType == 1 && image.nodeName == 'IMG')
			{
				this.indexArray[i] = index;
				
				/* Set image attributes to store values */
				image.url = image.getAttribute('longdesc');
				image.xPosition = (-i * thisObject.xStep);
				image.i = i;
				
				/* Add width and height as attributes only once */
				if(thisObject.firstRefresh)
				{
					if(image.getAttribute('width') !== null && image.getAttribute('height') !== null)
					{
						image.w = image.getAttribute('width');
						image.h = image.getAttribute('height') * multi;
					}
					else{
						image.w = image.width;
						image.h = image.height;
					}
				}
				/* Check source image format. Get image height minus reflection height! */
				if((image.w) > (image.h / (thisObject.reflectionP + 1))) 
				{
					/* Landscape format */
					image.pc = 118;
					image.pcMem = 118;
				}
				else
				{
					/* Portrait and square format */
					image.pc = 100;
					image.pcMem = 100;
				}

				/* Set image cursor type */
				image.style.cursor = thisObject.imageCursor;
				i++;
			}
		}
		this.max = thisObject.indexArray.length;
		
		/* Reset variable */
		if(thisObject.firstRefresh)
		{
			thisObject.firstRefresh = false;
		}

		/* Display images in current order */
		thisObject.moveTo(thisObject.current);
		thisObject.glideTo(thisObject.imageID);
	};
	

	/* Main animation function */
	this.moveTo = function(x)
	{
		this.current = x;
		this.zIndex = thisObject.max;

		/* Main loop */
		for (var index = 0; index < thisObject.max; index++)
		{
			var image = thisObject.imagesDiv.childNodes[thisObject.indexArray[index]];
			var currentImage = index * -thisObject.xStep;

			/* Don't display images that are not conf_focussed */
			if ((currentImage + thisObject.maxFocus) < thisObject.memTarget || (currentImage - thisObject.maxFocus) > thisObject.memTarget)
			{
				image.style.visibility = 'hidden';
				image.style.display = 'none';
			}
			else 
			{
				var z = Math.sqrt(10000 + x * x) + 100;
				var xs = x / z * thisObject.size + thisObject.size;

				/* Still hide images until they are processed, but set display style to block */
				image.style.display = 'block';
			
				/* Process new image height and image width */
				var newImageH = (image.h / image.w * image.pc) / z * thisObject.size;
				var newImageW = 0;
				switch (newImageH > thisObject.maxHeight)
				{
					case false:
						newImageW = image.pc / z * thisObject.size;
						break;

					default:
						newImageH = thisObject.maxHeight;
						newImageW = image.w * newImageH / image.h;
						break;
				}
				var newImageTop = (thisObject.iWidth * 0.34 - newImageH) + ((newImageH / (thisObject.reflectionP + 1)) * thisObject.reflectionP);

				/* Set new image properties */
				image.style.left = xs - (image.pc / 2) / z * thisObject.size + 'px';
				if(newImageW && newImageH)
				{ 
					image.style.height = newImageH + 'px'; 
					image.style.width = newImageW + 'px'; 
					image.style.top = newImageTop + 'px';
				}
				image.style.visibility = 'visible';

				/* Set image layer through zIndex */
				switch ( x < 0 )
				{
					case true:
						this.zIndex++;
						break;

					default:
						this.zIndex = thisObject.zIndex - 1;
						break;
				}
				
				/* Change zIndex and onclick function of the focussed image */
				switch ( image.i == thisObject.imageID )
				{
					case false:
						image.onclick = function() { thisObject.glideTo(this.i);};
						break;

					default:
						this.zIndex = thisObject.zIndex + 1;
						if(image.url !== '')
						{
							image.onclick = thisObject.onClick;
						}
						break;
				}
				image.style.zIndex = thisObject.zIndex;
			}
			x += thisObject.xStep;
		}
	};


	/* Initializes image gliding animation */
	this.glideTo = function(imageID)
	{	
		/* Calculate new image position target */
		var x = -imageID * thisObject.xStep;
		this.target = x;
		this.memTarget = x;
		this.imageID = imageID;

		/* Display new caption */
		var caption = thisObject.imagesDiv.childNodes[imageID].getAttribute('alt');
		if (caption === '' || thisObject.captions === false)
		{
			caption = '&nbsp;'; 
		}
		thisObject.captionDiv.innerHTML = caption;

		/* Set scrollbar slider to new position */
		if (thisObject.MouseDrag.busy === false)
		{
			this.newSliderX = (imageID * thisObject.scrollbarWidth) / (thisObject.max-1) - thisObject.MouseDrag.newX;
			thisObject.sliderDiv.style.marginLeft = (thisObject.newSliderX - thisObject.sliderWidth) + 'px';
		}
		
		/* Only process if opacity or a multiplicator for the focussed image has been set */
		if(thisObject.opacity === true || thisObject.imageFocusM !== thisObject.defaults.imageFocusM)
		{
			/* Set opacity for centered image */
			thisObject.setOpacity(thisObject.imagesDiv.childNodes[imageID], thisObject.opacityArray[0]);
			thisObject.imagesDiv.childNodes[imageID].pc = thisObject.imagesDiv.childNodes[imageID].pc * thisObject.imageFocusM;
			
			/* Set opacity for the other images that are displayed */
			var opacityValue = 0;
			var rightID = 0;
			var leftID = 0;
			var last = thisObject.opacityArray.length;

			for (var i = 1; i < (thisObject.imageFocusMax+1); i++)
			{
				if((i+1) > last)
				{
					opacityValue = thisObject.opacityArray[last-1];
				}
				else
				{
					opacityValue = thisObject.opacityArray[i];
				}

				rightID = imageID + i;
				leftID = imageID - i;				

				if (rightID < thisObject.max)
				{
					thisObject.setOpacity(thisObject.imagesDiv.childNodes[rightID], opacityValue);
					thisObject.imagesDiv.childNodes[rightID].pc = thisObject.imagesDiv.childNodes[rightID].pcMem;
				}
				if (leftID >= 0)
				{
					thisObject.setOpacity(thisObject.imagesDiv.childNodes[leftID], opacityValue);
					thisObject.imagesDiv.childNodes[leftID].pc = thisObject.imagesDiv.childNodes[leftID].pcMem;
				}
			}
		}

		/* animate gliding to new x position */
		if (thisObject.busy === false)
		{
			window.setTimeout(thisObject.animate, 50);
			thisObject.busy = true;
		}
	};

	
	/* animates image gliding */
	this.animate = function()
	{
		switch (thisObject.target < thisObject.current-1 || thisObject.target > thisObject.current+1) 
		{
			case true:
				thisObject.moveTo(thisObject.current + (thisObject.target-thisObject.current)/3);
				window.setTimeout(thisObject.animate, 50);
				thisObject.busy = true;
				break;

			default:
				thisObject.busy = false;
				break;
		}
	};


	/* Set image opacity */
	this.setOpacity = function(object, value)
	{
		if(thisObject.opacity === true)
		{
			object.style.opacity = value/10;
			object.style.filter = 'alpha(opacity=' + value*10 + ')';
		}
	};

	
	/* Initialize mouse wheel support */
	this.initMouseWheel = function()
	{
		if(window.addEventListener)
		{
			thisObject.ImageFlowDiv.addEventListener('DOMMouseScroll', thisObject.eventMouseWheel, false);
		}
		thisObject.ImageFlowDiv.onmousewheel = thisObject.eventMouseWheel;
	};


	/* Event handler for mouse wheel events */
	this.eventMouseWheel = function(event)
	{
		var delta = 0;
		if (!event)
		{
			event = window.event;
		}
		if (event.wheelDelta)
		{
			delta = event.wheelDelta / 120;
		}
		else if (event.detail)
		{
			delta = -event.detail / 3;
		}
		if (delta)
		{
			thisObject.handleMouseWheel(delta);
		}
		if (event.preventDefault)
		{
			event.preventDefault();
		}
		event.returnValue = false;
	};


	/* Handle the wheel angle change (delta) of the mouse wheel */
	this.handleMouseWheel = function(delta)
	{
		var change = false;
		var newImageID = 0;
		if(delta > 0)
		{
			if(thisObject.imageID >= 1)
			{
				newImageID = thisObject.imageID -1;
				change = true;
			}
		}
		else
		{
			if(thisObject.imageID < (thisObject.max-1))
			{
				newImageID = thisObject.imageID +1;
				change = true;
			}
		}

		/* Glide to next (mouse wheel down) / previous (mouse wheel up) image */
		if (change === true)
		{
			thisObject.glideTo(newImageID);
		}
	};

	
	/* MouseDrag */
	this.MouseDrag =
	{
		object: null,
		objectX: 0,
		mouseX: 0,
		newX: 0,
		busy: false,
		
		/* Init mouse event listener */
		init: function() 
		{
			thisObject.addEvent(thisObject.ImageFlowDiv,'mousemove',thisObject.MouseDrag.drag);
			thisObject.addEvent(thisObject.ImageFlowDiv,'mouseup',thisObject.MouseDrag.stop);
			thisObject.addEvent(document,'mouseup',thisObject.MouseDrag.stop);
	
			/* Avoid text and image selection while dragging  */
			thisObject.ImageFlowDiv.onselectstart = function () 
			{
				var selection = true;
				if (thisObject.MouseDrag.busy === true)
				{
					selection = false;
				}
				return selection;
			};
		},

		start: function(o) 
		{
			thisObject.MouseDrag.object = o;
			thisObject.MouseDrag.objectX = thisObject.MouseDrag.mouseX - o.offsetLeft + thisObject.newSliderX;
			
		},

		stop: function()
		{
			thisObject.MouseDrag.object = null;
			thisObject.MouseDrag.busy = false;
		},

		drag: function(e) 
		{
			var posx = 0;
			if (!e)
			{ 
				e = window.event;
			}
			if (e.pageX)
			{
				posx = e.pageX;
			}
			else if (e.clientX)
			{
				posx = e.clientX + document.body.scrollLeft	+ document.documentElement.scrollLeft;
			}
			thisObject.MouseDrag.mouseX = posx;

			if(thisObject.MouseDrag.object !== null)
			{
				var newX = (thisObject.MouseDrag.mouseX - thisObject.MouseDrag.objectX) + thisObject.sliderWidth;

				/* Make sure, that the slider is moved in proper relation to previous movements by the glideTo function */
				if(newX < ( - thisObject.newSliderX))
				{
					newX = - thisObject.newSliderX;
				}
				if(newX > (thisObject.scrollbarWidth - thisObject.newSliderX))
				{
					newX = thisObject.scrollbarWidth - thisObject.newSliderX;
				}
				
				/* Set new slider position */
				var step = (newX + thisObject.newSliderX) / (thisObject.scrollbarWidth / (thisObject.max-1));
				var imageID = Math.round(step);
				thisObject.MouseDrag.newX = newX;
				thisObject.MouseDrag.object.style.left = newX + 'px';
				thisObject.glideTo(imageID);

				thisObject.MouseDrag.busy = true;
			}
		}
	};
	
	/* Key support */
	this.Key =
	{
		/* Init key event listener */
		init: function() 
		{
			document.onkeydown = function(event){ thisObject.Key.handle(event); };
		},

		/* Handle the arrow keys */
		handle: function(event)
		{
			var charCode  = thisObject.Key.get(event);
			switch (charCode)
			{
				/* Right arrow key */
				case 39:
					thisObject.handleMouseWheel(-1);
					break;
				
				/* Left arrow key */
				case 37:
					thisObject.handleMouseWheel(1);
					break;
			}
		},
		
		/* Get the current keycode */
		get: function(event)
		{
			event = event || window.event;
			return event.keyCode;
		}
	};


	/* Adds events */
	this.addEvent = function( obj, type, fn )
	{
		if (obj.addEventListener)
		{
			obj.addEventListener( type, fn, false );
		}
		else if (obj.attachEvent)
		{
			obj["e"+type+fn] = fn;
			obj[type+fn] = function() { obj["e"+type+fn]( window.event ); };
			obj.attachEvent( "on"+type, obj[type+fn] );
		}
	};	

	/* Adds functions to the window.onresize event - can not be done by addEvent */
	this.addResizeEvent = function()
	{
		var otherFunctions = window.onresize;
		if(typeof window.onresize != 'function')
		{
			window.onresize = function()
			{
				thisObject.refresh();
			};
		}
		else
		{
			window.onresize = function(){
				if (otherFunctions)
				{
					otherFunctions();
				}
				thisObject.refresh();
			};
		}
	};
}


/* DOMContentLoaded event handler - by Tanny O'Haley [4] */
var domReadyEvent =
{
	name: "domReadyEvent",
	/* Array of DOMContentLoaded event handlers.*/
	events: {},
	domReadyID: 1,
	bDone: false,
	DOMContentLoadedCustom: null,

	/* Function that adds DOMContentLoaded listeners to the array.*/
	add: function(handler)
	{
		/* Assign each event handler a unique ID. If the handler has an ID, it has already been added to the events object or been run.*/
		if (!handler.$$domReadyID)
		{
			handler.$$domReadyID = this.domReadyID++;

			/* If the DOMContentLoaded event has happened, run the function. */
			if(this.bDone)
			{
				handler();
			}

			/* store the event handler in the hash table */
			this.events[handler.$$domReadyID] = handler;
		}
	},

	remove: function(handler)
	{
		/* Delete the event handler from the hash table */
		if (handler.$$domReadyID)
		{
			delete this.events[handler.$$domReadyID];
		}
	},

	/* Function to process the DOMContentLoaded events array. */
	run: function()
	{
		/* quit if this function has already been called */
		if (this.bDone)
		{
			return;
		}

		/* Flag this function so we don't do the same thing twice */
		this.bDone = true;

		/* iterates through array of registered functions */
		for (var i in this.events)
		{
			this.events[i]();
		}
	},

	schedule: function()
	{
		/* Quit if the init function has already been called*/
		if (this.bDone)
		{
			return;
		}
	
		/* First, check for Safari or KHTML.*/
		if(/KHTML|WebKit/i.test(navigator.userAgent))
		{
			if(/loaded|complete/.test(document.readyState))
			{
				this.run();
			}
			else
			{
				/* Not ready yet, wait a little more.*/
				setTimeout(this.name + ".schedule()", 100);
			}
		}
		else if(document.getElementById("__ie_onload"))
		{
			/* Second, check for IE.*/
			return true;
		}

		/* Check for custom developer provided function.*/
		if(typeof this.DOMContentLoadedCustom === "function")
		{
			/* if DOM methods are supported, and the body element exists (using a double-check 
			including document.body, for the benefit of older moz builds [eg ns7.1] in which 
			getElementsByTagName('body')[0] is undefined, unless this script is in the body section) */
			if(typeof document.getElementsByTagName !== 'undefined' && (document.getElementsByTagName('body')[0] !== null || document.body !== null))
			{
				/* Call custom function. */
				if(this.DOMContentLoadedCustom())
				{
					this.run();
				}
				else
				{
					/* Not ready yet, wait a little more. */
					setTimeout(this.name + ".schedule()", 250);
				}
			}
		}
		return true;
	},

	init: function()
	{
		/* If addEventListener supports the DOMContentLoaded event.*/
		if(document.addEventListener)
		{
			document.addEventListener("DOMContentLoaded", function() { domReadyEvent.run(); }, false);
		}

		/* Schedule to run the init function.*/
		setTimeout("domReadyEvent.schedule()", 100);

		function run()
		{
			domReadyEvent.run();
		}
		
		/* Just in case window.onload happens first, add it to onload using an available method.*/
		if(typeof addEvent !== "undefined")
		{
			addEvent(window, "load", run);
		}
		else if(document.addEventListener)
		{
			document.addEventListener("load", run, false);
		}
		else if(typeof window.onload === "function")
		{
			var oldonload = window.onload;
			window.onload = function()
			{
				domReadyEvent.run();
				oldonload();
			};
		}
		else
		{
			window.onload = run;
		}
		
		/* for Internet Explorer */
		/*@cc_on
			@if (@_win32 || @_win64)
			document.write("<script id=__ie_onload defer src=\"//:\"><\/script>");
			var script = document.getElementById("__ie_onload");
			script.onreadystatechange = function()
			{
				if (this.readyState == "complete")
				{
					domReadyEvent.run(); // call the onload handler
				}
			};
			@end
		@*/
	}
};

var domReady = function(handler) { domReadyEvent.add(handler); };
domReadyEvent.init();

/* Create ImageFlow instances when the DOM structure has been loaded */
domReady(function()
{
	var instanceOne = new ImageFlow();
	instanceOne.init({ ImageFlowID:'myImageFlow' });
});