jss = {
	// method to check for an array item, usually used to prevent duplicate entries
	findInArray: function(array,key)
	{
		// loop through the array looking for matches
		for(var x=0;x<array.length;x++)
		{
			// if a match is found, return true
			if(array[x]==key) return true;
		}
		// if no match is found, return false
		return false;
	},
	
	trimEmptyItems: function(array,emptyFunction)
	{
		var retArr = [];
		for(var z=0;z<array.length;z++)
		{
			if(emptyFunction(array[z])==false) {
				retArr[retArr.length]=array[z];
			}
		}
		return retArr;
	},
	
	// method to loop through arrays
	loop: function(opts) {
		this.loop.opts = {
			startIndex:((this.undefined(opts)||this.undefined(opts.startIndex))?0:opts.startIndex),
			array:((this.undefined(opts)||this.undefined(opts.array))?[]:opts.array),
			debug:((this.undefined(opts)||this.undefined(opts.debug))?false:opts.debug),
			callback:((this.undefined(opts)||this.undefined(opts.callback))?false:opts.callback)
		}	
		this.loop.opts.endIndex = ( (this.undefined(opts)||this.undefined(opts.endIndex) ) ? this.loop.opts.array.length : opts.endIndex );
		if(this.loop.opts.debug) {
			var alStr = "";
			for(var opt in this.loop.opts) {
				alStr+="loop.opts."+opt+": "+this.loop.opts[opt]+"\n";
			}
			alert(alStr);
		}
		if(this.loop.opts.callback) {
			for(((this.loop.opts.startIndex<=this.loop.opts.array.length)?this.loop.opts.startIndex:this.loop.opts.array.length);this.loop.opts.startIndex<((this.loop.opts.endIndex>=this.loop.opts.startIndex)?this.loop.opts.endIndex:this.loop.opts.array.length);this.loop.opts.startIndex++) {
				this.loop.opts.callback(this.loop.opts.array[this.loop.opts.startIndex]);
			}
		}
		return;
	},
	
	// collection of node types and test methods
	nodeType: {
		isElement: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 1; } },
		isAttribute: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 2; } },
		isText: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 3; } },
		isCdataSection: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 4; } },
		isEntityReference: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 5; } },
		isEntity: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 6; } },
		isProcessingInstruction: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 7; } },
		isComment: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 8; } },
		isDocument: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 9; } },
		isDocumentType: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 10; } },
		isDocumentFragment: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 11; } },
		isNotation: function(o) { if(typeof(o.nodeType)!="undefined") { return o.nodeType == 12; } },
		_1: "ELEMENT_NODE",
		_2: "ATTRIBUTE_NODE",
		_3: "TEXT_NODE",
		_4: "CDATA_SECTION_NODE",
		_5: "ENTITY_REFERENCE_NODE",
		_6: "ENTITY_NODE",
		_7: "PROCESSING_INSTRUCTION_NODE",
		_8: "COMMENT_NODE",
		_9: "DOCUMENT_NODE",
		_10: "DOCUMENT_TYPE_NODE",
		_11: "DOCUMENT_FRAGMENT_NODE",
		_12: "NOTATION_NODE"
	},
	
	// method to import stylesheets using supplied JSON data
	loadStylesheets: function(importJSON)
	{
		for(var sS in importJSON)
		{
			if(document.createStyleSheet) {
				var oSS = document.createStyleSheet(importJSON[sS]["url"]);
			}
			else {
				var oSS = document.createElement('style');
				oSS.appendChild(document.createTextNode(importJSON[sS]["url"]));
				document.getElementsByTagName("head")[0].appendChild(oSS);
			}
			oSS.setAttribute( "type" , ( (!jss.undefined(importJSON[sS]["type"]) && importJSON[sS]["type"] != "" ) ? importJSON[sS]["type"] : "text/css" ) );
			oSS.setAttribute( "media" , ( (!jss.undefined(importJSON[sS]["media"]) && importJSON[sS]["media"] != "" ) ? importJSON[sS]["media"] : "screen" ) );
			oSS.setAttribute( "id" , ( (!jss.undefined(importJSON[sS]["id"]) ) ? importJSON[sS]["id"] : sS+"" ) );
		}
		return;
	},
	
	// method to get all child nodes below a specified element
	getAllChildNodes: function(oElement)
	{
		// determine if this is part of recursively building the arrNodeCollection array (is this the function calling itself or not)
		var is_recursiveProcess = (jss.getAllChildNodes.caller==jss.getAllChildNodes);
		// set the arrNodeCollection array to an empty array if this is a new collection
		arrNodeCollection=((typeof(arrNodeCollection)=="undefined"||!is_recursiveProcess)?[]:arrNodeCollection);
		// get the the oElement object reference, or if not supplied -- the BODY element, to navigate through and build the child node collection
		var oElement=( ( ( "_" + oElement.nodeType ).match( /_[1348]{1}/ ) ) ? oElement : null );
		// check for children and recursively process them if present
		if( oElement.hasChildNodes() )
		{
			// loop through all children
			for(var i=0; i<oElement.childNodes.length; i++)
			{
				// recursively call this function to get all the child's children
				jss.getAllChildNodes(oElement.childNodes[i]);
			}
		}
		// oElement has no children, add it alone
		else
		{
			// add the oElement
			arrNodeCollection[arrNodeCollection.length]=oElement;
		}
		// return the array of nodes
		return arrNodeCollection;
	},

	// method to determine if a node is contained within another node
	contains: function(oTopNode,oNode)
	{
		// the following is based upon google's .contains found here: http://code.google.com/p/doctype/wiki/ArticleNodeContains
		// IE / Safari(some) DOM
		if (typeof(oTopNode.contains) != "undefined" && this.nodeType.isElement(oNode)) {
			return oNode == oTopNode || oTopNode.contains(oNode);
		}
		// W3C DOM Level 3
		if (typeof oTopNode.compareDocumentPosition != 'undefined') {
			return oTopNode == oNode ||
				Boolean(oTopNode.compareDocumentPosition(oNode) & 16);
		}
		// W3C DOM Level 1
		while (oNode && oTopNode != oNode) {
			oNode = oNode.parentNode;
		}
		return oNode == oTopNode;
	},
	
	undefined: function() {
		var args=this.undefined.arguments;
		var rtV=[];
		while(args.length>0) { 
			rtV[rtV.length] = ((typeof(args[rtV.length])=="undefined") ? true : false); 
			args.length--; 
		}
		return ((rtV.length==1)?rtV[0]:rtV);
	},

	// method to add class name(s) by content matching - used for content "pagination"
	getElementsByContentMatch: function(oContainer,strTagName,oMatchRE) 
	{
		// get the parent element (the container element which will contain all content to be paginated)
		var oContainer = (((typeof(oContainer)!="undefined")&&(typeof(oContainer.getElementsByTagName)!="undefined"))?oContainer:((typeof(oContainer)=="string")?document.getElementById(oContainer):null));
		// get the tag name of the element, or node type to search through
		var strTagName=((typeof(strTagName)!="undefined")?strTagName:null);
		// get the regular expression to match against
		var oMatchRE=(((typeof(oMatchRE)+"").toLowerCase().match(/object|function/))?oMatchRE:((typeof(oMatchRE)=="string")?new RegExp(oMatchRE):null));
		// if there's no container/parent element, 'child' element tag name or regular expression, abort and return null
		if(!oContainer||!strTagName||!oMatchRE)
			return;
		// set up an array to contain all matched nodes
		oContainer.arrMatchingNodeTree = [];
		// get the node collection from the parent element
		oContainer.arrChildNodes = jss.getAllChildNodes(oContainer);
		for(var nC=0;nC<oContainer.arrChildNodes.length;nC++)
		{
			// if the child 'tags' to match are comment or text nodes, proceed to look for matches
			if(strTagName=="comment"||strTagName=="text")
			{
				// make sure this is truly a comment (8) or text (3) node
				if(oContainer.arrChildNodes[nC].nodeType==8||oContainer.arrChildNodes[nC].nodeType==3)
				{
					// check to see if we have a match
					if(oContainer.arrChildNodes[nC].data.match(oMatchRE)&&!jss.findInArray(oContainer.arrMatchingNodeTree,oContainer.arrChildNodes[nC]))
					{
						// add the matched node data array
						oContainer.arrMatchingNodeTree[oContainer.arrMatchingNodeTree.length] = jss.getNodeParents(oContainer.arrChildNodes[nC],oContainer);
					}
				}
			}
			else
			{
				// since this isn't a comment or text node, get all the child nodes of this child (grandchild nodes)
				var allGrandchildNodes = jss.getAllChildNodes(oContainer.arrChildNodes[nC]);
				// loop through all this child nodes' child nodes
				for(var gC=0;gC<allGrandchildNodes.length;gC++)
				{
					// look only at comment (8) or text (3) nodes (since all pertinent content is one or the other)
					if((allGrandchildNodes[gC].nodeType==3)||(allGrandchildNodes[gC].nodeType==8))
					{
						// check to see if we have a match
						if( allGrandchildNodes[gC].data.match(oMatchRE) && !jss.findInArray(oContainer.arrMatchingNodeTree,allGrandchildNodes[gC]) )
						{
							// add the matched parent node to the arrParentsMatched array
							oContainer.arrMatchingNodeTree[oContainer.arrMatchingNodeTree.length] = jss.getNodeParents(oContainer.arrChildNodes[nC],oContainer);
						}
					}
				}
			}
		}
		// return the array of matching node trees (the matching node is at array index 0, topmost parent prior to the container node (or document body element) is last array item)
		return oContainer.arrChildNodes, oContainer.arrMatchingNodeTree;
	},

	getNodeParents: function(oNode,oTopNode)
	{
		var oTopNode = ((typeof(oTopNode)!="undefined")?oTopNode:document.getElementsByTagName("body"));
		var oNode = ((typeof(oNode)!="undefined")?oNode:null);
		var nodeParentTree = [];
		if(!oNode)
			return nodeParentTree;
		var oCurrentNode = ((typeof(oNode.parentNode)!="undefined"&&oNode.parentNode!=null)?oNode.parentNode:null);
		nodeParentTree[nodeParentTree.length]=oNode;
		var ovr=0;
		while((oCurrentNode)&&(oCurrentNode != oTopNode)&&(jss.contains(oTopNode,oCurrentNode))&&(ovr<1000))
		{
			nodeParentTree[nodeParentTree.length] = oCurrentNode;
			oCurrentNode=oCurrentNode.parentNode;
			ovr++;
		}
		return nodeParentTree.reverse();
	},

	removeNode: function(oNode,oParent)
	{
		// if removeNode method is available, use it otherwise, use the removeChild method
		return ((document.removeNode) ? oNode.removeNode(true):((document.removeChild)?oParent.removeChild(oNode):-1));
	},

	removeAllNodes: function(oParent)
	{
		// while the oParent node has children, remove the first child
		while(oParent.firstChild)
		{
			this.removeNode(oParent.firstChild,oParent);
		}
	},
	logMessage: function(strMsg)
	{
		if($("#logText").length==0) {
			$("body").append("<textarea id=\"logText\" style=\"font-size:10.75px;font-family:'monotype sorts','andale mono','lucida sans',monospace;width:100%;height:400px;\" ondblclick=\"this.style.overflow=(($('#logText').css('overflow')=='visible')?'auto':'visible'));\"></textarea>");
		}
		$("#logText")[0].value+="\n"+strMsg;
		return;
	},
	
	addPage: function(oPageSet,iPageIndex)
	{
		// create a new page DIV container element, and assign it class of oPageSet.pageItemClass
		oPageSet.pages[iPageIndex] = $("<div class=\"" + oPageSet.pageItemClass + " hidden\"></div>")[0];
		// create a context array of matched HTML tags (open or closed) ...
		// ... found in this pages' page content fragment
		oPageSet.arrPageFragmentContext[iPageIndex] = ( ( oPageSet.arrPageContentFragment[iPageIndex].replace(/<!\-\-.+?(\-{2})>/g, function(str) { return escape(str); }).replace(/<?(script|embed)((\s+\w+(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>.+?<\/\1?>/g, function(str) { return escape(str); } ).match(this.tagRegEx.htmlTags) != null ) ? oPageSet.arrPageContentFragment[iPageIndex].replace(/<!\-\-.+?(\-{2})>/g, function(str) { return escape(str); } ).replace(/<?(script|embed)((\s+\w+(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>.+?<\/\1?>/g, function(str) { return escape(str); } ).match(this.tagRegEx.htmlTags) : [] )
		// turn the array into a string delimited with the specified jss.tagDelimiter (manipulating the string is a little faster than the array)
			.join(jss.tagDelimiter.replace(/\\+/g,""))
			.replace(/.+/,function(str) { 
				// remove any complete tag sets at the start of the string of tags
				while(str.match(jss.tagRegEx.precedingTagSet)) { str = str.replace(jss.tagRegEx.precedingTagSet,""); };
				// remove any complete tag sets at the end of the string of tags
				while(str.match(jss.tagRegEx.recedingTagSet)) { str = str.replace(jss.tagRegEx.recedingTagSet,""); };
				// remove any complete tag sets at the 'core'/center of the string (removes complete 'nest' of tags)
				while(str.match(jss.tagRegEx.completeTagSet)) { str = str.replace(jss.tagRegEx.completeTagSet,""); };
				// remove any self closing tags like: link, br, hr, area etc.
				str=str.replace(jss.tagRegEx.selfClosingTag,"");
				// return the string 'cleaned' of tags that are already closed
				// ... leaving only fragmented/orphaned open and close tags
				return str; 
			})
			// convert the string to an array again
			.split(jss.tagDelimiter.replace(/\\+/g,""));
		// process any existing 'un-closed' html context
		if( typeof(oPageSet.arrCurrentFragmentContext) != "undefined" && ( oPageSet.arrCurrentFragmentContext.length>0 ) )
		{
			$(oPageSet.pages[iPageIndex]).prepend( $( $( oPageSet.arrCurrentFragmentContext.reverse() ).clone(true) ).empty() );
			oPageSet.arrPageContentFragment[iPageIndex] = 
				$(oPageSet.pages[iPageIndex])
					.html()
					.replace(/.+/,function(str){ while(str.match(jss.tagRegEx.closeTag)) { str = str.replace(jss.tagRegEx.closeTag,""); } return str; } )
					+ oPageSet.arrPageContentFragment[iPageIndex];
			oPageSet.arrCurrentFragmentContext.reverse();
		}	
		// set an overflow counter variable, in case the 'while' loop hangs
		var ovf=0;
		// remove any tags from the arrCurrentFragmentContext (if applicable) 
		// ... they're being closed by the current fragment
		while( oPageSet.arrCurrentFragmentContext && oPageSet.arrCurrentFragmentContext.length > 0 && oPageSet.arrPageFragmentContext[iPageIndex] && oPageSet.arrPageFragmentContext[iPageIndex].length > ovf && oPageSet.arrPageFragmentContext[iPageIndex][ovf].match(this.tagRegEx.closeTag) && ovf<1000 )
		{
			// ensure that this close tag matches the current open tag element from the arrMatchingNodeTree
			if( ( oPageSet.arrPageFragmentContext[iPageIndex][ovf].match( this.tagRegEx.closeTag)[1] + "" ).toLowerCase() ==  ( oPageSet.arrCurrentFragmentContext[0].tagName + "" ).toLowerCase() 
			)
			{
				oPageSet.arrCurrentFragmentContext.reverse();
				oPageSet.arrCurrentFragmentContext.length--;
				oPageSet.arrCurrentFragmentContext.reverse();
			}
			ovf++;
		}
		// reset the overflow counter
		ovf=0;
		// clone any un-closed parent elements and add them to the 'currentFragmentContext' property of this page set
		while( oPageSet.arrPageFragmentContext[iPageIndex] && oPageSet.arrPageFragmentContext[iPageIndex].length > 0 && oPageSet.arrPageFragmentContext[iPageIndex][oPageSet.arrPageFragmentContext[iPageIndex].length-1].match(this.tagRegEx.openTag) && ovf<1000 )
		{
			// ensure the match to the open tag element from the arrMatchingNodeTree array for this node
			if( (typeof(oPageSet.arrMatchingNodeTree[iPageIndex]) != "undefined") && (oPageSet.arrMatchingNodeTree[iPageIndex].length > 1) && ( oPageSet.arrPageFragmentContext[iPageIndex][oPageSet.arrPageFragmentContext[iPageIndex].length-1].match( this.tagRegEx.openTag )[1] + "" ).toLowerCase() ==  ( oPageSet.arrMatchingNodeTree[iPageIndex][oPageSet.arrMatchingNodeTree[iPageIndex].length - ( 2 + ovf )].tagName + "" ).toLowerCase() )
			{
				// clone any open tags and add them to the page set's arrCurrentFragmentContext array
				oPageSet.arrCurrentFragmentContext[oPageSet.arrCurrentFragmentContext.length] = $( $( oPageSet.arrMatchingNodeTree[iPageIndex][oPageSet.arrMatchingNodeTree[iPageIndex].length - ( 2 + ovf )] )
					.clone(true) )
					.empty()[0];
			}
			// remove this open tag from the arrPageFragmentContext for this node (page break)
			oPageSet.arrPageFragmentContext[iPageIndex].length--;
			// increment our overflow (and array index)
			ovf++;
		}
		$(oPageSet.pages[iPageIndex]).empty();
		// assign this fragment to the 'final' page contents array
		oPageSet.arrPageContent[iPageIndex] = oPageSet.arrPageContentFragment[iPageIndex];
		$(oPageSet.pages[iPageIndex]).append(oPageSet.arrPageContent[iPageIndex]);
	},
	
	paginateContent: function(oPageSet)
	{
		try {
			// set the oPageSet object ready state to "1:LOADING", this particularly disables ad refreshes on initial load
			oPageSet.readyState="1:LOADING";
			// make sure jquery is available
			if(typeof($)!="undefined") {
				// check the collection of page break node objects and...
				if( (typeof(oPageSet.arrMatchingNodeTree)=="undefined") || ( (typeof(oPageSet.arrMatchingNodeTree.length)!="undefined") && (oPageSet.arrMatchingNodeTree.length==0) ) ) {
					// return null if the collection (array) is undefined/doesn't exist or if it's empty
					return;
				}
				// proceed if the collection of break node objects exists
				else {
					// loop through the array of html fragments and replace any missing context/parent nodes
					for( oPageSet.pageCounter=0; oPageSet.pageCounter<oPageSet.arrPageContentFragment.length; oPageSet.pageCounter++ )
					{
						this.addPage(oPageSet,oPageSet.pageCounter);
					} // END :::  loop through html fragments
					// clear out the contents of the oPageContainer in preparation for the appending of the new page elements
					if(oPageSet.pages.length<=1)
					{
						return;
					}
					else
					{
						$(oPageSet.oPageContainer).empty();
						// append the page <DIV>s
						$(oPageSet.oPageContainer).append(oPageSet.pages);
					}
				}
			} // END :::  if(typeof($)!="undefined")
			// set the oPageSet.readyState to "2:LOADED" (NOTE: this is still not the final "4:COMPLETED" state)
			oPageSet.readyState="2:LOADED";
			return oPageSet;
		}
		catch(e)
		{
			return;
		}
	},

	// method to change the page view, used as the callback to jquery.pagination's callback on pageSelected
	viewPage: function(intPageIndex)
	{
		if( typeof(articlePages) == "undefined" )
			return;
		articlePages.activePageIndex = parseInt( ( ( articlePages.activePageIndex >= 0 ) && ( articlePages.activePageIndex < articlePages.pages.length ) ) ? articlePages.activePageIndex : '0' );
		intPageIndex = parseInt( ( intPageIndex && ( intPageIndex > 0 ) && ( intPageIndex < articlePages.pages.length ) ) ? intPageIndex : '0' );
		// set the articlePages.readyState to "3:INTERACTIVE" to indicate that it has loaded but is now being modified
		articlePages.readyState=((parseInt(articlePages.readyState)==4)?"3:INTERACTIVE":articlePages.readyState);
		// make sure the articlePages object exists 
		// due to jquery 'ownership' of the 'this.' keyword in the animation effects below...
		// and because the jquery pagination's pageSelected callback function which uses viewPage can't pass another parameter
		if(typeof(articlePages)=="undefined")
			return;
		// hide the page navigation controls
		$('.nav-article-pages').css({"display":"none"});
		$(articlePages.pages[articlePages.activePageIndex]).fadeOut(333, function() {
			$(this).addClass("hidden");
			with($(articlePages.pages[intPageIndex])) {
				removeClass("hidden");
				css({"display":"block"});
				fadeIn(555,function() {
					// set the articlePages.activePageIndex value to the currently viewed page
					articlePages.activePageIndex=intPageIndex;
					// show the page navigation controls
					$('.nav-article-pages').css({"display":"block"});
				})
			}
			$(this).css({"display":"block"});
		});
		// scroll to the top of the article 'page'
		var curTop = parseInt($($(".article_text").get(0)).offset().top - 65);
		var bodyTop = parseInt($($( ( ( (parseInt($($("html").get(0)).attr("scrollTop") ) <= 0 ) )?"body":"html") ).get(0)).attr("scrollTop"));
		if(curTop < bodyTop ) { $("html,body").attr( {scrollTop: curTop }); };
		// run any callback function intended to execute everytime the page view changes...
		// ...but only after checking to make sure this isn't the 'viewPage' being called on instantiation (first load)
		if((typeof(articlePages.callback)!="undefined") && (articlePages.callback!=null) && (parseInt(articlePages.readyState)==3)) {
			articlePages.callback();
			// set the articlePages.readyState to "2:LOADED"
			articlePages.readyState="2:LOADED";
		}	
		// set the articlePages.readyState to "4:COMPLETED"
		articlePages.readyState="4:COMPLETED";
		return articlePages.pages[articlePages.activePageIndex];
	},

	// method to pull, using a passed regular espression, matching strings from the location.hash string (precedence)...
	// ... or the location.search (query) string (secondary if hash doesn't pass a match)
	parseHashThenQuery: function(oRE)
	{
		return ((document.location&&document.location.hash&&document.location.hash.match(oRE))?RegExp.$1:((document.location&&document.location.search&&document.location.search.match(oRE))?RegExp.$1:1));
	},

	// method to get the current page value from the location.hash (first) or location.search string (second if not found in the location.hash)
	current_page: function()
	{
		// set a variable to hold the value of any 'page=#' string found in the hash or search/query string
		var curPage = ((document.location&&document.location.hash&&document.location.hash.match(/page\=([0-9]+)/i))?RegExp.$1:((document.location&&document.location.search&&document.location.search.match(/page\=([0-9]+)/i))?RegExp.$1:1));
		// if a numeric value is found, subtract 1 from it's value to 'sync' it with the zero-indexed array of pages...
		// ... if a non-numeric value is found, set the current page value to 0 (page 1)
		curPage = parseInt( ( !isNaN(curPage) && curPage>0 ) ? ( ( (typeof articlePages == "undefined" ) || (curPage-1 < articlePages.pages.length) ) ? curPage-1 : articlePages.pages.length-1 ) : 1 );
		// return the page value found, or 0 for default if not found
		return curPage;
	}
}	
jss.tagDelimiter = "\\^X\\^";
jss.tagRegEx = {
	htmlTags: new RegExp( "<\\/?[\\w\-:]+((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\\/?>","g" ),
//	-- i.e., htmlTags matches: <a href="www.osmosis.com"> | </a> | <ms:office-tag attr="attr:>dkdksaa<lkdjiejoijwlsl<>lskldlk">
	openTag: new RegExp( "<([\\w\-:]+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\\/?>" ),
	//	-- i.e., openTag matches: <p> | <div class="article-head_hover" onmouseover="alert('<div>')"> | <br />
	closeTag: new RegExp( "<\\/([\\w\-:]+)>" ),
	//	-- i.e., closeTag matches: </div> | </a> | </ms:office-tag>
	completeTagSet: new RegExp( "<([\\w\-:]+)+((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\/?>(" + "" + jss.tagDelimiter + "" + ")+<\\/\\1>(" + jss.tagDelimiter + "){0,1}" ),
	//	-- i.e., completeTagSet matches: <p class="someclass">,</p> | <a href="http://greeneffect.nationalgeographic.com">,,,,</a>
	precedingTagSet: new RegExp( "^<([\\w\-:]+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\\/?>" + jss.tagDelimiter + "<\\/(\\1)>(" + jss.tagDelimiter + "){0,1}" ),
	//	-- i.e., precedingTagSet matches: <a href="http://science.nationalgeographic.com" target="_blank">,</a> | <blockquote>,</blockquote> 
	//	-- but ONLY at the start of the string
	recedingTagSet:  new RegExp( "(" + jss.tagDelimiter + "){0,1}<([\\w\-:]+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\\/?>" + jss.tagDelimiter + "<\\/(\\2)>$" ),
	//	-- i.e., recedingTagSet matches: <a href="http://science.nationalgeographic.com" target="_blank">,</a> | <blockquote>,</blockquote> 
	//	-- but ONLY at the end of the string
	arrSelfClosingTags: ["br","hr","area","base","basefont","input","img","link","meta","embed"],
	//	-- an array of self closing tags to 'ignore' in html fragment/html node contexts
	getInvalidParentTags: function() { return ["object","embed","script","head","!doctype","button","image"].concat(this.arrSelfClosingTags); }
	//	-- an array of node contexts which are invalid for 'page_break' comments; page shouldn't break within these tags
	//	-- (includes the selfClosingTags)
}
jss.tagRegEx.arrInvalidParentTags = jss.tagRegEx.getInvalidParentTags();
jss.tagRegEx.selfClosingTag = new RegExp( "(" + jss.tagDelimiter + "){0,1}<(" + jss.tagRegEx.arrSelfClosingTags.join("|") + "|\\-|:+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\\/?>(" + jss.tagDelimiter + "){0,1}" , "gi" );

pageSet = function(opts) {
	eval("this.self = this");
	this.defaultOpts = {
		oPageContainer:((typeof($)!="undefined")?$("body"):document.getElementsByTagName("body")[0]),
		oMatchRE:new RegExp("page_*break"),
		strMatchTagName:"*",
		arrPageContent:[],
		arrPageFragmentContext:[],
		arrCurrentFragmentContext: [],
		pages: [],
		viewPage: jss.viewPage,
		activePageIndex:1,
		pageItemClass: "article-page-item hidden",
		hashVar: "page",
		maxPages:1000,
		readyState: "1:LOADING",
		stylesheetJSON:null,
		callback: null
	};
	for(var opt in this.defaultOpts) {
		this[opt] = ((typeof(opts[opt]))!="undefined"?opts[opt]:this.defaultOpts[opt]);
	}
	this.arrMatchingNodeTree = jss.getElementsByContentMatch(this.oPageContainer,this.strMatchTagName,this.oMatchRE);
	this.matchedTagRE = new RegExp("<!--\\s*"+this.oMatchRE.toString().replace(/\//g,"")+"\\s*-->","i");
	this.strRawHTML = $(this.oPageContainer).html()+"";
	this.arrPageContentFragment = jss.trimEmptyItems( this.strRawHTML.split(this.matchedTagRE),function(item){ return ( (item+"").replace(/(<!\-\-.+?(\-{2})>)+/g,"").replace(/([\W\t\r\n\f\s]+)/g,"") == "" ) ? true : false; } );
	this.initialize = jss.paginateContent(this);
	return this.self;
}