////////////////////////////////////////////////////////////////
//Software License Agreement (BSD License)
//
//Copyright (c) 2008, Omnicognic LLC.
//All rights reserved.
//
//Redistribution and use of this software in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
//* Redistributions of source code must retain the above
//  copyright notice, this list of conditions and the
//  following disclaimer.
//
//* Redistributions in binary form must reproduce the above
//  copyright notice, this list of conditions and the
//  following disclaimer in the documentation and/or other
//  materials provided with the distribution.
//
//* Neither the name of Omnicognic LLC nor the names of its
//  contributors may be used to endorse or promote products
//  derived from this software without specific prior
//  written permission of Omnicognic LLC.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
//PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
//TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////
//This JavaScript file contains a number of useful objects and functions 
//that help make web pages more interactive. Many of the features can be 
//used without having to write any JavaScript code. It is designed to work 
//with all popular browsers on Windows, Mac, and Unix/Linux without any 
//specific Operating System or Browser checking; and it is designed to 
//work with many variations of html code. All main functions are defined at
//the top of the file and all code is commented so that developers of varying 
//skill can understand what it is doing. Also all objects and functions
//are defined under the object InfoFind so this code will not interfere with
//any other JavaScript files. Some of the features include:
//	*) HTML Table Sorting
//	*) Picture Slide Show
//	*) Web Page Animation
//	*) Form Validation
//	*) Functions for working with Data Types (Strings, Numbers, Currency, etc)
//	*) Functions for working with Web Pages, CSS Scripts, and Individual Elements
//	*) Page Updates through Web Requests (Ajax)
//
//To use this file simply add a reference in your web page:
//	<script type="text/javascript" src="InfoFind.js"></script>
//
//For Data Sorting add the class "Sortable" to all tables that you want to allow sorting. 
//The last line of code in this file automatically runs after the page loads and then adds 
//sorting to the tables that have the class "Sortable". You can also sort specific tables 
//with the function [InfoFind.Sorting.MakeTableSortable()], and you can change the 
//regional number format with the property [InfoFind.DataTypes.NumberType].
//
//For a Picture Slide Show add the class "SlideShow" to all image links (a href) 
//that you want to view in as a slide show. The type of animation for the slide show 
//can be controlled from the property [InfoFind.SlideShow.AnimationType].
//The slide show is set up after the page loads.
//
//InfoFind can automatically validate forms without an JavaScript being added to the page.
//See the function InfoFind.DataForms.ValidateForm() for more on how to do this.
//
//Written by Conrad Sollitt.
////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////
//		Main Objects, Functons, and Properties
///////////////////////////////////////////////////////////

//////////////////////////////////////////////
//InfoFind.Version()
//InfoFind.Publisher()
//InfoFind.WebSite()
//InfoFind.Authors()
//InfoFind.CreateObject(ObjectName)
//InfoFind.OnLoad()
//InfoFind.ListObject(obj, ObjectName, TopObjects, bGetCode, aObjects, bShowNewObject, bCheckForCircularRef, bListPropertyType)

//////////////////////////////////////////////
//InfoFind.DataTypes.NumberType = "English/French/German/Swiss"
//InfoFind.DataTypes.IsNumeric(Value)
//InfoFind.DataTypes.StringToNumber(Value)
//InfoFind.DataTypes.IsCurrency(Value)
//InfoFind.DataTypes.CurrencyToNumber(Value)
//InfoFind.DataTypes.RoundToDecimal(number)
//InfoFind.DataTypes.RoundToNDecimal(number, DecimalPlaces)
//InfoFind.DataTypes.Random(MinNumber, MaxNumber)
//InfoFind.DataTypes.LTrim(Text)
//InfoFind.DataTypes.RTrim(Text)
//InfoFind.DataTypes.Trim(Text)
//InfoFind.DataTypes.StartsWith(Text, SearchFor, bCaseInsenstive)
//InfoFind.DataTypes.Contains(Text, SearchFor, bCaseInsenstive)
//InfoFind.DataTypes.EndsWith(Text, SearchFor, bCaseInsenstive)
//InfoFind.DataTypes.IsUCaseLetter(Character)
//InfoFind.DataTypes.Left(Text, CharacterCount)
//InfoFind.DataTypes.Mid(Text, StartPosition, CharacterCount)
//InfoFind.DataTypes.Right(Text, CharacterCount)
//InfoFind.DataTypes.PadLeft(Length, Character, Text)
//InfoFind.DataTypes.PadRight(Length, Character, Text)
//InfoFind.DataTypes.IsLike(Text, Pattern, bHandleNewLines)
//InfoFind.DataTypes.GetDbRegExpPattern(Pattern)
//InfoFind.DataTypes.GetDateUS(date)
//InfoFind.DataTypes.GetDateEuro(date)
//InfoFind.DataTypes.GetDateISO(date)
//InfoFind.DataTypes.GetDateTimeUS(date)
//InfoFind.DataTypes.GetDateTimeEuro(date)
//InfoFind.DataTypes.GetDateTimeISO(date)
//InfoFind.DataTypes.DateAddMilliseconds(date, Milliseconds)
//InfoFind.DataTypes.DateAddSeconds(date, Seconds)
//InfoFind.DataTypes.DateAddMinutes(date, Minutes)
//InfoFind.DataTypes.DateAddHours(date, Minutes)
//InfoFind.DataTypes.DateAddDays(date, Days)
//InfoFind.DataTypes.DateAddMonths(date, Months)
//InfoFind.DataTypes.DateAddYears(date, Years)
//InfoFind.DataTypes.IsDate(Value)
//InfoFind.DataTypes.IsDbDate(Value)
//InfoFind.DataTypes.IsDbDateTime(Value)
//InfoFind.DataTypes.IsEmail(Value)

//////////////////////////////////////////////
//InfoFind.HTML.ByID(ID)
//InfoFind.HTML.ByTag(TagName)
//InfoFind.HTML.AddEvent(Element, Event, Function)
//InfoFind.HTML.RemoveEvent(Element, Event, Function)
//InfoFind.HTML.StopEvent(e)

//////////////////////////////////////////////
//InfoFind.HTML.Window.GetHeight()
//InfoFind.HTML.Window.GetWidth()

//////////////////////////////////////////////
//InfoFind.HTML.Document.GetHeight()
//InfoFind.HTML.Document.GetMaxHeight()
//InfoFind.HTML.Document.GetWidth()
//InfoFind.HTML.Document.GetMaxWidth()
//InfoFind.HTML.Document.GetMousePosition(e)
//InfoFind.HTML.Document.GetScrollPosition()

//////////////////////////////////////////////
//InfoFind.HTML.Element.GetPosition(Element)
//InfoFind.HTML.Element.GetTop(Element)
//InfoFind.HTML.Element.GetLeft(Element)
//InfoFind.HTML.Element.GetHeight(Element)
//InfoFind.HTML.Element.GetWidth(Element)
//InfoFind.HTML.Element.ScrollTo(Element)
//InfoFind.HTML.Element.Move(Element, Top, Left, Height, Width, bFixed)
//InfoFind.HTML.Element.SetTop(Element, Top)
//InfoFind.HTML.Element.SetLeft(Element, Left)
//InfoFind.HTML.Element.SetHeight(Element, Height)
//InfoFind.HTML.Element.SetWidth(Element, Width)
//InfoFind.HTML.Element.Add(Tag, ObjectID)
//InfoFind.HTML.Element.Remove(Element)
//InfoFind.HTML.Element.Show(Element)
//InfoFind.HTML.Element.Hide(Element)
//InfoFind.HTML.Element.IsHidden(Element)
//InfoFind.HTML.Element.SetVisibility(Element, bVisible)
//InfoFind.HTML.Element.GetVisibility(Element)
//InfoFind.HTML.Element.IsVisible(Element)
//InfoFind.HTML.Element.HasClass(Element, ClassName)
//InfoFind.HTML.Element.AddClass(Element, ClassName)
//InfoFind.HTML.Element.RemoveClass(Element, ClassName)
//InfoFind.HTML.Element.SetOpacity(Element, Percent)
//InfoFind.HTML.Element.Redraw(Element)
//InfoFind.HTML.Element.SetText(Element, Text)

//////////////////////////////////////////////
//InfoFind.CSS.ChangeStyleSheet(StyleSheet, Location)
//InfoFind.CSS.ElementHasClass(Element, ClassName)
//InfoFind.CSS.ElementAddClass(Element, ClassName)
//InfoFind.CSS.ElementRemoveClass(Element, ClassName)

//////////////////////////////////////////////
//InfoFind.Cookies.Get(Name)
//InfoFind.Cookies.Set(Name, Value, DaysToExpire, Path, Domain, Secure)
//InfoFind.Cookies.Erase(Name)

//////////////////////////////////////////////
//InfoFind.WebRequest.DisplayError = [Default:true]
//InfoFind.WebRequest.DisplayUrlOnError = [Default:false]
//InfoFind.WebRequest.ErrorMessage = "Error updating page. Please refresh or try again later."
//InfoFind.WebRequest.LoadingHTML = ""
//InfoFind.WebRequest.GetConnection()
//InfoFind.WebRequest.UpdatePageElement(URL, ElementID, FuncPtr)

//////////////////////////////////////////////
//InfoFind.DataForms.ValidateForm(FormID)
//InfoFind.DataForms.Input_Validate(Input, Label, bRequired, bTrim, bNumber, bWholeNumber, bCurrency, bDate, bDbDate, bDbDateTime, bEmail)
//InfoFind.DataForms.Input_ValidateNumberByte(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumber16Bit(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumberUShort(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumber32Bit(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumberUInt(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumberFloat(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumber64Bit(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumberULong(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumberDouble(Input, Label, bRequired)
//InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, bTrim, bWholeNumber, MinNumber, MaxNumber)
//InfoFind.DataForms.Input_ValidateDateRange(Input, Label, bRequired, bTrim, MinDate, MaxDate)
//InfoFind.DataForms.GetOptionText(Control)
//InfoFind.DataForms.GetControlText(Control)
//InfoFind.DataForms.GetControlValue(Control)
//InfoFind.DataForms.SetControlValue(Control, Value)
//InfoFind.DataForms.SetOptionByText(Control, Text)
//InfoFind.DataForms.AttachSelectEvents()
//InfoFind.DataForms.Select_OnChange()

//////////////////////////////////////////////
//InfoFind.Animation.DebugInfoPrompt = [Default:false]
//InfoFind.Animation.Animate(ElementID, Seconds, AnimationScript, NumberOfAnimations)
//InfoFind.Animation.FadeOut(ElementID, Seconds)
//InfoFind.Animation.FadeIn(ElementID, Seconds)
//InfoFind.Animation.FadeOutAndIn(ElementID, Seconds)
//InfoFind.Animation.Opacity(ElementID, StartPercent, EndPercent, Seconds)
//InfoFind.Animation.Resize(ElementID, StartPercent, EndPercent, Seconds)
//InfoFind.Animation.RollDown(ElementID, Seconds)
//InfoFind.Animation.RollUp(ElementID, Seconds)
//InfoFind.Animation.RollRight(ElementID, Seconds)
//InfoFind.Animation.RollLeft(ElementID, Seconds)
//InfoFind.Animation.MoveTo(ElementID, Top, Left, Seconds)
//InfoFind.Animation.MoveToRandomBorder(ElementID, Seconds)
//InfoFind.Animation.MoveFromRight(ElementID, Seconds)
//InfoFind.Animation.MoveFromTop(ElementID, Seconds)
//InfoFind.Animation.MoveFromLeft(ElementID, Seconds)
//InfoFind.Animation.MoveFromBottom(ElementID, Seconds)
//InfoFind.Animation.MoveToRight(ElementID, Seconds)
//InfoFind.Animation.MoveToTop(ElementID, Seconds)
//InfoFind.Animation.MoveToLeft(ElementID, Seconds)
//InfoFind.Animation.MoveToBottom(ElementID, Seconds)
//InfoFind.Animation.MoveInCircle(ElementID, Seconds, Radius, Direction)

//////////////////////////////////////////////
//InfoFind.SlideShow.AnimationType = "Advanced/Simple/None"
//InfoFind.SlideShow.PageOverlayPercent = [0 To 100 - Default:50]
//InfoFind.SlideShow.PageOverlayZIndex = [Default:1]
//InfoFind.SlideShow.PageOverlayBackgroundColor = "black"
//InfoFind.SlideShow.PageOverlayBackgroundImage = ""
//InfoFind.SlideShow.DisplayImageSeconds = [# of Seconds]
//InfoFind.SlideShow.AnimationTime = [# of Seconds]
//InfoFind.SlideShow.ImageSize = [0 To 1 - Default:0.75]
//InfoFind.SlideShow.Event_BeforeDisplay = FuncPtr
//InfoFind.SlideShow.Event_AfterDisplay = FuncPtr
//InfoFind.SlideShow.Show(e)

//////////////////////////////////////////////
//InfoFind.Sorting.MakeTableSortable(TableID)
//InfoFind.Sorting.MakeTableSortable(Element)
//InfoFind.Sorting.MakeTableSortable({ObjectID:"ObjectID", BeforeClick:FuncPtr, AfterClick:FuncPtr})

//////////////////////////////////////////////
//InfoFind Root Object
//This puts all functions in this code in an object 
//model rather then having all functions as globals.
//////////////////////////////////////////////
var InfoFind = new Object();

//Properties of InfoFind Object
//-When modifying this file the best practice is to update the [Version], [Publisher],
// [WebSite], and [Authors] Properties. This allows external files to check if a needed  
// version of the file is being referenced.
InfoFind.Version	= function() { return 1.105; };
InfoFind.Publisher	= function() { return "Omnicognic LLC"; };
InfoFind.WebSite	= function() { return "http://www.omnicognic.com"; };
InfoFind.Authors	= function() { return "Conrad Sollitt"; };
InfoFind.TypeName	= function() { return "InfoFind"; };

//InfoFind.CreateObject(ObjectName)
//Example:
//	InfoFind.CreateObject("InfoFind.PageObject.MyClass")
//	  or
//	InfoFind.CreateObject("PageObject.MyClass")
//	  will create (if needed) or get and return the object
//	  InfoFind.PageObject.MyClass
//	Each object will also be assigned the function TypeName().
InfoFind.CreateObject = function(ObjectName) {
	//Invalid Input?
	if (!typeof(ObjectName) == "string") return null;
	//Parse string and point to Top-Level Object
	var Items = ObjectName.split(".");
	var CurrentObj = InfoFind;
	var ItemName = "";
	//Create or get each object, If InfoFind is passed as the First Item
	//then start at 1 otherwise start at 0. This works because CurrentObj 
	//is set to InfoFind in the code above.
	for (var n = (Items[0] == "InfoFind" ? 1 : 0); n < Items.length; ++n) {
		//String Name of the Object
		ItemName = Items[n];
		//Get or Create the Object
		CurrentObj[ItemName] = CurrentObj[ItemName] || new Object();
		//If it doesn't exist then add the function TypeName() to the Object
		if (!CurrentObj[ItemName].TypeName) CurrentObj[ItemName].TypeName = function() { return ItemName; };
		//Set the Current Object for Return Object or Next Item in the Loop
		CurrentObj = CurrentObj[ItemName];
	}
	//Return the Last Object
	return CurrentObj;
}

//This function performs actions on Elements of the Web Page
//when it first loads. It is used so that Web Designers and 
//Developers can use this JavaScript file without any programming.
InfoFind.OnLoad = function() {
    //Variables
    var n = 0;
	//Set up Table Sorting
	//Look for all Tables with the "Sortable" in the Class Name
	//If found then make the Table Sortable.
	var Tables = InfoFind.HTML.ByTag("table");
	if (Tables && Tables.length) {
		for (n = 0; n < Tables.length; n++) {
			if (InfoFind.HTML.Element.HasClass(Tables[n], "Sortable")) {
				InfoFind.Sorting.MakeTableSortable(Tables[n]);
			}
		}
	}
	//Set up Picture Slide Show
	var Links = InfoFind.HTML.ByTag("a");
	if (Links && Links.length) {
		for (n = 0; n < Links.length; n++) {
			if (InfoFind.HTML.Element.HasClass(Links[n], "SlideShow")) {
				InfoFind.HTML.AddEvent(Links[n], "click", InfoFind.SlideShow.Show);
			}
		}
	}
	//Set up Automatic Form Validation
	var Forms = InfoFind.HTML.ByTag("form");
	if (Forms && Forms.length) {
		for (n = 0; n < Forms.length; n++) {
			if (InfoFind.HTML.Element.HasClass(Forms[n], "ValidateForm")) {
			    InfoFind.HTML.AddEvent(Forms[n], "submit", (function(e){
                    var Form = null;
                    if (window.event && window.event.srcElement) {
	                    Form = window.event.srcElement;
                    } else if (e && e.target)  {
	                    Form = e.target;
	                }
	                if (!Form) return false;
			        if (!InfoFind.DataForms.ValidateForm(Form)) {
			            //FireFox requires StopEvent while IE does not.
			            InfoFind.HTML.StopEvent(e);
			            return false;
			        }
			        return true;
			    }) );
			}
		}
	}
	//If desired, handle all drop-down selections so that the user does
	//not accidently scroll when they are not paying attention. Before
	//using this read all comments in AttachSelectEvents(). This is only 
	//useful for certain database forms.
	if (document.body && document.body.className) {
		if (InfoFind.HTML.Element.HasClass(document.body, "WatchMouseWheel")) {
			InfoFind.DataForms.AttachSelectEvents();
		}
	}
}

