////////////////////////////////////////////////////
// Namespace creation

// Create the global symbol "com" if it doesn't exist
// Throw an error if it does exist but is not an object

/**
var com;
if (!com) {com = {};}
else if (typeof com != "object") {
	throw new Error("com already exists and is not an object");
}

if (!com.tp) {com.tp = {}; }
else if (typeof com.tp != "object") {
	throw new Error("com.tp already exists and is not an object");
}
*/


////////////////////////////////////////////////////
// com/tp/General.js
/***
 * General routines for stylesheets, fonts, etc.
 ***/
if (!window.Node) {
	// Define Window.Node Constants
	window.Node = {};
	Node.ELEMENT_NODE = 1;
	Node.ATTRIBUTE_NODE = 2;
	Node.TEXT_NODE = 3;
	Node.CDATA_SECTION_NODE = 4;
	Node.ENTITY_REFERENCE_NODE = 5;
	Node.ENTITY_NODE = 6;
	Node.PROCESSING_INSTRUCTION_NODE = 7;
	Node.COMMENT_NODE = 8;
	Node.DOCUMENT_NODE = 9;
	Node.DOCUMENT_TYPE_NODE = 10;
	Node.DOCUMENT_FRAGMENT_NODE = 11;
	Node.NOTATION_NODE = 12;
}
if (!document.createTreeWalker) {
      var NodeFilter = {
         FILTER_ACCEPT : 1,
         FILTER_REJECT : 2,
         FILTER_SKIP : 3,
         SHOW_ALL     : 0xFFFFFFFF,
         SHOW_ELEMENT : 0x00000001,
         SHOW_ATTRIBUTE : 0x00000002,
         SHOW_TEXT : 0x00000004,
         SHOW_CDATA_SECTION : 0x00000008,
         SHOW_ENTITY_REFERENCE : 0x00000010,
         SHOW_ENTITY : 0x00000020,
         SHOW_PROCESSING_INSTRUCTIONS : 0x00000040,
         SHOW_COMMENT : 0x00000080,
         SHOW_DOCUMENT : 0x00000100,
         SHOW_DOCUMENT_TYPE : 0x00000200,
         SHOW_DOCUMENT_FRAGMENT : 0x00000400,
         SHOW_NOTATION : 0x00000800
      };
}

// Throw an error if com.tp.User already exists
/* if (com.tp.General) {
    throw new Error("com.tp.General already exists");
} */
// Otherwise, create and populate the namespace with one big object literal
com.tp.General = {}; 

//************************************************************
//	Font Sniffing Utitlity
	
