docs: function XPathEvaluator(newDefaultEngineName) {
  // private
      var nativeEngine = new NativeEngine();
      var defaultEngineName = newDefaultEngineName || 'ajaxslt';
      var engines = {
          'ajaxslt'               : new AjaxsltEngine(),
          'javascript-xpath'      : new JavascriptXPathEngine(),
          'rpc-optimizing-ajaxslt': new MultiWindowRPCOptimizingEngine('test-doc-frame', new AjaxsltEngine()),
          'rpc-optimizing-jsxpath': new MultiWindowRPCOptimizingEngine('test-doc-frame', new JavascriptXPathEngine()),
          'native'                : nativeEngine
      };
  
      var currentEngineName = defaultEngineName;
      var allowNativeXPath = true;
      var ignoreAttributesWithoutValue = true;
  
      function preprocess(xpath) {
          // Trim any trailing "/": not valid xpath, and remains from attribute
          // locator.
          if (xpath.charAt(xpath.length - 1) == '/') {
              xpath = xpath.slice(0, -1);
          }
          // HUGE hack - remove namespace from xpath for IE
          if (browserVersion && browserVersion.isIE) {
              xpath = xpath.replace(/x:/g, '')
          }
  
          return xpath;
      }
  
      /**
       * Returns the most sensible engine given the settings and the document
       * object.
       */
      function getEngineFor(inDocument) {
          if (allowNativeXPath &&
              nativeEngine.setDocument(inDocument).isAvailable()) {
              return nativeEngine;
          }
  
          var currentEngine = engines[currentEngineName];
  
          if (currentEngine &&
              currentEngine.setDocument(inDocument).isAvailable()) {
              return currentEngine;
          }
  
          return engines[defaultEngineName].setDocument(inDocument);
      }
  
      /**
       * Dispatches an XPath evaluation method on the relevant engine for the
       * given document, and returns the result
       */
      function dispatch(methodName, inDocument, xpath, contextNode, namespaceResolver) {
          xpath = preprocess(xpath);
  
          if (! contextNode) {
              contextNode = inDocument;
          }
  
          var result = getEngineFor(inDocument)
              .setIgnoreAttributesWithoutValue(ignoreAttributesWithoutValue)
              [methodName](xpath, contextNode, namespaceResolver);
  
          return result;
      }
  
  // public
      /**
       * Registers a new engine by name, and returns whether the registration was
       * successful. Each registered engine must be an instance of XPathEngine.
       * The engines registered by default - "ajaxslt", "javascript-xpath",
       * "native", and "default" - can't be overwritten.
       */
      this.registerEngine = function(name, engine) {
          // can't overwrite one of these
          if (name == 'ajaxslt' ||
              name == 'javascript-xpath' ||
              name == 'native' ||
              name == 'default') {
              return false;
          }
  
          if (! (engine instanceof XPathEngine)) {
              return false;
          }
  
          engines[name] = engine;
          return true;
      };
  
      this.getRegisteredEngine = function(name) {
          return engines[name];
      };
  
      this.setCurrentEngine = function(name) {
          if (name == 'default') {
              currentEngineName = defaultEngineName;
          }
          else if (! engines[name]) {
              return;
          }
          else {
              currentEngineName = name;
          }
      };
  
      this.getCurrentEngine = function() {
          return currentEngineName || defaultEngineName;
      };
  
      this.setAllowNativeXPath = function(allow) {
          allowNativeXPath = allow;
      };
  
      this.isAllowNativeXPath = function() {
          return allowNativeXPath;
      };
  
      this.setIgnoreAttributesWithoutValue = function(ignore) {
          ignoreAttributesWithoutValue = ignore;
      };
  
      this.isIgnoreAttributesWithoutValue = function() {
          return ignoreAttributesWithoutValue;
      };
  
      this.selectNodes = function(inDocument, xpath, contextNode, namespaceResolver) {
          return dispatch('selectNodes', inDocument, xpath, contextNode,
              namespaceResolver);
      };
  
      this.selectSingleNode = function(inDocument, xpath, contextNode, namespaceResolver) {
          return dispatch('selectSingleNode', inDocument, xpath, contextNode,
              namespaceResolver);
      };
  
      this.countNodes = function(inDocument, xpath, contextNode, namespaceResolver) {
          return dispatch('countNodes', inDocument, xpath, contextNode,
              namespaceResolver);
      };
  
  // initialization
      this.init();
  }