//Recursive function that will list all of the properties and child objects for 
//any JavaScript Object. Returns a String. This function has many parameters and
//behaves differently based upon what is passed. This function is not dependant
//upon any other functions. It has been successfully tested with recent versions 
//of IE, Firefox, Opera, and Safari. However each browser will display the code 
//in a different manner. Some will format it and some will not and some will  
//remove comments from code and others will keep the comments.
//Examples:
//  1) Custom JavaScript Objects
//	   var str = InfoFind.ListObject(InfoFind, InfoFind.TypeName(), "", true, null, true, false, false);
//     This example will return a string with all function code and properties for 
//	   the JavaScript Object and all of it's Child Objects.
//	2) Native Data Types and Arrays
//	   alert(InfoFind.ListObject("", "String", "", false, null, true, false, false));
//	   This example will not find native functions/properties, but if custom functions 
//	   are defined such as String.prototype.lTrim (if defined) then this will list those items.
//	   Example with an Array:
//	   var a = new Array("a", "b");
//	   alert(ListObject(a, "a", "", false, null, true, false, false));
//	3) Native Objects
//	   InfoFind.HTML.ByID("Textarea1").value = InfoFind.ListObject(window, "window", "", false, null, false, true, false);
//	   InfoFind.HTML.ByID("Textarea1").value = InfoFind.ListObject(document, "document", "", false, null, false, true, false);
//	   The examples listed above would fill a TextBox with all function, properties,
//	   and child objects for window or document objects. When the above code is used
//	   the function takes many seconds to run and the results in Word are between
//	   200 and 1000 pages for IE, Opera, and Mozilla/Firefox, but for Apple Safari
//	   the results are less then one page. With these examples if bCheckForCircularRef 
//	   is not set to true then the function would error and not finish. Warning - this 
//	   worked with listing the [window] object on Opera for many versions but with one 
//	   recent verion it caused the browser to crash.
InfoFind.ListObject = function(obj, ObjectName, TopObjects, bGetCode, aObjects, bShowNewObject, bCheckForCircularRef, bListPropertyType) {
	//Variables
	var str = "", n = 0;
	//Errors occur when enumerating the window or document object.
	try {
		//Prevent endless looping / recursive calls for circular references
		//by not calling this function again if a object or function of the 
		//same name has already been called. Example: window.document.parentWindow.document
		//If this code is not included then enumerating window or document objects will
		//never finish and browser will come up with a call stack overflow error.
		if (bCheckForCircularRef) {
			if (aObjects && aObjects.length) {
				//Check all items to see if current object has been listed. If it has
				//then exit this function and return a blank string.
				for (n = 0; n < aObjects.length; n++) {
					if (aObjects[n] == ObjectName) return "";
				}
				aObjects[aObjects.length] = ObjectName;
			//First Object, create a new array.
			} else {
				aObjects = new Array();
				aObjects[0] = ObjectName;
			}
		}
		//Enumerate all Properties of the Object.
		for (var prop in obj) {
			//Mozilla/FireFox lists prototype with every single object
			if (prop != "prototype") {
				//Line break inbetween objects.
				if (typeof(obj[prop]) == "object" && obj[prop] != null) str += "\n";
				//List the Property. If the property name is a number
				//then that means it is part of an Array because JavaScript
				//Variables/Properties cannot be just numbers.
				if (typeof(prop) == "number" || !isNaN(prop)) {
					str += TopObjects + ObjectName + "[" + prop + "]";
				} else {
					str += TopObjects + ObjectName + "." + prop;
				}
				//Display code if a function? (Determined from function params.)
				if (bGetCode == true && typeof(obj[prop]) == "function") {
					str += " = " + obj[prop] + "\n";
				//Function/Object - Recursively call this function to get child 
				//					objects, functions, and properties.
				} else if (typeof(obj[prop]) == "function" || (typeof(obj[prop]) == "object" && obj[prop] != null)) {
					//Show as New Object?
					if (bShowNewObject && typeof(obj[prop]) == "object") {
						str += " = new Object();";
					//Display Function Params
					} else if (typeof(obj[prop]) == "function") {
						str += obj[prop].toString().substring(obj[prop].toString().search("\\("), obj[prop].toString().search("\\)") + 1) + ";";
					}
					//Recursive call
					if (typeof(prop) == "number" || !isNaN(prop)) { //Array
						str += "\n" + InfoFind.ListObject(obj[prop], "[" + prop + "]", TopObjects + ObjectName, bGetCode, aObjects, bShowNewObject, bCheckForCircularRef, bListPropertyType);
					} else {
						str += "\n" + InfoFind.ListObject(obj[prop], prop, TopObjects + ObjectName + ".", bGetCode, aObjects, bShowNewObject, bCheckForCircularRef, bListPropertyType);
					}
				//Basic Property - List the property type or value.
				} else {
					//Display Property Type
					if (bListPropertyType) {
						str += ' = typeof("' + typeof(obj[prop]) + '");\n';
					//Display Property Value
					} else {
						//Number or Boolean.
						if (typeof(obj[prop]) == "number" || !isNaN(obj[prop]) || typeof(obj[prop]) == "boolean") {
							str += " = " + obj[prop] + ";\n";
						//Format as a Valid JavaScript String.
						//Example of a test string that this works with: 'ABC\tDEF\n\\\'\"\f\r'
						} else {
							//Note - //.test() works but takes to long for large amounts of Code (i.e.: window Object)
							//if (/([\f\n\r\t\'\"\\])/.test(obj[prop])) {
							if (obj[prop].indexOf("\\") != -1 || obj[prop].indexOf('"') != -1 ||
								obj[prop].indexOf("'") != -1 || obj[prop].indexOf("\n") != -1 ||
								obj[prop].indexOf("\t") != -1 || obj[prop].indexOf("\f") != -1 ||
								obj[prop].indexOf("\r") != -1) {
								//
								var propValue = obj[prop];
								var SearchFor = new Array(/\\/g,	/"/g,	/'/g,	/\n/g, /\t/g, /\f/g, /\r/g);
								var ReplaceWith = new Array("\\\\", '\\"', "\\'", "\\n", "\\t", "\\f", "\\r");
								for (n = 0; n < SearchFor.length; n++) {
									propValue = propValue.replace(SearchFor[n], ReplaceWith[n]);
								}
								str += ' = "' + propValue + '";\n';
							} else {
								str += ' = "' + obj[prop] + '";\n';
							}
						}
					}
				}
			}
		}
	} catch(e) {
		//Do Nothing
	}
	//Return a String listing Current Object and all Child Objects.
	return str;
}

///////////////////////////////////////////////////////
//InfoFind.DataTypes
//Functions for easily working with different 
//data types (numbers, currency, strings, dates, etc).
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.DataTypes");

//Example of Number Formats:
//	JavaScript	|	1234567.89
//				=
//	English		|	1,234,567.89
//	French		|	1 234 567,89
//	German		|	1.234.567,89
//	Swiss		|	1'234'567,89
InfoFind.DataTypes.NumberType = "English"; //French, German, Swiss

//Is the Value a Number? Regional digit grouping and various
//negative number formats are allowed with this function. 
//Example: IsNumeric("1,234,567.89") = true
//Negative Number Formats Allowed = (#), -#, - #, #-, # -
InfoFind.DataTypes.IsNumeric = function(Value) {
	//Convert User Formatted Number to JavaScript Number.
	if (isNaN(Value)) {
		Value = InfoFind.DataTypes.RemoveNegativeSymbol(Value);
		Value = InfoFind.DataTypes.ChangeNumberFormat(Value);
	}
	//Now use JavaScript to validate the Number.
	return !isNaN(Value);
}

//Returns 0 if invalid, this allows calculations to occur without 
//error and this allows a App to always work with a numeric data 
//type for correct calculations.
InfoFind.DataTypes.StringToNumber = function(Value) {
	//Convert User Formatted Number to JavaScript Number.
	var bNegative = false;
	if (isNaN(Value)) {
		if (InfoFind.DataTypes.HasNegativeSymbol(Value) == true) {
			bNegative = true;
			Value = InfoFind.DataTypes.RemoveNegativeSymbol(Value);
		}
		Value = InfoFind.DataTypes.ChangeNumberFormat(Value);
		if (!isNaN(Value)) {
			Value = ((bNegative ? "-" : "") + Value);
		} else {
			Value = 0;
		}
	}
	//Return the Value as a Number Object
	return new Number(Value);
}

//See Comments from IsNumeric(), Returns true or false.
//This is a helper function and if the result is true
//it does not mean that a valid number was passed.
InfoFind.DataTypes.HasNegativeSymbol = function(Value) {
	Value = InfoFind.DataTypes.Trim(Value);
	var len = Value.length;
	if (len > 1) {
		if (Value.substring(0, 1) == "(" && Value.substring(len - 1, len) == ")") {
			return true;
		} else if (Value.substring(0, 1) == "-") {
			return true;
		} else if (Value.substring(len - 1, len) == "-") {
			return true;
		}
	}
	return false;
}

//See Comments from IsNumeric(), this is a helper function 
//and may or may not return an actual number.
InfoFind.DataTypes.RemoveNegativeSymbol = function(Value) {
	Value = InfoFind.DataTypes.Trim(Value);
	var len = Value.length;
	if (len > 1) {
		if (Value.substring(0, 1) == "(" && Value.substring(len - 1, len) == ")") {
			return Value.substring(1, len - 1);
		} else if (Value.substring(0, 1) == "-") {
			return Value.substring(1, len);
		} else if (Value.substring(len - 1, len) == "-") {
			return Value.substring(0, len - 1);
		}
	}
	return Value;
}

//See Comments from IsNumeric(), this is a helper function 
//and may or may not return an actual number.
InfoFind.DataTypes.ChangeNumberFormat = function(Value) {
	//Convert Formated Number to JavaScript Number.
	var NumberDecimalSeparator = "", NumberGroupSeparator = ""; 
	Value = InfoFind.DataTypes.Trim(Value);
	switch (InfoFind.DataTypes.NumberType) {
		//1 234 567,89
		case "French":
			NumberGroupSeparator = " ";
			NumberDecimalSeparator = ",";
			break;
		//1.234.567,89
		case "German":
			NumberGroupSeparator = ".";
			NumberDecimalSeparator = ",";
			break;
		//1'234'567,89
		case "Swiss":
			NumberGroupSeparator = "'";
			NumberDecimalSeparator = ",";
			break;
		//1,234,567.89
		default: //English
			NumberGroupSeparator = ",";
			NumberDecimalSeparator = ".";
	}
	//Remove Digit Grouping Separators
	Value = Value.split(NumberGroupSeparator).join("");
	//Convert Decimal Separator to dot/period [.]
	var DecimalSeparator = Value.indexOf(NumberDecimalSeparator);
	if (DecimalSeparator != -1) {
		Value = Value.substring(0, DecimalSeparator) + "." + Value.substring(DecimalSeparator + 1);
	}
	//Return the updated string
	return Value;
}

//Is the Value a Currency? Regional digit grouping, symbols, and 
//various negative number formats are allowed with this function. 
//Example: IsCurrency("$1,234,567.89") = true
//Negative Number Formats Allowed = ($#), -$#, $-#, $#-, (#$), -#$, #-$, #$-, -# $, -$ #, # $-, $ #-, $ -#, #- $, ($ #), (# $)
InfoFind.DataTypes.IsCurrency = function(Value) {
	//Convert User Formatted Currency to JavaScript Number.
	if (isNaN(Value)) {
		Value = InfoFind.DataTypes.RemoveCurrencySymbol(Value);
		if (isNaN(Value)) {
			Value = InfoFind.DataTypes.RemoveNegativeSymbol(Value);
			if (isNaN(Value)) {
				Value = InfoFind.DataTypes.RemoveCurrencySymbol(Value);
				Value = InfoFind.DataTypes.ChangeNumberFormat(Value);
			}
		}
	}
	//Now use JavaScript to validate the Number.
	return !isNaN(Value);
}

//See comments in IsCurrency() and StringToNumber().
InfoFind.DataTypes.CurrencyToNumber = function(Value) {
	//Convert User Formatted Currency to JavaScript Number.
	var bNegative = false;
	if (isNaN(Value)) {
		Value = InfoFind.DataTypes.RemoveCurrencySymbol(Value);
		if (isNaN(Value)) {
			if (InfoFind.DataTypes.HasNegativeSymbol(Value) == true) {
				bNegative = true;
				Value = InfoFind.DataTypes.RemoveNegativeSymbol(Value);
			}
			if (isNaN(Value)) {
				Value = InfoFind.DataTypes.RemoveCurrencySymbol(Value);
			}
			Value = InfoFind.DataTypes.ChangeNumberFormat(Value);
			if (!isNaN(Value)) {
				Value = ((bNegative ? "-" : "") + Value);
			} else {
				Value = 0;
			}
		}
	}
	//Return the Value as a Number Object
	return new Number(Value);
}

//See Comments from IsCurrency(), this is a helper function 
//and may or may not return an actual number.
InfoFind.DataTypes.RemoveCurrencySymbol = function(Value) {
	Value = InfoFind.DataTypes.Trim(Value);
	var len = Value.length;
	var IsCur = InfoFind.DataTypes.IsCurrencySymbol;
	if (len > 3) {
		if (IsCur(Value.substring(0, 3))) {
			return Value.substring(3, len);
		} else if (IsCur(Value.substring(len - 3, len))) {
			return Value.substring(0, len - 3);
		}
	}
	if (len > 2) {
		if (IsCur(Value.substring(0, 2))) {
			return Value.substring(2, len);
		} else if (IsCur(Value.substring(len - 2, len))) {
			return Value.substring(0, len - 2);
		}
	}
	if (len > 1) {
		if (IsCur(Value.substring(0, 1))) {
			return Value.substring(1, len);
		} else if (IsCur(Value.substring(len - 1, len))) {
			return Value.substring(0, len - 1);
		}
	}
	IsCur = null;
	return Value;
}

//Note - This is list contains some common currencies and can be modified to 
//		 include more. The unicode values of the symbols are written out so 
//		 that this file can be saved in ASCII format.
InfoFind.DataTypes.IsCurrencySymbol = function(Characters) {
	switch (Characters) {
		case "$":		//Dollar (Australia, Canada, Hong Kong, Singapore, Taiwan, USA, etc)
		case "\u00A3":	//British Pound
		case "\u00A5":	//Chinese Yuan, Japanese Yen
		case "\u20A9":	//Korean Won
		case "\u20AA":	//Israeli New Sheqel
		case "\u20AC":	//Euro
		case "K\u010D":	//Czech Koruna
		case "USD":		//United States Dollar
			return true;
	}
	return false;
}

//IEEE Floating Point Error Fix; Fix JavaScript Bug for Rounding.
//Both PC and Mac on all popular Browsers round numbers this way.
//Example = 4.225 * 100 = 422.49999999999994, but should = 422.5
InfoFind.DataTypes.RoundToDecimal = function(number) { 
	return Math.round(number * 100) / 100;
}

//Round to a Decimal Place. Example: RoundToNDecimal(4.225, 2) = 4.23
InfoFind.DataTypes.RoundToNDecimal = function(number, DecimalPlaces) { 
	if (Number(number).toFixed) {
		return Number(number).toFixed(DecimalPlaces);
	} else {
		var n = Number("1e" + DecimalPlaces);
		return Math.round(number * n) / n;
	}
}

//Return a random number within a specified range.
InfoFind.DataTypes.Random = function(MinNumber, MaxNumber) {
	return Math.floor(Math.random() * (MaxNumber - MinNumber + 1) + MinNumber);
}

//Note - \xA0 = ASCII Code 160. In Apple Safari when HTML
//	with the value of &nbsp; is converted to innerText
//	it is assigned ASCII 160 rather then 32 like other 
//	major browsers. These functions handle this. Safari 
//	converts &nbsp; to 160 because &nbsp; is actually equal 
//  to &#160; (ASCII 160) so this conversion is not a bug.
//	&nbsp; is commonly used with empty cells to prevent 
//	ugly table formatting.
//- The following 3 functions could also be defined in
//	the JavaScript String class as lTrim(), rTrim(), and trim().
//	However they are defined here instead because many JavaScript
//	Libraries define them incorrectly for Safari so if the 
//	String.prototype version is called and multiple JavaScript Libraries 
//	are used then there is no guarantee that the correct one will be used.
//- A String.prototype version is commented out above each function.
//String.prototype.lTrim = function() { return this.replace(/^(\s|\xA0)*/, ""); }
InfoFind.DataTypes.LTrim = function(Text) { 
	return String(Text).replace(/^(\s|\xA0)*/, ""); 
}

//String.prototype.rTrim = function() { return this.replace(/(\s|\xA0)*$/, ""); }
InfoFind.DataTypes.RTrim = function(Text) {
    return String(Text).replace(/(\s|\xA0)*$/, "");
}

//String.prototype.trim = function() { return this.lTrim().rTrim(); }
InfoFind.DataTypes.Trim = function(Text) {
    Text = InfoFind.DataTypes.LTrim(Text);
    return InfoFind.DataTypes.RTrim(Text);
}

//Returns true if a string starts with the specified search text. bCaseInsenstive
//is optional and if true then "TEST" would equal "test".
//Example: StartsWith("This is a test.", "This") = true
InfoFind.DataTypes.StartsWith = function(Text, SearchFor, bCaseInsenstive) {
    SearchFor = (bCaseInsenstive ? String(SearchFor).toLowerCase() : String(SearchFor));
    Text = String(Text).substring(0, SearchFor.length);
    if (bCaseInsenstive) Text = Text.toLowerCase();
    return (Text == SearchFor ? true : false);
}

//See comments from StartsWith() function.
InfoFind.DataTypes.Contains = function(Text, SearchFor, bCaseInsenstive) {
    SearchFor = (bCaseInsenstive ? String(SearchFor).toLowerCase() : String(SearchFor));
    Text = (bCaseInsenstive ? String(Text).toLowerCase() : String(Text));
    return (Text.indexOf(SearchFor) != -1 ? true : false);
}

//See comments from StartsWith() function.
InfoFind.DataTypes.EndsWith = function(Text, SearchFor, bCaseInsenstive) {
    SearchFor = (bCaseInsenstive ? String(SearchFor).toLowerCase() : String(SearchFor));
    Text = String(Text);
    Text = Text.substring(Text.length - SearchFor.length, Text.length);
    if (bCaseInsenstive) Text = Text.toLowerCase();
    return (Text == SearchFor ? true : false);
}

//This function expects a single character and will return true if it is an upper case letter
InfoFind.DataTypes.IsUCaseLetter = function(Character) {
    return ("ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(Character) != -1 ? true : false);
}

//String Functions from Excel and Visual Basic but not in JavaScript.
//They are included here to allow Excel Users and Visual Basic Developers
//to more easily work with JavaScript strings.
//Example: Left("This is a Test.", 4) = "This"
InfoFind.DataTypes.Left = function(Text, CharacterCount) {
    return String(Text).substring(0, CharacterCount);
}

//See comments in Left() function.
//First Character starts at 1 rather 0 like in JavaScript with this function.
//Examples:
//  Mid("This is a Test.", 6, 4) = "is a"
//  Mid("This is a Test.", 6) = "is a Test."
InfoFind.DataTypes.Mid = function(Text, StartPosition, CharacterCount) {
    if (!CharacterCount) CharacterCount = Text.length - StartPosition + 1;
    return String(Text).substring(StartPosition - 1, StartPosition + CharacterCount - 1);
}

//See comments in Left() function.
//Example: Right("This is a Test.", 5) = "Test."
InfoFind.DataTypes.Right = function(Text, CharacterCount) {
    var len = String(Text).length;
    return String(Text).substring(len - CharacterCount, len);
}

//Formats a string to a specified length with padding characters
//in front. This is commonly used with numbers. For example:
//PadLeft(6, "0", 1) = "000006"
InfoFind.DataTypes.PadLeft = function(Length, Character, Text) {
	//This function expects a single Character.
	if (Character.length != 1) { return Text; }
	//Add Characters to the Left of the Text if it's not long enough.
	var len = String(Text).length;
	while (len < Length) {
		Text = Character + Text;
		len++;
	}
	return Text;
}

//Formats a string to a specified length with padding characters
//at the end. Example: PadRight(7, ".", "Test") = "Test..."
InfoFind.DataTypes.PadRight = function(Length, Character, Text) {
	//This function expects a single Character.
	if (Character.length != 1) { return Text; }
	//Add Characters to the Right of the Text if it's not long enough.
	var len = String(Text).length;
	while (len < Length) {
		Text = Text + Character;
		len++;
	}
	return Text;
}

//*JavaScript Replacement for Database LIKE operator. 
//*See comments in the GetDbRegExpPattern() function.
//*This function may take a long time on a large loop so rather then using it 
// when looping it might be best to use GetDbRegExpPattern() with a Regex Object.
//*bHandleNewLines is only required if the string to check may contain new lines.
//*Examples:
//	IsLike("123-456-7890", "###-###-####") = true
//	IsLike("Mr. John Smith", "Mr.%Smith") = true
//	IsLike("AB12", "[A-Z]?##") = true
//	IsLike("AB12", "####") = false
//	IsLike("ab\ncd", "a*d") = false
//	IsLike("ab\ncd", "a*d", true) = true
InfoFind.DataTypes.IsLike = function(Text, Pattern, bHandleNewLines) {
	var reg = new RegExp(InfoFind.DataTypes.GetDbRegExpPattern(Pattern));
	if (bHandleNewLines) Text = Text.replace(/\n/g, "");
	return (reg.test(Text) ? true : false);
}

//*Many Application and Database Developers are familiar with the Database LIKE
// operator and not familiar with Regular Expressions (JavaScript RegExp Object).
// This function takes a Database LIKE pattern and converts it to RegExp syntax.
// This allows for Database Developers to write JavaScript "LIKE" code without
// having to learn the details of RegExp.
//*Most databases (SQL Server, Oracle, DB2, etc) use % as a wildcard while
// Microsoft Access uses the file search format of *. This function handles both.
//*This function is case-sensitive.
//*Unlike Databases the wild-card does not accept new lines ("\n" in JavaScript).
// However the IsLike() function provides an option to handle new lines.
//*Examples:
//	Database			=	JavaScript
//	"(###) ###-####"	=	"^\(\d\d\d\) \d\d\d-\d\d\d\d$"
//	"Mr.*Smith"			=	"^Mr[.](.*)Smith$"
//	"Mr.%Smith"			=	"^Mr[.](.*)Smith$"
InfoFind.DataTypes.GetDbRegExpPattern = function(Pattern) {
	//Many of these (but not all) must be called  
	//in a specific order for this to work.
	Pattern = Pattern.replace(/\\/g, "\\\\");
	Pattern = Pattern.replace(/\$/g, "[$]");
	Pattern = Pattern.replace(/\./g, "[.]");
	Pattern = Pattern.replace(/\(/g, "\\(");
	Pattern = Pattern.replace(/\)/g, "\\)");
	Pattern = Pattern.replace(/\+/g, "[+]");
	Pattern = Pattern.replace(/\?/g, ".");
	Pattern = Pattern.replace(/\*/g, "%");
	Pattern = Pattern.replace(/%/g, "(.*)");
	Pattern = Pattern.replace(/#/g, "\\d");
	Pattern = Pattern.replace(/\[!/g, "[^");
	Pattern = "^" + Pattern + "$";
	return Pattern;
}

//Format a date as MM/DD/YYYY
//This function expects a valid date to be passed.
InfoFind.DataTypes.GetDateUS = function(date) {
	return ((date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear());
}

//Format a date as DD/MM/YYYY
//This is just one of many formats. This file can be customized for more as needed.
InfoFind.DataTypes.GetDateEuro = function(date) {
	return (date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear());
}

//Format a date as YYYY-MM-DD
InfoFind.DataTypes.GetDateISO = function(date) {
	var l = function(n) { return InfoFind.DataTypes.PadLeft(2, "0", n); }
	return (date.getFullYear() + "-" + l(date.getMonth() + 1) + "-" + l(date.getDate()));
}

//Format a date as MM/DD/YYYY HH:MM {AM|PM}
InfoFind.DataTypes.GetDateTimeUS = function(date) {
	var time = "";
	var h = date.getHours(), m = date.getMinutes();
	if (m < 10) m = "0" + String(m);
	if (h == 13) {
		time = "12:" + m + " PM";
	} else if (h > 13) {
		time = (h - 12) + ":" + m + " PM";
	} else {
		time = h + ":" + m + " AM";
	}
	return ((date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear() + " " + time);
}

//Format a date as DD/MM/YYYY HH:MM
InfoFind.DataTypes.GetDateTimeEuro = function(date) {
	var l = function(n) { return InfoFind.DataTypes.PadLeft(2, "0", n); }
	return (date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear() + " " + l(date.getHours()) + ":" + l(date.getMinutes()));
}

//Format a date as YYYY-MM-DD HH:MM:SS
//Note - there are other ways for formatting ISO dates such as
//"YYYY-MM-DDTHH:MM:SS" which looks like "2008-12-31T23:59:59"
//or "YYYY-MM-DDTHH:MM:SSZ" with a "Z" at the end which means
//that the time is in GMT and not the local time zone. The "T"
//letter is not used with this function because it is not commonly
//used in writing and often it's harder for humans to read.
InfoFind.DataTypes.GetDateTimeISO = function(date) {
	var l = function(n) { return InfoFind.DataTypes.PadLeft(2, "0", n); }
	return (date.getFullYear() + "-" + l(date.getMonth() + 1) + "-" + l(date.getDate()) + 
		" " + l(date.getHours()) + ":" + l(date.getMinutes()) + ":" + l(date.getSeconds()));
}

//Add a number of milliseconds (1/1000th of a second) to a date object.
//This function and the related functions below expect valid date/numbers passed.
InfoFind.DataTypes.DateAddMilliseconds = function(date, Milliseconds) {
	return new Date(date.getTime() + Milliseconds);
}

//Add seconds to a date. To subtract just pass a negative number.
InfoFind.DataTypes.DateAddSeconds = function(date, Seconds) {
	return InfoFind.DataTypes.DateAddMilliseconds(date, (Seconds * 1000));
}

//Add minutes to a date.
InfoFind.DataTypes.DateAddMinutes = function(date, Minutes) {
	return InfoFind.DataTypes.DateAddMilliseconds(date, (Minutes * 60000));
}

//Add hours to a date.
InfoFind.DataTypes.DateAddHours = function(date, Minutes) {
	return InfoFind.DataTypes.DateAddMilliseconds(date, (Minutes * 3600000));
}

//Add dates to a date.
InfoFind.DataTypes.DateAddDays = function(date, Days) {
	date.setDate(date.getDate() + Days);
	return date;
}

//Add months to a date.
InfoFind.DataTypes.DateAddMonths = function(date, Months) {
	date.setMonth(date.getMonth() + Months);
	return date;
}

//Add years to a date.
InfoFind.DataTypes.DateAddYears = function(date, Years) {
	date.setFullYear(date.getFullYear() + Years);
	return date;
}

//Check if the value is a valid date for Javascript.
//For short date format see IsDbDate(). Even if a date 
//is valid for JavaScript it may not be valid for a database
//since JavaScript considers numbers such as "12345" to be dates.
InfoFind.DataTypes.IsDate = function(Value) {
	return !isNaN(Date.parse(Value));
}

//Validate that the value is a valid short date.
//Many server applications and databases dont't consider 
//a Javascript date to be a valid date.
//Example of Valid Dates: 1/1/08 or 01-01-2008
InfoFind.DataTypes.IsDbDate = function(Value) {
	if (InfoFind.DataTypes.IsDate(Value)) {
		Value = Value.replace(/-/g, "/");
		if (InfoFind.DataTypes.IsLike(Value, "#*/#*/##")) {
			return true;
		} else if (InfoFind.DataTypes.IsLike(Value, "#*/#*/####")) {
			return true;
		}
	}
	return false;
}

//Validate that the value is a valid short date and time.
//Many server applications and databases dont't consider 
//a Javascript date to be a valid date.
//Example of Valid Date/Times: 1/1/08 2:00 PM or 01-01-2008 14:00
InfoFind.DataTypes.IsDbDateTime = function(Value) {
	if (InfoFind.DataTypes.IsDate(Value)) {
		Value = Value.replace(/-/g, "/");
		if (InfoFind.DataTypes.IsLike(Value, "#*/#*/*# #:#*")) {
			return true;
		}
	}
	return false;
}

//Validate that the value is in a valid email format.
InfoFind.DataTypes.IsEmail = function(Value) {
	//Check that something was entered.
	if (typeof(Value) == "string" && Value != "") {
	    //Check for valid email format.
		if (InfoFind.DataTypes.IsLike(Value.toLowerCase(), "[a-z0-9]*@[a-z]*.*[a-z]")) {
			//Check for duplicate @ characters.
			var aData = Value.split("@");
			if (aData.length != 2) {
			    return false;
			}
			return true;
		}
	}
	return false;
}

///////////////////////////////////////////////////////
//InfoFind.HTML
//Help with general HTML information and objects.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.HTML");

//Get HTML Element if user Passed ID
InfoFind.HTML.ByID = function(ID) {
	var Element = ID;
	if (typeof(ID) == "string") {
		//All Modern Browsers (IE, Firefox, Opera, Safari, etc)
		if (document.getElementById) {
			Element = document.getElementById(ID);
		//Older Versions of IE (IE5+ are supported)
		} else if (document.all) {
			Element = document.all[ID];
		//Code for Netscape Navigator 4 - Not Supported
		} else if (document.layers) {
			//Return null so this code won't execute and errors
			//from InfoFind code will not happen.
			Element = null;
			//The following line would return the Netscape Navigator Element.
			//Element = document.layers[ID];
		}
	}
	return Element;
}

//Return Array of HTML Elements of the Same Tag Name
InfoFind.HTML.ByTag = function(TagName) {
	//All Modern Browsers (IE, Firefox, Opera, Safari, etc)
	if (document.getElementsByTagName) {
		return document.getElementsByTagName(TagName);
	//Older Versions of IE (IE5+ are supported)
	} else if (document.all) {
		return document.all.tags(TagName);
	//Code for Netscape Navigator 4 or Unknown Browser - Not Supported
	} else {
		return null;
	}
}

//Add Event to an HTML Element. Example:
//	InfoFind.HTML.AddEvent(window, "load", window_onload);
//Depending upon Browser this may or may not add the events in the 
//order they are passed. Example:
//	InfoFind.HTML.AddEvent(Button, "click", Func1);
//	InfoFind.HTML.AddEvent(Button, "click", Func2);
//	Either Func1() or Func2() might be called first. There is no way to know.
//If a specific order is needed then the best way is to create a new
//function with all the events to call and pass the new function. Example:
//	InfoFind.HTML.AddEvent(Button, "click", (function(e) {BeforeClick(e); Buttton_onclick(e); AfterClick(e);}) );
InfoFind.HTML.AddEvent = function(Element, Event, Function) {
	Element = InfoFind.HTML.ByID(Element);
	//Mozilla/Firefox/Safari
	if (Element.addEventListener) {
		Element.addEventListener(Event, Function, false);
	//IE
	} else if (Element.attachEvent) {
		Element.attachEvent("on" + Event, Function);
	//Older Browsers (IE4, etc)
	} else {
		//This works by checking if the event is already handled, if it is
		//then a new function is created that first calls the old event 
		//then the new event.
		var CurrentEvent = Element["on" + Event];
		if (CurrentEvent) {
			Element["on" + Event] = (function(e){CurrentEvent(e); Function(e);});
		} else {
			Element["on" + Event] = Function;
		}
	}
}

//Remove Event from an HTML Element. Example:
//	InfoFind.HTML.RemoveEvent(Button, "click", submit_onclick);
InfoFind.HTML.RemoveEvent = function(Element, Event, Function) {
	Element = InfoFind.HTML.ByID(Element);
	//Mozilla/Firefox/Safari
	if (Element.removeEventListener) {
		Element.removeEventListener(Event, Function, false);
	//IE
	} else if (Element.detachEvent) {
		Element.detachEvent("on" + Event, Function);
	//Older Browsers
	} else {
		//Not able to remove specific events with this function 
		//so the event is set to null when this is called.
		Element["on" + Event] = null;
	}
}

//Stop an Event from continuing. For example, if a link element
//opens a page in a new window but a JavaScript onclick event
//wants to cancel the action then some browsers will work with
//"return false;" but others will require a StopEvent() function. 
InfoFind.HTML.StopEvent = function(e) {
	e = e || window.event;
	//IE
	if (e.cancelBubble && e.returnValue) {
		e.cancelBubble = true;
		e.returnValue = false;
	//Mozilla
	} else if (e.preventDefault && e.stopPropagation) {
		e.preventDefault();
		e.stopPropagation();
	}
	return true;
}

///////////////////////////////////////////////////////
//InfoFind.HTML.Window
//Help with general HTML Window Properties.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.HTML.Window");

//Return height of the viewable window.
InfoFind.HTML.Window.GetHeight = function() {
	if (window.innerHeight) {
		return window.innerHeight;
	} else if (document.documentElement && document.documentElement.offsetHeight) {
		return document.documentElement.offsetHeight;
	} else if (document.body && document.body.clientHeight) {
		return document.body.clientHeight;
	}
	return 0;
}

//Return width of the viewable window.
InfoFind.HTML.Window.GetWidth = function() {
	if (window.innerWidth) {
		return window.innerWidth;
	} else if (document.documentElement && document.documentElement.offsetWidth) {
		return document.documentElement.offsetWidth;
	} else if (document.body && document.body.clientWidth) {
		return document.body.clientWidth;
	}
	return 0;
}

///////////////////////////////////////////////////////
//InfoFind.HTML.Document
//Help with general HTML document properties.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.HTML.Document");

//Return height of the entire document.
InfoFind.HTML.Document.GetHeight = function() {
	var Height = 0, Height1 = 0, Height2 = 0;
	if (document.documentElement && document.documentElement.scrollHeight) {
		Height1 = document.documentElement.scrollHeight;
	}
	if (document.body && document.body.scrollHeight) {
		Height2 = document.body.scrollHeight;
	}
	Height = Math.max(Math.max(Height1, Height2), InfoFind.HTML.Window.GetHeight());
	return Height;
}

//This function returns the height of the item that
//is furthest to the bottom of the page. It searches
//through every element and can possibly take a while
//depending upon the page. Because of this for some pages
//it may be best to perform calculations from the position 
//of a single known element if this information is needed.
InfoFind.HTML.Document.GetMaxHeight = function() {
	var Height = InfoFind.HTML.Document.GetHeight();
	var Elements = InfoFind.HTML.ByTag("*");
	var ElementHeight = 0, Location;
	for (n = 0; n < Elements.length; n++) {
		Location = InfoFind.HTML.Element.GetPosition(Elements[n]);
		if (Location.Height > 0) {
			ElementHeight = Location.Top + Location.Height;
			Height = Math.max(Height, ElementHeight);
		}
	}
	return Height;
}

//Return width of the entire document.
InfoFind.HTML.Document.GetWidth = function() {
	var Width = 0, Width1 = 0, Width2 = 0;
	if (document.documentElement && document.documentElement.scrollWidth) {
		Width1 = document.documentElement.scrollWidth;
	}
	if (document.body && document.body.scrollWidth) {
		Width2 = document.body.scrollWidth;
	}
	Width = Math.max(Math.max(Width1, Width2), InfoFind.HTML.Window.GetWidth());
	return Width;
}

//See comments from InfoFind.HTML.Document.GetMaxHeight().
InfoFind.HTML.Document.GetMaxWidth = function() {
	var Width = InfoFind.HTML.Document.GetWidth();
	var Elements = InfoFind.HTML.ByTag("*");
	var ElementWidth = 0, Location;
	for (n = 0; n < Elements.length; n++) {
		Location = InfoFind.HTML.Element.GetPosition(Elements[n]);
		if (Location.Width > 0) {
			ElementWidth = Location.Left + Location.Width;
			Width = Math.max(Width, ElementWidth);
		}
	}
	return Width;
}

//Get the position of the mouse pointer.
InfoFind.HTML.Document.GetMousePosition = function(e) {
	e = e || window.event;
	var Cursor = { Left:0, Top:0 };
	if (e.pageX || e.pageY) {
		Cursor.Left = e.pageX;
		Cursor.Top = e.pageY;
	} else if (document.documentElement && (document.documentElement.clientLeft || document.documentElement.clientTop)) {
		Cursor.Left = e.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft;
		Cursor.Top = e.clientY + document.documentElement.scrollTop - document.documentElement.clientTop;
	} else if (document.body && (document.body.clientLeft || document.body.clientTop)) {
		Cursor.Left = e.clientX + document.body.scrollLeft - document.body.clientLeft;
		Cursor.Top = e.clientY + document.body.scrollTop - document.body.clientTop;
	}
	return Cursor;
}

//Get the position of where the page is scroll to in relation
//to the very top/left of the page.
InfoFind.HTML.Document.GetScrollPosition = function() {
	var Location = { Left:0, Top:0 };
	if (window.pageXOffset || window.pageYOffset) {
		Location.Left = window.pageXOffset;
		Location.Top = window.pageYOffset;
	} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
		Location.Left = document.documentElement.scrollLeft;
		Location.Top = document.documentElement.scrollTop;
	} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
		Location.Left = document.body.scrollLeft;
		Location.Top = document.body.scrollTop;
	}
	return Location;
}

///////////////////////////////////////////////////////
//InfoFind.HTML.Element
//Help with basic HTML Element Properties.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.HTML.Element");

//Get Position in Pixels (Left, Top, Height, Width) of an Element.
//Note - for some browsers the css style position of the 
//element might have to be set with a value. (i.e.: style="position:absolute;")
InfoFind.HTML.Element.GetPosition = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
    var Location = { Left:0, Top:0, Width:0, Height:0 };
    if (Element.style && Element.style.width && !isNaN(parseInt(Element.style.width))) { 
		Location.Width = parseInt(Element.style.width);
	} else if (Element.offsetWidth) {
		Location.Width = Element.offsetWidth;
    }
    if (Element.style && Element.style.height && !isNaN(parseInt(Element.style.height))) { 
		Location.Height = parseInt(Element.style.height);
	} else if (Element.offsetHeight) {
		Location.Height = Element.offsetHeight;
    }
    if (Element.style.position == "fixed" || Element.style.position == "absolute") {
        Location.Left = Element.offsetLeft;
        Location.Top = Element.offsetTop;
    } else {
        while (Element) {
            if (Element.offsetLeft) Location.Left += Element.offsetLeft;
            if (Element.offsetTop) Location.Top += Element.offsetTop;
            Element = Element.offsetParent;
        }
    }
    return Location;
}

//Get the Top Location of the Element.
InfoFind.HTML.Element.GetTop = function(Element) {
	return InfoFind.HTML.Element.GetPosition(Element).Top;
}

//Get the Left Location of the Element.
InfoFind.HTML.Element.GetLeft = function(Element) {
	return InfoFind.HTML.Element.GetPosition(Element).Left;
}

//Get the Height of the Element.
InfoFind.HTML.Element.GetHeight = function(Element) {
	return InfoFind.HTML.Element.GetPosition(Element).Height;
}

//Get the Width of the Element.
InfoFind.HTML.Element.GetWidth = function(Element) {
	return InfoFind.HTML.Element.GetPosition(Element).Width;
}

//Focus the Viewable area of the Page to the Element.
InfoFind.HTML.Element.ScrollTo = function(Element) {
	var Location = InfoFind.HTML.Element.GetPosition(Element);
	if (Location && Location.Left && Location.Top) {
		window.ScrollTo(Location.Left, Location.Top);
	}
}

//Move an Element to a specific location on the page.
//Location is specified in Pixels.
//Example: InfoFind.HTML.Element.Move("Div1", 100, 100, 100, 100, false);
InfoFind.HTML.Element.Move = function(Element, Top, Left, Height, Width, bFixed) {
	Element = InfoFind.HTML.ByID(Element);
	if (Element && Element.style) {
		if (Top || Left) {
			//IE6 and below do not allow for "fixed" positioning.
			//Fixed positioning allows for an element to move
			//with the page as the user scrolls.
			if (bFixed) {
				try {
					Element.style.position = "fixed";
				} catch(e) {
					Element.style.position = "absolute";
				}
			} else {
				Element.style.position = "absolute";
			}
		}
		if (Top) Element.style.top = Top + "px";
		if (Left) Element.style.left = Left + "px";
		if (Height) Element.style.height = Height + "px";
		if (Width) Element.style.width = Width + "px";
	}
}

//Set the Top Location of the Element.
InfoFind.HTML.Element.SetTop = function(Element, Top) {
	InfoFind.HTML.Element.Move(Element, Top, null, null, null, false);
}

//Set the Left Location of the Element.
InfoFind.HTML.Element.SetLeft = function(Element, Left) {
	InfoFind.HTML.Element.Move(Element, null, Left, null, null, false);
}

//Set the Height of the Element.
InfoFind.HTML.Element.SetHeight = function(Element, Height) {
	InfoFind.HTML.Element.Move(Element, null, null, Height, null, false);
}

//Set the Width of the Element.
InfoFind.HTML.Element.SetWidth = function(Element, Width) {
	InfoFind.HTML.Element.Move(Element, null, null, null, Width, false);
}

//Add an Element to the Page and return it.
//Example: InfoFind.HTML.Element.Add("div", "Div1")
InfoFind.HTML.Element.Add = function(Tag, ObjectID) {
	var obj = document.createElement(Tag);
	obj.id = ObjectID;
	InfoFind.HTML.ByTag("body")[0].appendChild(obj);
	return obj;
}

//Remove an Element from the Page.
InfoFind.HTML.Element.Remove = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
	var parent = (Element.parentNode || Element.parentElement);
	if (parent) parent.removeChild(Element);
}

//Show an Element if it is Hidden. The difference between
//Show(), Hide() vs. SetVisibility() is that Show/Hide will
//hide completely the element from the page and other elements
//will adjust for the blank space while SetVisibility() will
//hide the element but preserve the layout of the page based
//upon the hidden elements dimensions.
InfoFind.HTML.Element.Show = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
	Element.style.display = "";
}

//Hide an Element, this might affect the page layout.
InfoFind.HTML.Element.Hide = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
	Element.style.display = "none";
}