com.tp.General.hasFont = function(sFont) {
	// this function working with XHTML 1.0 *strict* mode
	// tested in Win IE6, Opera 9, Firefox 1.5; Mac Safari 2.03
	// -haven't tested in browser quirks mode
	// Function can not match Courier since that is
	// the control font for comparison
	
	/* Create an element (id=tp_fillFont) if doesn't
	exist yet so I can paste some hidden content inside */   
	var ns = "com_tp_"; 
	var d = document; var b = d.body;
	var o; // object holder
	var eWriteDiv = d.getElementById(ns + 'fillFont');
	if (!eWriteDiv) {
		o = d.createElement('div');
		o.setAttribute('id', ns + 'fillFont');
		eWriteDiv = b.appendChild(o);
	}	// ================================================
	var oSpan = [];
	// can't use Courier or STFangsong as test fonts, as they are acting
	// as the control fonts.  This function needs to be updated when new
	// browsers and OSes are realeased as it's hard to know what Unicode Tibetan
	// font the browser will default to.
	
	// it appears that I don't need to have space-having fontnames in quotes
	// when I do this in JavaScript

	// improved for Leopard's 2 built in Tibetan fonts
	var sMacControlFont = "Kokonor, Kailasa, STFangsong";	
	if (sFont == "Kokonor") {
		sMacControlFont = "Kailasa, STFangsong";
	}
	if (sFont == "Kailasa") {
		sMacControlFont = "Kokonor, STFangsong";
	}

	// CHANGE THINGS SO THAT I DO NOT ADDED TIBETAN STYLING TO THIS WITH LATER FUNCTIONS!
	var aFontFamilies = [ sMacControlFont + ', Courier', (sFont + ", " + sMacControlFont + ", Courier")];
	var aFontIds = [ns + 'fontControl', ns + 'fontTest'];
	var testString = '\u0F4C\u0F66\u0F90\u0F4E\u0F54\u0F55\u0F56\u0F58\u0F5Babcdefghijklmnopqrstuvwxyz';
	var sCssText;
	// Safari doesn't take style properties set in BOM way after adding to XHTML tree,
	// (at least display= & position= properties, it seems)
	// so make sure to set them before adding to tree
	for (var i=0; i<aFontFamilies.length; i++) {
		o = d.getElementById(aFontIds[i]);
		if (!o) {
			o = d.createElement('span');
			o.id = aFontIds[i];
			// change the two lines below to positive 200 to see on screen
			o.style.left = '-200px';
			o.style.top = '-' + ((i+1)*(200)) + 'px';
			o.style.backgroundColor = ((i===0)?'red':'green');
			o.style.fontSize = '24pt';
			o.style.display = 'block';		
			o.style.position = 'absolute';			
			eWriteDiv.appendChild(o);
		} else {
			o.innerHTML = '';
			o.style.display = 'block';		 // just in case not set in real page
			o.style.position = 'absolute'; // ""               ""
		}
		o.style.fontFamily = aFontFamilies[i];
		o.appendChild(d.createTextNode(testString));		
	} // =======================================================
	// retrieve the widths of the two new font-relevant elements
	var nWidthControl = d.getElementById(ns + 'fontControl').offsetWidth;
	var nWidthTest = d.getElementById(ns + 'fontTest').offsetWidth;    
	// if the two widths are different, this means the fonts 
	// must be different, return TRUE to tp_hasFont question
	return (nWidthControl != nWidthTest);   
};

/*****************************************************************************
StyleSheet functions
*****************************************************************************/
// still to add, update DOM methods for updating selectors, rules
com.tp.General.createStyleSheetByTitle = function(sTitle, cssText) {
	var g = com.tp.General;
	// second parameter is optional
	// returns the stylesheet object created
	var d = document;
	var oSS = {}; // the style sheet
	if (cssText === undefined) {cssText = "";}
	// the IE way:
	if (d.createStyleSheet) {
		oSS = d.createStyleSheet();
		oSS.title = sTitle;
		oSS.owningElement.type = "text/css";
		// FIX HERE TO ADD OPTIONAL CSSTEXT for IE too. !!!!!!!!!!!!!!!!!! !!
		
	// DOM way:
	} else {
		oSS = d.createElement("style");
		oSS.type = "text/css";
		//oSS.title = sTitle; // YOU CAN NOT CREATE TITLE AT THIS POINT, SAFARI WILL IGNORE
		oSS.disabled = false;
			// have to enter some empty content for KHTML
			var text = cssText;
			var tStyle = d.createTextNode(text);
			oSS.appendChild(tStyle);
		var h = d.getElementsByTagName("head")[0];
		h.appendChild(oSS);
		h.lastChild.title = sTitle;
	// DELME? var ss = g.getStyleSheetByTitle(sTitle);
	}
	g.enableStyleSheetByTitle(sTitle);
};
	
com.tp.General.getStyleSheetByTitle = function(sTitle) {
	 var d = document;
	 var s = d.styleSheets;
		// KHTML needed to see ownerNode, others not(?)
	 for (var i=0; i<s.length; i++) {
			if (s[i].title == sTitle) {return s[i];}
			if (s[i].ownerNode) {
				if (s[i].ownerNode.title == sTitle) {
					return s[i];
				}
			}
	 }
	 return false;
};
	
