text: /*
   * xpath.js
   *
   * An XPath 1.0 library for JavaScript.
   *
   * Cameron McCormack <cam (at) mcc.id.au>
   *
   * This work is licensed under the Creative Commons Attribution-ShareAlike
   * License. To view a copy of this license, visit
   * http://creativecommons.org/licenses/by-sa/2.0/ or send a letter to Creative
   * Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
   *
   * Revision 13: May 3, 2005
   *   Node tests are case insensitive now if working in an HTML DOM.
   *
   * Revision 12: April 26, 2005
   *   Updated licence.  Slight code changes to enable use of Dean
   *   Edwards' script compression, http://dean.edwards.name/packer/ .
   *
   * Revision 11: April 23, 2005
   *   Fixed bug with 'and' and 'or' operators, fix thanks to
   *   Sandy McArthur <sandy (at) mcarthur.org>.
   *
   * Revision 10: April 15, 2005
   *   Added support for a virtual root node, supposedly helpful for
   *   implementing XForms.  Fixed problem with QName node tests and
   *   the parent axis.
   *
   * Revision 9: March 17, 2005
   *   Namespace resolver tweaked so using the document node as the context
   *   for namespace lookups is equivalent to using the document element.
   *
   * Revision 8: February 13, 2005
   *   Handle implicit declaration of 'xmlns' namespace prefix.
   *   Fixed bug when comparing nodesets.
   *   Instance data can now be associated with a FunctionResolver, and
   *     workaround for MSXML not supporting 'localName' and 'getElementById',
   *     thanks to Grant Gongaware.
   *   Fix a few problems when the context node is the root node.
   *   
   * Revision 7: February 11, 2005
   *   Default namespace resolver fix from Grant Gongaware
   *   <grant (at) gongaware.com>.
   *
   * Revision 6: February 10, 2005
   *   Fixed bug in 'number' function.
   *
   * Revision 5: February 9, 2005
   *   Fixed bug where text nodes not getting converted to string values.
   *
   * Revision 4: January 21, 2005
   *   Bug in 'name' function, fix thanks to Bill Edney.
   *   Fixed incorrect processing of namespace nodes.
   *   Fixed NamespaceResolver to resolve 'xml' namespace.
   *   Implemented union '|' operator.
   *
   * Revision 3: January 14, 2005
   *   Fixed bug with nodeset comparisons, bug lexing < and >.
   *
   * Revision 2: October 26, 2004
   *   QName node test namespace handling fixed.  Few other bug fixes.
   *   
   * Revision 1: August 13, 2004
   *   Bug fixes from William J. Edney <bedney (at) technicalpursuit.com>.
   *   Added minimal licence.
   *
   * Initial version: June 14, 2004
   */
  
  // XPathParser ///////////////////////////////////////////////////////////////
  
  XPathParser.prototype = new Object();
  XPathParser.prototype.constructor = XPathParser;
  XPathParser.superclass = Object.prototype;
  
  function XPathParser() {
  	this.init();
  }
  
  XPathParser.prototype.init = function() {
  	this.reduceActions = [];
  
  	this.reduceActions[3] = function(rhs) {
  		return new OrOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[5] = function(rhs) {
  		return new AndOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[7] = function(rhs) {
  		return new EqualsOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[8] = function(rhs) {
  		return new NotEqualOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[10] = function(rhs) {
  		return new LessThanOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[11] = function(rhs) {
  		return new GreaterThanOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[12] = function(rhs) {
  		return new LessThanOrEqualOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[13] = function(rhs) {
  		return new GreaterThanOrEqualOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[15] = function(rhs) {
  		return new PlusOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[16] = function(rhs) {
  		return new MinusOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[18] = function(rhs) {
  		return new MultiplyOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[19] = function(rhs) {
  		return new DivOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[20] = function(rhs) {
  		return new ModOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[22] = function(rhs) {
  		return new UnaryMinusOperation(rhs[1]);
  	};
  	this.reduceActions[24] = function(rhs) {
  		return new BarOperation(rhs[0], rhs[2]);
  	};
  	this.reduceActions[25] = function(rhs) {
  		return new PathExpr(undefined, undefined, rhs[0]);
  	};
  	this.reduceActions[27] = function(rhs) {
  		rhs[0].locationPath = rhs[2];
  		return rhs[0];
  	};
  	this.reduceActions[28] = function(rhs) {
  		rhs[0].locationPath = rhs[2];
  		rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), []));
  		return rhs[0];
  	};
  	this.reduceActions[29] = function(rhs) {
  		return new PathExpr(rhs[0], [], undefined);
  	};
  	this.reduceActions[30] = function(rhs) {
  		if (Utilities.instance_of(rhs[0], PathExpr)) {
  			if (rhs[0].filterPredicates == undefined) {
  				rhs[0].filterPredicates = [];
  			}
  			rhs[0].filterPredicates.push(rhs[1]);
  			return rhs[0];
  		} else {
  			return new PathExpr(rhs[0], [rhs[1]], undefined);
  		}
  	};
  	this.reduceActions[32] = function(rhs) {
  		return rhs[1];
  	};
  	this.reduceActions[33] = function(rhs) {
  		return new XString(rhs[0]);
  	};
  	this.reduceActions[34] = function(rhs) {
  		return new XNumber(rhs[0]);
  	};
  	this.reduceActions[36] = function(rhs) {
  		return new FunctionCall(rhs[0], []);
  	};
  	this.reduceActions[37] = function(rhs) {
  		return new FunctionCall(rhs[0], rhs[2]);
  	};
  	this.reduceActions[38] = function(rhs) {
  		return [ rhs[0] ];
  	};
  	this.reduceActions[39] = function(rhs) {
  		rhs[2].unshift(rhs[0]);
  		return rhs[2];
  	};
  	this.reduceActions[43] = function(rhs) {
  		return new LocationPath(true, []);
  	};
  	this.reduceActions[44] = function(rhs) {
  		rhs[1].absolute = true;
  		return rhs[1];
  	};
  	this.reduceActions[46] = function(rhs) {
  		return new LocationPath(false, [ rhs[0] ]);
  	};
  	this.reduceActions[47] = function(rhs) {
  		rhs[0].steps.push(rhs[2]);
  		return rhs[0];
  	};
  	this.reduceActions[49] = function(rhs) {
  		return new Step(rhs[0], rhs[1], []);
  	};
  	this.reduceActions[50] = function(rhs) {
  		return new Step(Step.CHILD, rhs[0], []);
  	};
  	this.reduceActions[51] = function(rhs) {
  		return new Step(rhs[0], rhs[1], rhs[2]);
  	};
  	this.reduceActions[52] = function(rhs) {
  		return new Step(Step.CHILD, rhs[0], rhs[1]);
  	};
  	this.reduceActions[54] = function(rhs) {
  		return [ rhs[0] ];
  	};
  	this.reduceActions[55] = function(rhs) {
  		rhs[1].unshift(rhs[0]);
  		return rhs[1];
  	};
  	this.reduceActions[56] = function(rhs) {
  		if (rhs[0] == "ancestor") {
  			return Step.ANCESTOR;
  		} else if (rhs[0] == "ancestor-or-self") {
  			return Step.ANCESTORORSELF;
  		} else if (rhs[0] == "attribute") {
  			return Step.ATTRIBUTE;
  		} else if (rhs[0] == "child") {
  			return Step.CHILD;
  		} else if (rhs[0] == "descendant") {
  			return Step.DESCENDANT;
  		} else if (rhs[0] == "descendant-or-self") {
  			return Step.DESCENDANTORSELF;
  		} else if (rhs[0] == "following") {
  			return Step.FOLLOWING;
  		} else if (rhs[0] == "following-sibling") {
  			return Step.FOLLOWINGSIBLING;
  		} else if (rhs[0] == "namespace") {
  			return Step.NAMESPACE;
  		} else if (rhs[0] == "parent") {
  			return Step.PARENT;
  		} else if (rhs[0] == "preceding") {
  			return Step.PRECEDING;
  		} else if (rhs[0] == "preceding-sibling") {
  			return Step.PRECEDINGSIBLING;
  		} else if (rhs[0] == "self") {
  			return Step.SELF;
  		}
  		return -1;
  	};
  	this.reduceActions[57] = function(rhs) {
  		return Step.ATTRIBUTE;
  	};
  	this.reduceActions[59] = function(rhs) {
  		if (rhs[0] == "comment") {
  			return new NodeTest(NodeTest.COMMENT, undefined);
  		} else if (rhs[0] == "text") {
  			return new NodeTest(NodeTest.TEXT, undefined);
  		} else if (rhs[0] == "processing-instruction") {
  			return new NodeTest(NodeTest.PI, undefined);
  		} else if (rhs[0] == "node") {
  			return new NodeTest(NodeTest.NODE, undefined);
  		}
  		return new NodeTest(-1, undefined);
  	};
  	this.reduceActions[60] = function(rhs) {
  		return new NodeTest(NodeTest.PI, rhs[2]);
  	};
  	this.reduceActions[61] = function(rhs) {
  		return rhs[1];
  	};
  	this.reduceActions[63] = function(rhs) {
  		rhs[1].absolute = true;
  		rhs[1].steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), []));
  		return rhs[1];
  	};
  	this.reduceActions[64] = function(rhs) {
  		rhs[0].steps.push(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), []));
  		rhs[0].steps.push(rhs[2]);
  		return rhs[0];
  	};
  	this.reduceActions[65] = function(rhs) {
  		return new Step(Step.SELF, new NodeTest(NodeTest.NODE, undefined), []);
  	};
  	this.reduceActions[66] = function(rhs) {
  		return new Step(Step.PARENT, new NodeTest(NodeTest.NODE, undefined), []);
  	};
  	this.reduceActions[67] = function(rhs) {
  		return new VariableReference(rhs[1]);
  	};
  	this.reduceActions[68] = function(rhs) {
  		return new NodeTest(NodeTest.NAMETESTANY, undefined);
  	};
  	this.reduceActions[69] = function(rhs) {
  		return new NodeTest(NodeTest.NAMETESTPREFIXANY, rhs[0].substring(0, rhs[0].indexOf(":") - 1));
  	};
  	this.reduceActions[70] = function(rhs) {
  		return new NodeTest(NodeTest.NAMETESTQNAME, rhs[0]);
  	};
  };
  
  XPathParser.actionTable = [
  	" s s        sssssssss    s ss  s  ss",
  	"                 s                  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"                rrrrr               ",
  	" s s        sssssssss    s ss  s  ss",
  	"rs  rrrrrrrr s  sssssrrrrrr  rrs rs ",
  	" s s        sssssssss    s ss  s  ss",
  	"                            s       ",
  	"                            s       ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"  s                                 ",
  	"                            s       ",
  	" s           s  sssss          s  s ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"a                                   ",
  	"r       s                    rr  r  ",
  	"r      sr                    rr  r  ",
  	"r   s  rr            s       rr  r  ",
  	"r   rssrr            rss     rr  r  ",
  	"r   rrrrr            rrrss   rr  r  ",
  	"r   rrrrrsss         rrrrr   rr  r  ",
  	"r   rrrrrrrr         rrrrr   rr  r  ",
  	"r   rrrrrrrr         rrrrrs  rr  r  ",
  	"r   rrrrrrrr         rrrrrr  rr  r  ",
  	"r   rrrrrrrr         rrrrrr  rr  r  ",
  	"r  srrrrrrrr         rrrrrrs rr sr  ",
  	"r  srrrrrrrr         rrrrrrs rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r   rrrrrrrr         rrrrrr  rr  r  ",
  	"r   rrrrrrrr         rrrrrr  rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"                sssss               ",
  	"r  rrrrrrrrr         rrrrrrr rr sr  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"                             s      ",
  	"r  srrrrrrrr         rrrrrrs rr  r  ",
  	"r   rrrrrrrr         rrrrr   rr  r  ",
  	"              s                     ",
  	"                             s      ",
  	"                rrrrr               ",
  	" s s        sssssssss    s sss s  ss",
  	"r  srrrrrrrr         rrrrrrs rr  r  ",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s s        sssssssss      ss  s  ss",
  	" s s        sssssssss    s ss  s  ss",
  	" s           s  sssss          s  s ",
  	" s           s  sssss          s  s ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	" s           s  sssss          s  s ",
  	" s           s  sssss          s  s ",
  	"r  rrrrrrrrr         rrrrrrr rr sr  ",
  	"r  rrrrrrrrr         rrrrrrr rr sr  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"                             s      ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"                             rr     ",
  	"                             s      ",
  	"                             rs     ",
  	"r      sr                    rr  r  ",
  	"r   s  rr            s       rr  r  ",
  	"r   rssrr            rss     rr  r  ",
  	"r   rssrr            rss     rr  r  ",
  	"r   rrrrr            rrrss   rr  r  ",
  	"r   rrrrr            rrrss   rr  r  ",
  	"r   rrrrr            rrrss   rr  r  ",
  	"r   rrrrr            rrrss   rr  r  ",
  	"r   rrrrrsss         rrrrr   rr  r  ",
  	"r   rrrrrsss         rrrrr   rr  r  ",
  	"r   rrrrrrrr         rrrrr   rr  r  ",
  	"r   rrrrrrrr         rrrrr   rr  r  ",
  	"r   rrrrrrrr         rrrrr   rr  r  ",
  	"r   rrrrrrrr         rrrrrr  rr  r  ",
  	"                                 r  ",
  	"                                 s  ",
  	"r  srrrrrrrr         rrrrrrs rr  r  ",
  	"r  srrrrrrrr         rrrrrrs rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr  r  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	" s s        sssssssss    s ss  s  ss",
  	"r  rrrrrrrrr         rrrrrrr rr rr  ",
  	"                             r      "
  ];
  
  XPathParser.actionTableNumber = [
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	"                 J                  ",
  	"a  aaaaaaaaa         aaaaaaa aa  a  ",
  	"                YYYYY               ",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	"K1  KKKKKKKK .  +*)('KKKKKK  KK# K\" ",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	"                            N       ",
  	"                            O       ",
  	"e  eeeeeeeee         eeeeeee ee ee  ",
  	"f  fffffffff         fffffff ff ff  ",
  	"d  ddddddddd         ddddddd dd dd  ",
  	"B  BBBBBBBBB         BBBBBBB BB BB  ",
  	"A  AAAAAAAAA         AAAAAAA AA AA  ",
  	"  P                                 ",
  	"                            Q       ",
  	" 1           .  +*)('          #  \" ",
  	"b  bbbbbbbbb         bbbbbbb bb  b  ",
  	"                                    ",
  	"!       S                    !!  !  ",
  	"\"      T\"                    \"\"  \"  ",
  	"$   V  $$            U       $$  $  ",
  	"&   &ZY&&            &XW     &&  &  ",
  	")   )))))            )))\\[   ))  )  ",
  	".   ....._^]         .....   ..  .  ",
  	"1   11111111         11111   11  1  ",
  	"5   55555555         55555`  55  5  ",
  	"7   77777777         777777  77  7  ",
  	"9   99999999         999999  99  9  ",
  	":  c::::::::         ::::::b :: a:  ",
  	"I  fIIIIIIII         IIIIIIe II  I  ",
  	"=  =========         ======= == ==  ",
  	"?  ?????????         ??????? ?? ??  ",
  	"C  CCCCCCCCC         CCCCCCC CC CC  ",
  	"J   JJJJJJJJ         JJJJJJ  JJ  J  ",
  	"M   MMMMMMMM         MMMMMM  MM  M  ",
  	"N  NNNNNNNNN         NNNNNNN NN  N  ",
  	"P  PPPPPPPPP         PPPPPPP PP  P  ",
  	"                +*)('               ",
  	"R  RRRRRRRRR         RRRRRRR RR aR  ",
  	"U  UUUUUUUUU         UUUUUUU UU  U  ",
  	"Z  ZZZZZZZZZ         ZZZZZZZ ZZ ZZ  ",
  	"c  ccccccccc         ccccccc cc cc  ",
  	"                             j      ",
  	"L  fLLLLLLLL         LLLLLLe LL  L  ",
  	"6   66666666         66666   66  6  ",
  	"              k                     ",
  	"                             l      ",
  	"                XXXXX               ",
  	" 1 0        /.-,+*)('    & %$m #  \"!",
  	"_  f________         ______e __  _  ",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1 0        /.-,+*)('      %$  #  \"!",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	" 1           .  +*)('          #  \" ",
  	" 1           .  +*)('          #  \" ",
  	">  >>>>>>>>>         >>>>>>> >> >>  ",
  	" 1           .  +*)('          #  \" ",
  	" 1           .  +*)('          #  \" ",
  	"Q  QQQQQQQQQ         QQQQQQQ QQ aQ  ",
  	"V  VVVVVVVVV         VVVVVVV VV aV  ",
  	"T  TTTTTTTTT         TTTTTTT TT  T  ",
  	"@  @@@@@@@@@         @@@@@@@ @@ @@  ",
  	"                             \x87      ",
  	"[  [[[[[[[[[         [[[[[[[ [[ [[  ",
  	"D  DDDDDDDDD         DDDDDDD DD DD  ",
  	"                             HH     ",
  	"                             \x88      ",
  	"                             F\x89     ",
  	"#      T#                    ##  #  ",
  	"%   V  %%            U       %%  %  ",
  	"'   'ZY''            'XW     ''  '  ",
  	"(   (ZY((            (XW     ((  (  ",
  	"+   +++++            +++\\[   ++  +  ",
  	"*   *****            ***\\[   **  *  ",
  	"-   -----            ---\\[   --  -  ",
  	",   ,,,,,            ,,,\\[   ,,  ,  ",
  	"0   00000_^]         00000   00  0  ",
  	"/   /////_^]         /////   //  /  ",
  	"2   22222222         22222   22  2  ",
  	"3   33333333         33333   33  3  ",
  	"4   44444444         44444   44  4  ",
  	"8   88888888         888888  88  8  ",
  	"                                 ^  ",
  	"                                 \x8a  ",
  	";  f;;;;;;;;         ;;;;;;e ;;  ;  ",
  	"<  f<<<<<<<<         <<<<<<e <<  <  ",
  	"O  OOOOOOOOO         OOOOOOO OO  O  ",
  	"`  `````````         ``````` ``  `  ",
  	"S  SSSSSSSSS         SSSSSSS SS  S  ",
  	"W  WWWWWWWWW         WWWWWWW WW  W  ",
  	"\\  \\\\\\\\\\\\\\\\\\         \\\\\\\\\\\\\\ \\\\ \\\\  ",
  	"E  EEEEEEEEE         EEEEEEE EE EE  ",
  	" 1 0        /.-,+*)('    & %$  #  \"!",
  	"]  ]]]]]]]]]         ]]]]]]] ]] ]]  ",
  	"                             G      "
  ];
  
  XPathParser.gotoTable = [
  	"3456789:;<=>?@ AB  CDEFGH IJ ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"L456789:;<=>?@ AB  CDEFGH IJ ",
  	"            M        EFGH IJ ",
  	"       N;<=>?@ AB  CDEFGH IJ ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"            S        EFGH IJ ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"              e              ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                        h  J ",
  	"              i          j   ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"o456789:;<=>?@ ABpqCDEFGH IJ ",
  	"                             ",
  	"  r6789:;<=>?@ AB  CDEFGH IJ ",
  	"   s789:;<=>?@ AB  CDEFGH IJ ",
  	"    t89:;<=>?@ AB  CDEFGH IJ ",
  	"    u89:;<=>?@ AB  CDEFGH IJ ",
  	"     v9:;<=>?@ AB  CDEFGH IJ ",
  	"     w9:;<=>?@ AB  CDEFGH IJ ",
  	"     x9:;<=>?@ AB  CDEFGH IJ ",
  	"     y9:;<=>?@ AB  CDEFGH IJ ",
  	"      z:;<=>?@ AB  CDEFGH IJ ",
  	"      {:;<=>?@ AB  CDEFGH IJ ",
  	"       |;<=>?@ AB  CDEFGH IJ ",
  	"       };<=>?@ AB  CDEFGH IJ ",
  	"       ~;<=>?@ AB  CDEFGH IJ ",
  	"         \x7f=>?@ AB  CDEFGH IJ ",
  	"\x80456789:;<=>?@ AB  CDEFGH IJ\x81",
  	"            \x82        EFGH IJ ",
  	"            \x83        EFGH IJ ",
  	"                             ",
  	"                     \x84 GH IJ ",
  	"                     \x85 GH IJ ",
  	"              i          \x86   ",
  	"              i          \x87   ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"                             ",
  	"o456789:;<=>?@ AB\x8cqCDEFGH IJ ",
  	"                             ",
  	"                             "
  ];
  
  XPathParser.productions = [
  	[1, 1, 2],
  	[2, 1, 3],
  	[3, 1, 4],
  	[3, 3, 3, -9, 4],
  	[4, 1, 5],
  	[4, 3, 4, -8, 5],
  	[5, 1, 6],
  	[5, 3, 5, -22, 6],
  	[5, 3, 5, -5, 6],
  	[6, 1, 7],
  	[6, 3, 6, -23, 7],
  	[6, 3, 6, -24, 7],
  	[6, 3, 6, -6, 7],
  	[6, 3, 6, -7, 7],
  	[7, 1, 8],
  	[7, 3, 7, -25, 8],
  	[7, 3, 7, -26, 8],
  	[8, 1, 9],
  	[8, 3, 8, -12, 9],
  	[8, 3, 8, -11, 9],
  	[8, 3, 8, -10, 9],
  	[9, 1, 10],
  	[9, 2, -26, 9],
  	[10, 1, 11],
  	[10, 3, 10, -27, 11],
  	[11, 1, 12],
  	[11, 1, 13],
  	[11, 3, 13, -28, 14],
  	[11, 3, 13, -4, 14],
  	[13, 1, 15],
  	[13, 2, 13, 16],
  	[15, 1, 17],
  	[15, 3, -29, 2, -30],
  	[15, 1, -15],
  	[15, 1, -16],
  	[15, 1, 18],
  	[18, 3, -13, -29, -30],
  	[18, 4, -13, -29, 19, -30],
  	[19, 1, 20],
  	[19, 3, 20, -31, 19],
  	[20, 1, 2],
  	[12, 1, 14],
  	[12, 1, 21],
  	[21, 1, -28],
  	[21, 2, -28, 14],
  	[21, 1, 22],
  	[14, 1, 23],
  	[14, 3, 14, -28, 23],
  	[14, 1, 24],
  	[23, 2, 25, 26],
  	[23, 1, 26],
  	[23, 3, 25, 26, 27],
  	[23, 2, 26, 27],
  	[23, 1, 28],
  	[27, 1, 16],
  	[27, 2, 16, 27],
  	[25, 2, -14, -3],
  	[25, 1, -32],
  	[26, 1, 29],
  	[26, 3, -20, -29, -30],
  	[26, 4, -21, -29, -15, -30],
  	[16, 3, -33, 30, -34],
  	[30, 1, 2],
  	[22, 2, -4, 14],
  	[24, 3, 14, -4, 23],
  	[28, 1, -35],
  	[28, 1, -2],
  	[17, 2, -36, -18],
  	[29, 1, -17],
  	[29, 1, -19],
  	[29, 1, -18]
  ];
  
  XPathParser.DOUBLEDOT = 2;
  XPathParser.DOUBLECOLON = 3;
  XPathParser.DOUBLESLASH = 4;
  XPathParser.NOTEQUAL = 5;
  XPathParser.LESSTHANOREQUAL = 6;
  XPathParser.GREATERTHANOREQUAL = 7;
  XPathParser.AND = 8;
  XPathParser.OR = 9;
  XPathParser.MOD = 10;
  XPathParser.DIV = 11;
  XPathParser.MULTIPLYOPERATOR = 12;
  XPathParser.FUNCTIONNAME = 13;
  XPathParser.AXISNAME = 14;
  XPathParser.LITERAL = 15;
  XPathParser.NUMBER = 16;
  XPathParser.ASTERISKNAMETEST = 17;
  XPathParser.QNAME = 18;
  XPathParser.NCNAMECOLONASTERISK = 19;
  XPathParser.NODETYPE = 20;
  XPathParser.PROCESSINGINSTRUCTIONWITHLITERAL = 21;
  XPathParser.EQUALS = 22;
  XPathParser.LESSTHAN = 23;
  XPathParser.GREATERTHAN = 24;
  XPathParser.PLUS = 25;
  XPathParser.MINUS = 26;
  XPathParser.BAR = 27;
  XPathParser.SLASH = 28;
  XPathParser.LEFTPARENTHESIS = 29;
  XPathParser.RIGHTPARENTHESIS = 30;
  XPathParser.COMMA = 31;
  XPathParser.AT = 32;
  XPathParser.LEFTBRACKET = 33;
  XPathParser.RIGHTBRACKET = 34;
  XPathParser.DOT = 35;
  XPathParser.DOLLAR = 36;
  
  XPathParser.prototype.tokenize = function(s1) {
  	var types = [];
  	var values = [];
  	var s = s1 + '\0';
  
  	var pos = 0;
  	var c = s.charAt(pos++);
  	while (1) {
  		while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
  			c = s.charAt(pos++);
  		}
  		if (c == '\0' || pos >= s.length) {
  			break;
  		}
  
  		if (c == '(') {
  			types.push(XPathParser.LEFTPARENTHESIS);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == ')') {
  			types.push(XPathParser.RIGHTPARENTHESIS);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '[') {
  			types.push(XPathParser.LEFTBRACKET);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == ']') {
  			types.push(XPathParser.RIGHTBRACKET);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '@') {
  			types.push(XPathParser.AT);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == ',') {
  			types.push(XPathParser.COMMA);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '|') {
  			types.push(XPathParser.BAR);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '+') {
  			types.push(XPathParser.PLUS);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '-') {
  			types.push(XPathParser.MINUS);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '=') {
  			types.push(XPathParser.EQUALS);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		if (c == '$') {
  			types.push(XPathParser.DOLLAR);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  		
  		if (c == '.') {
  			c = s.charAt(pos++);
  			if (c == '.') {
  				types.push(XPathParser.DOUBLEDOT);
  				values.push("..");
  				c = s.charAt(pos++);
  				continue;
  			}
  			if (c >= '0' && c <= '9') {
  				var number = "." + c;
  				c = s.charAt(pos++);
  				while (c >= '0' && c <= '9') {
  					number += c;
  					c = s.charAt(pos++);
  				}
  				types.push(XPathParser.NUMBER);
  				values.push(number);
  				continue;
  			}
  			types.push(XPathParser.DOT);
  			values.push('.');
  			continue;
  		}
  
  		if (c == '\'' || c == '"') {
  			var delimiter = c;
  			var literal = "";
  			while ((c = s.charAt(pos++)) != delimiter) {
  				literal += c;
  			}
  			types.push(XPathParser.LITERAL);
  			values.push(literal);
  			c = s.charAt(pos++);
  			continue;
  		}
  
  		if (c >= '0' && c <= '9') {
  			var number = c;
  			c = s.charAt(pos++);
  			while (c >= '0' && c <= '9') {
  				number += c;
  				c = s.charAt(pos++);
  			}
  			if (c == '.') {
  				if (s.charAt(pos) >= '0' && s.charAt(pos) <= '9') {
  					number += c;
  					number += s.charAt(pos++);
  					c = s.charAt(pos++);
  					while (c >= '0' && c <= '9') {
  						number += c;
  						c = s.charAt(pos++);
  					}
  				}
  			}
  			types.push(XPathParser.NUMBER);
  			values.push(number);
  			continue;
  		}
  
  		if (c == '*') {
  			if (types.length > 0) {
  				var last = types[types.length - 1];
  				if (last != XPathParser.AT
  						&& last != XPathParser.DOUBLECOLON
  						&& last != XPathParser.LEFTPARENTHESIS
  						&& last != XPathParser.LEFTBRACKET
  						&& last != XPathParser.AND
  						&& last != XPathParser.OR
  						&& last != XPathParser.MOD
  						&& last != XPathParser.DIV
  						&& last != XPathParser.MULTIPLYOPERATOR
  						&& last != XPathParser.SLASH
  						&& last != XPathParser.DOUBLESLASH
  						&& last != XPathParser.BAR
  						&& last != XPathParser.PLUS
  						&& last != XPathParser.MINUS
  						&& last != XPathParser.EQUALS
  						&& last != XPathParser.NOTEQUAL
  						&& last != XPathParser.LESSTHAN
  						&& last != XPathParser.LESSTHANOREQUAL
  						&& last != XPathParser.GREATERTHAN
  						&& last != XPathParser.GREATERTHANOREQUAL) {
  					types.push(XPathParser.MULTIPLYOPERATOR);
  					values.push(c);
  					c = s.charAt(pos++);
  					continue;
  				}
  			}
  			types.push(XPathParser.ASTERISKNAMETEST);
  			values.push(c);
  			c = s.charAt(pos++);
  			continue;
  		}
  
  		if (c == ':') {
  			if (s.charAt(pos) == ':') {
  				types.push(XPathParser.DOUBLECOLON);
  				values.push("::");
  				pos++;
  				c = s.charAt(pos++);
  				continue;
  			}
  		}
  
  		if (c == '/') {
  			c = s.charAt(pos++);
  			if (c == '/') {
  				types.push(XPathParser.DOUBLESLASH);
  				values.push("//");
  				c = s.charAt(pos++);
  				continue;
  			}
  			types.push(XPathParser.SLASH);
  			values.push('/');
  			continue;
  		}
  
  		if (c == '!') {
  			if (s.charAt(pos) == '=') {
  				types.push(XPathParser.NOTEQUAL);
  				values.push("!=");
  				pos++;
  				c = s.charAt(pos++);
  				continue;
  			}
  		}
  
  		if (c == '<') {
  			if (s.charAt(pos) == '=') {
  				types.push(XPathParser.LESSTHANOREQUAL);
  				values.push("<=");
  				pos++;
  				c = s.charAt(pos++);
  				continue;
  			}
  			types.push(XPathParser.LESSTHAN);
  			values.push('<');
  			c = s.charAt(pos++);
  			continue;
  		}
  
  		if (c == '>') {
  			if (s.charAt(pos) == '=') {
  				types.push(XPathParser.GREATERTHANOREQUAL);
  				values.push(">=");
  				pos++;
  				c = s.charAt(pos++);
  				continue;
  			}
  			types.push(XPathParser.GREATERTHAN);
  			values.push('>');
  			c = s.charAt(pos++);
  			continue;
  		}
  
  		if (c == '_' || Utilities.isLetter(c.charCodeAt(0))) {
  			var name = c;
  			c = s.charAt(pos++);
  			while (Utilities.isNCNameChar(c.charCodeAt(0))) {
  				name += c;
  				c = s.charAt(pos++);
  			}
  			if (types.length > 0) {
  				var last = types[types.length - 1];
  				if (last != XPathParser.AT
  						&& last != XPathParser.DOUBLECOLON
  						&& last != XPathParser.LEFTPARENTHESIS
  						&& last != XPathParser.LEFTBRACKET
  						&& last != XPathParser.AND
  						&& last != XPathParser.OR
  						&& last != XPathParser.MOD
  						&& last != XPathParser.DIV
  						&& last != XPathParser.MULTIPLYOPERATOR
  						&& last != XPathParser.SLASH
  						&& last != XPathParser.DOUBLESLASH
  						&& last != XPathParser.BAR
  						&& last != XPathParser.PLUS
  						&& last != XPathParser.MINUS
  						&& last != XPathParser.EQUALS
  						&& last != XPathParser.NOTEQUAL
  						&& last != XPathParser.LESSTHAN
  						&& last != XPathParser.LESSTHANOREQUAL
  						&& last != XPathParser.GREATERTHAN
  						&& last != XPathParser.GREATERTHANOREQUAL) {
  					if (name == "and") {
  						types.push(XPathParser.AND);
  						values.push(name);
  						continue;
  					}
  					if (name == "or") {
  						types.push(XPathParser.OR);
  						values.push(name);
  						continue;
  					}
  					if (name == "mod") {
  						types.push(XPathParser.MOD);
  						values.push(name);
  						continue;
  					}
  					if (name == "div") {
  						types.push(XPathParser.DIV);
  						values.push(name);
  						continue;
  					}
  				}
  			}
  			if (c == ':') {
  				if (s.charAt(pos) == '*') {
  					types.push(XPathParser.NCNAMECOLONASTERISK);
  					values.push(name + ":*");
  					pos++;
  					c = s.charAt(pos++);
  					continue;
  				}
  				if (s.charAt(pos) == '_' || Utilities.isLetter(s.charCodeAt(pos))) {
  					name += ':';
  					c = s.charAt(pos++);
  					while (Utilities.isNCNameChar(c.charCodeAt(0))) {
  						name += c;
  						c = s.charAt(pos++);
  					}
  					if (c == '(') {
  						types.push(XPathParser.FUNCTIONNAME);
  						values.push(name);
  						continue;
  					}
  					types.push(XPathParser.QNAME);
  					values.push(name);
  					continue;
  				}
  				if (s.charAt(pos) == ':') {
  					types.push(XPathParser.AXISNAME);
  					values.push(name);
  					continue;
  				}
  			}
  			if (c == '(') {
  				if (name == "comment" || name == "text" || name == "node") {
  					types.push(XPathParser.NODETYPE);
  					values.push(name);
  					continue;
  				}
  				if (name == "processing-instruction") {
  					if (s.charAt(pos) == ')') {
  						types.push(XPathParser.NODETYPE);
  					} else {
  						types.push(XPathParser.PROCESSINGINSTRUCTIONWITHLITERAL);
  					}
  					values.push(name);
  					continue;
  				}
  				types.push(XPathParser.FUNCTIONNAME);
  				values.push(name);
  				continue;
  			}
  			types.push(XPathParser.QNAME);
  			values.push(name);
  			continue;
  		}
  
  		throw new Error("Unexpected character " + c);
  	}
  	types.push(1);
  	values.push("[EOF]");
  	return [types, values];
  };
  
  XPathParser.SHIFT = 's';
  XPathParser.REDUCE = 'r';
  XPathParser.ACCEPT = 'a';
  
  XPathParser.prototype.parse = function(s) {
  	var types;
  	var values;
  	var res = this.tokenize(s);
  	if (res == undefined) {
  		return undefined;
  	}
  	types = res[0];
  	values = res[1];
  	var tokenPos = 0;
  	var state = [];
  	var tokenType = [];
  	var tokenValue = [];
  	var s;
  	var a;
  	var t;
  
  	state.push(0);
  	tokenType.push(1);
  	tokenValue.push("_S");
  
  	a = types[tokenPos];
  	t = values[tokenPos++];
  	while (1) {
  		s = state[state.length - 1];
  		switch (XPathParser.actionTable[s].charAt(a - 1)) {
  			case XPathParser.SHIFT:
  				tokenType.push(-a);
  				tokenValue.push(t);
  				state.push(XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32);
  				a = types[tokenPos];
  				t = values[tokenPos++];
  				break;
  			case XPathParser.REDUCE:
  				var num = XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][1];
  				var rhs = [];
  				for (var i = 0; i < num; i++) {
  					tokenType.pop();
  					rhs.unshift(tokenValue.pop());
  					state.pop();
  				}
  				var s_ = state[state.length - 1];
  				tokenType.push(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0]);
  				if (this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32] == undefined) {
  					tokenValue.push(rhs[0]);
  				} else {
  					tokenValue.push(this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32](rhs));
  				}
  				state.push(XPathParser.gotoTable[s_].charCodeAt(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0] - 2) - 33);
  				break;
  			case XPathParser.ACCEPT:
  				return new XPath(tokenValue.pop());
  			default:
  				throw new Error("XPath parse error");
  		}
  	}
  };
  
  // XPath /////////////////////////////////////////////////////////////////////
  
  XPath.prototype = new Object();
  XPath.prototype.constructor = XPath;
  XPath.superclass = Object.prototype;
  
  function XPath(e) {
  	this.expression = e;
  }
  
  XPath.prototype.toString = function() {
  	return this.expression.toString();
  };
  
  XPath.prototype.evaluate = function(c) {
  	c.contextNode = c.expressionContextNode;
  	c.contextSize = 1;
  	c.contextPosition = 1;
  	c.caseInsensitive = false;
  	if (c.contextNode != null) {
  		var doc = c.contextNode;
  		if (doc.nodeType != 9 /*Node.DOCUMENT_NODE*/) {
  			doc = doc.ownerDocument;
  		}
  		c.caseInsensitive = doc.implementation == null
  			|| doc.implementation.hasFeature("HTML", "2.0");
  	}
  	return this.expression.evaluate(c);
  };
  
  XPath.XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
  XPath.XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
  
  // Expression ////////////////////////////////////////////////////////////////
  
  Expression.prototype = new Object();
  Expression.prototype.constructor = Expression;
  Expression.superclass = Object.prototype;
  
  function Expression() {
  }
  
  Expression.prototype.init = function() {
  };
  
  Expression.prototype.toString = function() {
  	return "<Expression>";
  };
  
  Expression.prototype.evaluate = function(c) {
  	throw new Error("Could not evaluate expression.");
  };
  
  // UnaryOperation ////////////////////////////////////////////////////////////
  
  UnaryOperation.prototype = new Expression();
  UnaryOperation.prototype.constructor = UnaryOperation;
  UnaryOperation.superclass = Expression.prototype;
  
  function UnaryOperation(rhs) {
  	if (arguments.length > 0) {
  		this.init(rhs);
  	}
  }
  
  UnaryOperation.prototype.init = function(rhs) {
  	this.rhs = rhs;
  };
  
  // UnaryMinusOperation ///////////////////////////////////////////////////////
  
  UnaryMinusOperation.prototype = new UnaryOperation();
  UnaryMinusOperation.prototype.constructor = UnaryMinusOperation;
  UnaryMinusOperation.superclass = UnaryOperation.prototype;
  
  function UnaryMinusOperation(rhs) {
  	if (arguments.length > 0) {
  		this.init(rhs);
  	}
  }
  
  UnaryMinusOperation.prototype.init = function(rhs) {
  	UnaryMinusOperation.superclass.init.call(this, rhs);
  };
  
  UnaryMinusOperation.prototype.evaluate = function(c) {
  	return this.rhs.evaluate(c).number().negate();
  };
  
  UnaryMinusOperation.prototype.toString = function() {
  	return "-" + this.rhs.toString();
  };
  
  // BinaryOperation ///////////////////////////////////////////////////////////
  
  BinaryOperation.prototype = new Expression();
  BinaryOperation.prototype.constructor = BinaryOperation;
  BinaryOperation.superclass = Expression.prototype;
  
  function BinaryOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  BinaryOperation.prototype.init = function(lhs, rhs) {
  	this.lhs = lhs;
  	this.rhs = rhs;
  };
  
  // OrOperation ///////////////////////////////////////////////////////////////
  
  OrOperation.prototype = new BinaryOperation();
  OrOperation.prototype.constructor = OrOperation;
  OrOperation.superclass = BinaryOperation.prototype;
  
  function OrOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  OrOperation.prototype.init = function(lhs, rhs) {
  	OrOperation.superclass.init.call(this, lhs, rhs);
  };
  
  OrOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")";
  };
  
  OrOperation.prototype.evaluate = function(c) {
  	var b = this.lhs.evaluate(c).bool();
  	if (b.booleanValue()) {
  		return b;
  	}
  	return this.rhs.evaluate(c).bool();
  };
  
  // AndOperation //////////////////////////////////////////////////////////////
  
  AndOperation.prototype = new BinaryOperation();
  AndOperation.prototype.constructor = AndOperation;
  AndOperation.superclass = BinaryOperation.prototype;
  
  function AndOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  AndOperation.prototype.init = function(lhs, rhs) {
  	AndOperation.superclass.init.call(this, lhs, rhs);
  };
  
  AndOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " and " + this.rhs.toString() + ")";
  };
  
  AndOperation.prototype.evaluate = function(c) {
  	var b = this.lhs.evaluate(c).bool();
  	if (!b.booleanValue()) {
  		return b;
  	}
  	return this.rhs.evaluate(c).bool();
  };
  
  // EqualsOperation ///////////////////////////////////////////////////////////
  
  EqualsOperation.prototype = new BinaryOperation();
  EqualsOperation.prototype.constructor = EqualsOperation;
  EqualsOperation.superclass = BinaryOperation.prototype;
  
  function EqualsOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  EqualsOperation.prototype.init = function(lhs, rhs) {
  	EqualsOperation.superclass.init.call(this, lhs, rhs);
  };
  
  EqualsOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")";
  };
  
  EqualsOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).equals(this.rhs.evaluate(c));
  };
  
  // NotEqualOperation /////////////////////////////////////////////////////////
  
  NotEqualOperation.prototype = new BinaryOperation();
  NotEqualOperation.prototype.constructor = NotEqualOperation;
  NotEqualOperation.superclass = BinaryOperation.prototype;
  
  function NotEqualOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  NotEqualOperation.prototype.init = function(lhs, rhs) {
  	NotEqualOperation.superclass.init.call(this, lhs, rhs);
  };
  
  NotEqualOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")";
  };
  
  NotEqualOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c));
  };
  
  // LessThanOperation /////////////////////////////////////////////////////////
  
  LessThanOperation.prototype = new BinaryOperation();
  LessThanOperation.prototype.constructor = LessThanOperation;
  LessThanOperation.superclass = BinaryOperation.prototype;
  
  function LessThanOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  LessThanOperation.prototype.init = function(lhs, rhs) {
  	LessThanOperation.superclass.init.call(this, lhs, rhs);
  };
  
  LessThanOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c));
  };
  
  LessThanOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")";
  };
  
  // GreaterThanOperation //////////////////////////////////////////////////////
  
  GreaterThanOperation.prototype = new BinaryOperation();
  GreaterThanOperation.prototype.constructor = GreaterThanOperation;
  GreaterThanOperation.superclass = BinaryOperation.prototype;
  
  function GreaterThanOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  GreaterThanOperation.prototype.init = function(lhs, rhs) {
  	GreaterThanOperation.superclass.init.call(this, lhs, rhs);
  };
  
  GreaterThanOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c));
  };
  
  GreaterThanOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")";
  };
  
  // LessThanOrEqualOperation //////////////////////////////////////////////////
  
  LessThanOrEqualOperation.prototype = new BinaryOperation();
  LessThanOrEqualOperation.prototype.constructor = LessThanOrEqualOperation;
  LessThanOrEqualOperation.superclass = BinaryOperation.prototype;
  
  function LessThanOrEqualOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  LessThanOrEqualOperation.prototype.init = function(lhs, rhs) {
  	LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
  };
  
  LessThanOrEqualOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c));
  };
  
  LessThanOrEqualOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")";
  };
  
  // GreaterThanOrEqualOperation ///////////////////////////////////////////////
  
  GreaterThanOrEqualOperation.prototype = new BinaryOperation();
  GreaterThanOrEqualOperation.prototype.constructor = GreaterThanOrEqualOperation;
  GreaterThanOrEqualOperation.superclass = BinaryOperation.prototype;
  
  function GreaterThanOrEqualOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  GreaterThanOrEqualOperation.prototype.init = function(lhs, rhs) {
  	GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
  };
  
  GreaterThanOrEqualOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c));
  };
  
  GreaterThanOrEqualOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")";
  };
  
  // PlusOperation /////////////////////////////////////////////////////////////
  
  PlusOperation.prototype = new BinaryOperation();
  PlusOperation.prototype.constructor = PlusOperation;
  PlusOperation.superclass = BinaryOperation.prototype;
  
  function PlusOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  PlusOperation.prototype.init = function(lhs, rhs) {
  	PlusOperation.superclass.init.call(this, lhs, rhs);
  };
  
  PlusOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).number().plus(this.rhs.evaluate(c).number());
  };
  
  PlusOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " + " + this.rhs.toString() + ")";
  };
  
  // MinusOperation ////////////////////////////////////////////////////////////
  
  MinusOperation.prototype = new BinaryOperation();
  MinusOperation.prototype.constructor = MinusOperation;
  MinusOperation.superclass = BinaryOperation.prototype;
  
  function MinusOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  MinusOperation.prototype.init = function(lhs, rhs) {
  	MinusOperation.superclass.init.call(this, lhs, rhs);
  };
  
  MinusOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).number().minus(this.rhs.evaluate(c).number());
  };
  
  MinusOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " - " + this.rhs.toString() + ")";
  };
  
  // MultiplyOperation /////////////////////////////////////////////////////////
  
  MultiplyOperation.prototype = new BinaryOperation();
  MultiplyOperation.prototype.constructor = MultiplyOperation;
  MultiplyOperation.superclass = BinaryOperation.prototype;
  
  function MultiplyOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  MultiplyOperation.prototype.init = function(lhs, rhs) {
  	MultiplyOperation.superclass.init.call(this, lhs, rhs);
  };
  
  MultiplyOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).number().multiply(this.rhs.evaluate(c).number());
  };
  
  MultiplyOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " * " + this.rhs.toString() + ")";
  };
  
  // DivOperation //////////////////////////////////////////////////////////////
  
  DivOperation.prototype = new BinaryOperation();
  DivOperation.prototype.constructor = DivOperation;
  DivOperation.superclass = BinaryOperation.prototype;
  
  function DivOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  DivOperation.prototype.init = function(lhs, rhs) {
  	DivOperation.superclass.init.call(this, lhs, rhs);
  };
  
  DivOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).number().div(this.rhs.evaluate(c).number());
  };
  
  DivOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " div " + this.rhs.toString() + ")";
  };
  
  // ModOperation //////////////////////////////////////////////////////////////
  
  ModOperation.prototype = new BinaryOperation();
  ModOperation.prototype.constructor = ModOperation;
  ModOperation.superclass = BinaryOperation.prototype;
  
  function ModOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  ModOperation.prototype.init = function(lhs, rhs) {
  	ModOperation.superclass.init.call(this, lhs, rhs);
  };
  
  ModOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).number().mod(this.rhs.evaluate(c).number());
  };
  
  ModOperation.prototype.toString = function() {
  	return "(" + this.lhs.toString() + " mod " + this.rhs.toString() + ")";
  };
  
  // BarOperation //////////////////////////////////////////////////////////////
  
  BarOperation.prototype = new BinaryOperation();
  BarOperation.prototype.constructor = BarOperation;
  BarOperation.superclass = BinaryOperation.prototype;
  
  function BarOperation(lhs, rhs) {
  	if (arguments.length > 0) {
  		this.init(lhs, rhs);
  	}
  }
  
  BarOperation.prototype.init = function(lhs, rhs) {
  	BarOperation.superclass.init.call(this, lhs, rhs);
  };
  
  BarOperation.prototype.evaluate = function(c) {
  	return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
  };
  
  BarOperation.prototype.toString = function() {
  	return this.lhs.toString() + " | " + this.rhs.toString();
  };
  
  // PathExpr //////////////////////////////////////////////////////////////////
  
  PathExpr.prototype = new Expression();
  PathExpr.prototype.constructor = PathExpr;
  PathExpr.superclass = Expression.prototype;
  
  function PathExpr(filter, filterPreds, locpath) {
  	if (arguments.length > 0) {
  		this.init(filter, filterPreds, locpath);
  	}
  }
  
  PathExpr.prototype.init = function(filter, filterPreds, locpath) {
  	PathExpr.superclass.init.call(this);
  	this.filter = filter;
  	this.filterPredicates = filterPreds;
  	this.locationPath = locpath;
  };
  
  PathExpr.prototype.evaluate = function(c) {
  	var nodes;
  	var xpc = new XPathContext();
  	xpc.variableResolver = c.variableResolver;
  	xpc.functionResolver = c.functionResolver;
  	xpc.namespaceResolver = c.namespaceResolver;
  	xpc.expressionContextNode = c.expressionContextNode;
  	xpc.virtualRoot = c.virtualRoot;
  	xpc.caseInsensitive = c.caseInsensitive;
  	if (this.filter == null) {
  		nodes = [ c.contextNode ];
  	} else {
  		var ns = this.filter.evaluate(c);
  		if (!Utilities.instance_of(ns, XNodeSet)) {
  			if (this.filterPredicates != null && this.filterPredicates.length > 0 || this.locationPath != null) {
  				throw new Error("Path expression filter must evaluate to a nodset if predicates or location path are used");
  			}
  			return ns;
  		}
  		nodes = ns.toArray();
  		if (this.filterPredicates != null) {
  			// apply each of the predicates in turn
  			for (var j = 0; j < this.filterPredicates.length; j++) {
  				var pred = this.filterPredicates[j];
  				var newNodes = [];
  				xpc.contextSize = nodes.length;
  				for (xpc.contextPosition = 1; xpc.contextPosition <= xpc.contextSize; xpc.contextPosition++) {
  					xpc.contextNode = nodes[xpc.contextPosition - 1];
  					if (this.predicateMatches(pred, xpc)) {
  						newNodes.push(xpc.contextNode);
  					}
  				}
  				nodes = newNodes;
  			}
  		}
  	}
  	if (this.locationPath != null) {
  		if (this.locationPath.absolute) {
  			if (nodes[0].nodeType != 9 /*Node.DOCUMENT_NODE*/) {
  				if (xpc.virtualRoot != null) {
  					nodes = [ xpc.virtualRoot ];
  				} else {
  					nodes = [ nodes[0].ownerDocument ];
  				}
  			} else {
  				nodes = [ nodes[0] ];
  			}
  		}
  		for (var i = 0; i < this.locationPath.steps.length; i++) {
  			var step = this.locationPath.steps[i];
  			var newNodes = [];
  			for (var j = 0; j < nodes.length; j++) {
  				xpc.contextNode = nodes[j];
  				switch (step.axis) {
  					case Step.ANCESTOR:
  						// look at all the ancestor nodes
  						if (xpc.contextNode === xpc.virtualRoot) {
  							break;
  						}
  						var m;
  						if (xpc.contextNode.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) {
  							m = this.getOwnerElement(xpc.contextNode);
  						} else {
  							m = xpc.contextNode.parentNode;
  						}
  						while (m != null) {
  							if (step.nodeTest.matches(m, xpc)) {
  								newNodes.push(m);
  							}
  							if (m === xpc.virtualRoot) {
  								break;
  							}
  							m = m.parentNode;
  						}
  						break;
  
  					case Step.ANCESTORORSELF:
  						// look at all the ancestor nodes and the current node
  						for (var m = xpc.contextNode; m != null; m = m.nodeType == 2 /*Node.ATTRIBUTE_NODE*/ ? this.getOwnerElement(m) : m.parentNode) {
  							if (step.nodeTest.matches(m, xpc)) {
  								newNodes.push(m);
  							}
  							if (m === xpc.virtualRoot) {
  								break;
  							}
  						}
  						break;
  
  					case Step.ATTRIBUTE:
  						// look at the attributes
  						var nnm = xpc.contextNode.attributes;
  						if (nnm != null) {
  							for (var k = 0; k < nnm.length; k++) {
  								var m = nnm.item(k);
  								if (step.nodeTest.matches(m, xpc)) {
  									newNodes.push(m);
  								}
  							}
  						}
  						break;
  
  					case Step.CHILD:
  						// look at all child elements
  						for (var m = xpc.contextNode.firstChild; m != null; m = m.nextSibling) {
  							if (step.nodeTest.matches(m, xpc)) {
  								newNodes.push(m);
  							}
  						}
  						break;
  
  					case Step.DESCENDANT:
  						// look at all descendant nodes
  						var st = [ xpc.contextNode.firstChild ];
  						while (st.length > 0) {
  							for (var m = st.pop(); m != null; ) {
  								if (step.nodeTest.matches(m, xpc)) {
  									newNodes.push(m);
  								}
  								if (m.firstChild != null) {
  									st.push(m.nextSibling);
  									m = m.firstChild;
  								} else {
  									m = m.nextSibling;
  								}
  							}
  						}
  						break;
  
  					case Step.DESCENDANTORSELF:
  						// look at self
  						if (step.nodeTest.matches(xpc.contextNode, xpc)) {
  							newNodes.push(xpc.contextNode);
  						}
  						// look at all descendant nodes
  						var st = [ xpc.contextNode.firstChild ];
  						while (st.length > 0) {
  							for (var m = st.pop(); m != null; ) {
  								if (step.nodeTest.matches(m, xpc)) {
  									newNodes.push(m);
  								}
  								if (m.firstChild != null) {
  									st.push(m.nextSibling);
  									m = m.firstChild;
  								} else {
  									m = m.nextSibling;
  								}
  							}
  						}
  						break;
  
  					case Step.FOLLOWING:
  						if (xpc.contextNode === xpc.virtualRoot) {
  							break;
  						}
  						var st = [];
  						if (xpc.contextNode.firstChild != null) {
  							st.unshift(xpc.contextNode.firstChild);
  						} else {
  							st.unshift(xpc.contextNode.nextSibling);
  						}
  						for (var m = xpc.contextNode.parentNode; m != null && m.nodeType != 9 /*Node.DOCUMENT_NODE*/ && m !== xpc.virtualRoot; m = m.parentNode) {
  							st.unshift(m.nextSibling);
  						}
  						do {
  							for (var m = st.pop(); m != null; ) {
  								if (step.nodeTest.matches(m, xpc)) {
  									newNodes.push(m);
  								}
  								if (m.firstChild != null) {
  									st.push(m.nextSibling);
  									m = m.firstChild;
  								} else {
  									m = m.nextSibling;
  								}
  							}
  						} while (st.length > 0);
  						break;
  						
  					case Step.FOLLOWINGSIBLING:
  						if (xpc.contextNode === xpc.virtualRoot) {
  							break;
  						}
  						for (var m = xpc.contextNode.nextSibling; m != null; m = m.nextSibling) {
  							if (step.nodeTest.matches(m, xpc)) {
  								newNodes.push(m);
  							}
  						}
  						break;
  
  					case Step.NAMESPACE:
  						var n = {};
  						if (xpc.contextNode.nodeType == 1 /*Node.ELEMENT_NODE*/) {
  							n["xml"] = XPath.XML_NAMESPACE_URI;
  							n["xmlns"] = XPath.XMLNS_NAMESPACE_URI;
  							for (var m = xpc.contextNode; m != null && m.nodeType == 1 /*Node.ELEMENT_NODE*/; m = m.parentNode) {
  								for (var k = 0; k < m.attributes.length; k++) {
  									var attr = m.attributes.item(k);
  									var nm = String(attr.name);
  									if (nm == "xmlns") {
  										if (n[""] == undefined) {
  											n[""] = attr.value;
  										}
  									} else if (nm.length > 6 && nm.substring(0, 6) == "xmlns:") {
  										var pre = nm.substring(6, nm.length);
  										if (n[pre] == undefined) {
  											n[pre] = attr.value;
  										}
  									}
  								}
  							}
  							for (var pre in n) {
  								var nsn = new NamespaceNode(pre, n[pre], xpc.contextNode);
  								if (step.nodeTest.matches(nsn, xpc)) {
  									newNodes.push(nsn);
  								}
  							}
  						}
  						break;
  
  					case Step.PARENT:
  						m = null;
  						if (xpc.contextNode !== xpc.virtualRoot) {
  							if (xpc.contextNode.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) {
  								m = this.getOwnerElement(xpc.contextNode);
  							} else {
  								m = xpc.contextNode.parentNode;
  							}
  						}
  						if (m != null && step.nodeTest.matches(m, xpc)) {
  							newNodes.push(m);
  						}
  						break;
  
  					case Step.PRECEDING:
  						var st;
  						if (xpc.virtualRoot != null) {
  							st = [ xpc.virtualRoot ];
  						} else {
  							st = xpc.contextNode.nodeType == 9 /*Node.DOCUMENT_NODE*/
  								? [ xpc.contextNode ]
  								: [ xpc.contextNode.ownerDocument ];
  						}
  						outer: while (st.length > 0) {
  							for (var m = st.pop(); m != null; ) {
  								if (m == xpc.contextNode) {
  									break outer;
  								}
  								if (step.nodeTest.matches(m, xpc)) {
  									newNodes.unshift(m);
  								}
  								if (m.firstChild != null) {
  									st.push(m.nextSibling);
  									m = m.firstChild;
  								} else {
  									m = m.nextSibling;
  								}
  							}
  						}
  						break;
  
  					case Step.PRECEDINGSIBLING:
  						if (xpc.contextNode === xpc.virtualRoot) {
  							break;
  						}
  						for (var m = xpc.contextNode.previousSibling; m != null; m = m.previousSibling) {
  							if (step.nodeTest.matches(m, xpc)) {
  								newNodes.push(m);
  							}
  						}
  						break;
  
  					case Step.SELF:
  						if (step.nodeTest.matches(xpc.contextNode, xpc)) {
  							newNodes.push(xpc.contextNode);
  						}
  						break;
  
  					default:
  				}
  			}
  			nodes = newNodes;
  			// apply each of the predicates in turn
  			for (var j = 0; j < step.predicates.length; j++) {
  				var pred = step.predicates[j];
  				var newNodes = [];
  				xpc.contextSize = nodes.length;
  				for (xpc.contextPosition = 1; xpc.contextPosition <= xpc.contextSize; xpc.contextPosition++) {
  					xpc.contextNode = nodes[xpc.contextPosition - 1];
  					if (this.predicateMatches(pred, xpc)) {
  						newNodes.push(xpc.contextNode);
  					} else {
  					}
  				}
  				nodes = newNodes;
  			}
  		}
  	}
  	var ns = new XNodeSet();
  	ns.addArray(nodes);
  	return ns;
  };
  
  PathExpr.prototype.predicateMatches = function(pred, c) {
  	var res = pred.evaluate(c);
  	if (Utilities.instance_of(res, XNumber)) {
  		return c.contextPosition == res.numberValue();
  	}
  	return res.booleanValue();
  };
  
  PathExpr.prototype.toString = function() {
  	if (this.filter != undefined) {
  		var s = this.filter.toString();
  		if (Utilities.instance_of(this.filter, XString)) {
  			s = "'" + s + "'";
  		}
  		if (this.filterPredicates != undefined) {
  			for (var i = 0; i < this.filterPredicates.length; i++) {
  				s = s + "[" + this.filterPredicates[i].toString() + "]";
  			}
  		}
  		if (this.locationPath != undefined) {
  			if (!this.locationPath.absolute) {
  				s += "/";
  			}
  			s += this.locationPath.toString();
  		}
  		return s;
  	}
  	return this.locationPath.toString();
  };
  
  PathExpr.prototype.getOwnerElement = function(n) {
  	// DOM 2 has ownerElement
  	if (n.ownerElement) {
  		return n.ownerElement;
  	}
  	// DOM 1 Internet Explorer can use selectSingleNode (ironically)
  	if (n.selectSingleNode) {
  		return n.selectSingleNode("..");
  	}
  	// Other DOM 1 implementations must use this egregious search
  	var doc = n.nodeType == 9 /*Node.DOCUMENT_NODE*/
  			? n
  			: n.ownerDocument;
  	var elts = doc.getElementsByTagName("*");
  	for (var i = 0; i < elts.length; i++) {
  		var elt = elts.item(i);
  		var nnm = elt.attributes;
  		for (var j = 0; j < nnm.length; j++) {
  			var an = nnm.item(j);
  			if (an === n) {
  				return elt;
  			}
  		}
  	}
  	return null;
  };
  
  // LocationPath //////////////////////////////////////////////////////////////
  
  LocationPath.prototype = new Object();
  LocationPath.prototype.constructor = LocationPath;
  LocationPath.superclass = Object.prototype;
  
  function LocationPath(abs, steps) {
  	if (arguments.length > 0) {
  		this.init(abs, steps);
  	}
  }
  
  LocationPath.prototype.init = function(abs, steps) {
  	this.absolute = abs;
  	this.steps = steps;
  };
  
  LocationPath.prototype.toString = function() {
  	var s;
  	if (this.absolute) {
  		s = "/";
  	} else {
  		s = "";
  	}
  	for (var i = 0; i < this.steps.length; i++) {
  		if (i != 0) {
  			s += "/";
  		}
  		s += this.steps[i].toString();
  	}
  	return s;
  };
  
  // Step //////////////////////////////////////////////////////////////////////
  
  Step.prototype = new Object();
  Step.prototype.constructor = Step;
  Step.superclass = Object.prototype;
  
  function Step(axis, nodetest, preds) {
  	if (arguments.length > 0) {
  		this.init(axis, nodetest, preds);
  	}
  }
  
  Step.prototype.init = function(axis, nodetest, preds) {
  	this.axis = axis;
  	this.nodeTest = nodetest;
  	this.predicates = preds;
  };
  
  Step.prototype.toString = function() {
  	var s;
  	switch (this.axis) {
  		case Step.ANCESTOR:
  			s = "ancestor";
  			break;
  		case Step.ANCESTORORSELF:
  			s = "ancestor-or-self";
  			break;
  		case Step.ATTRIBUTE:
  			s = "attribute";
  			break;
  		case Step.CHILD:
  			s = "child";
  			break;
  		case Step.DESCENDANT:
  			s = "descendant";
  			break;
  		case Step.DESCENDANTORSELF:
  			s = "descendant-or-self";
  			break;
  		case Step.FOLLOWING:
  			s = "following";
  			break;
  		case Step.FOLLOWINGSIBLING:
  			s = "following-sibling";
  			break;
  		case Step.NAMESPACE:
  			s = "namespace";
  			break;
  		case Step.PARENT:
  			s = "parent";
  			break;
  		case Step.PRECEDING:
  			s = "preceding";
  			break;
  		case Step.PRECEDINGSIBLING:
  			s = "preceding-sibling";
  			break;
  		case Step.SELF:
  			s = "self";
  			break;
  	}
  	s += "::";
  	s += this.nodeTest.toString();
  	for (var i = 0; i < this.predicates.length; i++) {
  		s += "[" + this.predicates[i].toString() + "]";
  	}
  	return s;
  };
  
  Step.ANCESTOR = 0;
  Step.ANCESTORORSELF = 1;
  Step.ATTRIBUTE = 2;
  Step.CHILD = 3;
  Step.DESCENDANT = 4;
  Step.DESCENDANTORSELF = 5;
  Step.FOLLOWING = 6;
  Step.FOLLOWINGSIBLING = 7;
  Step.NAMESPACE = 8;
  Step.PARENT = 9;
  Step.PRECEDING = 10;
  Step.PRECEDINGSIBLING = 11;
  Step.SELF = 12;
  
  // NodeTest //////////////////////////////////////////////////////////////////
  
  NodeTest.prototype = new Object();
  NodeTest.prototype.constructor = NodeTest;
  NodeTest.superclass = Object.prototype;
  
  function NodeTest(type, value) {
  	if (arguments.length > 0) {
  		this.init(type, value);
  	}
  }
  
  NodeTest.prototype.init = function(type, value) {
  	this.type = type;
  	this.value = value;
  };
  
  NodeTest.prototype.toString = function() {
  	switch (this.type) {
  		case NodeTest.NAMETESTANY:
  			return "*";
  		case NodeTest.NAMETESTPREFIXANY:
  			return this.value + ":*";
  		case NodeTest.NAMETESTQNAME:
  			return this.value;
  		case NodeTest.COMMENT:
  			return "comment()";
  		case NodeTest.TEXT:
  			return "text()";
  		case NodeTest.PI:
  			if (this.value != undefined) {
  				return "processing-instruction(\"" + this.value + "\")";
  			}
  			return "processing-instruction()";
  		case NodeTest.NODE:
  			return "node()";
  	}
  	return "<unknown nodetest type>";
  };
  
  NodeTest.prototype.matches = function(n, xpc) {
  	switch (this.type) {
  		case NodeTest.NAMETESTANY:
  			if (n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/
  					|| n.nodeType == 1 /*Node.ELEMENT_NODE*/
  					|| n.nodeType == NodeTest.NAMESPACE_NODE) {
  				return true;
  			}
  			return false;
  		case NodeTest.NAMETESTPREFIXANY:
  			if ((n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/ || n.nodeType == 1 /*Node.ELEMENT_NODE*/)
  					&& n.namespaceURI == xpc.namespaceResolver.getNamespace(this.value, xpc.expressionContextNode)) {
  				return true;	
  			}
  			return false;
  		case NodeTest.NAMETESTQNAME:
  			if (n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/
  					|| n.nodeType == 1 /*Node.ELEMENT_NODE*/
  					|| n.nodeType == NodeTest.NAMESPACE_NODE) {
  				var test = Utilities.resolveQName(this.value, xpc.namespaceResolver, xpc.expressionContextNode, false);
  				test[0] = String(test[0]);
  				if (test[0] == "") {
  					test[0] = null;
  				}
  				var node = Utilities.resolveQName(n.nodeName, xpc.namespaceResolver, xpc.contextNode, true);
  				node[0] = String(node[0]);
  				if (node[0] == "") {
  					node[0] = null;
  				}
  				if (xpc.caseInsensitive) {
  					return test[0] == node[0] && String(test[1]).toLowerCase() == String(node[1]).toLowerCase();
  				}
  				return test[0] == node[0] && test[1] == node[1];
  			}
  			return false;
  		case NodeTest.COMMENT:
  			return n.nodeType == 8 /*Node.COMMENT_NODE*/;
  		case NodeTest.TEXT:
  			return n.nodeType == 3 /*Node.TEXT_NODE*/ || n.nodeType == 4 /*Node.CDATA_SECTION_NODE*/;
  		case NodeTest.PI:
  			return n.nodeType == 7 /*Node.PROCESSING_INSTRUCTION_NODE*/
  				&& (this.value == null || n.nodeName == this.value);
  		case NodeTest.NODE:
  			return n.nodeType == 9 /*Node.DOCUMENT_NODE*/
  				|| n.nodeType == 1 /*Node.ELEMENT_NODE*/
  				|| n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/
  				|| n.nodeType == 3 /*Node.TEXT_NODE*/
  				|| n.nodeType == 4 /*Node.CDATA_SECTION_NODE*/
  				|| n.nodeType == 8 /*Node.COMMENT_NODE*/
  				|| n.nodeType == 7 /*Node.PROCESSING_INSTRUCTION_NODE*/;
  	}
  	return false;
  };
  
  NodeTest.NAMETESTANY = 0;
  NodeTest.NAMETESTPREFIXANY = 1;
  NodeTest.NAMETESTQNAME = 2;
  NodeTest.COMMENT = 3;
  NodeTest.TEXT = 4;
  NodeTest.PI = 5;
  NodeTest.NODE = 6;
  
  NodeTest.NAMESPACE_NODE = 1024;
  
  // VariableReference /////////////////////////////////////////////////////////
  
  VariableReference.prototype = new Expression();
  VariableReference.prototype.constructor = VariableReference;
  VariableReference.superclass = Expression.prototype;
  
  function VariableReference(v) {
  	if (arguments.length > 0) {
  		this.init(v);
  	}
  }
  
  VariableReference.prototype.init = function(v) {
  	this.variable = v;
  };
  
  VariableReference.prototype.toString = function() {
  	return "$" + this.variable;
  };
  
  VariableReference.prototype.evaluate = function(c) {
  	return c.variableResolver.getVariable(this.variable, c);
  };
  
  // FunctionCall //////////////////////////////////////////////////////////////
  
  FunctionCall.prototype = new Expression();
  FunctionCall.prototype.constructor = FunctionCall;
  FunctionCall.superclass = Expression.prototype;
  
  function FunctionCall(fn, args) {
  	if (arguments.length > 0) {
  		this.init(fn, args);
  	}
  }
  
  FunctionCall.prototype.init = function(fn, args) {
  	this.functionName = fn;
  	this.arguments = args;
  };
  
  FunctionCall.prototype.toString = function() {
  	var s = this.functionName + "(";
  	for (var i = 0; i < this.arguments.length; i++) {
  		if (i > 0) {
  			s += ", ";
  		}
  		s += this.arguments[i].toString();
  	}
  	return s + ")";
  };
  
  FunctionCall.prototype.evaluate = function(c) {
  	var f = c.functionResolver.getFunction(this.functionName, c);
  	if (f == undefined) {
  		throw new Error("Unknown function " + this.functionName);
  	}
  	var a = [c].concat(this.arguments);
  	return f.apply(c.functionResolver.thisArg, a);
  };
  
  // XString ///////////////////////////////////////////////////////////////////
  
  XString.prototype = new Expression();
  XString.prototype.constructor = XString;
  XString.superclass = Expression.prototype;
  
  function XString(s) {
  	if (arguments.length > 0) {
  		this.init(s);
  	}
  }
  
  XString.prototype.init = function(s) {
  	this.str = s;
  };
  
  XString.prototype.toString = function() {
  	return this.str;
  };
  
  XString.prototype.evaluate = function(c) {
  	return this;
  };
  
  XString.prototype.string = function() {
  	return this;
  };
  
  XString.prototype.number = function() {
  	return new XNumber(this.str);
  };
  
  XString.prototype.bool = function() {
  	return new XBoolean(this.str);
  };
  
  XString.prototype.nodeset = function() {
  	throw new Error("Cannot convert string to nodeset");
  };
  
  XString.prototype.stringValue = function() {
  	return this.str;
  };
  
  XString.prototype.numberValue = function() {
  	return this.number().numberValue();
  };
  
  XString.prototype.booleanValue = function() {
  	return this.bool().booleanValue();
  };
  
  XString.prototype.equals = function(r) {
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.bool().equals(r);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.number().equals(r);
  	}
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithString(this, Operators.equals);
  	}
  	return new XBoolean(this.str == r.str);
  };
  
  XString.prototype.notequal = function(r) {
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.bool().notequal(r);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.number().notequal(r);
  	}
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithString(this, Operators.notequal);
  	}
  	return new XBoolean(this.str != r.str);
  };
  
  XString.prototype.lessthan = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.greaterthanorequal);
  	}
  	return this.number().lessthan(r.number());
  };
  
  XString.prototype.greaterthan = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.lessthanorequal);
  	}
  	return this.number().greaterthan(r.number());
  };
  
  XString.prototype.lessthanorequal = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.greaterthan);
  	}
  	return this.number().lessthanorequal(r.number());
  };
  
  XString.prototype.greaterthanorequal = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.lessthan);
  	}
  	return this.number().greaterthanorequal(r.number());
  };
  
  // XNumber ///////////////////////////////////////////////////////////////////
  
  XNumber.prototype = new Expression();
  XNumber.prototype.constructor = XNumber;
  XNumber.superclass = Expression.prototype;
  
  function XNumber(n) {
  	if (arguments.length > 0) {
  		this.init(n);
  	}
  }
  
  XNumber.prototype.init = function(n) {
  	this.num = Number(n);
  };
  
  XNumber.prototype.toString = function() {
  	return this.num;
  };
  
  XNumber.prototype.evaluate = function(c) {
  	return this;
  };
  
  XNumber.prototype.string = function() {
  	return new XString(this.num);
  };
  
  XNumber.prototype.number = function() {
  	return this;
  };
  
  XNumber.prototype.bool = function() {
  	return new XBoolean(this.num);
  };
  
  XNumber.prototype.nodeset = function() {
  	throw new Error("Cannot convert number to nodeset");
  };
  
  XNumber.prototype.stringValue = function() {
  	return this.string().stringValue();
  };
  
  XNumber.prototype.numberValue = function() {
  	return this.num;
  };
  
  XNumber.prototype.booleanValue = function() {
  	return this.bool().booleanValue();
  };
  
  XNumber.prototype.negate = function() {
  	return new XNumber(-this.num);
  };
  
  XNumber.prototype.equals = function(r) {
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.bool().equals(r);
  	}
  	if (Utilities.instance_of(r, XString)) {
  		return this.equals(r.number());
  	}
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this, Operators.equals);
  	}
  	return new XBoolean(this.num == r.num);
  };
  
  XNumber.prototype.notequal = function(r) {
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.bool().notequal(r);
  	}
  	if (Utilities.instance_of(r, XString)) {
  		return this.notequal(r.number());
  	}
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this, Operators.notequal);
  	}
  	return new XBoolean(this.num != r.num);
  };
  
  XNumber.prototype.lessthan = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this, Operators.greaterthanorequal);
  	}
  	if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
  		return this.lessthan(r.number());
  	}
  	return new XBoolean(this.num < r.num);
  };
  
  XNumber.prototype.greaterthan = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this, Operators.lessthanorequal);
  	}
  	if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
  		return this.greaterthan(r.number());
  	}
  	return new XBoolean(this.num > r.num);
  };
  
  XNumber.prototype.lessthanorequal = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this, Operators.greaterthan);
  	}
  	if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
  		return this.lessthanorequal(r.number());
  	}
  	return new XBoolean(this.num <= r.num);
  };
  
  XNumber.prototype.greaterthanorequal = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this, Operators.lessthan);
  	}
  	if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
  		return this.greaterthanorequal(r.number());
  	}
  	return new XBoolean(this.num >= r.num);
  };
  
  XNumber.prototype.plus = function(r) {
  	return new XNumber(this.num + r.num);
  };
  
  XNumber.prototype.minus = function(r) {
  	return new XNumber(this.num - r.num);
  };
  
  XNumber.prototype.multiply = function(r) {
  	return new XNumber(this.num * r.num);
  };
  
  XNumber.prototype.div = function(r) {
  	return new XNumber(this.num / r.num);
  };
  
  XNumber.prototype.mod = function(r) {
  	return new XNumber(this.num % r.num);
  };
  
  // XBoolean //////////////////////////////////////////////////////////////////
  
  XBoolean.prototype = new Expression();
  XBoolean.prototype.constructor = XBoolean;
  XBoolean.superclass = Expression.prototype;
  
  function XBoolean(b) {
  	if (arguments.length > 0) {
  		this.init(b);
  	}
  }
  
  XBoolean.prototype.init = function(b) {
  	this.b = Boolean(b);
  };
  
  XBoolean.prototype.toString = function() {
  	return this.b.toString();
  };
  
  XBoolean.prototype.evaluate = function(c) {
  	return this;
  };
  
  XBoolean.prototype.string = function() {
  	return new XString(this.b);
  };
  
  XBoolean.prototype.number = function() {
  	return new XNumber(this.b);
  };
  
  XBoolean.prototype.bool = function() {
  	return this;
  };
  
  XBoolean.prototype.nodeset = function() {
  	throw new Error("Cannot convert boolean to nodeset");
  };
  
  XBoolean.prototype.stringValue = function() {
  	return this.string().stringValue();
  };
  
  XBoolean.prototype.numberValue = function() {
  	return this.num().numberValue();
  };
  
  XBoolean.prototype.booleanValue = function() {
  	return this.b;
  };
  
  XBoolean.prototype.not = function() {
  	return new XBoolean(!this.b);
  };
  
  XBoolean.prototype.equals = function(r) {
  	if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
  		return this.equals(r.bool());
  	}
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithBoolean(this, Operators.equals);
  	}
  	return new XBoolean(this.b == r.b);
  };
  
  XBoolean.prototype.notequal = function(r) {
  	if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
  		return this.notequal(r.bool());
  	}
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithBoolean(this, Operators.notequal);
  	}
  	return new XBoolean(this.b != r.b);
  };
  
  XBoolean.prototype.lessthan = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.greaterthanorequal);
  	}
  	return this.number().lessthan(r.number());
  };
  
  XBoolean.prototype.greaterthan = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.lessthanorequal);
  	}
  	return this.number().greaterthan(r.number());
  };
  
  XBoolean.prototype.lessthanorequal = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.greaterthan);
  	}
  	return this.number().lessthanorequal(r.number());
  };
  
  XBoolean.prototype.greaterthanorequal = function(r) {
  	if (Utilities.instance_of(r, XNodeSet)) {
  		return r.compareWithNumber(this.number(), Operators.lessthan);
  	}
  	return this.number().greaterthanorequal(r.number());
  };
  
  // XNodeSet //////////////////////////////////////////////////////////////////
  
  XNodeSet.prototype = new Expression();
  XNodeSet.prototype.constructor = XNodeSet;
  XNodeSet.superclass = Expression.prototype;
  
  function XNodeSet() {
  	this.init();
  }
  
  XNodeSet.prototype.init = function() {
  	this.tree = null;
  	this.size = 0;
  };
  
  XNodeSet.prototype.toString = function() {
  	var p = this.first();
  	if (p == null) {
  		return "";
  	}
  	return this.stringForNode(p);
  };
  
  XNodeSet.prototype.evaluate = function(c) {
  	return this;
  };
  
  XNodeSet.prototype.string = function() {
  	return new XString(this.toString());
  };
  
  XNodeSet.prototype.stringValue = function() {
  	return this.toString();
  };
  
  XNodeSet.prototype.number = function() {
  	return new XNumber(this.string());
  };
  
  XNodeSet.prototype.numberValue = function() {
  	return Number(this.string());
  };
  
  XNodeSet.prototype.bool = function() {
  	return new XBoolean(this.tree != null);
  };
  
  XNodeSet.prototype.booleanValue = function() {
  	return this.tree != null;
  };
  
  XNodeSet.prototype.nodeset = function() {
  	return this;
  };
  
  XNodeSet.prototype.stringForNode = function(n) {
  	if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/) {
  		n = n.documentElement;
  	}
  	if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) {
  		return this.stringForNodeRec(n);
  	}
  	if (n.isNamespaceNode) {
  		return n.namespace;
  	}
  	return n.nodeValue;
  };
  
  XNodeSet.prototype.stringForNodeRec = function(n) {
  	var s = "";
  	for (var n2 = n.firstChild; n2 != null; n2 = n2.nextSibling) {
  		if (n2.nodeType == 3 /*Node.TEXT_NODE*/) {
  			s += n2.nodeValue;
  		} else if (n2.nodeType == 1 /*Node.ELEMENT_NODE*/) {
  			s += this.stringForNodeRec(n2);
  		}
  	}
  	return s;
  };
  
  XNodeSet.prototype.first = function() {
  	var p = this.tree;
  	if (p == null) {
  		return null;
  	}
  	while (p.left != null) {
  		p = p.left;
  	}
  	return p.node;
  };
  
  XNodeSet.prototype.add = function(n) {
  	if (this.tree == null) {
  		this.tree = new Object();
  		this.tree.node = n;
  		this.tree.left = null;
  		this.tree.right = null;
  		this.size = 1;
  		return;
  	}
  
  	var p = this.tree;
  	while (1) {
  		var o = this.order(n, p.node);
  		if (o == 0) {
  			return;
  		}
  		if (o > 0) {
  			if (p.right == null) {
  				p.right = new Object();
  				p.right.node = n;
  				p.right.left = null;
  				p.right.right = null;
  				this.size++;
  				return;
  			}
  			p = p.right;
  		} else {
  			if (p.left == null) {
  				p.left = new Object();
  				p.left.node = n;
  				p.left.left = null;
  				p.left.right = null;
  				this.size++;
  				return;
  			}
  			p = p.left;
  		}
  	}
  };
  
  XNodeSet.prototype.addArray = function(ns) {
  	for (var i = 0; i < ns.length; i++) {
  		this.add(ns[i]);
  	}
  };
  
  XNodeSet.prototype.toArray = function() {
  	var a = [];
  	this.toArrayRec(this.tree, a);
  	return a;
  };
  
  XNodeSet.prototype.toArrayRec = function(t, a) {
  	if (t != null) {
  		this.toArrayRec(t.left, a);
  		a.push(t.node);
  		this.toArrayRec(t.right, a);
  	}
  };
  
  XNodeSet.prototype.order = function(n1, n2) {
  	if (n1 == n2) {
  		return 0;
  	}
  	var d1 = 0;
  	var d2 = 0;
  	for (var m1 = n1; m1 != null; m1 = m1.parentNode) {
  		d1++;
  	}
  	for (var m2 = n2; m2 != null; m2 = m2.parentNode) {
  		d2++;
  	}
  	if (d1 > d2) {
  		while (d1 > d2) {
  			n1 = n1.parentNode;
  			d1--;
  		}
  		if (n1 == n2) {
  			return 1;
  		}
  	} else if (d2 > d1) {
  		while (d2 > d1) {
  			n2 = n2.parentNode;
  			d2--;
  		}
  		if (n1 == n2) {
  			return -1;
  		}
  	}
  	while (n1.parentNode != n2.parentNode) {
  		n1 = n1.parentNode;
  		n2 = n2.parentNode;
  	}
  	while (n1.previousSibling != null && n2.previousSibling != null) {
  		n1 = n1.previousSibling;
  		n2 = n2.previousSibling;
  	}
  	if (n1.previousSibling == null) {
  		return -1;
  	}
  	return 1;
  };
  
  XNodeSet.prototype.compareWithString = function(r, o) {
  	var a = this.toArray();
  	for (var i = 0; i < a.length; i++) {
  		var n = a[i];
  		var l = new XString(this.stringForNode(n));
  		var res = o(l, r);
  		if (res.booleanValue()) {
  			return res;
  		}
  	}
  	return new XBoolean(false);
  };
  
  XNodeSet.prototype.compareWithNumber = function(r, o) {
  	var a = this.toArray();
  	for (var i = 0; i < a.length; i++) {
  		var n = a[i];
  		var l = new XNumber(this.stringForNode(n));
  		var res = o(l, r);
  		if (res.booleanValue()) {
  			return res;
  		}
  	}
  	return new XBoolean(false);
  };
  
  XNodeSet.prototype.compareWithBoolean = function(r, o) {
  	return o(this.bool(), r);
  };
  
  XNodeSet.prototype.compareWithNodeSet = function(r, o) {
  	var a = this.toArray();
  	for (var i = 0; i < a.length; i++) {
  		var n = a[i];
  		var l = new XString(this.stringForNode(n));
  		var b = r.toArray();
  		for (var j = 0; j < b.length; j++) {
  			var n2 = b[j];
  			var r = new XString(this.stringForNode(n2));
  			var res = o(l, r);
  			if (res.booleanValue()) {
  				return res;
  			}
  		}
  	}
  	return new XBoolean(false);
  };
  
  XNodeSet.prototype.equals = function(r) {
  	if (Utilities.instance_of(r, XString)) {
  		return this.compareWithString(r, Operators.equals);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.compareWithNumber(r, Operators.equals);
  	}
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.compareWithBoolean(r, Operators.equals);
  	}
  	return this.compareWithNodeSet(r, Operators.equals);
  };
  
  XNodeSet.prototype.notequal = function(r) {
  	if (Utilities.instance_of(r, XString)) {
  		return this.compareWithString(r, Operators.notequal);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.compareWithNumber(r, Operators.notequal);
  	}
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.compareWithBoolean(r, Operators.notequal);
  	}
  	return this.compareWithNodeSet(r, Operators.notequal);
  };
  
  XNodeSet.prototype.lessthan = function(r) {
  	if (Utilities.instance_of(r, XString)) {
  		return this.compareWithNumber(r.number(), Operators.lessthan);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.compareWithNumber(r, Operators.lessthan);
  	}
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.compareWithBoolean(r, Operators.lessthan);
  	}
  	return this.compareWithNodeSet(r, Operators.lessthan);
  };
  
  XNodeSet.prototype.greaterthan = function(r) {
  	if (Utilities.instance_of(r, XString)) {
  		return this.compareWithNumber(r.number(), Operators.greaterthan);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.compareWithNumber(r, Operators.greaterthan);
  	}
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.compareWithBoolean(r, Operators.greaterthan);
  	}
  	return this.compareWithNodeSet(r, Operators.greaterthan);
  };
  
  XNodeSet.prototype.lessthanorequal = function(r) {
  	if (Utilities.instance_of(r, XString)) {
  		return this.compareWithNumber(r.number(), Operators.lessthanorequal);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.compareWithNumber(r, Operators.lessthanorequal);
  	}
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.compareWithBoolean(r, Operators.lessthanorequal);
  	}
  	return this.compareWithNodeSet(r, Operators.lessthanorequal);
  };
  
  XNodeSet.prototype.greaterthanorequal = function(r) {
  	if (Utilities.instance_of(r, XString)) {
  		return this.compareWithNumber(r.number(), Operators.greaterthanorequal);
  	}
  	if (Utilities.instance_of(r, XNumber)) {
  		return this.compareWithNumber(r, Operators.greaterthanorequal);
  	}
  	if (Utilities.instance_of(r, XBoolean)) {
  		return this.compareWithBoolean(r, Operators.greaterthanorequal);
  	}
  	return this.compareWithNodeSet(r, Operators.greaterthanorequal);
  };
  
  XNodeSet.prototype.union = function(r) {
  	var ns = new XNodeSet();
  	ns.tree = this.tree;
  	ns.size = this.size;
  	ns.addArray(r.toArray());
  	return ns;
  };
  
  // NamespaceNode /////////////////////////////////////////////////////////////
  
  NamespaceNode.prototype = new Object();
  NamespaceNode.prototype.constructor = NamespaceNode;
  NamespaceNode.superclass = Object.prototype;
  
  function NamespaceNode(pre, ns, p) {
  	this.isNamespaceNode = true;
  	this.prefix = pre;
  	this.namespace = ns;
  	this.parentNode = p;
  	this.localName = pre;
  	this.nodeType = NodeTest.NAMESPACE_NODE;
  }
  
  NamespaceNode.prototype.toString = function() {
  	return "{ \"" + this.prefix + "\", \"" + this.namespace + "\" }";
  };
  
  // Operators /////////////////////////////////////////////////////////////////
  
  var Operators = new Object();
  
  Operators.equals = function(l, r) {
  	return l.equals(r);
  };
  
  Operators.notequal = function(l, r) {
  	return l.notequal(r);
  };
  
  Operators.lessthan = function(l, r) {
  	return l.lessthan(r);
  };
  
  Operators.greaterthan = function(l, r) {
  	return l.greaterthan(r);
  };
  
  Operators.lessthanorequal = function(l, r) {
  	return l.lessthanorequal(r);
  };
  
  Operators.greaterthanorequal = function(l, r) {
  	return l.greaterthanorequal(r);
  };
  
  // XPathContext //////////////////////////////////////////////////////////////
  
  XPathContext.prototype = new Object();
  XPathContext.prototype.constructor = XPathContext;
  XPathContext.superclass = Object.prototype;
  
  function XPathContext(vr, nr, fr) {
  	this.variableResolver = vr != null ? vr : new VariableResolver();
  	this.namespaceResolver = nr != null ? nr : new NamespaceResolver();
  	this.functionResolver = fr != null ? fr : new FunctionResolver();
  }
  
  // VariableResolver //////////////////////////////////////////////////////////
  
  VariableResolver.prototype = new Object();
  VariableResolver.prototype.constructor = VariableResolver;
  VariableResolver.superclass = Object.prototype;
  
  function VariableResolver() {
  }
  
  VariableResolver.prototype.getVariable = function(vn, c) {
  	var parts = Utilities.splitQName(vn);
  	if (parts[0] != null) {
  		parts[0] = c.namespaceResolver.getNamespace(parts[0], c.expressionContextNode);
  	}
  	return this.getVariableWithName(parts[0], parts[1], c.expressionContextNode);
  };
  
  VariableResolver.prototype.getVariableWithName = function(ns, ln, c) {
  	return null;
  };
  
  // FunctionResolver //////////////////////////////////////////////////////////
  
  FunctionResolver.prototype = new Object();
  FunctionResolver.prototype.constructor = FunctionResolver;
  FunctionResolver.superclass = Object.prototype;
  
  function FunctionResolver(thisArg) {
  	this.thisArg = thisArg != null ? thisArg : Functions;
  	this.functions = new Object();
  	this.addStandardFunctions();
  }
  
  FunctionResolver.prototype.addStandardFunctions = function() {
  	this.functions["{}last"] = Functions.last;
  	this.functions["{}position"] = Functions.position;
  	this.functions["{}count"] = Functions.count;
  	this.functions["{}id"] = Functions.id;
  	this.functions["{}local-name"] = Functions.localName;
  	this.functions["{}namespace-uri"] = Functions.namespaceURI;
  	this.functions["{}name"] = Functions.name;
  	this.functions["{}string"] = Functions.string;
  	this.functions["{}concat"] = Functions.concat;
  	this.functions["{}starts-with"] = Functions.startsWith;
  	this.functions["{}contains"] = Functions.contains;
  	this.functions["{}substring-before"] = Functions.substringBefore;
  	this.functions["{}substring-after"] = Functions.substringAfter;
  	this.functions["{}substring"] = Functions.substring;
  	this.functions["{}string-length"] = Functions.stringLength;
  	this.functions["{}normalize-space"] = Functions.normalizeSpace;
  	this.functions["{}translate"] = Functions.translate;
  	this.functions["{}boolean"] = Functions.boolean_;
  	this.functions["{}not"] = Functions.not;
  	this.functions["{}true"] = Functions.true_;
  	this.functions["{}false"] = Functions.false_;
  	this.functions["{}lang"] = Functions.lang;
  	this.functions["{}number"] = Functions.number;
  	this.functions["{}sum"] = Functions.sum;
  	this.functions["{}floor"] = Functions.floor;
  	this.functions["{}ceiling"] = Functions.ceiling;
  	this.functions["{}round"] = Functions.round;
  };
  
  FunctionResolver.prototype.addFunction = function(ns, ln, f) {
  	this.functions["{" + ns + "}" + ln] = f;
  };
  
  FunctionResolver.prototype.getFunction = function(fn, c) {
  	var parts = Utilities.resolveQName(fn, c.namespaceResolver, c.contextNode, false);
  	return this.getFunctionWithName(parts[0], parts[1], c.contextNode);
  };
  
  FunctionResolver.prototype.getFunctionWithName = function(ns, ln, c) {
  	return this.functions["{" + ns + "}" + ln];
  };
  
  // NamespaceResolver /////////////////////////////////////////////////////////
  
  NamespaceResolver.prototype = new Object();
  NamespaceResolver.prototype.constructor = NamespaceResolver;
  NamespaceResolver.superclass = Object.prototype;
  
  function NamespaceResolver() {
  }
  
  NamespaceResolver.prototype.getNamespace = function(prefix, n) {
  	if (prefix == "xml") {
  		return XPath.XML_NAMESPACE_URI;
  	} else if (prefix == "xmlns") {
  		return XPath.XMLNS_NAMESPACE_URI;
  	}
  	if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/) {
  		n = n.documentElement;
  	} else if (n.nodeType != 1 /*Node.ELEMENT_NODE*/) {
  		n = n.parentNode;
  	}
  	while (n != null && n.nodeType == 1 /*Node.ELEMENT_NODE*/) {
  		var nnm = n.attributes;
  		for (var i = 0; i < nnm.length; i++) {
  			var a = nnm.item(i);
  			var aname = a.nodeName;
  			if (aname == "xmlns" && prefix == ""
  					|| aname == "xmlns:" + prefix) {
  				return a.nodeValue;
  			}
  		}
  		n = n.parentNode;
  	}
  	return null;
  };
  
  // Functions /////////////////////////////////////////////////////////////////
  
  Functions = new Object();
  
  Functions.last = function() {
  	var c = arguments[0];
  	if (arguments.length != 1) {
  		throw new Error("Function last expects ()");
  	}
  	return new XNumber(c.contextSize);
  };
  
  Functions.position = function() {
  	var c = arguments[0];
  	if (arguments.length != 1) {
  		throw new Error("Function position expects ()");
  	}
  	return new XNumber(c.contextPosition);
  };
  
  Functions.count = function() {
  	var c = arguments[0];
  	var ns;
  	if (arguments.length != 2 || !Utilities.instance_of(ns = arguments[1].evaluate(c), XNodeSet)) {
  		throw new Error("Function count expects (node-set)");
  	}
  	return new XNumber(ns.size);
  };
  
  Functions.id = function() {
  	var c = arguments[0];
  	var id;
  	if (arguments.length != 2) {
  		throw new Error("Function id expects (object)");
  	}
  	id = arguments[1].evaluate(c);
  	if (Utilities.instance_of(id, XNodeSet)) {
  		id = id.toArray().join(" ");
  	} else {
  		id = id.stringValue();
  	}
  	var ids = id.split(/[\x0d\x0a\x09\x20]+/);
  	var count = 0;
  	var ns = new XNodeSet();
  	var doc = c.contextNode.nodeType == 9 /*Node.DOCUMENT_NODE*/
  			? c.contextNode
  			: c.contextNode.ownerDocument;
  	for (var i = 0; i < ids.length; i++) {
  		var n;
  		if (doc.getElementById) {
  			n = doc.getElementById(ids[i]);
  		} else {
  			n = Utilities.getElementById(doc, ids[i]);
  		}
  		if (n != null) {
  			ns.add(n);
  			count++;
  		}
  	}
  	return ns;
  };
  
  Functions.localName = function() {
  	var c = arguments[0];
  	var n;
  	if (arguments.length == 1) {
  		n = c.contextNode;
  	} else if (arguments.length == 2) {
  		n = arguments[1].evaluate(c).first();
  	} else {
  		throw new Error("Function local-name expects (node-set?)");
  	}
  	if (n == null) {
  		return new XString("");
  	}
  	return new XString(n.localName ? n.localName : n.baseName);
  };
  
  Functions.namespaceURI = function() {
  	var c = arguments[0];
  	var n;
  	if (arguments.length == 1) {
  		n = c.contextNode;
  	} else if (arguments.length == 2) {
  		n = arguments[1].evaluate(c).first();
  	} else {
  		throw new Error("Function namespace-uri expects (node-set?)");
  	}
  	if (n == null) {
  		return new XString("");
  	}
  	return new XString(n.namespaceURI);
  };
  
  Functions.name = function() {
  	var c = arguments[0];
  	var n;
  	if (arguments.length == 1) {
  		n = c.contextNode;
  	} else if (arguments.length == 2) {
  		n = arguments[1].evaluate(c).first();
  	} else {
  		throw new Error("Function name expects (node-set?)");
  	}
  	if (n == null) {
  		return new XString("");
  	}
  	if (n.nodeType == 1 /*Node.ELEMENT_NODE*/ || n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) {
  		return new XString(n.nodeName);
  	} else if (n.localName == null) {
  		return new XString("");
  	} else {
  		return new XString(n.localName);
  	}
  };
  
  Functions.string = function() {
  	var c = arguments[0];
  	if (arguments.length == 1) {
  		return XNodeSet.prototype.stringForNode(c.contextNode);
  	} else if (arguments.length == 2) {
  		return arguments[1].evaluate(c).string();
  	}
  	throw new Error("Function string expects (object?)");
  };
  
  Functions.concat = function() {
  	var c = arguments[0];
  	if (arguments.length < 3) {
  		throw new Error("Function concat expects (string, string, string*)");
  	}
  	var s = "";
  	for (var i = 1; i < arguments.length; i++) {
  		s += arguments[i].evaluate(c).stringValue();
  	}
  	return new XString(s);
  };
  
  Functions.startsWith = function() {
  	var c = arguments[0];
  	if (arguments.length != 3) {
  		throw new Error("Function startsWith expects (string, string)");
  	}
  	var s1 = arguments[1].evaluate(c).stringValue();
  	var s2 = arguments[2].evaluate(c).stringValue();
  	return new XBoolean(s1.substring(0, s2.length) == prefix);
  };
  
  Functions.contains = function() {
  	var c = arguments[0];
  	if (arguments.length != 3) {
  		throw new Error("Function contains expects (string, string)");
  	}
  	var s1 = arguments[1].evaluate(c).stringValue();
  	var s2 = arguments[2].evaluate(c).stringValue();
  	return new XBoolean(s1.indexOf(s2) != -1);
  };
  
  Functions.substringBefore = function() {
  	var c = arguments[0];
  	if (arguments.length != 3) {
  		throw new Error("Function substring-before expects (string, string)");
  	}
  	var s1 = arguments[1].evaluate(c).stringValue();
  	var s2 = arguments[2].evaluate(c).stringValue();
  	return new XString(s1.substring(0, s1.indexOf(s2)));
  };
  
  Functions.substringAfter = function() {
  	var c = arguments[0];
  	if (arguments.length != 3) {
  		throw new Error("Function substring-after expects (string, string)");
  	}
  	var s1 = arguments[1].evaluate(c).stringValue();
  	var s2 = arguments[2].evaluate(c).stringValue();
  	if (s2.length == 0) {
  		return new XString(s1);
  	}
  	var i = s1.indexOf(s2);
  	if (i == -1) {
  		return new XString("");
  	}
  	return new XString(s1.substring(s1.indexOf(s2) + 1));
  };
  
  Functions.substring = function() {
  	var c = arguments[0];
  	if (!(arguments.length == 3 || arguments.length == 4)) {
  		throw new Error("Function substring expects (string, number, number?)");
  	}
  	var s = arguments[1].evaluate(c).stringValue();
  	var n1 = Math.round(arguments[2].evaluate(c).numberValue()) - 1;
  	var n2 = arguments.length == 4 ? n1 + Math.round(arguments[3].evaluate(c).numberValue()) : undefined;
  	return new XString(s.substring(n1, n2));
  };
  
  Functions.stringLength = function() {
  	var c = arguments[0];
  	var s;
  	if (arguments.length == 2) {
  		s = XNodeSet.prototype.stringForNode(c.contextNode);
  	} else if (arguments.length == 3) {
  		s = arguments[1].evaluate(c).stringValue();
  	} else {
  		throw new Error("Function string-length expects (string?)");
  	}
  	return new XNumber(s.length);
  };
  
  Functions.normalizeSpace = function() {
  	var c = arguments[0];
  	var s;
  	if (arguments.length == 1) {
  		s = XNodeSet.prototype.stringForNode(c.contextNode);
  	} else if (arguments.length == 2) {
  		s = arguments[1].evaluate(c).stringValue();
  	} else {
  		throw new Error("Function normalize-space expects (string?)");
  	}
  	var i = 0;
  	var j = s.length - 1;
  	while (Utilities.isSpace(s.charCodeAt(j))) {
  		j--;
  	}
  	var t = "";
  	while (i <= j && Utilities.isSpace(s.charCodeAt(i))) {
  		i++;
  	}
  	while (i <= j) {
  		if (Utilities.isSpace(s.charCodeAt(i))) {
  			t += " ";
  			while (i <= j && Utilities.isSpace(s.charCodeAt(i))) {
  				i++;
  			}
  		} else {
  			t += s.charAt(i);
  			i++;
  		}
  	}
  	return new XString(t);
  };
  
  Functions.translate = function() {
  	var c = arguments[0];
  	if (arguments.length != 4) {
  		throw new Error("Function translate expects (string, string, string)");
  	}
  	var s1 = arguments[1].evaluate(c).stringValue();
  	var s2 = arguments[2].evaluate(c).stringValue();
  	var s3 = arguments[3].evaluate(c).stringValue();
  	var map = [];
  	for (var i = 0; i < s2.length; i++) {
  		var j = s2.charCodeAt(i);
  		if (map[j] == undefined) {
  			var k = i > s3.length ? "" : s3.charAt(i);
  			map[j] = k;
  		}
  	}
  	var t = "";
  	for (var i = 0; i < s1.length; i++) {
  		var c = s1.charCodeAt(i);
  		var r = map[c];
  		if (r == undefined) {
  			t += s1.charAt(i);
  		} else {
  			t += r;
  		}
  	}
  	return new XString(t);
  };
  
  Functions.boolean_ = function() {
  	var c = arguments[0];
  	if (arguments.length != 2) {
  		throw new Error("Function boolean expects (object)");
  	}
  	return arguments[1].evaluate(c).bool();
  };
  
  Functions.not = function() {
  	var c = arguments[0];
  	if (arguments.length != 2) {
  		throw new Error("Function not expects (object)");
  	}
  	return arguments[1].evaluate(c).bool().not();
  };
  
  Functions.true_ = function() {
  	if (arguments.length != 1) {
  		throw new Error("Function true expects ()");
  	}
  	return new XBoolean(true);
  };
  
  Functions.false_ = function() {
  	if (arguments.length != 1) {
  		throw new Error("Function false expects ()");
  	}
  	return new XBoolean(false);
  };
  
  Functions.lang = function() {
  	var c = arguments[0];
  	if (arguments.length != 2) {
  		throw new Error("Function lang expects (string)");
  	}
  	var lang;
  	for (var n = c.contextNode; n != null && n.nodeType != 9 /*Node.DOCUMENT_NODE*/; n = n.parentNode) {
  		var a = n.getAttributeNS(XPath.XML_NAMESPACE_URI, "lang");
  		if (a != null) {
  			lang = String(a);
  			break;
  		}
  	}
  	if (lang == null) {
  		return new XBoolean(false);
  	}
  	var s = arguments[1].evaluate(c).stringValue();
  	return new XBoolean(lang.substring(0, s.length) == s
  				&& (lang.length == s.length || lang.charAt(s.length) == '-'));
  };
  
  Functions.number = function() {
  	var c = arguments[0];
  	if (!(arguments.length == 1 || arguments.length == 2)) {
  		throw new Error("Function number expects (object?)");
  	}
  	if (arguments.length == 1) {
  		return new XNumber(XNodeSet.prototype.stringForNode(c.contextNode));
  	}
  	return arguments[1].evaluate(c).number();
  };
  
  Functions.sum = function() {
  	var c = arguments[0];
  	var ns;
  	if (arguments.length != 2 || !Utilities.instance_of((ns = arguments[1].evaluate(c)), XNodeSet)) {
  		throw new Error("Function sum expects (node-set)");
  	}
  	ns = ns.toArray();
  	var n = 0;
  	for (var i = 0; i < ns.length; i++) {
  		n += new XNumber(XNodeSet.prototype.stringForNode(ns[i])).numberValue();
  	}
  	return new XNumber(n);
  };
  
  Functions.floor = function() {
  	var c = arguments[0];
  	if (arguments.length != 2) {
  		throw new Error("Function floor expects (number)");
  	}
  	return new XNumber(Math.floor(arguments[1].evaluate(c).numberValue()));
  };
  
  Functions.ceiling = function() {
  	var c = arguments[0];
  	if (arguments.length != 2) {
  		throw new Error("Function ceiling expects (number)");
  	}
  	return new XNumber(Math.ceil(arguments[1].evaluate(c).numberValue()));
  };
  
  Functions.round = function() {
  	var c = arguments[0];
  	if (arguments.length != 2) {
  		throw new Error("Function round expects (number)");
  	}
  	return new XNumber(Math.round(arguments[1].evaluate(c).numberValue()));
  };
  
  // Utilities /////////////////////////////////////////////////////////////////
  
  Utilities = new Object();
  
  Utilities.splitQName = function(qn) {
  	var i = qn.indexOf(":");
  	if (i == -1) {
  		return [ null, qn ];
  	}
  	return [ qn.substring(0, i), qn.substring(i + 1) ];
  };
  
  Utilities.resolveQName = function(qn, nr, n, useDefault) {
  	var parts = Utilities.splitQName(qn);
  	if (parts[0] != null) {
  		parts[0] = nr.getNamespace(parts[0], n);
  	} else {
  		if (useDefault) {
  			parts[0] = nr.getNamespace("", n);
  			if (parts[0] == null) {
  				parts[0] = "";
  			}
  		} else {
  			parts[0] = "";
  		}
  	}
  	return parts;
  };
  
  Utilities.isSpace = function(c) {
  	return c == 0x9 || c == 0xd || c == 0xa || c == 0x20;
  };
  
  Utilities.isLetter = function(c) {
  	return c >= 0x0041 && c <= 0x005A ||
  		c >= 0x0061 && c <= 0x007A ||
  		c >= 0x00C0 && c <= 0x00D6 ||
  		c >= 0x00D8 && c <= 0x00F6 ||
  		c >= 0x00F8 && c <= 0x00FF ||
  		c >= 0x0100 && c <= 0x0131 ||
  		c >= 0x0134 && c <= 0x013E ||
  		c >= 0x0141 && c <= 0x0148 ||
  		c >= 0x014A && c <= 0x017E ||
  		c >= 0x0180 && c <= 0x01C3 ||
  		c >= 0x01CD && c <= 0x01F0 ||
  		c >= 0x01F4 && c <= 0x01F5 ||
  		c >= 0x01FA && c <= 0x0217 ||
  		c >= 0x0250 && c <= 0x02A8 ||
  		c >= 0x02BB && c <= 0x02C1 ||
  		c == 0x0386 ||
  		c >= 0x0388 && c <= 0x038A ||
  		c == 0x038C ||
  		c >= 0x038E && c <= 0x03A1 ||
  		c >= 0x03A3 && c <= 0x03CE ||
  		c >= 0x03D0 && c <= 0x03D6 ||
  		c == 0x03DA ||
  		c == 0x03DC ||
  		c == 0x03DE ||
  		c == 0x03E0 ||
  		c >= 0x03E2 && c <= 0x03F3 ||
  		c >= 0x0401 && c <= 0x040C ||
  		c >= 0x040E && c <= 0x044F ||
  		c >= 0x0451 && c <= 0x045C ||
  		c >= 0x045E && c <= 0x0481 ||
  		c >= 0x0490 && c <= 0x04C4 ||
  		c >= 0x04C7 && c <= 0x04C8 ||
  		c >= 0x04CB && c <= 0x04CC ||
  		c >= 0x04D0 && c <= 0x04EB ||
  		c >= 0x04EE && c <= 0x04F5 ||
  		c >= 0x04F8 && c <= 0x04F9 ||
  		c >= 0x0531 && c <= 0x0556 ||
  		c == 0x0559 ||
  		c >= 0x0561 && c <= 0x0586 ||
  		c >= 0x05D0 && c <= 0x05EA ||
  		c >= 0x05F0 && c <= 0x05F2 ||
  		c >= 0x0621 && c <= 0x063A ||
  		c >= 0x0641 && c <= 0x064A ||
  		c >= 0x0671 && c <= 0x06B7 ||
  		c >= 0x06BA && c <= 0x06BE ||
  		c >= 0x06C0 && c <= 0x06CE ||
  		c >= 0x06D0 && c <= 0x06D3 ||
  		c == 0x06D5 ||
  		c >= 0x06E5 && c <= 0x06E6 ||
  		c >= 0x0905 && c <= 0x0939 ||
  		c == 0x093D ||
  		c >= 0x0958 && c <= 0x0961 ||
  		c >= 0x0985 && c <= 0x098C ||
  		c >= 0x098F && c <= 0x0990 ||
  		c >= 0x0993 && c <= 0x09A8 ||
  		c >= 0x09AA && c <= 0x09B0 ||
  		c == 0x09B2 ||
  		c >= 0x09B6 && c <= 0x09B9 ||
  		c >= 0x09DC && c <= 0x09DD ||
  		c >= 0x09DF && c <= 0x09E1 ||
  		c >= 0x09F0 && c <= 0x09F1 ||
  		c >= 0x0A05 && c <= 0x0A0A ||
  		c >= 0x0A0F && c <= 0x0A10 ||
  		c >= 0x0A13 && c <= 0x0A28 ||
  		c >= 0x0A2A && c <= 0x0A30 ||
  		c >= 0x0A32 && c <= 0x0A33 ||
  		c >= 0x0A35 && c <= 0x0A36 ||
  		c >= 0x0A38 && c <= 0x0A39 ||
  		c >= 0x0A59 && c <= 0x0A5C ||
  		c == 0x0A5E ||
  		c >= 0x0A72 && c <= 0x0A74 ||
  		c >= 0x0A85 && c <= 0x0A8B ||
  		c == 0x0A8D ||
  		c >= 0x0A8F && c <= 0x0A91 ||
  		c >= 0x0A93 && c <= 0x0AA8 ||
  		c >= 0x0AAA && c <= 0x0AB0 ||
  		c >= 0x0AB2 && c <= 0x0AB3 ||
  		c >= 0x0AB5 && c <= 0x0AB9 ||
  		c == 0x0ABD ||
  		c == 0x0AE0 ||
  		c >= 0x0B05 && c <= 0x0B0C ||
  		c >= 0x0B0F && c <= 0x0B10 ||
  		c >= 0x0B13 && c <= 0x0B28 ||
  		c >= 0x0B2A && c <= 0x0B30 ||
  		c >= 0x0B32 && c <= 0x0B33 ||
  		c >= 0x0B36 && c <= 0x0B39 ||
  		c == 0x0B3D ||
  		c >= 0x0B5C && c <= 0x0B5D ||
  		c >= 0x0B5F && c <= 0x0B61 ||
  		c >= 0x0B85 && c <= 0x0B8A ||
  		c >= 0x0B8E && c <= 0x0B90 ||
  		c >= 0x0B92 && c <= 0x0B95 ||
  		c >= 0x0B99 && c <= 0x0B9A ||
  		c == 0x0B9C ||
  		c >= 0x0B9E && c <= 0x0B9F ||
  		c >= 0x0BA3 && c <= 0x0BA4 ||
  		c >= 0x0BA8 && c <= 0x0BAA ||
  		c >= 0x0BAE && c <= 0x0BB5 ||
  		c >= 0x0BB7 && c <= 0x0BB9 ||
  		c >= 0x0C05 && c <= 0x0C0C ||
  		c >= 0x0C0E && c <= 0x0C10 ||
  		c >= 0x0C12 && c <= 0x0C28 ||
  		c >= 0x0C2A && c <= 0x0C33 ||
  		c >= 0x0C35 && c <= 0x0C39 ||
  		c >= 0x0C60 && c <= 0x0C61 ||
  		c >= 0x0C85 && c <= 0x0C8C ||
  		c >= 0x0C8E && c <= 0x0C90 ||
  		c >= 0x0C92 && c <= 0x0CA8 ||
  		c >= 0x0CAA && c <= 0x0CB3 ||
  		c >= 0x0CB5 && c <= 0x0CB9 ||
  		c == 0x0CDE ||
  		c >= 0x0CE0 && c <= 0x0CE1 ||
  		c >= 0x0D05 && c <= 0x0D0C ||
  		c >= 0x0D0E && c <= 0x0D10 ||
  		c >= 0x0D12 && c <= 0x0D28 ||
  		c >= 0x0D2A && c <= 0x0D39 ||
  		c >= 0x0D60 && c <= 0x0D61 ||
  		c >= 0x0E01 && c <= 0x0E2E ||
  		c == 0x0E30 ||
  		c >= 0x0E32 && c <= 0x0E33 ||
  		c >= 0x0E40 && c <= 0x0E45 ||
  		c >= 0x0E81 && c <= 0x0E82 ||
  		c == 0x0E84 ||
  		c >= 0x0E87 && c <= 0x0E88 ||
  		c == 0x0E8A ||
  		c == 0x0E8D ||
  		c >= 0x0E94 && c <= 0x0E97 ||
  		c >= 0x0E99 && c <= 0x0E9F ||
  		c >= 0x0EA1 && c <= 0x0EA3 ||
  		c == 0x0EA5 ||
  		c == 0x0EA7 ||
  		c >= 0x0EAA && c <= 0x0EAB ||
  		c >= 0x0EAD && c <= 0x0EAE ||
  		c == 0x0EB0 ||
  		c >= 0x0EB2 && c <= 0x0EB3 ||
  		c == 0x0EBD ||
  		c >= 0x0EC0 && c <= 0x0EC4 ||
  		c >= 0x0F40 && c <= 0x0F47 ||
  		c >= 0x0F49 && c <= 0x0F69 ||
  		c >= 0x10A0 && c <= 0x10C5 ||
  		c >= 0x10D0 && c <= 0x10F6 ||
  		c == 0x1100 ||
  		c >= 0x1102 && c <= 0x1103 ||
  		c >= 0x1105 && c <= 0x1107 ||
  		c == 0x1109 ||
  		c >= 0x110B && c <= 0x110C ||
  		c >= 0x110E && c <= 0x1112 ||
  		c == 0x113C ||
  		c == 0x113E ||
  		c == 0x1140 ||
  		c == 0x114C ||
  		c == 0x114E ||
  		c == 0x1150 ||
  		c >= 0x1154 && c <= 0x1155 ||
  		c == 0x1159 ||
  		c >= 0x115F && c <= 0x1161 ||
  		c == 0x1163 ||
  		c == 0x1165 ||
  		c == 0x1167 ||
  		c == 0x1169 ||
  		c >= 0x116D && c <= 0x116E ||
  		c >= 0x1172 && c <= 0x1173 ||
  		c == 0x1175 ||
  		c == 0x119E ||
  		c == 0x11A8 ||
  		c == 0x11AB ||
  		c >= 0x11AE && c <= 0x11AF ||
  		c >= 0x11B7 && c <= 0x11B8 ||
  		c == 0x11BA ||
  		c >= 0x11BC && c <= 0x11C2 ||
  		c == 0x11EB ||
  		c == 0x11F0 ||
  		c == 0x11F9 ||
  		c >= 0x1E00 && c <= 0x1E9B ||
  		c >= 0x1EA0 && c <= 0x1EF9 ||
  		c >= 0x1F00 && c <= 0x1F15 ||
  		c >= 0x1F18 && c <= 0x1F1D ||
  		c >= 0x1F20 && c <= 0x1F45 ||
  		c >= 0x1F48 && c <= 0x1F4D ||
  		c >= 0x1F50 && c <= 0x1F57 ||
  		c == 0x1F59 ||
  		c == 0x1F5B ||
  		c == 0x1F5D ||
  		c >= 0x1F5F && c <= 0x1F7D ||
  		c >= 0x1F80 && c <= 0x1FB4 ||
  		c >= 0x1FB6 && c <= 0x1FBC ||
  		c == 0x1FBE ||
  		c >= 0x1FC2 && c <= 0x1FC4 ||
  		c >= 0x1FC6 && c <= 0x1FCC ||
  		c >= 0x1FD0 && c <= 0x1FD3 ||
  		c >= 0x1FD6 && c <= 0x1FDB ||
  		c >= 0x1FE0 && c <= 0x1FEC ||
  		c >= 0x1FF2 && c <= 0x1FF4 ||
  		c >= 0x1FF6 && c <= 0x1FFC ||
  		c == 0x2126 ||
  		c >= 0x212A && c <= 0x212B ||
  		c == 0x212E ||
  		c >= 0x2180 && c <= 0x2182 ||
  		c >= 0x3041 && c <= 0x3094 ||
  		c >= 0x30A1 && c <= 0x30FA ||
  		c >= 0x3105 && c <= 0x312C ||
  		c >= 0xAC00 && c <= 0xD7A3 ||
  		c >= 0x4E00 && c <= 0x9FA5 ||
  		c == 0x3007 ||
  		c >= 0x3021 && c <= 0x3029;
  };
  
  Utilities.isNCNameChar = function(c) {
  	return c >= 0x0030 && c <= 0x0039 
  		|| c >= 0x0660 && c <= 0x0669 
  		|| c >= 0x06F0 && c <= 0x06F9 
  		|| c >= 0x0966 && c <= 0x096F 
  		|| c >= 0x09E6 && c <= 0x09EF 
  		|| c >= 0x0A66 && c <= 0x0A6F 
  		|| c >= 0x0AE6 && c <= 0x0AEF 
  		|| c >= 0x0B66 && c <= 0x0B6F 
  		|| c >= 0x0BE7 && c <= 0x0BEF 
  		|| c >= 0x0C66 && c <= 0x0C6F 
  		|| c >= 0x0CE6 && c <= 0x0CEF 
  		|| c >= 0x0D66 && c <= 0x0D6F 
  		|| c >= 0x0E50 && c <= 0x0E59 
  		|| c >= 0x0ED0 && c <= 0x0ED9 
  		|| c >= 0x0F20 && c <= 0x0F29
  		|| c == 0x002E
  		|| c == 0x002D
  		|| c == 0x005F
  		|| Utilities.isLetter(c)
  		|| c >= 0x0300 && c <= 0x0345 
  		|| c >= 0x0360 && c <= 0x0361 
  		|| c >= 0x0483 && c <= 0x0486 
  		|| c >= 0x0591 && c <= 0x05A1 
  		|| c >= 0x05A3 && c <= 0x05B9 
  		|| c >= 0x05BB && c <= 0x05BD 
  		|| c == 0x05BF 
  		|| c >= 0x05C1 && c <= 0x05C2 
  		|| c == 0x05C4 
  		|| c >= 0x064B && c <= 0x0652 
  		|| c == 0x0670 
  		|| c >= 0x06D6 && c <= 0x06DC 
  		|| c >= 0x06DD && c <= 0x06DF 
  		|| c >= 0x06E0 && c <= 0x06E4 
  		|| c >= 0x06E7 && c <= 0x06E8 
  		|| c >= 0x06EA && c <= 0x06ED 
  		|| c >= 0x0901 && c <= 0x0903 
  		|| c == 0x093C 
  		|| c >= 0x093E && c <= 0x094C 
  		|| c == 0x094D 
  		|| c >= 0x0951 && c <= 0x0954 
  		|| c >= 0x0962 && c <= 0x0963 
  		|| c >= 0x0981 && c <= 0x0983 
  		|| c == 0x09BC 
  		|| c == 0x09BE 
  		|| c == 0x09BF 
  		|| c >= 0x09C0 && c <= 0x09C4 
  		|| c >= 0x09C7 && c <= 0x09C8 
  		|| c >= 0x09CB && c <= 0x09CD 
  		|| c == 0x09D7 
  		|| c >= 0x09E2 && c <= 0x09E3 
  		|| c == 0x0A02 
  		|| c == 0x0A3C 
  		|| c == 0x0A3E 
  		|| c == 0x0A3F 
  		|| c >= 0x0A40 && c <= 0x0A42 
  		|| c >= 0x0A47 && c <= 0x0A48 
  		|| c >= 0x0A4B && c <= 0x0A4D 
  		|| c >= 0x0A70 && c <= 0x0A71 
  		|| c >= 0x0A81 && c <= 0x0A83 
  		|| c == 0x0ABC 
  		|| c >= 0x0ABE && c <= 0x0AC5 
  		|| c >= 0x0AC7 && c <= 0x0AC9 
  		|| c >= 0x0ACB && c <= 0x0ACD 
  		|| c >= 0x0B01 && c <= 0x0B03 
  		|| c == 0x0B3C 
  		|| c >= 0x0B3E && c <= 0x0B43 
  		|| c >= 0x0B47 && c <= 0x0B48 
  		|| c >= 0x0B4B && c <= 0x0B4D 
  		|| c >= 0x0B56 && c <= 0x0B57 
  		|| c >= 0x0B82 && c <= 0x0B83 
  		|| c >= 0x0BBE && c <= 0x0BC2 
  		|| c >= 0x0BC6 && c <= 0x0BC8 
  		|| c >= 0x0BCA && c <= 0x0BCD 
  		|| c == 0x0BD7 
  		|| c >= 0x0C01 && c <= 0x0C03 
  		|| c >= 0x0C3E && c <= 0x0C44 
  		|| c >= 0x0C46 && c <= 0x0C48 
  		|| c >= 0x0C4A && c <= 0x0C4D 
  		|| c >= 0x0C55 && c <= 0x0C56 
  		|| c >= 0x0C82 && c <= 0x0C83 
  		|| c >= 0x0CBE && c <= 0x0CC4 
  		|| c >= 0x0CC6 && c <= 0x0CC8 
  		|| c >= 0x0CCA && c <= 0x0CCD 
  		|| c >= 0x0CD5 && c <= 0x0CD6 
  		|| c >= 0x0D02 && c <= 0x0D03 
  		|| c >= 0x0D3E && c <= 0x0D43 
  		|| c >= 0x0D46 && c <= 0x0D48 
  		|| c >= 0x0D4A && c <= 0x0D4D 
  		|| c == 0x0D57 
  		|| c == 0x0E31 
  		|| c >= 0x0E34 && c <= 0x0E3A 
  		|| c >= 0x0E47 && c <= 0x0E4E 
  		|| c == 0x0EB1 
  		|| c >= 0x0EB4 && c <= 0x0EB9 
  		|| c >= 0x0EBB && c <= 0x0EBC 
  		|| c >= 0x0EC8 && c <= 0x0ECD 
  		|| c >= 0x0F18 && c <= 0x0F19 
  		|| c == 0x0F35 
  		|| c == 0x0F37 
  		|| c == 0x0F39 
  		|| c == 0x0F3E 
  		|| c == 0x0F3F 
  		|| c >= 0x0F71 && c <= 0x0F84 
  		|| c >= 0x0F86 && c <= 0x0F8B 
  		|| c >= 0x0F90 && c <= 0x0F95 
  		|| c == 0x0F97 
  		|| c >= 0x0F99 && c <= 0x0FAD 
  		|| c >= 0x0FB1 && c <= 0x0FB7 
  		|| c == 0x0FB9 
  		|| c >= 0x20D0 && c <= 0x20DC 
  		|| c == 0x20E1 
  		|| c >= 0x302A && c <= 0x302F 
  		|| c == 0x3099 
  		|| c == 0x309A
  		|| c == 0x00B7 
  		|| c == 0x02D0 
  		|| c == 0x02D1 
  		|| c == 0x0387 
  		|| c == 0x0640 
  		|| c == 0x0E46 
  		|| c == 0x0EC6 
  		|| c == 0x3005 
  		|| c >= 0x3031 && c <= 0x3035 
  		|| c >= 0x309D && c <= 0x309E 
  		|| c >= 0x30FC && c <= 0x30FE;
  };
  
  Utilities.coalesceText = function(n) {
  	for (var m = n.firstChild; m != null; m = m.nextSibling) {
  		if (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) {
  			var s = m.nodeValue;
  			var first = m;
  			m = m.nextSibling;
  			while (m != null && (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/)) {
  				s += m.nodeValue;
  				var del = m;
  				m = m.nextSibling;
  				del.parentNode.removeChild(del);
  			}
  			if (first.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) {
  				var p = first.parentNode;
  				if (first.nextSibling == null) {
  					p.removeChild(first);
  					p.appendChild(p.ownerDocument.createTextNode(s));
  				} else {
  					var next = first.nextSibling;
  					p.removeChild(first);
  					p.insertBefore(p.ownerDocument.createTextNode(s), next);
  				}
  			} else {
  				first.nodeValue = s;
  			}
  			if (m == null) {
  				break;
  			}
  		} else if (m.nodeType == 1 /*Node.ELEMENT_NODE*/) {
  			Utilities.coalesceText(m);
  		}
  	}
  };
  
  Utilities.instance_of = function(o, c) {
  	while (o != null) {
  		if (o.constructor === c) {
  			return true;
  		}
  		if (o === Object) {
  			return false;
  		}
  		o = o.constructor.superclass;
  	}
  	return false;
  };
  
  Utilities.getElementById = function(n, id) {
  	// Note that this does not check the DTD to check for actual
  	// attributes of type ID, so this may be a bit wrong.
  	if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) {
  		if (n.getAttribute("id") == id
  				|| n.getAttributeNS(null, "id") == id) {
  			return n;
  		}
  	}
  	for (var m = n.firstChild; m != null; m = m.nextSibling) {
  		var res = Utilities.getElementById(m, id);
  		if (res != null) {
  			return res;
  		}
  	}
  	return null;
  };
  