//Return true if Element or any of it's parent nodes are hidden.
InfoFind.HTML.Element.IsHidden = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
	var bHidden = false;
	while (Element.style && Element.style.display != "none") {
		var parent = (Element.parentNode || Element.parentElement);
		if (!parent) break;
		Element = parent;
	}
	if (Element.style && Element.style.display) {
		if (Element.style.display == "none") bHidden = true;
	}
	return bHidden;
}

//Show or Hide and Element without affecting the page layout.
InfoFind.HTML.Element.SetVisibility = function(Element, bVisible) {
	Element = InfoFind.HTML.ByID(Element);
	Element.style.visibility = (bVisible ? "visible" : "hidden");
}

//Return true if visibility is not hidden for the 
//Element and it's parent nodes.
InfoFind.HTML.Element.GetVisibility = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
	var bVisible = true;
	//Note - inherit is the default so check parent nodes.
	while (Element.style && Element.style.visibility != "hidden") {
		var parent = (Element.parentNode || Element.parentElement);
		if (!parent) break;
		Element = parent;
	}
	if (Element.style && Element.style.visibility) {
		if (Element.style.visibility == "hidden") bVisible = false;
	}
	return bVisible;
}

//Return true if Element is Visible and false if it cannot be 
//seen based on either style.display or style.visibility.
InfoFind.HTML.Element.IsVisible = function(Element) {
	Element = InfoFind.HTML.ByID(Element);
	return (InfoFind.HTML.Element.IsHidden(Element) || !InfoFind.HTML.Element.GetVisibility(Element) ? false : true);
}