com.tp.General.appendStyleSheetByTitle = function(sCSSselector, sCSSrule, sTitle) {
	var d = document;
	var g = com.tp.General;
	var u = com.tp.User;
	var ss = g.getStyleSheetByTitle(sTitle);
	var sText = sCSSselector + " {" + sCSSrule + "} ";
	// IE way
	if (ss.cssText !== undefined) {
		ss.addRule(sCSSselector, sCSSrule);
	}
	else if (u._checkBrowersDoesDOMStylesheets()) {
		ss.insertRule(sText, ss.cssRules.length);
		g._refreshAfterStyleSheetChange();
	}
	else {
		// DOM way
		// use this method, have to go through process twice with KHTML
		//oStyleSheet.insertRule(sText, oStyleSheet.cssRules.length);
		 
		 // use this method, KHTML updates right away
		 //var nText = d.createTextNode(sText);
		 //ss.ownerNode.appendChild(nText);
		// Safari can't do above when in quirksmode it appears (but strict it can) 
		var o = ss.ownerNode;
		var h = d.getElementsByTagName("head")[0];
		var cssText = o.innerHTML + " " + sText;
		h.removeChild(o);
		g.createStyleSheetByTitle(sTitle, cssText);
	}
	g.enableStyleSheetByTitle(sTitle);
	//document.body.innerHTML = document.body.innerHTML;
};

com.tp.General.replaceStyleSheetByTitle = function(sCSSselector, sCSSrule, sTitle) {
	var d = document;
	var h = d.getElementsByTagName("head")[0];
	var g = com.tp.General;
	var cssText = sCSSselector + " {" + sCSSrule + "} ";
	var u = com.tp.User;
	var ss = g.getStyleSheetByTitle(sTitle);
	if (ss.cssText !== undefined) { // ie
		// improve: iterate thru rules
		// if no rules yet, don't try to delete a rule
		// that is, if length is zero, skip
		if (ss.rules.length) {
			ss.removeRule(0);
		}
		ss.addRule(sCSSselector, sCSSrule);
	}
	else if (u._checkBrowersDoesDOMStylesheets()) {
		if (ss.cssRules.length) {
			ss.deleteRule(0);
		}
		ss.insertRule(cssText, ss.cssRules.length);
		g._refreshAfterStyleSheetChange();
	}
	else { // others
		// improve: use DOM methods for non-KHTML browsers
		var o = ss.ownerNode;
		h.removeChild(o);
		//h.removeStyleSheetByTitle(sTitle);
		g.createStyleSheetByTitle(sTitle, cssText);
	}
	g.enableStyleSheetByTitle(sTitle);
};

com.tp.General.toggleStyleSheetByTitle = function(s) {
	// after change, will return new disabled state (boolean)
	// *** THIS IS NOT CURRENTLY WORKING IN KHTML, others yes
	var g = com.tp.General;
	var o = g.getStyleSheetByTitle(s); // give title, object back
	o.disabled = !o.disabled;          // toggle sheet object on or off
	return o.disabled;                 // return current state
};

com.tp.General.enableStyleSheetByTitle = function(sTitle) {
	// THIS IS NOT CURRENTLY WORKING IN KHTML, others yes
	// will return new disabled state (boolean)
	var d = document;
	var General = com.tp.General;
	var oSheet = General.getStyleSheetByTitle(sTitle);
	oSheet.disabled = false;
	return oSheet.disabled;
};

com.tp.General.disableStyleSheetByTitle = function(sTitle) {
	// THIS IS NOT CURRENTLY WORKING IN KHTML, others yes
	// will return new disabled state (boolean)
	var d = document;
	var General = com.tp.General;
	var oSheet = General.getStyleSheetByTitle(sTitle);
	oSheet.disabled = true;
	return oSheet.disabled;
};

com.tp.General.removeStyleSheetByTitle = function(sTitle) {
	// removes owning STYLE element from tree
	var d = document;
	var General = com.tp.General;
	var oSheet = General.getStyleSheetByTitle(sTitle);		
	
	// IE way:
	if (oSheet.owningElement) {
		oSheet.owningElement.parentNode.removeChild(oSheet.owningElement);
		// IE needs to refresh the content screen
		var body = d.getElementsByTagName("body")[0];
		body.innerHTML = body.innerHTML;
		
	// non-IE way:
	} else {
		oSheet.ownerNode.parentNode.removeChild(oSheet.ownerNode);
	}
};

