/*

	Offspring.js -- adds the following classes as needed:



		.first-child

		.last-child

		.only-child

		.nth-child-odd

		.nth-child-even

		.nth-child-##

		

	Configuration:

	

	Offspring can be configured by defining an "offspringConfiguration" 

	object before referencing offspring.js. That object can contain

	one or more of these parameters. (If any parameter is omitted -- which

	is fine -- it gets the default value as described below.) 

	

	offspringConfiguration = 

	{

		runningMode: 'full',                        <-- valid values are 'full' and 'light' (default: 'full')

		autoStart: true,                            <-- valid values are true and false (default: true)

		shouldRemoveOldOffspringClassesFirst: false <-- valid values are true and false (default: false)

	}

	

	* runningMode: 

		'full' -- Offspring applies all of its classes (as listed at the very top) [default]

		'light' -- Offspring only applies 'first-child', 'last-child', and 'only-child',

					omitting 'nth-child-odd', 'nth-child-even', and 'nth-child-##'.

					(This may allow for faster page-processing in certain scenarios.)

					

	* autoStart:

		true -- Offspring runs automatically as soon as the DOM is ready [default]

		false -- Offspring must be run manually. This can be done by calling Offspring.start();

		

	* shouldRemoveOldOffspringClassesFirst:

		true --Offspring first removes any old Offspring classes before applying the new ones.

				(This might be of use if Offspring is to be called on a page that has already

				been processed, such as if a table has been sorted or content has been loaded

				via Ajax.)

		false -- Offspring applies its classes without first removing old Offspring classes that

				might be there. Unless you're doing fancy DOM updates, this is probably the

				better option in most cases. [default]



	================================================================== */