//Return True/False if an Element has a Class (Case-Insensitive).
//(i.e.: class="FONT1" - InfoFind.HTML.Element.HasClass("div1", "font1") = true)
InfoFind.HTML.Element.HasClass = function(Element, ClassName) {
	Element = InfoFind.HTML.ByID(Element);
	if (!ClassName || ClassName == "") return false;
	ClassName = ClassName.toLowerCase();
	var CurClass = " " + Element.className.toLowerCase() + " ";
	if (CurClass.indexOf(" " + ClassName + " ") != -1) {
		return true;
	}
	return false;
}

//Add a class to an Element.
InfoFind.HTML.Element.AddClass = function(Element, ClassName) {
	Element = InfoFind.HTML.ByID(Element);
	if (!ClassName || ClassName == "") return;
	var CurClass = " " + Element.className + " ";
	if (CurClass.indexOf(" " + ClassName + " ") == -1) {
		CurClass = Element.className + " " + ClassName;
		Element.className = InfoFind.DataTypes.Trim(CurClass);
	}
}

//Remove a class from an Element.
InfoFind.HTML.Element.RemoveClass = function(Element, ClassName) {
	Element = InfoFind.HTML.ByID(Element);
	if (!ClassName || ClassName == "") return;
	var CurClass = " " + Element.className + " ";
	if (CurClass.indexOf(" " + ClassName + " ") != -1) {
		CurClass = CurClass.replace(" " + ClassName + " ", " ");
		Element.className = InfoFind.DataTypes.Trim(CurClass);
	}
}

//Set the Opacity of an Element.
//Example: 
//	Hide Completely: InfoFind.HTML.Element.SetOpacity("div1", 0);
//	Show at 50%: InfoFind.HTML.Element.SetOpacity("div1", 50);
InfoFind.HTML.Element.SetOpacity = function(Element, Percent) {
	Element = InfoFind.HTML.ByID(Element);
	if (Element && Element.style) {
		//Opera/W3C CSS3 Definition (Most Recent Firefox/Safari Browsers)
		//Konqueror 3.5 and above, 3.4 does not support Opacity.
		//Opera 9.5 includes a filter property so opacity must be checked first.
		if (typeof(Element.style.opacity) == "string") {
			Element.style.opacity = (Percent / 100);
		//IE
		} else if (typeof(Element.style.filter) == "string") { 
			//Note - IE allows many types of filters and transformations. Example: If
			//		 DXImageTransform.Microsoft.Gradient is specified with !important for 
			//		 an Element in a CSS File and Element.style.filter were called the 
			//		 opacity feature would not work. However if the CSS defines both 
			//		 DXImageTransform.Microsoft.Gradient and DXImageTransform.Microsoft.Alpha
			//		 before hand then this code will work and merge both Grandient and Opacity.
			//		 This rule applies to other filters as well. If no filter is set then this
			//		 code will set the style.filter of the Element.
			//For IE 5.5 and above
			var Filter = "DXImageTransform.Microsoft.Alpha";
			var FilterText = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + Percent + ")";
			//For IE 4.0 to 5.5 - Deterine using conditional compilation. Only IE uses conditional 
			//compilation and the version of IE is not checked rather the version of JScript.
			/*@cc_on
				@if (@_jscript_version < 5.5)
					Filter = "alpha";
					FilterText = "alpha(opacity=" + Percent + ")";
				@end
			@*/
			var bCreateFilter = true;
			if (Element.filters && Element.filters.length > 0) {
				var Alpha = Element.filters[Filter];
				if (Alpha) {
					Alpha.opacity = Percent;
					bCreateFilter = false;
				}
			}
			if (bCreateFilter) {
				Element.style.filter = FilterText;
			}
		//Older Firefox/Mozilla
		} else if (typeof(Element.style.MozOpacity) == "string") {
			Element.style.MozOpacity = (Percent / 100);
		//Older Safari
		} else if (typeof(Element.style.KhtmlOpacity) == "string") {
			Element.style.KhtmlOpacity = (Percent / 100);
		}
	}
}

//Force an Element to Redraw itself. This function can be used when
//an element doesn't look good after some other action on the page.
//On InfoFind's test page this is used for bugs with IE when part of
//an element disappears after various events are called. If this 
//doesn't work for a specific page another option is to remove 
//and add a class from the element's style.
InfoFind.HTML.Element.Redraw = function(Element) {
	try {
		Element = InfoFind.HTML.ByID(Element);
		var BlankText = document.createTextNode(" ");
		Element.appendChild(BlankText);
		Element.removeChild(BlankText);
		BlankText = null;
	} catch(e) {
		//Do Nothing
	}
}

//Set the inside text of an Element. Different browsers handle
//this differently.
InfoFind.HTML.Element.SetText = function(Element, Text) {
    Element = InfoFind.HTML.ByID(Element);
    //Opera/IE/Safari
    if (typeof(Element.innerText) == "string") {
        Element.innerText = Text;
    //Mozilla/Firefox doesn't support innerText.
    } else if (typeof(Element.textContent) == "string") {
        Element.textContent = Text;
    //Just in case
    } else if (typeof(Element.innerHTML) == "string") {
        Element.innerHTML = Text;
    }
}

///////////////////////////////////////////////////////
//InfoFind.CSS
//Cascade Style Sheets (CSS) helper functions.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.CSS");

//This works with all browsers but the Style Sheet needs to be defined
//with an ID. Example:
//HTML:
//	<link id="StyleLink" href="Theme1.css" type="text/css" rel="stylesheet">
//Javascript:
//	InfoFind.CSS.ChangeStyleSheet("StyleLink", "Theme2.css");
//
//Note - At time of publishing Firefox 3 has just been released, this  
//still works but the page flickers. This does not happen in any other 
//browser or in Firefox 1 or 2 so it's not yet known if this is a new 
//bug with Firefox 3 or if this is permanent rendering behavior change.
InfoFind.CSS.ChangeStyleSheet = function(StyleSheet, Location) {
	StyleSheet = InfoFind.HTML.ByID(StyleSheet);
	StyleSheet.href = Location;
}

//Return True/False if an Element has a Class (Case-Insensitive).
//(i.e.: class="FONT1" - InfoFind.CSS.ElementHasClass("div1", "font1") = true)
InfoFind.CSS.ElementHasClass = function(Element, ClassName) {
	return InfoFind.HTML.Element.HasClass(Element, ClassName);
}

//Add a class to an Element.
InfoFind.CSS.ElementAddClass = function(Element, ClassName) {
	return InfoFind.HTML.Element.AddClass(Element, ClassName);
}

//Remove a class from an Element.
InfoFind.CSS.ElementRemoveClass = function(Element, ClassName) {
	return InfoFind.HTML.Element.RemoveClass(Element, ClassName);
}

///////////////////////////////////////////////////////
//InfoFind.Cookies
//Cookies allow variables to be saved on a users
//computer so next time the same page is accessed 
//information can be remembered.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.Cookies");

//Get a cookie by name or if it doesn't exist then
//return an empty string.
InfoFind.Cookies.Get = function(Name) {
	var Cookies = document.cookie.split("; ");
	for (var n = 0; n < Cookies.length; n++) {
		var Cookie = Cookies[n].split("=");
		if (Cookie && Cookie.length >= 1) {
			if (Cookie[0] == Name) {
				if (Cookie[1] == "undefined") {
					return "";
				} else {
					return unescape(Cookie[1]);
				}
			}
		}
	}
	return "";
}

//Set a cookie by name.
//Examples:
//InfoFind.Cookies.Set("User", "JohnDoe")
// or
//InfoFind.Cookies.Set("User", "JohnDoe", 5)
// or
//InfoFind.Cookies.Set("User", "JohnDoe", 5, "/UserInfo", "www.domain.com", true)
InfoFind.Cookies.Set = function(Name, Value, DaysToExpire, Path, Domain, Secure) {
	var Cookie = "";
	Cookie = Name + "=" + escape(Value);
	if (DaysToExpire) {
		var d = new Date();
		d.setTime(d.getTime() + (DaysToExpire * 24 * 60 * 60 * 1000));
		expire = "; expires=" + d.toGMTString();
	}
	Cookie += "; path=" + ((Path) ? Path : "/");
	if (Domain) Cookie += "; domain=" + Domain;
	if (Secure) Cookie += "; secure";
	document.cookie = Cookie;
}

//Erase a cookie by name.
InfoFind.Cookies.Erase = function(Name) {
	InfoFind.Cookies.Set(Name, "", -1);
}

///////////////////////////////////////////////////////
//InfoFind.WebRequest
//Functions for getting and sending data to server
//without refreshing page. Years ago this technique was 
//often called "Internet(or)Web-RFC" (Remote Function Call). 
//Then it became known as "Web Services" and now it is commonly 
//referred to as Ajax (Asynchronous JavaScript and XML).
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.WebRequest");

//If true then the error contents will be displayed
//in the innerHTML of the element that was to be updated.
InfoFind.WebRequest.DisplayError = true;
//DisplayUrlOnError can be set to true for debug use. It will
//display the URL that caused the error with alert().
InfoFind.WebRequest.DisplayUrlOnError = false;
//If ErrorMessage is filled in then it will display with
//an alert() if an error occurs.
InfoFind.WebRequest.ErrorMessage = "Error updating page. Please refresh or try again later.";
//To display a progress bar or other loading status set this with valid HTML.
//Example: '<img src="images/loading.gif" style="background-color: white;"></img>';
InfoFind.WebRequest.LoadingHTML = "";

//Return the XMLHttpRequest Object.
InfoFind.WebRequest.GetConnection = function() {
	//If native object
	if (typeof(XMLHttpRequest) != "undefined") {
		return new XMLHttpRequest();
	}
	//Currently only IE supports conditional compilation.
	//Find the best one for Versions of IE prior to 7
	var progIDs = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
	for (var i = 0; i < progIDs.length; i++)
	{
		try {
			var XmlHttp = new ActiveXObject(progIDs[i]);
			return XmlHttp;
		} catch(e) {
		}
	}
    return null;
}