com.tp.General._refreshAfterStyleSheetChange = function() {
	// Go through ALL the text nodes of the document and refresh them
	// (thus not refreshing event bindings that happen with refreshing the
	// the entire document.body)
	// This function requires TreeWalker support, but since this is only
	// needed for Firefox (which has), that's fine.
	var d = document;
	var walker = d.createTreeWalker(d.body, NodeFilter.SHOW_TEXT, null, false);
	var oNode = walker.nextNode();
	var myNodes = [];
	while(oNode) {
		myNodes.push(oNode);
		oNode = walker.nextNode();
	}
	for (var i=0; i<myNodes.length; i++) {
		myNodes[i].nodeValue = myNodes[i].nodeValue;
	}
};

	/**************************************************************************
		DOM createTreeWalker method for uncapable browsers
	**************************************************************************/

// DOM2 Traversal  v1.0
// documentation: http://www.dithered.com/javascript/dom2_traversal/index.html
// license: creativecommons.org1.0
// code by Chris Nott (chris[at]dithered[dot]com)

//if (!(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('Traversal', '2.0'))) {
// if (true) { 
	

   /*****************************************************************************
      TreeWalker Interface
    *****************************************************************************/ 
   
   //if (!document.createTreeWalker) {
   // if (true) { 
		 
      function TreeWalker(root, whatToShow, filter, expandEntityReferences) {
         this.root = root;
         this.whatToShow = whatToShow;
         this.filter = filter;
         this.expandEntityReferences = expandEntityReferences;
         this.currentNode = root;
      }
      
      //*************************************
      // Public Members
      
      TreeWalker.prototype.parentNode = function() {
         var testNode = currentNode;
         do {
            if (testNode.parentNode != this.root && testNode.parentNode != null) {
               testNode = testNode.parentNode;
            }
            else {
               return null;
            }
         } while (this._getFilteredStatus(testNode) != NodeFilter.FILTER_ACCEPT);
         return testNode;
      };
      
      TreeWalker.prototype.firstChild = function() {
         var childNodes = currentNode.childNodes;
         for (var childIndex = 0; childIndex < childNodes.length; childIndex++) {
            var testNode = childNodes[childIndex];
            if (this._getFilteredStatus(testNode) != NodeFilter.FILTER_ACCEPT) {
               this.currentNode = testNode;
               return testNode;
            }
         }
         return null;
      };
      
      TreeWalker.prototype.lastChild = function() {
         var childNodes = currentNode.childNodes;
         for (var childIndex = childNodes.length - 1; childIndex >= 0; childIndex--) {
            var testNode = childNodes[childIndex];
            if (this._getFilteredStatus(testNode) != NodeFilter.FILTER_ACCEPT) {
               this.currentNode = testNode;
               return testNode;
            }
         }
         return null;      
      };
      
      TreeWalker.prototype.nextNode = function() {
         // look for a filter-acceptable node after current node
         var testNode = this.currentNode;
         while (testNode != null) {
            
            // next node is the first child, if any
            if (testNode.childNodes.length != 0 && this._getFilteredStatus(testNode) != NodeFilter.FILTER_REJECT) {
               testNode = testNode.firstChild;
            }
            
            // or the next sibling, if any
            else if (testNode.nextSibling != null ){
						        testNode = testNode.nextSibling;
            }
            
            // or the closest ancestor with a next sibling's next sibling, if any
            else {
               do {
                  if (testNode.parentNode != this.root && testNode.parentNode != null) {
                     if (testNode.parentNode.nextSibling != null) {
                        testNode = testNode.parentNode.nextSibling;
                        break;
                     }
                     else {
                        testNode = testNode.parentNode;
                     }
                  }
                  else {
                     testNode = null;
                  }
               } while (testNode != null);
            }
            
            if (testNode != null && this._getFilteredStatus(testNode) == NodeFilter.FILTER_ACCEPT) {
							var s1 = "this.whatToShow: " + this.whatToShow + "\n";
							var s2 = "testNode.nodeType: " + testNode.nodeType + "\n";
              break;
            }
         }
         
         // if an acceptable node was found, update the current node
         if (testNode != null) {
            this.currentNode = testNode;
         }
				 
         // return found node (or null if no next node)
         return testNode;
      };
      
      TreeWalker.prototype.previousNode = function() {
         // look for a filter-acceptable node before current node
         var testNode = this.currentNode;
         while (testNode != null) {
            
            // next node is the last child, if any (as long as test node isn't the current node)
            if (testNode != currentNode && testNode.childNodes.length != 0 && this._getFilteredStatus(testNode) != NodeFilter.FILTER_REJECT) {
               testNode = testNode.lastChild;
            }
            
            // or the previous sibling, if any
            else if (testNode.previousSibling != null) {
               testNode = testNode.previousSibling;
            }
            
            // or the closest ancestor with a previous sibling's previous sibling, if any
            else {
               do {
                  if (testNode.parentNode != this.root && testNode.parentNode != null) {
                     if (testNode.parentNode.previousSibling != null) {
                        testNode = testNode.parentNode.previousSibling;
                        break;
                     }
                     else {
                        testNode = testNode.parentNode;
                     }
                  }
                  else {
                     testNode = null;
                  }
               } while (testNode != null);
            }
            
            if (testNode != null && this._getFilteredStatus(testNode) == NodeFilter.FILTER_ACCEPT) {
               break;
            }
         }
         
         // if an acceptable node was found, update the reference node
         if (testNode != null) {
            this.currentNode = testNode;
         }
         
         // return found node (or null if no previous node)
         return testNode;
      };
      
      TreeWalker.prototype.nextSibling = function() {
         var testNode = currentNode;
         do {
            if (currentNode.nextSibling != null) {
               testNode = currentNode.nextSibling;
            }
            else {
               return null;
            }
         } while (this._getFilteredStatus(testNode) != NodeFilter.FILTER_ACCEPT);
         return testNode;
      };

      TreeWalker.prototype.previousSibling = function() {
         var testNode = currentNode;
         do {
            if (currentNode.previousSibling != null) {
               testNode = currentNode.previousSibling;
            }
            else {
               return null;
            }
         } while (this._getFilteredStatus(testNode) != NodeFilter.FILTER_ACCEPT);
         return testNode;
      };
      
      document.createTreeWalker2 = function(root, whatToShow, filter, expandEntityReferences) { //!!!!!!!!!!!!!!!!
         return new TreeWalker(root, whatToShow, filter, expandEntityReferences);
      };


      //*************************************
      // Private Members
   
      TreeWalker.prototype._getFilteredStatus = function(node) {
				/* var nt = node.nodeType;
				if ((nt == Node.ELEMENT_NODE) && (this.whatToShow != NodeFilter.SHOW_ELEMENT)) {
					return NodeFilter.FILTER_SKIP;
				} */
				  
         if ( (node.nodeType == Node.ELEMENT_NODE && (this.whatToShow & NodeFilter.SHOW_ELEMENT == 0x0) ) ||
           (node.nodeType == Node.ATTRIBUTE_NODE && (this.whatToShow & NodeFilter.SHOW_ATTRIBUTE == 0x0) ) ||
           (node.nodeType == Node.TEXT_NODE && (this.whatToShow & NodeFilter.SHOW_TEXT == 0x0) ) ||
           (node.nodeType == Node.CDATA_SECTION_NODE && (this.whatToShow & NodeFilter.SHOW_CDATA_SECTION == 0x0) ) ||
           (node.nodeType == Node.ENTITY_REFERENCE_NODE && (this.whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE == 0x0) ) ||
           (node.nodeType == Node.ENTITY_NODE && (this.whatToShow & NodeFilter.SHOW_ENTITY == 0x0) ) ||
           (node.nodeType == Node.PROCESSING_INSTRUCTION_NODE && (this.whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION == 0x0) ) ||
           (node.nodeType == Node.COMMENT_NODE && (this.whatToShow & NodeFilter.SHOW_COMMENT == 0x0) ) ||
           (node.nodeType == Node.DOCUMENT_NODE && (this.whatToShow & NodeFilter.SHOW_DOCUMENT == 0x0) ) ||
           (node.nodeType == Node.DOCUMENT_TYPE_NODE && (this.whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE == 0x0) ) ||
           (node.nodeType == Node.DOCUMENT_FRAGMENT_NODE && (this.whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT == 0x0) ) ||
           (node.nodeType == Node.NOTATION_NODE && (this.whatToShow & NodeFilter.SHOW_NOTATION == 0x0) ) ) {
            return NodeFilter.FILTER_SKIP;
         }
         
         // check node against filter if one exists
         if (this.filter != null && this.filter.acceptNode != null) {
            return this.filter.acceptNode(node);
         }
         else {
            return NodeFilter.FILTER_ACCEPT;
         }
      };
   // }