var offspring = {

	firstChildClass: "first-child",

	lastChildClass:  "last-child",

	oddChildClass:   "nth-child-odd",

	evenChildClass:  "nth-child-even",

	onlyChildClass:  "only-child",

	nthChildClassPrefix:   "nth-child-",



	classNamesArray: [],

	classNameSubstringsArray: [],



	cacheLevel: 0, // current size of the classNames cache



	nthChildren: [],



	regularHashTable: [],

	regularHashTableArray: [],



	lastChildHashTable: [],

	lastChildHashTableArray: [],



	/* Configuration defaults */

	configuration:

	{

		runningMode: 'full', /* Possible values: 'full' / 'light' */

		autoStart: true, /* If Offspring is configured in autoStart mode (which it is by default),

		 					it runs as soon as the DOM is ready */

		shouldRemoveOldOffspringClassesFirst: false /* If this is set to 'true', Offspring first

														removes any old Offspring-related classes

														before applying the new ones */

	},



	// Initialize

	init: function() {



		/*

			Offspring's configuration is stored in Offspring.configuration, but

			that con be overridden by users by defining an "offspringConfiguratin"

			object.

		*/

		if (typeof offspringConfiguration != "undefined")

		{

			for (var configParameter in offspringConfiguration)

			{

				this.configuration[configParameter] = offspringConfiguration[configParameter];

			}



			// Make sure this option is stored in lowercase

			this.configuration.runningMode = this.configuration.runningMode.toLowerCase();

		}





		/* Set the values for classNamesArray & classNameSubstringArray */



		switch (this.configuration.runningMode)

		{

			case 'full':

				// this represents all possible offspring-related classnames

				this.classNamesArray = [this.firstChildClass, this.lastChildClass, this.oddChildClass, this.evenChildClass, this.onlyChildClass];



				// this represents a list of substrings to match such as for removing classNames

				this.classNameSubstringsArray = [this.nthChildClassPrefix];

				break;



			case 'light':

				// this represents all possible offspring-related classnames

				this.classNamesArray = [this.firstChildClass, this.lastChildClass, this.onlyChildClass];



				// this represents a list of substrings to match such as for removing classNames

				this.classNameSubstringsArray = [];

				break;

		}



		// Define the iterator function on-the-fly depending

		// on the configuration options that were sent in

		this.defineTraverseChildrenFunction();



		// Define the fillCacheTo funtion's iterator on-the-fly

		// depending on the configuration options that were sent in

		this.defineFillCacheToFunction();

		this.fillCacheTo(); // seed the cache with a basic set of values



 

		/* If Offspring is configured in autoStart mode (which it is by default),

		 	it runs as soon as the DOM is ready */

		if (this.configuration.autoStart)

		{

			var _this = this; // Closure



			this.ContentLoaded(window, function() {

				_this.start();

			});			

		}



	},



	// Executed once the page has loaded

	start: function() {

		var startTime = new Date();



		this.traverseChildren(document.getElementsByTagName("body")[0]);



		var endTime = new Date();

		// alert("Offspring Exec time: " + (endTime.getTime() - startTime.getTime()) + "ms");

		// window.status += "Offspring Exec time: " + (endTime.getTime() - startTime.getTime()) + "ms";



	},



	/* Maintenance note for defineTraverseChildrenFunction:

	

		There are several blocks of code that are marked off as "traverseChildren.A"

		or "traverseChildren.B" -- each of these are identical, respectively. (That is,

		all "traverseChildren.A" blocks are the same and all "traverseChildren.B" are 

		the same.) 

		

		So, why not just create a function where the code can be kept in one place? 

		While normally a sensible idea, I decided against that approach only so 

		that the speed hits associated with the creation of the function stack

		could be averted. At the same time, I didn't want to compromise

		the code's maintainability; so, if any block needs to be updated, they

		can all be kept in sync with some basic copy-n-pasting from one 

		block to the next.

	*/





	/* This defines the internal iterator function on-the-fly,

		depending on the configuration options */

	defineTraverseChildrenFunction: function() {



		switch (this.configuration.shouldRemoveOldOffspringClassesFirst)

		{

			case true: // shouldRemoveOldOffspringClassesFirst is true



				switch (this.configuration.runningMode)

				{

					case 'full': // 'full' running mode and shouldRemoveOldOffspringClassesFirst is true

						this.traverseChildren = function(parent)

						{

							/* ============= Begin Code Block "traverseChildren.A" ================ */



								// If the node has no children, exit

								if (!parent.childNodes.length) return;





								/* First, gather up all the element nodes */

								var childElementNodes = [];



								var testNode = parent.childNodes[0]; // initialize



								while (testNode)

								{

									if (testNode.nodeType == 1)

									{

										childElementNodes.push(testNode);

									}

									testNode = testNode.nextSibling;

								}



								/*

									empty this variable to ensure that the JavaScript

									interpreter doesn't have to update the variable's

									nodelist as DOM changes are made

								*/

								testNode = null;



								var childElementNodesLength = childElementNodes.length;



								// If no element nodes were found, exit

								if (!childElementNodesLength) return;



								// Make sure that the CSS-classnames cache has enough entries to cover

								// the number of child nodes

								if (childElementNodesLength > this.cacheLevel)

								{

									this.fillCacheTo(childElementNodesLength);

								}



								var lastIndex = childElementNodesLength - 1; // index of the last element node



							/* ============= /End Code Block "traverseChildren.A" ================ */



							// First, take care of all but the last element

							for (var i = 0; i < lastIndex; i++)

							{

								var currentElement = childElementNodes[i];



								this.removeMultipleClassNames(currentElement, this.classNamesArray, this.classNameSubstringsArray);



								// argument syntax: node to act upon, current index, boolean for whether isLast

								this._addOffspringClassNames(currentElement, i, false);

								this.traverseChildren(currentElement);

							}



							currentElement = null; // prevent memory leaks



							// Then, take care of the last one

							var lastElement = childElementNodes[lastIndex];



							this.removeMultipleClassNames(lastElement, this.classNamesArray, this.classNameSubstringsArray);



							this._addOffspringClassNames(lastElement, lastIndex, true);

							this.traverseChildren(lastElement);



							lastElement = null; // prevent memory leaks



							/* ============= Begin Code Block "traverseChildren.B" ================ */



								// prevent memory leaks

								lastElement = null;

								parent = null;



							/* ============= /End Code Block "traverseChildren.B" ================ */



						}; // end of traverseChildren function definition

						break;



					case 'light': // 'light' running mode and shouldRemoveOldOffspringClassesFirst is true

						this.traverseChildren = function(parent)

						{

							/* ============= Begin Code Block "traverseChildren.A" ================ */



								// If the node has no children, exit

								if (!parent.childNodes.length) return;





								/* First, gather up all the element nodes */

								var childElementNodes = [];



								var testNode = parent.childNodes[0]; // initialize



								while (testNode)

								{

									if (testNode.nodeType == 1)

									{

										childElementNodes.push(testNode);

									}

									testNode = testNode.nextSibling;

								}



								/*

									empty this variable to ensure that the JavaScript

									interpreter doesn't have to update the variable's

									nodelist as DOM changes are made

								*/

								testNode = null;



								var childElementNodesLength = childElementNodes.length;



								// If no element nodes were found, exit

								if (!childElementNodesLength) return;



								// Make sure that the CSS-classnames cache has enough entries to cover

								// the number of child nodes

								if (childElementNodesLength > this.cacheLevel)

								{

									this.fillCacheTo(childElementNodesLength);

								}



								var lastIndex = childElementNodesLength - 1; // index of the last element node



							/* ============= /End Code Block "traverseChildren.A" ================ */



							switch (childElementNodesLength)

							{

								case 0: return;

										break;



								case 1:

									/* Take care of the only element */



									var onlyElement = childElementNodes[0];

									this.removeMultipleClassNames(onlyElement, this.classNamesArray, this.classNameSubstringsArray);



									// argument syntax: node to act upon, current index, boolean for whether isLast

									this._addOffspringClassNames( onlyElement, lastIndex, true );



									onlyElement = null; // prevent memory leaks



									break;



								default:

									/* Take care of the first element */



									var firstElement = childElementNodes[0];

									this.removeMultipleClassNames(firstElement, this.classNamesArray, this.classNameSubstringsArray);



									// argument syntax: node to act upon, current index, boolean for whether isLast

									this._addOffspringClassNames( firstElement, 0, false );



									firstElement = null; // prevent memory leaks



									/* Take care of the last element */



									var lastElement = childElementNodes[lastIndex];

									this.removeMultipleClassNames(lastElement, this.classNamesArray, this.classNameSubstringsArray);



									// argument syntax: node to act upon, current index, boolean for whether isLast

									this._addOffspringClassNames( lastElement , lastIndex, true );



									lastElement = null; // prevent memory leaks



									break;



							} // end of switch statement for childElementNodesLength



							// Lastly, loop over all the childern elements

							for (var i = 0; i < childElementNodesLength; i++)

							{

								this.traverseChildren( childElementNodes[i] );

							}



							/* ============= Begin Code Block "traverseChildren.B" ================ */



								// prevent memory leaks

								lastElement = null;

								parent = null;



							/* ============= /End Code Block "traverseChildren.B" ================ */



						}; // end of traverseChildren function definition



						break;



				} // end of switch-statement for configuration.runningMode



				break;



			case false: // shouldRemoveOldOffspringClassesFirst is false



				switch (this.configuration.runningMode)

				{

					case 'full': // 'full' running mode and shouldRemoveOldOffspringClassesFirst is false

						this.traverseChildren = function(parent)

						{

							/* ============= Begin Code Block "traverseChildren.A" ================ */



								// If the node has no children, exit

								if (!parent.childNodes.length) return;





								/* First, gather up all the element nodes */

								var childElementNodes = [];



								var testNode = parent.childNodes[0]; // initialize



								while (testNode)

								{

									if (testNode.nodeType == 1)

									{

										childElementNodes.push(testNode);

									}

									testNode = testNode.nextSibling;

								}



								/*

									empty this variable to ensure that the JavaScript

									interpreter doesn't have to update the variable's

									nodelist as DOM changes are made

								*/

								testNode = null;



								var childElementNodesLength = childElementNodes.length;



								// If no element nodes were found, exit

								if (!childElementNodesLength) return;



								// Make sure that the CSS-classnames cache has enough entries to cover

								// the number of child nodes

								if (childElementNodesLength > this.cacheLevel)

								{

									this.fillCacheTo(childElementNodesLength);

								}



								var lastIndex = childElementNodesLength - 1; // index of the last element node



							/* ============= /End Code Block "traverseChildren.A" ================ */



							// First, take care of all but the last element

							for (var i = 0; i < lastIndex; i++)

							{

								var currentElement = childElementNodes[i];



								// argument syntax: node to act upon, current index, boolean for whether isLast

								this._addOffspringClassNames(currentElement, i, false);

								this.traverseChildren(currentElement);

							}



							currentElement = null; // prevent memory leaks



							/*

								Then, take care of the last one

								(this set of code isn't integrated into

								the for-loop above so as to avoid having

								an addiitional if-statement inside there)

							*/

							var lastElement = childElementNodes[lastIndex];



							this._addOffspringClassNames(lastElement, lastIndex, true);

							this.traverseChildren(lastElement);

							lastElement = null; // prevent memory leaks



							/* ============= Begin Code Block "traverseChildren.B" ================ */



								// prevent memory leaks

								lastElement = null;

								parent = null;



							/* ============= /End Code Block "traverseChildren.B" ================ */



						}; // end of traverseChildren function definition

						break;



					case 'light': // 'light' running mode and shouldRemoveOldOffspringClassesFirst is false

						this.traverseChildren = function(parent)

						{

							/* ============= Begin Code Block "traverseChildren.A" ================ */



								// If the node has no children, exit

								if (!parent.childNodes.length) return;





								/* First, gather up all the element nodes */

								var childElementNodes = [];



								var testNode = parent.childNodes[0]; // initialize



								while (testNode)

								{

									if (testNode.nodeType == 1)

									{

										childElementNodes.push(testNode);

									}

									testNode = testNode.nextSibling;

								}



								/*

									empty this variable to ensure that the JavaScript

									interpreter doesn't have to update the variable's

									nodelist as DOM changes are made

								*/

								testNode = null;



								var childElementNodesLength = childElementNodes.length;



								// If no element nodes were found, exit

								if (!childElementNodesLength) return;



								// Make sure that the CSS-classnames cache has enough entries to cover

								// the number of child nodes

								if (childElementNodesLength > this.cacheLevel)

								{

									this.fillCacheTo(childElementNodesLength);

								}



								var lastIndex = childElementNodesLength - 1; // index of the last element node



							/* ============= /End Code Block "traverseChildren.A" ================ */



							switch (childElementNodesLength)

							{

								case 0: break;



								case 1:

									/* Take care of the only element */



									// argument syntax: node to act upon, current index, boolean for whether isLast

									this._addOffspringClassNames( childElementNodes[0], lastIndex, true );



									// Lastly, loop over all the childern elements

									for (var i = 0; i < childElementNodesLength; i++)

									{

										this.traverseChildren( childElementNodes[i] );

									}



									break;



								default:

									/* Take care of the first element */



									// argument syntax: node to act upon, current index, boolean for whether isLast

									this._addOffspringClassNames( childElementNodes[0], 0, false );



									/* Take care of the last element */



									// argument syntax: node to act upon, current index, boolean for whether isLast

									this._addOffspringClassNames( childElementNodes[lastIndex] , lastIndex, true );



									// Lastly, loop over all the childern elements

									for (var i = 0; i < childElementNodesLength; i++)

									{

										this.traverseChildren( childElementNodes[i] );

									}



									break;

							}



							/* ============= Begin Code Block "traverseChildren.B" ================ */



								// prevent memory leaks

								lastElement = null;

								parent = null;



							/* ============= /End Code Block "traverseChildren.B" ================ */



						}; // end of traverseChildren function definition



						break;

				} // end of switch-statement for configuration.runningMode



				break;



		} // end of switch-statement for configuration.shouldRemoveOldOffspringClassesFirst



	}, // end of defineTraverseChildrenFunction



	// Recursive



	/*

		If "shouldRemoveOldOffspringClassesFirst" is deined and set to true

	 	(it's optional), traverseChildren will remove old Offspring-related

	 	classes before applying new ones to a node. This could be useful

	 	for reapplying classes if the DOM is rejiggered.

	*/



	traverseChildren: function(parent) {



		/* ============= Begin Code Block "traverseChildren.A" ================ */



			// If the node has no children, exit

			if (!parent.childNodes.length) return;





			/* First, gather up all the element nodes */

			var childElementNodes = [];



			var testNode = parent.childNodes[0]; // initialize



			while (testNode)

			{

				if (testNode.nodeType == 1)

				{

					childElementNodes.push(testNode);

				}

				testNode = testNode.nextSibling;

			}



			/*

				empty this variable to ensure that the JavaScript

				interpreter doesn't have to update the variable's

				nodelist as DOM changes are made

			*/

			testNode = null;



			var childElementNodesLength = childElementNodes.length;



			// If no element nodes were found, exit

			if (!childElementNodesLength) return;



			// Make sure that the CSS-classnames cache has enough entries to cover

			// the number of child nodes

			if (childElementNodesLength > this.cacheLevel)

			{

				this.fillCacheTo(childElementNodesLength);

			}



			var lastIndex = childElementNodesLength - 1; // index of the last element node



		/* ============= /End Code Block "traverseChildren.A" ================ */





		/* ==== Add the classes ====== */



		this._childrenIterator(childElementNodes, childElementNodesLength, lastIndex);





		/* ============= Begin Code Block "traverseChildren.B" ================ */



			// prevent memory leaks

			lastElement = null;

			parent = null;



		/* ============= /End Code Block "traverseChildren.B" ================ */



	},



	/*

		This function adds the Offspring classnames to a given element,

		given its position among it siblings (with zero being "first")

		and whether it's the last element in its set.

	*/

	_addOffspringClassNames: function(element, index, isLastElement) {



		index++; // normalize since the arrays are indexed with a "1" starting point



		// Steps if the element has no existing classnames...



		if ((!element.className) || (!element.className.length))

		{

			switch (isLastElement)

			{

				case false: // it isn't the last element

						element.className = this.regularHashTable[index];

						return;

						break;



				case true: // it is the last element

				 		element.className = this.lastChildHashTable[index];

						return;

						break;



			} // end of isLastElement switch-statement



		} // end of if-statement for checking whether the element has no existing className



		// At this point, the incoming element already has className(s)



		switch (isLastElement)

		{

			case false: // it isn't the last element

					var applicableClassNames = this.regularHashTableArray[index];

					break;



			case true: // it is the last element

					var applicableClassNames = this.lastChildHashTableArray[index];

					break;



		} // end of isLastElement switch-statement



		var originalClassNames = element.className.split(' ');



		var classNamesToAdd = originalClassNames; // initialize



		for (var i = 0, applicableClassNamesLength = applicableClassNames.length; i < applicableClassNamesLength; i++)

		{

			var alreadyThere = false; // boolean for whether a given class name is already assigned to the element



			var testApplicableClassName = applicableClassNames[i];



			for (var j = 0, originalClassNamesLength = originalClassNames.length; j < originalClassNamesLength; j++)

			{

				if (originalClassNames[j] == testApplicableClassName)

				{

					alreadyThere = true;

					break;

				} // end of if-statement for checking if the element already has a given className



			} // end of the originalClassNames for-loop



			if (!alreadyThere)

			{

				classNamesToAdd.push(testApplicableClassName);

			}



		} // end of applicableClassNames for-loop





		// Then, after checking over the element's existing classNames, add the new version

		element.className = classNamesToAdd.join(' ');

		element = null; // prevent memory leaks



		return;



	}, // end of _addOffspringClassNames()



	/* Maintenance note for defineFillCacheToFunction:

	

		[Aside: This is basically conveys the same idea as the comment above 

		defineTraverseChildrenFunction. So, if you're read that one, you 

		probably already have the basic idea of what's going on here.]

	

		There are several blocks of code that are marked off as "fillCacheTo.A"

		or "fillCacheTo.B" -- each of these are identical, respectively. (That is,

		all "fillCacheTo.A" blocks are the same and all "fillCacheTo.B" are 

		the same.) 

		

		So, why not just create a function where the code can be kept in one place? 

		While normally a sensible idea, I decided against that approach only so 

		that the speed hits associated with the creation of the function stack

		could be averted. At the same time, I didn't want to compromise

		the code's maintainability; so, if any block needs to be updated, they

		can all be kept in sync with some basic copy-n-pasting from one 

		block to the next.

	*/





	/* This defines the internal loop function for fillCacheTo,

		depending on how the configuration options are set */

	defineFillCacheToFunction: function() {



		switch (this.configuration.runningMode)

		{

			case 'full': // 'full' running mode

				this.fillCacheTo = function(fillAmount)

				{

					/* ============= Begin Code Block "fillCacheTo.A" ================ */



						var fillAmount = fillAmount || 15; // default value



						if (!this.cacheLevel) this.cacheLevel = 0; // set this to a default value if needed



						// If the cache level is already full enough, exit

						if (this.cacheLevel >= fillAmount) return;



						var startingPoint = this.cacheLevel++;



					/* ============= /End Code Block "fillCacheTo.A" ================ */



					var isOdd = !((startingPoint % 2) == 0); // initialize



					// cache these object name resolutions

					var firstChildClass = this.firstChildClass;

					var lastChildClass = this.lastChildClass;

					var oddChildClass = this.oddChildClass;

					var evenChildClass = this.evenChildClass;

					var onlyChildClass = this.onlyChildClass;

					var nthChildClassPrefix = this.nthChildClassPrefix;



					for (var i = startingPoint; i <= fillAmount; i++)

					{

						this.nthChildren[i] = [nthChildClassPrefix, i].join('');



						var nthChildrenI = this.nthChildren[i]; // cache this look-up



						switch (i)

						{

							case 1:

									this.regularHashTableArray[i] = [firstChildClass, oddChildClass, nthChildrenI];

									this.lastChildHashTableArray[i] = [firstChildClass, oddChildClass, onlyChildClass, nthChildrenI, lastChildClass];

									break;



							default:

									switch (isOdd)

									{

										case true: // "odd" is true

												this.regularHashTableArray[i] = [oddChildClass, nthChildrenI];

												this.lastChildHashTableArray[i] = [oddChildClass, nthChildrenI, lastChildClass];

												break;



										case false: // "odd" is false

												this.regularHashTableArray[i] = [evenChildClass, nthChildrenI];

												this.lastChildHashTableArray[i] = [evenChildClass, nthChildrenI, lastChildClass];

												break;



									} // end of isOdd switch-statement





						} // end of switch-statement for i



						// Now make the joined versions for a given "i"



						this.regularHashTable[i] = this.regularHashTableArray[i].join(' ');

						this.lastChildHashTable[i] = this.lastChildHashTableArray[i].join(' ');



						isOdd = !isOdd; // flip the isOdd flag



					} // end of filling for-loop



					/* ============= Begin Code Block "fillCacheTo.B" ================ */



						// If it got this far, the cacheLevel must made it to the fill amount, so update that

						this.cacheLevel = fillAmount;



					/* ============= /End Code Block "fillCacheTo.B" ================ */



				}; // end of fillCacheTo function definition

				break;



			case 'light': // 'light' running mode

				this.fillCacheTo = function(fillAmount)

				{

					/* ============= Begin Code Block "fillCacheTo.A" ================ */



						var fillAmount = fillAmount || 15; // default value



						if (!this.cacheLevel) this.cacheLevel = 0; // set this to a default value if needed



						// If the cache level is already full enough, exit

						if (this.cacheLevel >= fillAmount) return;



						var startingPoint = this.cacheLevel++;



					/* ============= /End Code Block "fillCacheTo.A" ================ */



					// cache these object name resolutions

					var firstChildClass = this.firstChildClass;

					var lastChildClass = this.lastChildClass;



					var onlyChildClass = this.onlyChildClass;



					for (var i = startingPoint; i <= fillAmount; i++)

					{



						switch (i)

						{

							case 1:

									this.regularHashTableArray[i] = [firstChildClass];

									this.lastChildHashTableArray[i] = [firstChildClass, onlyChildClass, lastChildClass];

									break;



							default:



									this.regularHashTableArray[i] = [];

									this.lastChildHashTableArray[i] = [lastChildClass];



						} // end of switch-statement for i



						// Now make the joined versions for a given "i"



						this.regularHashTable[i] = this.regularHashTableArray[i].join(' ');

						this.lastChildHashTable[i] = this.lastChildHashTableArray[i].join(' ');



					} // end of filling for-loop



					/* ============= Begin Code Block "fillCacheTo.B" ================ */



						// If it got this far, the cacheLevel must made it to the fill amount, so update that

						this.cacheLevel = fillAmount;



					/* ============= /End Code Block "fillCacheTo.B" ================ */



				}; // end of fillCacheTo function definition

				break;



		} // end of switch statement for this.configuration.runningMode



	}, // end of defineFillCacheToFunction



	// This fills the className caches to the specified amount

	fillCacheTo: function(fillAmount) {



		/* ============= Begin Code Block "fillCacheTo.A" ================ */



			var fillAmount = fillAmount || 15; // default value



			if (!this.cacheLevel) this.cacheLevel = 0; // set this to a default value if needed



			// If the cache level is already full enough, exit

			if (this.cacheLevel >= fillAmount) return;



			var startingPoint = this.cacheLevel++;



		/* ============= /End Code Block "fillCacheTo.A" ================ */



		this._fillCacheToIterator(startingPoint, fillAmount);



		/* ============= Begin Code Block "fillCacheTo.B" ================ */



			// If it got this far, the cacheLevel must made it to the fill amount, so update that

			this.cacheLevel = fillAmount;



		/* ============= /End Code Block "fillCacheTo.B" ================ */



	}, // end of fillCacheTo()



	/* Returns true if testString is found in the array,

		or returns false otherwise */

	_checkIfStringFoundInArray: function(testString, testArray) {



		// Loop through all testArray[] and if/when there's a match, return true

		for (var i = 0, len=testArray.length; i < len; i++)

		{

			if (testString == testArray[i]) return true;

		}



		// If it got this far, it must not have found the string in the array

		return false;



	}, // end of _checkIfStringFoundInArray



	/* Returns true if the beginning of testString matches one of the substrings

		in the array. Otherwise, it returns false.



		For example, given the array ['plum', 'orange', 'pine'] and

		the testString 'pineapples', the function would return true. However,

		given the testString 'range', it would return false (since none of

		the strings in the array start with 'range')

	*/

	_checkIfStringMatchInSubstringArray: function(testString, testArray) {



		// Loop through all testArray[] and if/when there's a match, return true

		for (var i = 0, len=testArray.length; i < len; i++)

		{

			var currentArrayItem = testArray[i];



			/* string.substr() accepts two parameters:

				- The starting point of the substring

				- The length of the substring

			*/

			var testSubstring = testString.substr(0, currentArrayItem.length);



			if (testSubstring == currentArrayItem) return true;

		}



		// If it got this far, it must not have found the string in the array

		return false;



	}, // end of _checkIfStringMatchInSubstringArray



	/*

		This removes multiple classnames from an element. It does this by

		checking each of an element's class names against

		classNameStrings[] for an exact match and, if a given class name

		didn't match there, it's then checked to see if it matches

		as a substring against classNAmeSubstrings[].



		Of note, when comparing substrings, this intentionally only compares

		the beginning of the strings for a match. So, for example, "ora" would

		match as a substring of "orange", but "range" would not match as a substring

		of "orange". It was done this way because that was the only type of substring-

		comparison that was needed in this case, and a more thorough substring

		comparison would needlesslly use processor time.

	*/

	removeMultipleClassNames: function(element, classNameStrings, classNameSubstrings) {



		if (!element) return;

		var newClassName = '';

		var classNamesArray = element.className.split(' ');



    	for (var i = 0, len = classNamesArray.length; i < len; i++)

		{

			var currentClassName = classNamesArray[i];



			var isStringInClassNameStrings = this._checkIfStringFoundInArray(currentClassName, classNameStrings);



			if (isStringInClassNameStrings) continue;



			var isStringMatchingClassNameSubstrings = this._checkIfStringMatchInSubstringArray(currentClassName, classNameSubstrings);



			if (isStringMatchingClassNameSubstrings) continue;



			// If it got this far, it must not have matched any of the potential classNameStrings

			// or classNameRegexes, so add the current iteration to the neClassName



			if (i > 0) newClassName = newClassName + ' ';

    		newClassName = newClassName + currentClassName;



    	}

   		element.className = newClassName;



	}, // end of removeMultipleClassNames





	/*

	 *

	 * ContentLoaded.js

	 *

	 * Author: Diego Perini (diego.perini at gmail.com)

	 * Summary: Cross-browser wrapper for DOMContentLoaded

	 * Updated: 05/10/2007

	 * License: GPL/CC

	 * Version: 1.0

	 *

	 * http://javascript.nwbox.com/ContentLoaded/

	 *

	 * Notes:

	 *

	 *  based on code by Dean Edwards and John Resig

	 *  http://dean.edwards.name/weblog/2006/06/again/

	 *

	 *

	 */



	/*

	 * Example call, in this case:



	 	Offspring.ContentLoaded(window,

			function () {

				document.body.style.backgroundColor = 'green';

			}

		);

	*

	*/



	// @w	window reference

	// @f	function reference

	ContentLoaded: function (w, fn) {

		var d = w.document,

			u = w.navigator.userAgent.toLowerCase();



		function init(e) {

			if (!arguments.callee.done) {

				arguments.callee.done = true;

				fn(e);

			}

		}



		// konqueror/safari

		if (/khtml|webkit/.test(u)) {



			(function () {

				if (/complete|loaded/.test(d.readyState)) {

					init('poll');

				} else {

					setTimeout(arguments.callee, 10);

				}

			})();



		// internet explorer all versions

		} else if (/msie/.test(u) && !w.opera) {



			(function () {

				try {

					d.documentElement.doScroll('left');

				} catch (e) {

					setTimeout(arguments.callee, 10);

					return;

				}

				init('poll');

			})();

			d.attachEvent('onreadystatechange',

				function (e) {

					if (d.readyState == 'complete') {

						d.detachEvent('on'+e.type, arguments.callee);

						init(e.type);

					}

				}

			);



		// browsers having native DOMContentLoaded

		} else if (d.addEventListener &&

			(/gecko/.test(u) && parseFloat(u.split('rv:')[1]) >= 1.8) ||

			(/opera/.test(u) && parseFloat(u.split('opera ')[1]) > 9)) {



			d.addEventListener('DOMContentLoaded',

				function (e) {

					this.removeEventListener(e.type, arguments.callee, false);

					init(e.type);

				}, false

			);



		// fallback to last resort

		} else {



			// from Simon Willison

			var oldonload = w.onload;

			w.onload = function (e) {

				if (typeof oldonload == 'function') {

					oldonload(e || w.event);

				}

				init((e || w.event).type);

			};



		}

	} // end of ContentLoaded



}





// Kick off

offspring.init();