//Update an Element on the Page with HTML from a Web Request.
//Call with or without FuncPtr.
//Examples: 
//	InfoFind.WebRequest.UpdatePageElement(URL, "DataQuery");
//	InfoFind.WebRequest.UpdatePageElement(URL, "DataQuery", UpdateTable);
InfoFind.WebRequest.UpdatePageElement = function(URL, ElementID, FuncPtr) {
	var Connection = InfoFind.WebRequest.GetConnection();
	if (Connection) {
		Connection.onreadystatechange = function() {
			if (Connection.readyState == 4 && Connection.status == 200) {
				InfoFind.HTML.ByID(ElementID).innerHTML = Connection.responseText;
				if (FuncPtr) {
					FuncPtr();
				}
			} else if (Connection.readyState == 4) {
				InfoFind.HTML.ByID(ElementID).innerHTML = "";
				if (InfoFind.WebRequest.ErrorMessage) {
					alert(InfoFind.WebRequest.ErrorMessage);
				}
				if (InfoFind.WebRequest.DisplayUrlOnError) {
					alert(URL);
				}
				if (InfoFind.WebRequest.DisplayError) {
					InfoFind.HTML.ByID(ElementID).innerHTML = Connection.responseText;
				}
			}
		}
		InfoFind.HTML.ByID(ElementID).innerHTML = InfoFind.WebRequest.LoadingHTML;
		Connection.open("GET", URL, true);
		Connection.send(null);
	}
}

///////////////////////////////////////////////////////
//InfoFind.DataForms
//Functions for easily working with Web Forms. This
//includes functions for reading/writing to controls
//and functions for automatically validating a wide
//range of data types without having to add any JavaScript
//to the web page.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.DataForms");

//This function will validate a form. It can be called manually through JavaScript at
//any time or automatically if the class "ValidateForm" is added to the form.
//	Example: <form method="post" name="Form1" class="ValidateForm" action="...
//Then to validate the actual fields you can add one of many validation rules as a 
//css class. For example to validate a required entry with a numeric range of 50 to 100 
//and without decimal numbers you could use the following classes.
//	<input type="text" class="ValidateNumber_50_100 ValidateWholeNumber IsRequired"...
//To see all of the options please look at the sample files or review the code.
//The full list of validation rules are as follows:
//	ValidateNumber_XX_XX, ValidateDate_XX_XX, IsRequired, ValidateNumber, ValidateWholeNumber
//	ValidateNumberByte, ValidateNumber16Bit, ValidateNumberUShort, ValidateNumber32Bit
//	ValidateNumberUInt, ValidateNumberFloat, ValidateNumber64Bit, ValidateNumberULong
//	ValidateNumberDouble, ValidateCurrency, ValidateDate, ValidateDbDate
//	ValidateDbDateTime, ValidateEmail
InfoFind.DataForms.ValidateForm = function(FormID) {
    //Get the Form
    var Form = InfoFind.HTML.ByID(FormID);
    //Check each control on the form.
	for (var n = 0; n < Form.elements.length; n++) {
	    var Control = Form.elements[n];
	    var aData, aData2, m = 0;
		//Validate controls for specific data types, etc.
	    var bIsRequired = false, bNumber = false, bCurrency = false;
	    var bDate = false, bDbDate = false, bDbDateTime = false;
	    var bWholeNumber = false, bEmail = false, bNumberByte = false;
	    var bNumber16Bit = false, bNumberUShort = false; 
	    var bNumber32Bit = false, bNumberUInt = false;
	    var bNumber64Bit = false, bNumberULong = false;
	    var bNumberFloat = false, bNumberDouble = false;
	    var bNumberRange = false, MinNumber = 0, MaxNumber = 0;
	    var bDateRange = false, MinDate = null, MaxDate = null;
		//Validate a specific range of numbers or dates. Example to validate 
		//between 50 and 100 add this class "ValidateNumber_50_100". For dates
		//validation is in days from today so to validate for -30 Days to +30 Days 
		//from today add the class "ValidateDate_30_30".
        if (Control.className && Control.className != "") {
            aData = Control.className.split(" ");
            for (m = 0; m < aData.length; m++) {
				//Validate a Number Range
                if (InfoFind.DataTypes.IsLike(String(aData[m]).toLowerCase(), "ValidateNumber_*#_*#".toLowerCase())) {
                    aData2 = aData[m].split("_");
                    MinNumber = InfoFind.DataTypes.StringToNumber(aData2[1]);
                    MaxNumber = InfoFind.DataTypes.StringToNumber(aData2[2]);
                    if (MinNumber > 0 || MaxNumber > 0) bNumberRange = true;
                    break;
                //Validate a Date Range
                } else if (InfoFind.DataTypes.IsLike(String(aData[m]).toLowerCase(), "ValidateDate_*#_*#".toLowerCase())) {
                    aData2 = aData[m].split("_");
                    MinDate = InfoFind.DataTypes.StringToNumber(aData2[1]);
                    MaxDate = InfoFind.DataTypes.StringToNumber(aData2[2]);
                    MinDate = InfoFind.DataTypes.DateAddDays((new Date()), -MinDate);
                    MaxDate = InfoFind.DataTypes.DateAddDays((new Date()), MaxDate);
                    bDateRange = true;
                    break;
                }
            }
        }
        //General Validation Properties - Required, Whole Number
        var e = InfoFind.HTML.Element;
	    if (e.HasClass(Control, "IsRequired")) bIsRequired = true;
	    if (e.HasClass(Control, "ValidateWholeNumber")) bWholeNumber = true;
	    //General Data Types
	    if (!bNumberRange && !bDateRange) {
		    if (e.HasClass(Control, "ValidateNumber")) {
		        bNumber = true;
		    } else if (e.HasClass(Control, "ValidateNumberByte")) {
		        bNumberByte = true;
		    } else if (e.HasClass(Control, "ValidateNumber16Bit")) {
		        bNumber16Bit = true;
		    } else if (e.HasClass(Control, "ValidateNumberUShort")) {
		        bNumberUShort = true;
		    } else if (e.HasClass(Control, "ValidateNumber32Bit")) {
		        bNumber32Bit = true;
		    } else if (e.HasClass(Control, "ValidateNumberUInt")) {
		        bNumberUInt = true;
		    } else if (e.HasClass(Control, "ValidateNumberFloat")) {
		        bNumberFloat = true;
		    } else if (e.HasClass(Control, "ValidateNumber64Bit")) {
		        bNumber64Bit = true;
		    } else if (e.HasClass(Control, "ValidateNumberULong")) {
		        bNumberULong = true;
		    } else if (e.HasClass(Control, "ValidateNumberDouble")) {
		        bNumberDouble = true;
		    } else if (e.HasClass(Control, "ValidateCurrency")) {
		        bCurrency = true;
		    } else if (e.HasClass(Control, "ValidateDate")) {
		        bDate = true;
		    } else if (e.HasClass(Control, "ValidateDbDate")) {
		        bDbDate = true;
		    } else if (e.HasClass(Control, "ValidateDbDateTime")) {
		        bDbDateTime = true;
		    } else if (e.HasClass(Control, "ValidateEmail")) {
		        bEmail = true;
		    }
        }
		//Is this control being validated?
		if (bIsRequired || bDateRange || bNumberRange || bNumber || bWholeNumber || bNumberByte || 
			bNumber16Bit || bNumberUShort || bNumber32Bit || bNumberUInt || bNumberFloat || bNumber64Bit || 
			bNumberULong || bNumberDouble || bCurrency || bDate || bDbDate || bDbDateTime || bEmail) {
	        //Get the Label
	        var Label = "";
	        //First check the class of the control for something like "Label_FirstName".
	        if (Control.className && Control.className != "") {
	            aData = Control.className.split(" ");
	            for (m = 0; m < aData.length; m++) {
	                if (InfoFind.DataTypes.StartsWith(aData[m], "Label_")) {
	                    Label = InfoFind.DataTypes.Mid(aData[m], "Label_".length + 1);
	                    if (Label != "") break;
	                }
	            }
	        }
	        //Nothing found use the name of the control. If the name begins one of 
	        //the common input prefixes of ("txt", "cbo") then remove the prefix.
	        if (Label == "") Label = Control.name;
	        switch (InfoFind.DataTypes.Left(Label, 3).toLowerCase()) {
				case "txt":
				case "cbo":
					Label = InfoFind.DataTypes.Mid(Label, 4);
					break;
			}
	        //Still nothing then use the following
	        if (Label == "") {
	            Label = "The selected field";
	        //Otherwise separate the name first by underscore character "_" or if no
	        //underscore then by casing - example "First_Name" or "FirstName" will be displayed as "First Name"
	        } else {
				if (Label.indexOf("_") != -1) {
					Label = Label.replace(/_/g, " ");
				} else {
					var OldLabel = Label;
					Label = "";
					for (m = 0; m < OldLabel.length; m++) {
						var Char = OldLabel.substring(m, m + 1); 
						if (InfoFind.DataTypes.IsUCaseLetter(Char)) Label += " ";
						Label += Char;
					}
				}
	        }
	        //Only trim spaces for text boxes
	        var bTrim = (Control.type == "text" ? true : false);
	        //Now Validate - if false is returned the focus of the cursor will be set to the control with the error.
	        var f = InfoFind.DataForms;
	        if (bNumberRange) {
	            if (!f.Input_ValidateNumberRange(Control, Label, bIsRequired, bTrim, bWholeNumber, MinNumber, MaxNumber)) return false;
	        } else if (bDateRange) {
				if (!f.Input_ValidateDateRange(Control, Label, bIsRequired, bTrim, MinDate, MaxDate)) return false;
	        } else if (bNumberByte) {
	            if (!f.Input_ValidateNumberByte(Control, Label, bIsRequired)) return false;
	        } else if (bNumber16Bit) {
	            if (!f.Input_ValidateNumber16Bit(Control, Label, bIsRequired)) return false;
	        } else if (bNumberUShort) {
	            if (!f.Input_ValidateNumberUShort(Control, Label, bIsRequired)) return false;
	        } else if (bNumber32Bit) {
	            if (!f.Input_ValidateNumber32Bit(Control, Label, bIsRequired)) return false;
	        } else if (bNumberUInt) {
	            if (!f.Input_ValidateNumberUInt(Control, Label, bIsRequired)) return false;
	        } else if (bNumberFloat) {
				if (!f.Input_ValidateNumberFloat(Control, Label, bIsRequired)) return false;
	        } else if (bNumber64Bit) {
	            if (!f.Input_ValidateNumber64Bit(Control, Label, bIsRequired)) return false;
	        } else if (bNumberULong) {
	            if (!f.Input_ValidateNumberULong(Control, Label, bIsRequired)) return false;
	        } else if (bNumberDouble) {
				if (!f.Input_ValidateNumberDouble(Control, Label, bIsRequired)) return false;
	        } else if (!f.Input_Validate(Control, Label, bIsRequired, bTrim, bNumber, bWholeNumber, bCurrency, bDate, bDbDate, bDbDateTime, bEmail)) {
                return false;
		    }
		}
	}
	//If code makes it here the form is valid.
	return true;
}

//Validate a control or a specific data type. Return true if valid and false if invalid. 
//If invalid the user will be prompted and the cursor will be focused to the control.
//Examples:
//  Validate for a number = Input_Validate("txtAmount", "Amount", true, true, true)
//  Validate for a short date or blank = Input_Validate("txtDate", "Date", false, true, false, false, false, false, true)
//  Validate for a non-blank string = Input_Validate("txtFirstName", "First Name", true, true)
InfoFind.DataForms.Input_Validate = function(Input, Label, bRequired, bTrim, bNumber, bWholeNumber, bCurrency, bDate, bDbDate, bDbDateTime, bEmail) {
    var f = InfoFind.DataForms;
    if (bTrim) f.SetControlValue(Input, InfoFind.DataTypes.Trim(f.GetControlValue(Input)));
    var Text = f.GetControlValue(Input);
    //Text Entered?
    if (Text == "") {
        if (!bRequired) return true;
        alert(Label + " must be filled in.");
        Input.focus();
        return false;
    }
    //Check for a number
    if (bNumber || bWholeNumber) {
        if (!InfoFind.DataTypes.IsNumeric(Text)) {
            alert(Label + " must be filled in with a valid number.");
            Input.focus();
            return false;
        }
		//Check for whole number - no decimal places
        if (bWholeNumber) {
			var num = InfoFind.DataTypes.StringToNumber(Text);
			if (String(num).indexOf(".") > -1) {
				alert(Label + " must be entered as a whole number with no decimal places.");
				Input.focus();
				return false;
			}
        }
    //Check for a currency
    } else if (bCurrency) {
        if (!InfoFind.DataTypes.IsCurrency(Text)) {
            alert(Label + " must be filled in with a valid currency.");
            Input.focus();
            return false;
        }
    //Check for a date
    } else if (bDate) {
        if (!InfoFind.DataTypes.IsDate(Text)) {
            alert(Label + " must be filled in with a valid date.");
            Input.focus();
            return false;
        }
    //Check for a date entered as a short format
    } else if (bDbDate) {
        if (!InfoFind.DataTypes.IsDbDate(Text)) {
            alert(Label + " must be filled in with a valid date.");
            Input.focus();
            return false;
        }
    //Check for a date/time entered as a short format
    } else if (bDbDateTime) {
        if (!InfoFind.DataTypes.IsDbDateTime(Text)) {
            alert(Label + " must be filled in with a valid date and time.");
            Input.focus();
            return false;
        }
    //Check for an email
    } else if (bEmail) {
        if (!InfoFind.DataTypes.IsEmail(Text)) {
            alert(Label + " must be filled in with a valid email.");
            Input.focus();
            return false;
        }
    }
    //Return true, Input is valid.
    return true;
}

//Validate for a byte number - Range = 0 To 255
InfoFind.DataForms.Input_ValidateNumberByte = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, 0, 255);
}

//Validate for a 16-bit number - Range = -2^15 To 2^15-1
InfoFind.DataForms.Input_ValidateNumber16Bit = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, -32768, 32767);
}

//Validate for an Unsigned 16-bit number (No negative) - Range = 0 To 2^16-1
InfoFind.DataForms.Input_ValidateNumberUShort = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, 0, 65535);
}

//Validate for a 32-bit number - Range = -2^31 To 2^31-1
InfoFind.DataForms.Input_ValidateNumber32Bit = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, -2147483648, 2147483647);
}

//Validate for an Unsigned 32-bit number (No negative) - Range = 0 To 2^32-1
InfoFind.DataForms.Input_ValidateNumberUInt = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, 0, 4294967295);
}

//Validate for a single-precision floating-point number.
//Approximate range is 10^-38 To 10^38 with accuracy of about 7 digits.
InfoFind.DataForms.Input_ValidateNumberFloat = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, false, Math.pow(10, -44), Math.pow(10, 38));
}

//Validate for a 64-bit number - Range = -2^63 To 2^63-1
//Note - JavaScript does not usually support high-precision 64-Bit Numbers so the 
//actual validation will probably be from -9223372036854776000 to 9223372036854776000.
//The browser will round the numbers as needed.
InfoFind.DataForms.Input_ValidateNumber64Bit = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, -9223372036854775808, 9223372036854775807);
}

//Validate for an Unsigned 64-bit number (No negative) - Range = 0 To 2^64-1
//See comments in Input_ValidateNumber64Bit() - the actual 
//validation will probably be from 0 to 18446744073709552000.
InfoFind.DataForms.Input_ValidateNumberULong = function(Input, Label, bRequired) {
	return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, true, 0, 18446744073709551615);
}

//Validate for a double-precision floating-point number. This is the largest number that JavaScript currently supports.
//Approximate range is 10^-323 To 10^308 with accuracy of about 15 digits.
InfoFind.DataForms.Input_ValidateNumberDouble = function(Input, Label, bRequired) {
    return InfoFind.DataForms.Input_ValidateNumberRange(Input, Label, bRequired, true, false, Math.pow(10, -323), Math.pow(10, 308));
}

//Validate a number range.  See comments for Input_Validate()
InfoFind.DataForms.Input_ValidateNumberRange = function(Input, Label, bRequired, bTrim, bWholeNumber, MinNumber, MaxNumber) {
    var f = InfoFind.DataForms;
    if (bTrim) f.SetControlValue(Input, InfoFind.DataTypes.Trim(f.GetControlValue(Input)));
    var Text = f.GetControlValue(Input);
    //Text Entered?
    if (Text == "") {
        if (!bRequired) return true;
        alert(Label + " must be filled in with a valid number.");
        Input.focus();
        return false;
    }
    //Number Entered?
    if (!InfoFind.DataTypes.IsNumeric(Text)) {
        alert(Label + " must be filled in with a valid number.");
        Input.focus();
        return false;
    }
    //Whole Number Required?
    var num = InfoFind.DataTypes.StringToNumber(Text);
    if (bWholeNumber) {
		if (String(num).indexOf(".") > -1) {
			alert(Label + " must be entered as a whole number with no decimal places.");
			Input.focus();
			return false;
		}
    }
    //Validate the Range
    if (num < MinNumber || num > MaxNumber) {
        alert(Label + " must be filled in with a valid number between " + MinNumber + " and " + MaxNumber + ".");
        Input.focus();
        return false;
    }
    //Return true, Input is valid.
    return true;
}

//Validate a date range. See comments for Input_Validate()
InfoFind.DataForms.Input_ValidateDateRange = function(Input, Label, bRequired, bTrim, MinDate, MaxDate) {
    var f = InfoFind.DataForms;
    if (bTrim) f.SetControlValue(Input, InfoFind.DataTypes.Trim(f.GetControlValue(Input)));
    var Text = f.GetControlValue(Input);
    //Text Entered?
    if (Text == "") {
        if (!bRequired) return true;
        alert(Label + " must be filled in with a valid date.");
        Input.focus();
        return false;
    }
    //Date Entered?
    if (!InfoFind.DataTypes.IsDate(Text)) {
        alert(Label + " must be filled in with a valid date.");
        Input.focus();
        return false;
    }
    //Validate the Range
    var dt = new Date(Text);
    if (dt < MinDate || dt > MaxDate) {
        alert(Label + " must be filled in with a valid date between \n[" + MinDate + "] and \n[" + MaxDate + "].");
        Input.focus();
        return false;
    }
    //Return true, Input is valid.
    return true;
}