// }


	/**************************************************************************
		2nd try
	**********************************************************************=================================================================****/


   /*****************************************************************************
      com.tp.General.TreeWalker Interface
    *****************************************************************************/ 
	 
	com.tp.General.TreeWalker = function(root, whatToShow, filter, expandEntityReferences) {
         this.root = root;
         this.whatToShow = whatToShow;
         this.filter = filter;
         this.expandEntityReferences = expandEntityReferences;
         this.currentNode = root;
   };
      
      //*************************************
      // Public Members
      
      com.tp.General.TreeWalker.prototype.parentNode = function() {
         var testNode = this.currentNode;
         do {
            if (testNode.parentNode !== this.root && testNode.parentNode !== null) {
               testNode = testNode.parentNode;
            }
            else {
               return null;
            }
         } while (this._getFilteredStatus(testNode) !== NodeFilter.FILTER_ACCEPT);
         return testNode;
      };
      
      com.tp.General.TreeWalker.prototype.firstChild = function() {
         var childNodes = this.currentNode.childNodes;
         for (var childIndex = 0; childIndex < childNodes.length; childIndex++) {
            var testNode = childNodes[childIndex];
            if (this._getFilteredStatus(testNode) !== NodeFilter.FILTER_ACCEPT) {
               this.currentNode = testNode;
               return testNode;
            }
         }
         return null;
      };
      
      com.tp.General.TreeWalker.prototype.lastChild = function() {
         var childNodes = this.currentNode.childNodes;
         for (var childIndex = childNodes.length - 1; childIndex >= 0; childIndex--) {
            var testNode = childNodes[childIndex];
            if (this._getFilteredStatus(testNode) !== NodeFilter.FILTER_ACCEPT) {
               this.currentNode = testNode;
               return testNode;
            }
         }
         return null;      
      };
      
      com.tp.General.TreeWalker.prototype.nextNode = function() {         
         // look for a filter-acceptable node after current node
         var testNode = this.currentNode;
         while (testNode !== null) {           
            // next node is the first child, if any
            if (testNode.childNodes.length !== 0 && this._getFilteredStatus(testNode) !== NodeFilter.FILTER_REJECT) {
               testNode = testNode.firstChild;
            }          
            // or the next sibling, if any
            else if (testNode.nextSibling !== null ){
						        testNode = testNode.nextSibling;
            }          
            // or the closest ancestor with a next sibling's next sibling, if any
            else {
               do {
                  if ((testNode.parentNode !== this.root) && (testNode.parentNode !== null)) {
										// there is a parent we are allowed access to
                     if (testNode.parentNode.nextSibling !== null) {
											 // and that parent does have siblings
                        testNode = testNode.parentNode.nextSibling;
												// ACCEPTABLE! leave immediate loop
                        break;
                     }
                     else {
											 // otherwise keep moving up the parentage, do loop to immediate top
                        testNode = testNode.parentNode;
                     }
                  }
                  else {
										// if there isn't any parent at all testnode set to null and break out of immediate loop
                     testNode = null;
                  }
               } while (testNode !== null);
            }
            // if we found something made sure that we shouldn't filter it out for other reasons
						// if okay, break out of top loop
            if (testNode !== null && (this._getFilteredStatus(testNode) === NodeFilter.FILTER_ACCEPT)) {
              break;
            }
						// otherwise, we had found a potential node, but we filtered it out, so keep looping upper top loop
         }       
         // if an acceptable node was found, update the current node
         if (testNode !== null) {
            this.currentNode = testNode;
         }				 
         // return found node (or null if no next node)
         return testNode;
      };
      
      com.tp.General.TreeWalker.prototype.previousNode = function() {
         
         // look for a filter-acceptable node before current node
         var testNode = this.currentNode;
         while (testNode !== null) {
            
            // next node is the last child, if any (as long as test node isn't the current node)
            if (testNode !== this.currentNode && testNode.childNodes.length !== 0 && this._getFilteredStatus(testNode) !== NodeFilter.FILTER_REJECT) {
               testNode = testNode.lastChild;
            }
            
            // or the previous sibling, if any
            else if (testNode.previousSibling !== null) {
               testNode = testNode.previousSibling;
            }
            
            // or the closest ancestor with a previous sibling's previous sibling, if any
            else {
               do {
                  if (testNode.parentNode !== this.root && testNode.parentNode !== null) {
                     if (testNode.parentNode.previousSibling !== null) {
                        testNode = testNode.parentNode.previousSibling;
                        break;
                     }
                     else {
                        testNode = testNode.parentNode;
                     }
                  }
                  else {
                     testNode = null;
                  }
               } while (testNode !== null);
            }
            
            if (testNode !== null && this._getFilteredStatus(testNode) === NodeFilter.FILTER_ACCEPT) {
               break;
            }
         }
         
         // if an acceptable node was found, update the reference node
         if (testNode !== null) {
            this.currentNode = testNode;
         }
         
         // return found node (or null if no previous node)
         return testNode;
      };
      
      com.tp.General.TreeWalker.prototype.nextSibling = function() {
         var testNode = this.currentNode;
         do {
            if (this.currentNode.nextSibling !== null) {
               testNode = this.currentNode.nextSibling;
            }
            else {
               return null;
            }
         } while (this._getFilteredStatus(testNode) !== NodeFilter.FILTER_ACCEPT);
         return testNode;
      };

      com.tp.General.TreeWalker.prototype.previousSibling = function() {
         var testNode = this.currentNode;
         do {
            if (this.currentNode.previousSibling !== null) {
               testNode = this.currentNode.previousSibling;
            }
            else {
               return null;
            }
         } while (this._getFilteredStatus(testNode) !== NodeFilter.FILTER_ACCEPT);
         return testNode;
      };
      
      //*************************************
      // Private Members
   
      com.tp.General.TreeWalker.prototype._getFilteredStatus = function(node) {
         if ( (node.nodeType === Node.ELEMENT_NODE && (this.whatToShow & NodeFilter.SHOW_ELEMENT === 0x0) ) ||
           (node.nodeType === Node.ATTRIBUTE_NODE && (this.whatToShow & NodeFilter.SHOW_ATTRIBUTE === 0x0) ) ||
           (node.nodeType === Node.TEXT_NODE && (this.whatToShow & NodeFilter.SHOW_TEXT === 0x0) ) ||
           (node.nodeType === Node.CDATA_SECTION_NODE && (this.whatToShow & NodeFilter.SHOW_CDATA_SECTION === 0x0) ) ||
           (node.nodeType === Node.ENTITY_REFERENCE_NODE && (this.whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE === 0x0) ) ||
           (node.nodeType === Node.ENTITY_NODE && (this.whatToShow & NodeFilter.SHOW_ENTITY === 0x0) ) ||
           (node.nodeType === Node.PROCESSING_INSTRUCTION_NODE && (this.whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION === 0x0) ) ||
           (node.nodeType === Node.COMMENT_NODE && (this.whatToShow & NodeFilter.SHOW_COMMENT === 0x0) ) ||
           (node.nodeType === Node.DOCUMENT_NODE && (this.whatToShow & NodeFilter.SHOW_DOCUMENT === 0x0) ) ||
           (node.nodeType === Node.DOCUMENT_TYPE_NODE && (this.whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE === 0x0) ) ||
           (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && (this.whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT === 0x0) ) ||
           (node.nodeType === Node.NOTATION_NODE && (this.whatToShow & NodeFilter.SHOW_NOTATION === 0x0) ) ) {
            return NodeFilter.FILTER_SKIP;
         }
         
         // check node against filter if one exists
         if (this.filter !== null && this.filter.acceptNode !== null) {
            return this.filter.acceptNode(node);
         }
         else {
            return NodeFilter.FILTER_ACCEPT;
         }
      };