//Return Selected Text of Drop-Down or "".
//Pass ID of Control or the Control.
//Examples:
//  InfoFind.DataForms.GetOptionText("Select1")
//  InfoFind.DataForms.GetOptionText(Form1.Select1)
InfoFind.DataForms.GetOptionText = function(Control) {
	var Value = "";
	Control = InfoFind.HTML.ByID(Control);
	if (Control.type == "select-one") {
		if (Control.selectedIndex != -1) {
			Value = Control.options[Control.selectedIndex].text;
		}
	}
	return Value;
}

//Alias for InfoFind.DataForms.GetOptionText()
InfoFind.DataForms.GetControlText = function(Control) {
	return InfoFind.DataForms.GetOptionText(Control);
}

//Return Selected Value of Drop-Down or "", or the Value of any Control.
//Pass ID of Control or the Control.
//Examples:
//  InfoFind.DataForms.GetControlValue("Text1")
//  InfoFind.DataForms.GetControlValue(Form1.Text1)
InfoFind.DataForms.GetControlValue = function(Control) {
	var Value = "";
	Control = InfoFind.HTML.ByID(Control);
	if (Control.type == "select-one") {
		if (Control.selectedIndex != -1) {
			Value = Control.options[Control.selectedIndex].value;
		}
	} else {
		Value = Control.value;
	}
	return Value;
}

//Set the Control Value, for Drop-Downs this function
//compares to the value of the option element.
InfoFind.DataForms.SetControlValue = function(Control, Value) {
	Control = InfoFind.HTML.ByID(Control);
	if (Control.type == "select-one") {
		for (var n = 0; n < Control.options.length; n++) {
			if (Control.options[n].value == Value) {
				Control.selectedIndex = n;
				return true;
			}
		}
	} else {
		Control.value = Value;
		return true;
	}
	return false;
}

//Select a Drop-Down Item by it's text.
InfoFind.DataForms.SetOptionByText = function(Control, Text) {
	Control = InfoFind.HTML.ByID(Control);
	if (Control.type == "select-one") {
		for (var n = 0; n < Control.options.length; n++) {
			if (Control.options[n].text == Text) {
				Control.selectedIndex = n;
				return true;
			}
		}
	}
	return false;
}

//Call on when pages loads.
//See comments in InfoFind.DataForms.Select_OnChange()
InfoFind.DataForms.AttachSelectEvents = function() {
	var Controls = InfoFind.HTML.ByTag("SELECT");
	for (var n = 0; n < Controls.length; n++) {
		InfoFind.HTML.AddEvent(Controls[n], "change", InfoFind.DataForms.Select_OnChange);
	}
}

//Prevent user from accidently scrolling with mouse 
//wheel by focusing to document rather then selection.
//This is useful for certain situations such as 
//corporate web database applications. It is mainly for
//IE and is only needed for very large drop-downs. 
//It is to prevent users from scrolling the combo box
//when the don't realize that they are. A negative feature
//of using this though is that the [tab] and [up/down] keys
//may not work as expected for power users.
InfoFind.DataForms.Select_OnChange = function() {
	try {
		document.body.focus();
	} catch(e) {
	}
}

///////////////////////////////////////////////////////
//InfoFind.Animation
//Animation class, all animation is handled by the 
//function InfoFind.Animation.Animate() and there are a number 
//of helper functions such as InfoFind.Animation.FadeOut() 
//to help make calling an animation easy.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.Animation");

//If true then the last script from InfoFind.Animation.Animate() 
//will be display in an alert() prompt.
InfoFind.Animation.DebugInfoPrompt = false;  

//Examples: 
//	InfoFind.Animation.Animate("Div1", 2, "Opacity,100,0"); //Fade Out
//	InfoFind.Animation.Animate("Div1", 2, "Opacity,0,100"); //Fade In
//	InfoFind.Animation.Animate("Div1", 2, "Opacity,0,100;Resize,10,100"); //Fade In and Resize from 10%
InfoFind.Animation.Animate = function(ElementID, Seconds, AnimationScript, NumberOfAnimations) {
	//Get Element and Check that it is Valid
	var Element = InfoFind.HTML.ByID(ElementID);
	if (!Element && !Element.id) return;
	ElementID = "'" + Element.id + "'";
	
	//General Variables
	var Animations = NumberOfAnimations || 100, bError = false;
	var Interval = Seconds * 1000 / Animations;
	var n = 0, js = "";
	//Opacity Variables
	var bOpacity = false, OpacityStart = 0, OpacityEnd = 0, OpacityCurrent = 0, OpacityAdd = 0;
	//Size & Position Variables
	var WinHeight = InfoFind.HTML.Window.GetHeight(), WinWidth = InfoFind.HTML.Window.GetWidth();
	var DocOffset = InfoFind.HTML.Document.GetScrollPosition();
	var Location = InfoFind.HTML.Element.GetPosition(Element);
	var bResize = false, SizeStart = 0, SizeEnd = 0, SizeCurrent = 0, SizeAdd = 0;
	var Top = 0, Left = 0, Height = 0, Width = 0;
	var bRollDown = false, bRollUp = false, bRollRight = false, bRollLeft = false;
	var TargetTop = 0, StartTop = 0, TargetLeft = 0, StartLeft = 0;
	var bMoveTo = false, bMoveTop = false, bMoveLeft = false;
	var bMoveCircle = false, Angle = 0, Radius = 0, Degree = 0, DegreeAdd = 0;
	var Direction = 0;
	
	//Parse the Script and Create Rules
	AnimationScript = AnimationScript.split(";");
	for (n = 0; n < AnimationScript.length; n++) {
		AnimationScript[n] = AnimationScript[n].split(",");
		switch (AnimationScript[n][0]) {
			//Opacity - StartPercent, EndPercent
			case "Opacity":
				OpacityStart = AnimationScript[n][1] || OpacityStart;
				OpacityEnd = AnimationScript[n][2] || OpacityEnd;
				bOpacity = (OpacityStart > 0 || OpacityEnd > 0);
				if (bOpacity) {
					OpacityCurrent = Number(OpacityStart);
					OpacityAdd = Number((OpacityEnd - OpacityStart) / Animations);
				} else {
					bError = true;
				}
				break;
			//Resize - StartPercent, EndPercent
			case "Resize":
				SizeStart = AnimationScript[n][1] || SizeStart;
				SizeEnd = AnimationScript[n][2] || SizeEnd;
				bResize = (SizeStart > 0 || SizeEnd > 0);
				if (bResize) {
					SizeCurrent = Number(SizeStart / 100);
					SizeAdd = Number((SizeEnd - SizeStart) / Animations / 100);
				} else {
					bError = true;
				}
				break;
			//Roll Down
			case "RollDown":
				bRollDown = true;
				break;
			//Roll Up
			case "RollUp":
				bRollUp = true;
				break;
			//Roll Right
			case "RollRight":
				bRollRight = true;
				break;
			//Roll Left
			case "RollLeft":
				bRollLeft = true;
				break;
			//Move To Position
			case "MoveTo":
				TargetTop = AnimationScript[n][1] || 0;
				StartTop = Number(Location.Top);
				TargetLeft = AnimationScript[n][2] || 0;
				StartLeft = Number(Location.Left);
				bMoveTo = true;
				break;
			//Move To Random Border
			case "MoveToRandomBorder":
				StartTop = Number(Location.Top);
				StartLeft = Number(Location.Left);
				TargetTop = InfoFind.DataTypes.Random(0, (DocOffset.Top + WinHeight - Location.Height));
				TargetLeft = InfoFind.DataTypes.Random(0, (DocOffset.Left + WinWidth - Location.Width));
				switch (InfoFind.DataTypes.Random(0, 3)) {
					//Top
					case 0:
						TargetTop = Number(DocOffset.Top);
						bMoveTo = true;
						break;
					//Right
					case 1:
						TargetLeft = Number(DocOffset.Left + WinWidth - Location.Width);
						bMoveTo = true;
						break;
					//Bottom
					case 2:
						TargetTop = Number(DocOffset.Top + WinHeight - Location.Height);
						bMoveTo = true;
						break;
					//Left
					case 3:
						TargetLeft = Number(DocOffset.Left);
						bMoveTo = true;
						break;
				}
				break;
			//Move from Top
			case "MoveFromTop":
				bMoveTop = true;
				TargetTop = Number(Location.Top);
				StartTop = Number(DocOffset.Top);
				break;
			//Move to Top
			case "MoveToTop":
				bMoveTop = true;
				TargetTop = Number(DocOffset.Top);
				StartTop = Number(Location.Top);
				break;
			//Move from Left
			case "MoveFromLeft":
				bMoveLeft = true;
				TargetLeft = Number(Location.Left);
				StartLeft = Number(DocOffset.Left);
				break;
			//Move to Left
			case "MoveToLeft":
				bMoveLeft = true;
				TargetLeft = Number(DocOffset.Left);
				StartLeft = Number(Location.Left);
				break;
			//Move from Bottom
			case "MoveFromBottom":
				bMoveTop = true;
				TargetTop = Number(Location.Top);
				StartTop = Number(DocOffset.Top + WinHeight - Location.Height);
				break;
			//Move to Bottom
			case "MoveToBottom":
				bMoveTop = true;
				TargetTop = Number(DocOffset.Top + WinHeight - Location.Height);
				StartTop = Number(Location.Top);
				break;
			//Move from Right
			case "MoveFromRight":
				bMoveLeft = true;
				TargetLeft = Number(Location.Left);
				StartLeft = Number(DocOffset.Left + WinWidth - Location.Width);
				break;
			//Move to Right
			case "MoveToRight":
				bMoveLeft = true;
				TargetLeft = Number(DocOffset.Left + WinWidth - Location.Width);
				StartLeft = Number(Location.Left);
				break;
			//Move in Circle
			case "MoveInCircle":
				Radius = AnimationScript[n][1] || Radius;
				Direction = AnimationScript[n][2] || Direction;
				bMoveCircle = (Radius > 0);
				if (bMoveCircle) {
					DegreeAdd = (360 / Animations);
					//If 0 then move up and counter clockwise.
					//If 1 then move up and clockwise.
					//If 2 then move down and counter clockwise.
					//If 3 then move down and clockwise.
					if (Direction == 1 || Direction == 3) {
						DegreeAdd = -DegreeAdd;
					}
					if (Direction == 2 || Direction == 3) {
						Radius = -Radius;
					}
					StartLeft = Number(Location.Left);
					StartTop = Number(Location.Top);
				} else {
					bError = true;
				}
				break;
			//Blank Line Ignore
			case "":
				break;
			//Unknown
			default:
				throw "Unknown Animation Script: " + AnimationScript[n][0];
		}
		if (bError) {
			throw "Invalid Animation Script Parameters for " + AnimationScript[n][0];
		}
	}
	
	//Run the Animation by Setting a Timer for each step to display.
	for (n = 0; n <= Animations; n++) {
		js = "";
		//Opacity
		if (bOpacity) {
			js += "InfoFind.HTML.Element.SetOpacity(" + ElementID + ", " + OpacityCurrent + "); ";
			OpacityCurrent += OpacityAdd;
		}
				
		//Moving
		if (bMoveCircle) {
			Degree = Degree + DegreeAdd;
			Angle = Degree * Math.PI / 180; //Degrees to Radians
			Location.Top = InfoFind.DataTypes.RoundToDecimal(StartTop + (Radius * Math.cos(Angle)) - Radius);
			Location.Left = InfoFind.DataTypes.RoundToDecimal(StartLeft + (Radius * Math.sin(Angle)) + (Radius < 0 ? 0 : Radius) - ((Direction == 0 || Direction == 3) ? (Math.PI * 2) : -(Math.PI * 2)));
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", " + Location.Top + ", " + Location.Left + "); ";
		} else if (bMoveTo || bMoveTop || bMoveLeft) {
			if (bMoveTo || bMoveTop) Location.Top = StartTop + ((TargetTop - StartTop) * n / Animations);
			if (bMoveTo || bMoveLeft) Location.Left = StartLeft + ((TargetLeft - StartLeft) * n / Animations);
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", " + Location.Top + ", " + Location.Left + "); ";
		}
		
		//Resize - Only allow one.
		if (bResize) {
			//Note - InfoFind.DataTypes.RoundToDecimal() is used rather then parseInt() or other functions because it produces better results.
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", null, null, " + InfoFind.DataTypes.RoundToDecimal(Location.Height * SizeCurrent) + ", " + InfoFind.DataTypes.RoundToDecimal(Location.Width * SizeCurrent) + "); ";
			SizeCurrent += SizeAdd;
		} else if (bRollDown) {
			Height = Location.Height * n / Animations;
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", " + Location.Top + ", " + Location.Left + ", " + Height + "); ";
		} else if (bRollUp) {
			Height = Location.Height * n / Animations;
			Top = Location.Top + Location.Height - Height;
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", " + Top + ", " + Location.Left + ", " + Height + "); ";
		} else if (bRollRight) {
			Width = Location.Width * n / Animations;
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", " + Location.Top + ", " + Location.Left + ", null, " + Width + "); ";
		} else if (bRollLeft) {
			Width = Location.Width * n / Animations;
			Left = Location.Left + Location.Width - Width;
			js += "InfoFind.HTML.Element.Move(" + ElementID + ", " + Location.Top + ", " + Left + ", null, " + Width + "); ";
		}
		
		//Set Timer
		if (js != "") window.setTimeout(js, n * Interval);
	}
	//If needed for debug after last animation is set.
	if (InfoFind.Animation.DebugInfoPrompt) {
		alert(js);
	}
}

InfoFind.Animation.FadeOut = function(ElementID, Seconds) {
	InfoFind.Animation.Opacity(ElementID, 100, 0, Seconds);
}

InfoFind.Animation.FadeIn = function(ElementID, Seconds) {
	InfoFind.Animation.Opacity(ElementID, 0, 100, Seconds);
}

InfoFind.Animation.FadeOutAndIn = function(ElementID, Seconds) {
	Seconds = Seconds / 2 - 0.5;
	InfoFind.Animation.FadeOut(ElementID, Seconds);
	window.setTimeout("InfoFind.Animation.FadeIn('" + InfoFind.HTML.ByID(ElementID).id + "', " + Seconds + ")", (Seconds * 1000) + 500);
}

InfoFind.Animation.Opacity = function(ElementID, StartPercent, EndPercent, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "Opacity," + StartPercent + "," + EndPercent);
}

InfoFind.Animation.Resize = function(ElementID, StartPercent, EndPercent, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "Resize," + StartPercent + "," + EndPercent);
}

InfoFind.Animation.RollDown = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "RollDown");
}

InfoFind.Animation.RollUp = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "RollUp");
}

InfoFind.Animation.RollRight = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "RollRight");
}

InfoFind.Animation.RollLeft = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "RollLeft");
}

InfoFind.Animation.MoveTo = function(ElementID, Top, Left, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveTo," + Top + "," + Left);
}

InfoFind.Animation.MoveToRandomBorder = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveToRandomBorder");
}

InfoFind.Animation.MoveFromRight = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveFromRight");
}

InfoFind.Animation.MoveFromTop = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveFromTop");
}

InfoFind.Animation.MoveFromLeft = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveFromLeft");
}

InfoFind.Animation.MoveFromBottom = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveFromBottom");
}

InfoFind.Animation.MoveToRight = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveToRight");
}

InfoFind.Animation.MoveToTop = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveToTop");
}

InfoFind.Animation.MoveToLeft = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveToLeft");
}

InfoFind.Animation.MoveToBottom = function(ElementID, Seconds) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveToBottom");
}

//Rules for Direction:
//	If 0 then move up and counter clockwise.
//	If 1 then move up and clockwise.
//	If 2 then move down and counter clockwise.
//	If 3 then move down and clockwise.
InfoFind.Animation.MoveInCircle = function(ElementID, Seconds, Radius, Direction) {
	InfoFind.Animation.Animate(ElementID, Seconds, "MoveInCircle," + Radius + "," + Direction);
}

///////////////////////////////////////////////////////
//InfoFind.SlideShow
//This object allows for a slide show to be created on a web page
//without having to type any JavaScript. To all images would need 
//to be set up with the class "SlideShow" - example:
//	<a href="Pictures\Pic1.jpg" class="SlideShow" target="_blank">
//		<img src="Thumbnails\Thumnail1.png" alt="Pic1">
//	</a>
//The this JavaScript file simply has to be included with the web 
//page. If JavaScript is turned off or for browsers that don't support
//this file (i.e.: Mobile Phones, IE4, etc) the page will function as
//it normally would. A number of options exist below that affect how
//the slide show is displayed.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.SlideShow");

//////////////////////////////////////////
//Public Properties - These properties affect how
//	the slide show animates, etc. The can be set from
//	the page that calls contains the slide show. Below 
//	they are set with the default values.
//Set this to change how the animation works. As of early 2008 
//all major browsers (IE, FireFox, Safari, and Opera) work well
//with all three animation types, however IE works the best with
//the advanced animation effects because IE handles resizing a DIV
//containing a child IMG better then the other browsers. This is
//not a major problem though because the animation looks good 
//with all four browsers. For IE 5.0 "None" should be set otherwise
//the browser will probably crash. IE 5.5 and above all work well.
InfoFind.SlideShow.AnimationType = "Advanced"; //Simple, None
//How dark to make the page (0 to 100 with 0 = lightest)
InfoFind.SlideShow.PageOverlayPercent = 50;
//What zIndex to set for the page overlay. This will work by 
//default however if other elements on the page use a higher 
//zIndex then this needs be set to something to a higher number.
InfoFind.SlideShow.PageOverlayZIndex = 1;
//What html color to use for the page overlay.
InfoFind.SlideShow.PageOverlayBackgroundColor = "black";
//Include an image with the Page Overlay Background. None by
//default. To use this create an image and then set the property
//with a value in the correct css format such as "url(OverlayBackground.png)"
InfoFind.SlideShow.PageOverlayBackgroundImage = "";
//If 0, then user must click on image to see the next one.
//Otherwise this determines how many seconds an image stays up after
//the initial animation.
InfoFind.SlideShow.DisplayImageSeconds = 2;
//Number of seconds to perform the animation. Examples:
//For half a second enter 0.5, one second = 1.
InfoFind.SlideShow.AnimationTime = 1;
//Resize the image to a maximum percentage of the screen.
//This can be a decimal number between 0 and 1. The default
//is to show the image at 75% of the screen's size.
InfoFind.SlideShow.ImageSize = 0.75;
//Events to allow the user to run a function before or after
//the slide show is displayed. To set an event simply point a 
//function to it.
InfoFind.SlideShow.Event_BeforeDisplay = null;
InfoFind.SlideShow.Event_AfterDisplay = null;
//////////////////////////////////////////
//Private Properties - Used by this class
//CurrentImage is used by this class to keep track of an image between
//different events.
InfoFind.SlideShow.CurrentImage = null;

//Display the Slide Show, this is called when the user first clicks
//on an image to start the slide show. It can be set to a link with
//the following line of code:
//	InfoFind.HTML.AddEvent(Link, "click", InfoFind.SlideShow.Show);
InfoFind.SlideShow.Show = function(e) {
	var Link;
	InfoFind.SlideShow.CurrentImage = new Image();
	//Get the event
	if (window.event && window.event.srcElement) {
		Link = window.event.srcElement;
	} else if (e && e.target)  {
		Link = e.target;
	} else {
		return true;
	}
	//Get the Link Element
	if (Link.tagName.toLowerCase() != "a") {
		Link = (Link.parentNode || Link.parentElement);
		if (Link.tagName.toLowerCase() != "a") {
			return true;
		}
	}
	//Run event before displaying SlideShow if one is set.
	if (InfoFind.SlideShow.Event_BeforeDisplay) {
		InfoFind.SlideShow.Event_BeforeDisplay();
	}
	//Load the Image
	InfoFind.SlideShow.CurrentImage.src = Link.href;
	//Wait until the image loads before displaying it.
	InfoFind.SlideShow.CheckFirstImage();
	//Return false and stop the event to cancel the link from opening.
	InfoFind.HTML.StopEvent(e);
	return false;
}

//Check every 1/4 of a second until the image is loaded. This code is required
//otherwise the animation and positioning of the image won't work.
InfoFind.SlideShow.CheckFirstImage = function() {
	//Note - [.compelete] will often = true before the image is actually loaded.
	//To work around this [.width] and [.height] are also checked.
	//In addition the timer still must be set afterwards for Safari otherwise the 
	//first animation does not look good and the image ends up on the wrong position.
	//Even with this delay Safari will still have trouble sometimes and the first image
	//will end up in the wrong place. This error only seems to happen when Safari is 
	//loading a local image and not a image from the internet.
	if (InfoFind.SlideShow.CurrentImage && InfoFind.SlideShow.CurrentImage.complete && 
		InfoFind.SlideShow.CurrentImage.width && InfoFind.SlideShow.CurrentImage.height) {
		//
		window.setTimeout(InfoFind.SlideShow.ShowFirstImage, 250);
	} else {
		window.setTimeout(InfoFind.SlideShow.CheckFirstImage, 250);
	}
}

//Show the first image. This is called from the function CheckFirstImage()
//and is only called once the image is loaded.
InfoFind.SlideShow.ShowFirstImage = function() {
	//Get Settings, etc.
	var DocHeight = InfoFind.HTML.Document.GetHeight();
	var DocWidth = InfoFind.HTML.Document.GetWidth();
	var WinHeight = InfoFind.HTML.Window.GetHeight();
	var WinWidth = InfoFind.HTML.Window.GetWidth();
	var Img = InfoFind.SlideShow.CurrentImage;
	//Create the Page Overlay (this darkens the page)
	var PageOverlay = InfoFind.HTML.Element.Add("div", "PageOverlay");
	PageOverlay.zIndex = InfoFind.SlideShow.PageOverlayZIndex; //Make this appear above page elements
	InfoFind.HTML.Element.SetOpacity(PageOverlay, InfoFind.SlideShow.PageOverlayPercent);
	PageOverlay.style.backgroundColor = InfoFind.SlideShow.PageOverlayBackgroundColor;
	if (InfoFind.SlideShow.PageOverlayBackgroundImage != "") {
		PageOverlay.style.backgroundImage = InfoFind.SlideShow.PageOverlayBackgroundImage;
	}
	InfoFind.HTML.Element.Move(PageOverlay, 1, 1, DocHeight, DocWidth);
	InfoFind.HTML.AddEvent(PageOverlay, "click", InfoFind.SlideShow.Close);
	//Create the Dialog, create it hidden so that the image can fade into view.
	var SlideShow = InfoFind.HTML.Element.Add("div", "SlideShow");
	SlideShow.zIndex = (InfoFind.SlideShow.PageOverlayZIndex + 1); //Make this appear above page elements and the overlay.
	SlideShow.innerHTML = '<img id="SlideShowImage" src="' + Img.src + '" alt="" ' + (InfoFind.SlideShow.DisplayImageSeconds == 0 ? 'onclick="InfoFind.SlideShow.NextImage()" ' : '') + 'style="display:none;">';
	//Setup Initial Image Opacity
	var SlideShowImage = InfoFind.HTML.ByID("SlideShowImage");
	InfoFind.HTML.Element.SetOpacity(SlideShowImage, 0); //Hide with Opacity = 0%
	InfoFind.HTML.Element.Show(SlideShowImage); //Now show the hidden element with Opacity still at 0%
	//Resize the Image if needed and Position the Dialog centered on screen.
	SlideShow.style.position = "absolute"; //Set this to make sure Height/Width is properly read.
	var Position = InfoFind.HTML.Element.GetPosition(SlideShow);
	InfoFind.SlideShow.SizeAndPosition(WinHeight, WinWidth, Position.Height, Position.Width);
	//Show the Image
	if (InfoFind.SlideShow.AnimationType == "None") {
		//No Animation - Just show it.
		InfoFind.HTML.Element.SetOpacity(SlideShowImage, 100);
	} else {
		//Animate to display the image (fade in from 50% while resizing from 10%).
		InfoFind.Animation.Animate(SlideShowImage, InfoFind.SlideShow.AnimationTime, "Opacity,50,100;Resize,10,100");
	}
	//Clean Up
	Img = null;
	InfoFind.SlideShow.CurrentImage = null;
	//Set a timer for the next image if this option is set.
	if (InfoFind.SlideShow.DisplayImageSeconds > 0) {
		window.setTimeout("InfoFind.SlideShow.NextImage()", ((InfoFind.SlideShow.AnimationTime + InfoFind.SlideShow.DisplayImageSeconds) * 1000));
	}
}

//Resize the Image if needed and Position the Dialog centered on screen.
InfoFind.SlideShow.SizeAndPosition = function(WinHeight, WinWidth, ImgHeight, ImgWidth) {
	//Resize the Image if it is too large for the screen.
	if (Number(ImgHeight) > (Number(WinHeight) * InfoFind.SlideShow.ImageSize) ||
		Number(ImgWidth) > (Number(WinWidth) * InfoFind.SlideShow.ImageSize)) {
		//
        var PctH = Number(ImgHeight) / Number(WinHeight);
        var PctW = Number(ImgWidth) / Number(WinWidth);
        var PercentScale = Math.max(PctW, PctH);
        ImgHeight = (Number(ImgHeight) / PercentScale) * InfoFind.SlideShow.ImageSize;
        ImgWidth = (Number(ImgWidth) / PercentScale) * InfoFind.SlideShow.ImageSize;
	}
	//Size the IMG element to fit the new image.
	InfoFind.HTML.Element.Move("SlideShowImage", null, null, ImgHeight, ImgWidth);
	//Move the Slide Show to the center of the screen.
	var ScrollPosition = InfoFind.HTML.Document.GetScrollPosition();
	var Top = (Number(WinHeight) - Number(ImgHeight)) / 2;
	var Left = (Number(WinWidth) - Number(ImgWidth)) / 2;
	InfoFind.HTML.Element.Move("SlideShow", ScrollPosition.Top + Top, ScrollPosition.Left + Left, ImgHeight, ImgWidth);
}

//This is called when the user clicks on the slide show image. It searches the
//document to find the next image or if it's at the end then it displays the
//first image.
InfoFind.SlideShow.NextImage = function() {
	var bNext = false, FirstItem = -1, bFound = false;
	var SlideShowImage = InfoFind.HTML.ByID("SlideShowImage");
	if (!SlideShowImage) return;
	InfoFind.SlideShow.CurrentImage = new Image();
	//Get all Link Elements
	var Links = InfoFind.HTML.ByTag("a");
	for (var n = 0; n < Links.length; n++) {
		//Only check links with "SlideShow" in the class name.
		if (InfoFind.HTML.Element.HasClass(Links[n], "SlideShow")) {
			if (FirstItem == -1) FirstItem = n;
			//Was the previous image being currently displayed?
			//If yes then load this image and exit the loop.
			if (bNext) {
				InfoFind.SlideShow.CurrentImage.src = Links[n].href;
				bFound = true;
				FirstItem = -1;
				break;
			//Is it the same as the current image? If yes
			//then use the next image.
			} else if (SlideShowImage.src == Links[n].href) {
				bNext = true;
			}
		}
	}
	//Made it to the end now show the first image.
	if (FirstItem > -1) {
		InfoFind.SlideShow.CurrentImage.src = Links[FirstItem].href;
		bFound = true;
	}
	//Wait until the image loads before displaying it.
	if (bFound) {
		InfoFind.SlideShow.CheckNextImage();
	}
}

//Check every 1/4 of a second until the image is loaded. This code is required
//otherwise the animation and positioning of the image won't work.
InfoFind.SlideShow.CheckNextImage = function() {
	//Note - [.compelete] will often = true before the image is actually loaded.
	//To work around this [.width] and [.height] are also checked.
	if (InfoFind.SlideShow.CurrentImage && InfoFind.SlideShow.CurrentImage.complete && 
		InfoFind.SlideShow.CurrentImage.width && InfoFind.SlideShow.CurrentImage.height) {
		//
		InfoFind.SlideShow.ShowNextImage();
	} else {
		window.setTimeout(InfoFind.SlideShow.CheckNextImage, 250);
	}
}

//Animate the previous image and loading of the new one. 
//This is called from the function CheckNextImage() because
//it will only work once the image is loaded.
InfoFind.SlideShow.ShowNextImage = function() {
	//Determine Animation to Run.
	var AnimateScriptOut = "";
	var AnimateScriptIn = "";
	//No Animation - Hide the Old Image, Resize it and Display the new one.
	if (InfoFind.SlideShow.AnimationType == "None") {
		//Get Elements, Settings, etc.
		var SlideShow = InfoFind.HTML.ByID("SlideShow");
		var SlideShowImage = InfoFind.HTML.ByID("SlideShowImage");
		if (!SlideShow || !SlideShowImage) return;
		var WinHeight = InfoFind.HTML.Window.GetHeight();
		var WinWidth = InfoFind.HTML.Window.GetWidth();
		var ImgHeight = InfoFind.SlideShow.CurrentImage.height;
		var ImgWidth = InfoFind.SlideShow.CurrentImage.width;
		//Resize the Image if needed and Position the Dialog centered on screen.
		SlideShowImage.src = ""; //Clear the Image Location
		InfoFind.SlideShow.SizeAndPosition(WinHeight, WinWidth, ImgHeight, ImgWidth);
		//Set the source of the hidden image.
		SlideShowImage.src = InfoFind.SlideShow.CurrentImage.src;
		//Clean up
		InfoFind.SlideShow.CurrentImage = null;
		//Set a timer for the next image if this option is set.
		if (InfoFind.SlideShow.DisplayImageSeconds > 0) {
			window.setTimeout("InfoFind.SlideShow.NextImage()", (InfoFind.SlideShow.DisplayImageSeconds * 1000));
		}
		return;
	//Basic Animation - Just Fade In and Out
	} else if (InfoFind.SlideShow.AnimationType == "Simple") {
		AnimateScriptOut = "Opacity,100,0"; //Fade Out
		AnimateScriptIn = "Opacity,0,100"; //Fade In
	//Advanced Animation - pick one at Random.
	} else { //(InfoFind.SlideShow.AnimationType == "Advanced"
		//Create a Number between 0 and 8.
		switch (InfoFind.DataTypes.Random(0, 8)) {
			case 0:
				AnimateScriptOut = "Opacity,100,0";
				AnimateScriptIn = "Opacity,0,100;RollDown";
				break;
			case 1:
				AnimateScriptOut = "Opacity,100,0";
				AnimateScriptIn = "Opacity,0,100;RollUp";
				break;
			case 2:
				AnimateScriptOut = "Opacity,100,0";
				AnimateScriptIn = "Opacity,0,100;RollLeft";
				break;
			case 3:
				AnimateScriptOut = "Opacity,100,0";
				AnimateScriptIn = "Opacity,0,100;RollRight";
				break;
			case 4:
				AnimateScriptOut = "Opacity,100,0";
				AnimateScriptIn = "Opacity,50,100;Resize,10,100";
				break;
			case 5:
				AnimateScriptOut = "MoveToRight";
				AnimateScriptIn = "Opacity,0,100;MoveFromLeft";
				break;
			case 6:
				AnimateScriptOut = "MoveToTop";
				AnimateScriptIn = "Opacity,0,100;MoveFromBottom";
				break;
			case 7:
				AnimateScriptOut = "MoveToLeft";
				AnimateScriptIn = "Opacity,0,100;MoveFromRight";
				break;
			case 8:
				AnimateScriptOut = "MoveToBottom";
				AnimateScriptIn = "Opacity,0,100;MoveFromTop";
				break;
			default: //In Case of Error
				AnimateScriptOut = "Opacity,100,0";
				AnimateScriptIn = "Opacity,0,100";
				break;
		}
	}
	//If no Animation then code execution will not reach this point.
	//Animate out the the current image (fade out, etc).
	InfoFind.Animation.Animate("SlideShow", InfoFind.SlideShow.AnimationTime, AnimateScriptOut);
	//Reset the image 1/10 of a second after animating it off the screen.
	window.setTimeout(function() {
		var SlideShowImage = InfoFind.HTML.ByID("SlideShowImage");
		if (!SlideShowImage) return;
		SlideShowImage.src = ""; //Clear the Image Location
		InfoFind.HTML.Element.SetOpacity("SlideShow", 0); //Hide Image with Opacity
		InfoFind.HTML.Element.Show("SlideShow"); //Show the Image with Opacity at 0%
	}, ((InfoFind.SlideShow.AnimationTime * 1000) + 100));
	//Animate the display of the new image 2/10ths of a second after the first animation.
	window.setTimeout(function() {
		//Get Elements, Settings, etc.
		var SlideShow = InfoFind.HTML.ByID("SlideShow");
		var SlideShowImage = InfoFind.HTML.ByID("SlideShowImage");
		if (!SlideShow || !SlideShowImage || !InfoFind.SlideShow.CurrentImage) return;
		var WinHeight = InfoFind.HTML.Window.GetHeight();
		var WinWidth = InfoFind.HTML.Window.GetWidth();
		var ImgHeight = InfoFind.SlideShow.CurrentImage.height;
		var ImgWidth = InfoFind.SlideShow.CurrentImage.width;
		//Resize the Image if needed and position the Dialog centered on screen.
		InfoFind.SlideShow.SizeAndPosition(WinHeight, WinWidth, ImgHeight, ImgWidth);
		//Set the source of the hidden image.
		SlideShowImage.src = InfoFind.SlideShow.CurrentImage.src;
		//Animate the image to display (fade in, etc).
		InfoFind.Animation.Animate("SlideShow", InfoFind.SlideShow.AnimationTime, AnimateScriptIn);
		//Clean up
		InfoFind.SlideShow.CurrentImage = null;
		//Set a timer for the next image if this option is set.
		if (InfoFind.SlideShow.DisplayImageSeconds > 0) {
			window.setTimeout("InfoFind.SlideShow.NextImage()", ((InfoFind.SlideShow.AnimationTime + InfoFind.SlideShow.DisplayImageSeconds) * 1000));
		}
	}, ((InfoFind.SlideShow.AnimationTime * 1000) + 200));
}

//Close the Slide Show, this is called when
//the User clicks on the Page Overlay.
InfoFind.SlideShow.Close = function() {
	InfoFind.HTML.Element.Remove("SlideShow");
	InfoFind.HTML.Element.Remove("PageOverlay");
	//Run event after displaying SlideShow if one is set.
	if (InfoFind.SlideShow.Event_AfterDisplay) {
		InfoFind.SlideShow.Event_AfterDisplay();
	}
}

///////////////////////////////////////////////////////
//InfoFind.Sorting
//Add Sorting to an HTML Table with a Basic Function call.
//The only function from here that needs to be called is 
//MakeTableSortable(). This adds advanced sorting that uses 
//the sort order - Blanks, Numbers/Currency/File Size, Dates,
//and Text (Case-Insensitive, but if Equal Upper First).
//This code works with all popular browsers on all major OS's
//but it doesn't do any OS or Browser checking. Also, this code
//checks if the table is using alternating row colors based on
//class description and handles tables with or without table 
//footer and with the Column Headers either THEAD/TH or TR/TD.
///////////////////////////////////////////////////////
InfoFind.CreateObject("InfoFind.Sorting");

//Call this function to set a Table so that it can be sorted
//on the client side by clicking the column header cells.
//For alternating row styles the Classes in first two Rows of 
//the Table Body will be read to determine how to style the table.
//This function can be called several ways:
//	<table id="Table1"...
//	MakeTableSortable(document.getElementById("Table1"));
//	MakeTableSortable("Table1");
//	or to add you own Before or After click events use the following:
//	function Table1_BeforeClick() { /*do something*/ return true; }
//	function Table1_AfterClick() { /*do something*/ }
//	MakeTableSortable({ObjectID:"Table1", BeforeClick:Table1_BeforeClick, AfterClick:Table1_AfterClick})
InfoFind.Sorting.MakeTableSortable = function(TableID) {
	//Get Table
	var Table = InfoFind.HTML.ByID(TableID);
	var BeforeClick = null, AfterClick = null;
	if (Table.ObjectID) {
		BeforeClick = Table.BeforeClick || null;
		AfterClick = Table.AfterClick || null;
		Table = InfoFind.HTML.ByID(Table.ObjectID);
	}
	var Cell = null;
	if (!Table) return;
	//Set Attributes in Table to remember what is sorted and how to sort.
	Table.setAttribute("SortColumn", "-1");
	Table.setAttribute("SortOrder", "Asc");
	InfoFind.Sorting.FindTableRowClasses(Table);
	if (Table.rows.length > 0) {
		//Change Column Header to Cursor
		//Older versions of IE (IE4, etc) do not support "pointer" and will
		//raise an error. In addition IE4 (but not IE5) doesn't support try...catch 
		//error handling so use IE's conditional compile to check if it's an old
		//version of IE and set the cursor first. The actual version of IE is not 
		//checked but rather the JScript version that is supported by IE. Currently
		//only IE supports conditional compilation.
		/*@cc_on
			@if (@_jscript_version <= 5.6)
				Table.rows[0].style.cursor = "hand";
			@end
		@*/
		if (Table.rows[0].style.cursor != "hand") {
			Table.rows[0].style.cursor = "pointer";
		}
		//Add onclick Events for Column Headers.
		for (var n = 0; n < Table.rows[0].cells.length; n++) {
			Cell = Table.rows[0].cells[n];
			//Adding both BeforeClick and AfterClick. BeforeClick must 
			//return true for code to continue. AddEvent() doesn't 
			//actually add events in predictable order (different 
			//browsers do different things) so the only way to get
			//this to work is specify the order of the events here in a
			//new function and then add that function to the column header.
			if (BeforeClick && AfterClick) {
				InfoFind.HTML.AddEvent(Cell, "click", (function(e) {
					var Result = BeforeClick(e); 
					if (Result) {
						InfoFind.Sorting.ColumnClick(e); 
						AfterClick(e);
					}
				}));
			//Adding BeforeClick
			} else if (BeforeClick) {
				InfoFind.HTML.AddEvent(Cell, "click", (function(e){var Result = BeforeClick(e); if (Result) InfoFind.Sorting.ColumnClick(e);}) );
			//Adding AfterClick
			} else if (AfterClick) {
				InfoFind.HTML.AddEvent(Cell, "click", (function(e){InfoFind.Sorting.ColumnClick(e); AfterClick(e);}) );
			//Standard Sorting event
			} else {
				InfoFind.HTML.AddEvent(Cell, "click", InfoFind.Sorting.ColumnClick);
			}
			Cell = null;
		}
	}
}

//This function finds the first two Styles used in the 
//Rows of the Table Body and remembers them for later use.
InfoFind.Sorting.FindTableRowClasses = function(Table) {
	var length = Table.rows.length - 1;
	var Class1 = "", Class2 = "", Parent = null;
	//The very first row in the Table will be the Column Header
	//even if it is grouped in THEAD. That's why the loop starts
	//with [n = 0] but the data uses [n+1].
	for (var n = 0; n < length; n++) {
		//In Opera 9 if the footer (TFOOT) is before the body (TBODY) then
		//Opera returns the TFOOT row before the other rows. This code
		//prevents that from happening.
		//Older versions or IE (IE4, etc) don't use parentNode and instead use parentElement.
		Parent = (Table.rows[n+1].parentNode || Table.rows[n+1].parentElement)
		if (Parent.tagName != "TFOOT") {
			if (Class1 != "") {
				Class2 = Table.rows[n+1].className;
				if (Class2 != "") {
					break;
				}
			} else {
				Class1 = Table.rows[n+1].className;
			}
		}
	}
	//Remember the Values to use.
	Table.setAttribute("C1", Class1);
	Table.setAttribute("C2", Class2);	
}

//This code performs the sorting.
InfoFind.Sorting.ColumnClick = function(e) {
	//Variables/Get Event
	var Table = null, Column = null, CellIndex = 0;
	if (window.event && window.event.srcElement) {
		Column = window.event.srcElement;
	} else if (e && e.target)  {
		Column = e.target;
	} else {
		return;
	}
	var n = 0, m = 0;
	//Get Column, Table and Values from Event Element.
	//Search up the node chain to find Cell and Table.
	//This allows the header cells to be as varied as:
	//<td class=a><nobr><font class=b><u>Field Name</u></font></nobr></td>
	//or just
	//<th>Field Name</th>
	while (Column && Column.tagName.toLowerCase() != "td" && Column.tagName.toLowerCase() != "th") {
		//Older versions or IE (IE4, etc) don't use parentNode and instead use parentElement.
		Column = (Column.parentNode || Column.parentElement);
	}
	if (!Column) return;
	//Get the Table Element.
	Table = (Column.parentNode || Column.parentElement);
	while (Table && Table.tagName.toLowerCase() != "table") {
		Table = (Table.parentNode || Table.parentElement);
	}
	if (!Table) return;
	//Get Column Index that the User clicked on and the saved row style names.
	CellIndex = InfoFind.Sorting.GetCellIndex(Table, Column);
	var ClassName1 = Table.getAttribute("C1");
	var ClassName2 = Table.getAttribute("C2");
	//Get all Rows into an Array.
	var Rows = InfoFind.Sorting.GetColumnData(Table, CellIndex);
	var tBody = Table.tBodies[0];
	//Sort the Array using JavaScript sort() function and a custom sort routine.
	Rows.sort(InfoFind.Sorting.SortCompare);
	//Remember Sort Settings
	if (Table.getAttribute("SortColumn") == CellIndex && Table.getAttribute("SortOrder") == "Asc") {
		//Sort Descending?
		Rows.reverse();
		Table.setAttribute("SortOrder", "Desc");
	} else {
		Table.setAttribute("SortOrder", "Asc");
	}
	Table.setAttribute("SortColumn", CellIndex);
	//Add the Rows back to the Table in the Sorted Order
	//All modern browsers support tBody.appendChild() it moves the row
	//to the end of the table body so looping through the sorted array
	//adds all rows back in the sorted order.
	if (tBody.appendChild) {
		for (n = 0; n < Rows.length; n++) {
			//For every other row, change the row style to allow for 
			//tables with alternating row styles.
			Rows[n].Row.className = (n % 2 == 0 ? ClassName1 : ClassName2);
			//Move the row.
			tBody.appendChild(Rows[n].Row);
		}
	} else {
		//For IE4 - Can't use [tBody.appendChild] or [tBody.innerHTML]
		//so add each row as a copy in the sorted order, then go back 
		//and delete the original rows. This is very slow compared to
		//new browsers with appendChild() but it works and advanced
		//functionality on Win9X won't be fast anyways.
		var NewRow = null, NewCell = null, length = Rows.length;
		//Re-add each row in the sorted order.
		for (n = 0; n < length; n++) {
			NewRow = tBody.insertRow();
			NewRow.className = (n % 2 == 0 ? ClassName1 : ClassName2);
			//Add each cell for the row.
			for (m = 0; m < Rows[n].Row.cells.length; m++) {
				NewCell = NewRow.insertCell();
				NewCell.innerHTML = Rows[n].Row.cells[m].innerHTML;
			}
		}
		//Clean up
		NewCell = null;
		NewRow = null;
		//Delete original rows
		for (n = length - 1; n >= 0; n--) {
			tBody.deleteRow(n);
		}
	}
	//Clean up
	for (n = 0; n < Rows.length; n++) {
		Rows[n].Value = null;
		Rows[n].Row = null;
		Rows[n] = null;
	}
	Rows = null;
	Column = null;
	Table = null;
}

//This is a workaround for Safari on Mac because Safari always 
//returns cell.cellIndex = 0. This bug is fixed for the most recent
//Beta Version of Safari on Windows. For this code to work all 
//Columns in the table must have a unique name.
InfoFind.Sorting.GetCellIndex = function(Table, Column) {
	var CellIndex = Column.cellIndex;
	//Only do the test if the First Column is clicked and
	//if the Clicked Column Text does not match the First Column's
	//Text. This part won't run on Firefox/Mozilla because of the
	//[Column.innerText] test.
	if (CellIndex == 0 && Column.innerText) {
		if (Table.rows[0].cells[0].innerText != Column.innerText) {
			//Only older versions of Safari will reach this point.
			for (var n = 0; n < Table.rows[0].cells.length; n++) {
				if (Table.rows[0].cells[n].innerText == Column.innerText) {
					CellIndex = n;
					break;
				}
			}
		}
	}
	return CellIndex;
}

//Returns all Table's Rows in an Array for sorting.
InfoFind.Sorting.GetColumnData = function(Table, CellIndex) {
	//Variables / Determine the correct Array Length.
	var length = Table.rows.length - 1;
	var fLength = 0;
	if (Table.tFoot && Table.tFoot.rows)  {
		fLength = Table.tFoot.rows.length;
	}
	var Rows = new Array(length - fLength);
	var m = 0, Parent = null;
	//The very first row in the Table will be the Column Header
	//even if it is grouped in THEAD. That's why the loop starts
	//with [n = 0] but the data uses [n+1].
	for (var n = 0; n < length; n++) {
		//In Opera 9 if the footer (TFOOT) is before the body (TBODY) then
		//Opera returns the TFOOT row before the other rows. This code
		//prevents that from happening.
		Parent = (Table.rows[n+1].parentNode || Table.rows[n+1].parentElement)
		if (Parent.tagName != "TFOOT") {
			Rows[m] = new InfoFind.Sorting.TableRow(Table.rows[n+1], CellIndex);
			m++;
		}
	}
	return Rows;
};

//Custom Sort function to pass to Javascript:Array.sort()
//Sort Order - Blanks, Numbers/Currency/File Size, Dates, 
//	Text (Case-Insensitive, but if Equal the Upper-Case First)
InfoFind.Sorting.SortCompare = function(Row1, Row2) {
	//Commented out below is an example of basic sorting that can be used.
	/*
	if (Row1.Value < Row2.Value) {
		return -1;
	} else if (Row2.Value < Row1.Value) {
		return 1;
	} else {
		return 0;
	}
	*/
	//Compare the Values
	//Are they Equal?
	if (Row1.LCaseValue == Row2.LCaseValue) {
		//If Yes, then Check Casing, UpperCase First
		if (Row1.Value == Row2.Value) {
			return 0;
		} else if (Row1.Value < Row2.Value) {
			return -1;
		} else {
			return 1;
		}
	} else {
		//Empty Values?
		if (Row1.Value == "") {
			return -1;
		} else if (Row2.Value == "") {
			return 1;
		} else {
			//Check for Numbers
			if (Row1.IsNumber && Row2.IsNumber) {
				//If both are numbers then compare as numbers.
				if (Row1.ValueNum < Row2.ValueNum) {
					return -1;
				} else {
					return 1;
				}
			} else if (Row1.IsNumber) {
				return -1;
			} else if (Row2.IsNumber) {
				return 1;
			} else {
				//Check for Dates
				if (Row1.IsDate && Row2.IsDate) {
					//If both are dates then compare as dates.
					if (Row1.ValueDate < Row2.ValueDate) {
						return -1;
					} else {
						return 1;
					}
				} else if (Row1.IsDate) {
					return -1;
				} else if (Row2.IsDate) {
					return 1;
				} else {
					//Compare Text Case-Insensitive
					if (Row1.LCaseValue < Row2.LCaseValue) {
						return -1;
					} else {
						return 1;
					}
				} //if (Row1.IsDate && Row2.IsDate) 
			} //if (Row1.IsNumber && Row2.IsNumber)
		} //if (Row1.Value == "")
	} //if (Row1.LCaseValue == Row2.LCaseValue)
}

//TableRow object used for sorting.
InfoFind.Sorting.TableRow = function(Row, CellIndex) {
	//Check for Input/Image Controls First, otherwise get Text
	var bSet = false;
	if (Row.cells[CellIndex].childNodes) {
	    if (Row.cells[CellIndex].childNodes[0].nodeName == "INPUT") {
		    this.Value = Row.cells[CellIndex].childNodes[0].value;
		    bSet = true;
	    } else if (Row.cells[CellIndex].childNodes[0].nodeName == "SELECT") {
		    this.Value = "";
		    var cnt = Row.cells[CellIndex].childNodes[0];
		    if (cnt.selectedIndex != -1) {
			    this.Value = cnt.options[cnt.selectedIndex].text;
		    }
		    cnt = null;
		    bSet = true;
	    } else if (Row.cells[CellIndex].childNodes[0].nodeName == "IMG") {
		    this.Value = Row.cells[CellIndex].childNodes[0].src;
		    bSet = true;
		}
	}
	if (!bSet) {
	    //Text - Opera/IE/Safari
	    if (Row.cells[CellIndex].innerText) {
		    this.Value = Row.cells[CellIndex].innerText;
	    //Text - Mozilla/Firefox doesn't support innerText.
	    } else if (Row.cells[CellIndex].textContent) {
		    this.Value = Row.cells[CellIndex].textContent;
	    } else if (Row.cells[CellIndex].firstChild && Row.cells[CellIndex].firstChild.nodeValue) {
		    this.Value = Row.cells[CellIndex].firstChild.nodeValue;
	    //Just in case
	    } else {
		    this.Value = Row.cells[CellIndex].innerHTML;
	    }
	}
	//Fix the Value and Save Lower-Case Version
	this.Value = InfoFind.DataTypes.Trim(this.Value);
	this.LCaseValue = this.Value.toLowerCase();
	if (this.LCaseValue == "<nobr></nobr>") {
		this.Value = "";
		this.LCaseValue = "";
	}
	//File Size? If yes then convert to number.
	var length = this.Value.length;
	var bFileSize = false;
	if (length >= 4) {
		if (this.Value.substring(length - 3, length) == " KB") {
			var temp = this.Value.substring(0, length - 3);
			if (InfoFind.DataTypes.IsNumeric(temp)) {
				bFileSize = true;
				this.IsDate = false;
				this.ValueDate = null;
				this.IsNumber = true;
				this.ValueNum = InfoFind.DataTypes.StringToNumber(temp);
			}
		}
	}
	//Date or Number?
	if (!bFileSize) {
		this.IsDate = false;
		this.ValueDate = null;
		//Check for Number
		this.IsNumber = InfoFind.DataTypes.IsCurrency(this.Value);
		this.ValueNum = null;
		if (this.IsNumber) {
			this.ValueNum = InfoFind.DataTypes.CurrencyToNumber(this.Value);
		} else {
			//Check for Date
			if (!isNaN(Date.parse(this.Value))) {
				this.IsDate = true;
				this.ValueDate = new Date(this.Value);
				//Work Around because of Date Compare Bug with Safari. This bug has been fixed
				//with the most recent versions of Safari on Windows and on Mac. This code will
				//only execute for Versions of Safari that cause the problem and IE, Opera, and
				//Firefox won't run it. This code is looking for dates similar to the 
				//following formats: "MM/DD/YY HH:MM:SS {AM|PM}", "DD/MM/YY HH:MM", etc
				//Only versions of Safari that cause the error evaluate true with the code:
				//	Date.valueOf() == -2147483648000
				if (this.ValueDate.valueOf() == -2147483648000) {
					//Many Versions of Safari can't parse Dates that include the time. 
					//Because of that get the first part of the string to the first 
					//blank space and test if it's a valid date. If it is then set that 
					//as the date and manually parse the time and add the seconds to 
					//get the correct date.
					var a = this.Value.split(" ");
					if (!isNaN(Date.parse(a[0]))) {
						this.ValueDate = new Date(a[0]);
						//Manually parse the time into seconds and add to the date.
						var sTime = "";
						var Seconds = 0;
						//First Check if AM/PM and look for the Time.
						switch (a.length) {
							//Item 3 can show up and will be undefined
							//Date Like: MM/DD/YY HH:MM:SS {AM|PM}
							case 2, 3:
								a[2] = a[2].toLowerCase();
								if (a[2] == "am") {
									sTime = a[1];
								} else if (a[2] == "pm") {
									Seconds = 60 * 60 * 12; //12 Hours of Seconds
									sTime = a[1];
								}
								break;
							//Date Like: MM/DD/YY HH:MM:SS
							case 1:
								sTime = a[1];
								break
							default:
								//Do Nothing
						}
						//Parse the Time into Seconds in either the form 
						//HH:MM:SS or HH:MM
						if (sTime != "") {
							a = sTime.split(":");
							switch (a.length) {
								//Item 3 can show up and will be undefined
								case 2, 3:
									if (!isNaN(a[0]) && !isNaN(a[1]) && !isNaN(a[2])) {
										Seconds += (Number(a[0]) * 60 * 60); //Hours
										Seconds += (Number(a[1]) * 60); //Minutes
										Seconds += (Number(a[2])); //Seconds
									}
									break;
								case 1:
									if (!isNaN(a[0]) && !isNaN(a[1])) {
										Seconds += (Number(a[0]) * 60 * 60); //Hours
										Seconds += (Number(a[1]) * 60); //Minutes
									}
									break;
							}
							//Add the Number of Seconds to the Date
							if (Seconds != 0) {
								this.ValueDate.setSeconds(Seconds);
							}
						}
					} else {
						//Sort as Text, Safari is unable to parse the date.
						this.ValueDate = this.Value;
					}
				}
			}
		}
	}
	//HTML Element
	this.Row = Row;
}

//Global Code that executes once the Page loads. To see what it does
//look at the code and comments in InfoFind.OnLoad(). To prevent it
//from running automatically simply comment out the next line.
InfoFind.HTML.AddEvent(window, "load", InfoFind.OnLoad);
