


   //Upgrader Scrollers
   // This code is from the book JavaScript: The Definitive Guide, 5th Edition,
   // This code is from the book JavaScript: The Definitive Guide, 5th Edition,
// by David Flanagan. Copyright 2006 O'Reilly Media, Inc. (ISBN #0596101996)
/*
 * Handler.js -- Portable event handler registration functions
 *
 * This module defines event handler registration and deregistration functions
 * Handler.add() and Handler.remove(). Both functions take three arguments:
 *
 *   element: the DOM element, document, or window on which the handler
 *      is to be added or removed.
 *
 *   eventType: a string that specifies the type of event for which the
 *      handler is to be invoked.  Use DOM-standard type names, which do
 *      not include an "on" prefix. Examples: "click", "load", "mouseover".
 *
 *   handler: The function to be invoked when an event of the specified type
 *      occurs on the specified element.  This function will be invoked as
 *      a method of the element on which it is registered, and the "this"
 *      keyword will refer to that element.  The handler function will be
 *      passed an event object as its sole argument.  This event object will
 *      either be a DOM-standard Event object or a simulated one. If a
 *      simulated event object is passed, it will have the following DOM-
 *      compliant properties: type, target, currentTarget, relatedTarget,
 *      eventPhase, clientX, clientY, screenX, screenY, altKey, ctrlKey,
 *      shiftKey, charCode, stopPropagation(), and preventDefault()
 *
 * Handler.add() and Handler.remove() have no return value.
 *
 * Handler.add() ignores duplicate registrations of the same handler for
 * the same event type and element.  Handler.remove() does nothing if called
 * to remove a handler that has not been registered.
 *
 * Implementation notes:
 *
 * In browsers that support the DOM standard addEventListener() and
 * removeEventListener() event registration functions, Handler.add() and
 * Handler.remove() simply invoke these functions, passing false as the
 * third argument (meaning that the event handlers are never registered as
 * capturing event handlers).
 *
 * In versions of Internet Explorer that support attachEvent(), Handler.add()
 * and Handler.remove() use attachEvent() and detachEvent(). To
 * invoke the handler function with the correct this keyword, a closure is
 * used.  Since closures of this sort cause memory leaks in Internet Explorer,
 * Handler.add() automatically registers an onunload handler to deregister
 * all event handlers when the page is unloaded. To keep track of
 * registered handlers, Handler.add() creates a property named _allHandlers on
 * the window object and creates a property named _handlers on any element on
 * which a handler is registered.
 */
var Handler = {};

// In DOM-compliant browsers, our functions are trivial wrappers around
// addEventListener() and removeEventListener().
if (document.addEventListener) {
    Handler.add = function(element, eventType, handler) {
        element.addEventListener(eventType, handler, false);
    };

    Handler.remove = function(element, eventType, handler) {
        element.removeEventListener(eventType, handler, false);
    };
}
// In IE 5 and later, we use attachEvent() and detachEvent(), with a number of
// hacks to make them compatible with addEventListener and removeEventListener.
else if (document.attachEvent) {
    Handler.add = function(element, eventType, handler) {
        // Don't allow duplicate handler registrations
        // _find() is a private utility function defined below.
        if (Handler._find(element, eventType, handler) != -1) return;

        // To invoke the handler function as a method of the
        // element, we've got to define this nested function and register
        // it instead of the handler function itself.
        var wrappedHandler = function(e) {
            if (!e) e = window.event;

            // Create a synthetic event object with partial compatibility
            // with DOM events.
            var event = {
                _event: e,    // In case we really want the IE event object
                type: e.type,           // Event type
                target: e.srcElement,   // Where the event happened
                currentTarget: element, // Where we're handling it
                relatedTarget: e.fromElement?e.fromElement:e.toElement,
                eventPhase: (e.srcElement==element)?2:3,

                // Mouse coordinates
                clientX: e.clientX, clientY: e.clientY,
                screenX: e.screenX, screenY: e.screenY,

                // Key state
                altKey: e.altKey, ctrlKey: e.ctrlKey,
                shiftKey: e.shiftKey, charCode: e.keyCode,

                // Event management functions
                stopPropagation: function() {this._event.cancelBubble = true;},
                preventDefault: function() {this._event.returnValue = false;}
            }

            // Invoke the handler function as a method of the element, passing
            // the synthetic event object as its single argument.
            // Use Function.call() if defined; otherwise do a hack
            if (Function.prototype.call)
                handler.call(element, event);
            else {
                // If we don't have Function.call, fake it like this
                element._currentHandler = handler;
                element._currentHandler(event);
                element._currentHandler = null;
            }
        };

        // Now register that nested function as our event handler.
        element.attachEvent("on" + eventType, wrappedHandler);

        // Now we must do some record keeping to associate the user-supplied
        // handler function and the nested function that invokes it.

        // We have to do this so that we can deregister the handler with the
        // remove() method and also deregister it automatically on page unload.

        // Store all info about this handler into an object
        var h = {
            element: element,
            eventType: eventType,
            handler: handler,
            wrappedHandler: wrappedHandler
        };

        // Figure out what document this handler is part of.
        // If the element has no "document" property, it is not
        // a window or a document element, so it must be the document
        // object itself.
        var d = element.document || element;
        // Now get the window associated with that document
        var w = d.parentWindow;

        // We have to associate this handler with the window,
        // so we can remove it when the window is unloaded
        var id = Handler._uid();  // Generate a unique property name
        if (!w._allHandlers) w._allHandlers = {};  // Create object if needed
        w._allHandlers[id] = h; // Store the handler info in this object

        // And associate the id of the handler info with this element as well
        if (!element._handlers) element._handlers = [];
        element._handlers.push(id);

        // If there is not an onunload handler associated with the window,
        // register one now.
        if (!w._onunloadHandlerRegistered) {
            w._onunloadHandlerRegistered = true;
            w.attachEvent("onunload", Handler._removeAllHandlers);
        }
    };

    Handler.remove = function(element, eventType, handler) {
        // Find this handler in the element._handlers[] array.
        var i = Handler._find(element, eventType, handler);
        if (i == -1) return;  // If the handler was not registered, do nothing

        // Get the window of this element
        var d = element.document || element;
        var w = d.parentWindow;

        // Look up the unique id of this handler
        var handlerId = element._handlers[i];
        // And use that to look up the handler info
        var h = w._allHandlers[handlerId];
        // Using that info, we can detach the handler from the element
        element.detachEvent("on" + eventType, h.wrappedHandler);
        // Remove one element from the element._handlers array
        element._handlers.splice(i, 1);
        // And delete the handler info from the per-window _allHandlers object
        delete w._allHandlers[handlerId];
    };

    // A utility function to find a handler in the element._handlers array
    // Returns an array index or -1 if no matching handler is found
    Handler._find = function(element, eventType, handler) {
        var handlers = element._handlers;
        if (!handlers) return -1;  // if no handlers registered, nothing found

        // Get the window of this element
        var d = element.document || element;
        var w = d.parentWindow;

        // Loop through the handlers associated with this element, looking
        // for one with the right type and function.
        // We loop backward because the most recently registered handler
        // is most likely to be the first removed one.
        for(var i = handlers.length-1; i >= 0; i--) {
            var handlerId = handlers[i];        // get handler id
            var h = w._allHandlers[handlerId];  // get handler info
            // If handler info matches type and handler function, we found it.
            if (h.eventType == eventType && h.handler == handler)
                return i;
        }
        return -1;  // No match found
    };

    Handler._removeAllHandlers = function() {
        // This function is registered as the onunload handler with
        // attachEvent.  This means that the this keyword refers to the
        // window in which the event occurred.
        var w = this;

        // Iterate through all registered handlers
        for(id in w._allHandlers) {
            // Get handler info for this handler id
            var h = w._allHandlers[id];
            // Use the info to detach the handler
            h.element.detachEvent("on" + h.eventType, h.wrappedHandler);
            // Delete the handler info from the window
            delete w._allHandlers[id];
        }
    }

    // Private utility to generate unique handler ids
    Handler._counter = 0;
    Handler._uid = function() { return "h" + Handler._counter++; };
}





// This code is from the book JavaScript: The Definitive Guide, 5th Edition,
// by David Flanagan. Copyright 2006 O'Reilly Media, Inc. (ISBN #0596101996)
/*
 * runOnLoad.js: portable registration for onload event handlers.
 *
 * This module defines a single runOnLoad() function for portably registering
 * functions that can be safely invoked only when the document is fully loaded
 * and the DOM is available.
 *
 * Functions registered with runOnLoad() will not be passed any arguments when
 * invoked. They will not be invoked as a method of any meaningful object, and
 * the this keyword should not be used.  Functions registered with runOnLoad()
 * will be invoked in the order in which they were registered.  There is no
 * way to deregister a function once it has been passed to runOnLoad().
 *
 * In old browsers that do not support addEventListener() or attachEvent(),
 * this function relies on the DOM Level 0 window.onload property and will not
 * work correctly when used in documents that set the onload attribute
 * of their body or frameset tags.
 */
function runOnLoad(f) {
    if (runOnLoad.loaded) f();    // If already loaded, just invoke f() now.
    else runOnLoad.funcs.push(f); // Otherwise, store it for later
}

runOnLoad.funcs = []; // The array of functions to call when the document loads
runOnLoad.loaded = false; // The functions have not been run yet.

// Run all registered functions in the order in which they were registered.
// It is safe to call runOnLoad.run() more than once: invocations after the
// first do nothing. It is safe for an initialization function to call
// runOnLoad() to register another function.
runOnLoad.run = function() {
    if (runOnLoad.loaded) return;  // If we've already run, do nothing
    for(var i = 0; i < runOnLoad.funcs.length; i++) {
        try { runOnLoad.funcs[i](); }
        catch(e) { /* An exception in one function shouldn't stop the rest */ }
    }

    runOnLoad.loaded = true; // Remember that we've already run once.
    delete runOnLoad.funcs;  // But don't remember the functions themselves.
    delete runOnLoad.run;    // And forget about this function too!
};

// Register runOnLoad.run() as the onload event handler for the window
if (window.addEventListener)
    window.addEventListener("load", runOnLoad.run, false);
else if (window.attachEvent) window.attachEvent("onload", runOnLoad.run);
else window.onload = runOnLoad.run;






function CNT_ScrollBar(scrollAreaId, scrollBarId, autoHide)
{
  /* self-referencing instance variable; needed for event handling and execution contexts
  where 'this' refers to something else */
  var myself = this;

  this.scrollActiveIntervalId = null;
  this.scrollInterval = 50;
  this.scrollStep = 50;
  this.autoHide = (autoHide == null) ? false : autoHide;
  this.isScrollBarHidden = false;
  this.scrollJumpOffsetFactor = 0.5;

  this.doScrollUp_interval = function()
  {
    with (myself) {
      scrollArea.scrollTop = Math.max(scrollArea.scrollTop - scrollStep, 0);
      doAdjustScrollBar();
    }
  }



  this.doScrollDown_interval = function()
  {
    with (myself) {
      scrollArea.scrollTop = Math.min(scrollArea.scrollHeight - scrollArea.clientHeight, scrollArea.scrollTop + scrollStep);
      doAdjustScrollBar();
    }
  }



  this.handleDocumentEvent = function(e)
  {
    e.preventDefault();
    e.stopPropagation();

    with (myself) {
      if (e.type == "mousemove") {
        event_document_mousemove(e);
      }
      else if (e.type == "mouseup") {
        event_document_mouseup(e);
      }
    }

  }



  this.handleScrollAreaEvent = function(e)
  {
    var className = e.target.className;
    if (!className)
      className = "";

    with (myself) {
      if (!myself.isScrollBarHidden && (e.type == "DOMMouseScroll" || e.type == "mousewheel")) {
        e.preventDefault();
        e.stopPropagation();
        event_scrollArea_wheel(e);
      }
    }
  }

  this.handleScrollBarEvent = function(e)
  {
    var className = e.target.className;
    if (!className)
      className || "";

    e.preventDefault();
    e.stopPropagation();

    with (myself) {
      /* need to handle thumb first before trough, because thumb is a descendant of trough */
      if (/\bcnt-scroll-thumb\b/.test(className) || isNodeOrDescendant(e.target, scrollThumb)) {
        if (e.type == "mousedown")
          event_thumb_mousedown(e);
      }
      else if (/\bcnt-scroll-trough\b/.test(className) || isNodeOrDescendant(e.target, scrollTrough)) {
        if (e.type == "mousedown")
          event_trough_mousedown(e);
      }
      else if (/\bcnt-scroll-button-up\b/.test(className) || isNodeOrDescendant(e.target, scrollButtonUp)) {
        if (e.type == "mousedown")
          event_buttonUp_mousedown(e);
      }
      else if (/\bcnt-scroll-button-down\b/.test(className) || isNodeOrDescendant(e.target, scrollButtonDown)) {
        if (e.type == "mousedown")
          event_buttonDown_mousedown(e);
      }
    }
  }

  this.scrollAreaId = scrollAreaId;
  this.scrollBarId = scrollBarId;
  this.scrollArea = document.getElementById(scrollAreaId);
  this.scrollArea.scrollBar = this;
  this.scrollBar = document.getElementById(scrollBarId);

  this.scrollButtonUp = getElementsByClass("scroll-button-up", this.scrollBar, "div")[0];
  this.scrollButtonDown = getElementsByClass("scroll-button-down", this.scrollBar, "div")[0];
  this.scrollTrough = getElementsByClass("scroll-trough", this.scrollBar, "div")[0];
  this.scrollThumb = getElementsByClass("scroll-thumb", this.scrollTrough, "div")[0];

  Handler.add(this.scrollBar, "mousedown", this.handleScrollBarEvent);

  Handler.add(this.scrollArea, "DOMMouseScroll", this.handleScrollAreaEvent);
  Handler.add(this.scrollBar, "DOMMouseScroll", this.handleScrollAreaEvent);
  Handler.add(this.scrollArea, "mousewheel", this.handleScrollAreaEvent);
  Handler.add(this.scrollBar, "mousewheel", this.handleScrollAreaEvent);
  this.scrollArea.onmousewheel = this.scrollBar.onmousewheel = function()
  {
    myself.event_scrollArea_wheel(window.event);
  }

  this.doAdjustScrollBar();
}

CNT_ScrollBar.prototype.doScrollUp = function()
{
  this.scrollActiveIntervalId = setInterval(this.doScrollUp_interval, this.scrollInterval);
}

CNT_ScrollBar.prototype.doScrollDown = function()
{
  this.scrollActiveIntervalId = setInterval(this.doScrollDown_interval, this.scrollInterval);
}

CNT_ScrollBar.prototype.doScrollJump = function(y)
{
  this.scrollArea.scrollTop = y;
  this.doAdjustScrollBar();
}

CNT_ScrollBar.prototype.doScrollJumpToId = function(id)
{
  var element = document.getElementById(id);
  if (element && element != this.scrollArea && isNodeOrDescendant(element, this.scrollArea))
    this.doScrollJump(getOffsetFrom(element, this.scrollArea) - this.scrollArea.clientHeight * this.scrollJumpOffsetFactor);
}

CNT_ScrollBar.prototype.doAdjustScrollBar = function()
{
  if (this.scrollArea.clientHeight == 0 && this.scrollArea.scrollHeight == 0)
  {


  }
  else if ((this.scrollArea.clientHeight >= this.scrollArea.scrollHeight) || this.scrollArea.clientHeight == 0) {
    this.scrollThumb.style.height = this.scrollTrough.clientHeight + "px";
    if (this.autoHide) {
      this.isScrollBarHidden = true;
      this.scrollBar.style.display = "none";
      if (isSafari) {  // workaround for Safari float layout flow bug
        this.scrollArea.style.width = "100%";
      }
    }
  }
  else {
    var thumbHeightFrac = this.scrollArea.clientHeight / this.scrollArea.scrollHeight;

    if (isNaN(thumbHeightFrac) || !isFinite(thumbHeightFrac))
      thumbHeight = 1.0;

    thumbHeightFrac = Math.max(0.1, thumbHeightFrac);


    if (thumbHeightFrac == 1.0 && this.autoHide) {
      this.isScrollBarHidden = true;
      this.scrollBar.style.display = "none";
      if (isSafari) { // workaround for Safari float layout flow bug
        this.scrollArea.style.width = "100%";
      }
    }
    else {
      this.isScrollBarHidden = false;
      this.scrollBar.style.display = "block";
      if (isSafari) { // workaround for Safari float layout flow bug
        this.scrollArea.style.width = "";
      }
    }

    var thumbHeightPx = Math.round(this.scrollTrough.clientHeight * thumbHeightFrac);
    /*
    if (this.thumbHeightPx != thumbHeightPx)
    {
      if( this.scrollArea.id == 'hotlist-style-scroll-area2' || this.scrollArea.id == 'features-style-scroll-area2' ||
          this.scrollArea.id == 'hotlist-gear-scroll-area2' || this.scrollArea.id == 'features-gear-scroll-area2' ||
          this.scrollArea.id == 'hotlist-living-scroll-area2' || this.scrollArea.id == 'features-living-scroll-area2')
      {
        this.scrollThumb.style.height = "19px";
      }
      else
/* (this.thumbHeightPx = thumbHeightPx) +
        this.scrollThumb.style.height = "30px";
    }    */

  }

  var scrollAreaPercent = this.scrollArea.scrollTop / (this.scrollArea.scrollHeight - this.scrollArea.clientHeight);

  var thumbTop = scrollAreaPercent * (this.scrollTrough.clientHeight - this.scrollThumb.clientHeight);

  /* if thumb is at the bottom, align it exactly with the bottom */
  thumbTop = Math.min(thumbTop, this.scrollTrough.clientHeight - this.scrollThumb.clientHeight);
  /* if thumb is at the top, align it exactly with the top */
  if (this.scrollArea.scrollTop == 0)
    thumbTop = 0;

  thumbTop = Math.round(thumbTop);

  if (this.thumbTop != thumbTop)
    this.scrollThumb.style.top = (this.thumbTop = thumbTop) + "px";

}

CNT_ScrollBar.prototype.stopScroll = function()
{
  clearInterval(this.scrollActiveIntervalId);
}

CNT_ScrollBar.prototype.event_trough_mousedown = function(e)
{
  var absoluteY = e.clientY + ((isIE && (isIE < 7)) ? document.body.scrollTop : document.documentElement.scrollTop);
  var relativeY = absoluteY - getTotalOffset(this.scrollTrough); // relative to trough
  var relativeThumbOffset = Math.round(Math.max(Math.min(relativeY - this.scrollThumb.clientHeight / 2.0, this.scrollTrough.clientHeight - this.scrollThumb.clientHeight), 0));
  var scrollAreaPercent = relativeThumbOffset / (this.scrollTrough.clientHeight - this.scrollThumb.clientHeight);
  var scrollAreaScrollTop = Math.round((this.scrollArea.scrollHeight - this.scrollArea.clientHeight) * scrollAreaPercent);
  this.scrollArea.scrollTop = scrollAreaScrollTop;
  this.scrollThumb.style.top = "" + relativeThumbOffset + "px";
  this.event_thumb_mousedown(e);
}

CNT_ScrollBar.prototype.event_scrollArea_wheel = function(e)
{
  if (e.detail) {
    if (e.detail < 0)
      this.doScrollUp_interval();
    else
      this.doScrollDown_interval();
  }
  else if (e.wheelDelta) {
    if (e.wheelDelta > 0)
      this.doScrollUp_interval();
    else
      this.doScrollDown_interval();
  }
}

CNT_ScrollBar.prototype.event_buttonDown_mousedown = function(e)
{
  Handler.add(document, "mouseup", this.handleDocumentEvent);
  this.doScrollDown();
}

CNT_ScrollBar.prototype.event_buttonUp_mousedown = function(e)
{
  Handler.add(document, "mouseup", this.handleDocumentEvent);
  this.doScrollUp();
}



/**
 * This function handles the mouseup event when it is registered on the document
 * element.  In the CNT_ScrollBar object, this event is only triggered for
 * the scroll up and down buttons, or when the thumb is released from being
 * dragged.  The code is the same for all three cases, so no checking is
 * necessary to see which case occurred.
 */
CNT_ScrollBar.prototype.event_document_mouseup = function(e)
{
  /*
  The mousemove event is registered only for the duration of a thumb drag;
  if the thumb has been released, the event handler should be removed.
  if the thumb is not being dragged, removing the (non-existant) event is
  harmless.
  */
  Handler.remove(document, "mousemove", this.handleDocumentEvent);

  /*
  The mouseup event is registered only when a corresponding mousedown event
  is triggered over the scroll buttons or the thumb.  When the mouse button
  is released, the event is no longer needed and should be removed.
  */
  Handler.remove(document, "mouseup", this.handleDocumentEvent);

  /* in case the scroll buttons were pressed, so that the scrollarea was
  being scrolled at scrollInterval intervals, stop the scrolling */
  this.stopScroll();
}



CNT_ScrollBar.prototype.event_thumb_mousedown = function(e)
{
  Handler.add(document, "mousemove", this.handleDocumentEvent);
  Handler.add(document, "mouseup", this.handleDocumentEvent);
  this.scrollThumb.dragThumbOffsetY = e.clientY - getTotalOffset(this.scrollThumb) + document.documentElement.scrollTop;
}



/**
 * This function handles the mousemove event when it is registered on the document
 * element.  In the CNT_ScrollBar object, this only happens when the thumb is being
 * dragged, so this code assumes that is the case.
 */
CNT_ScrollBar.prototype.event_document_mousemove = function(e)
{
  var absoluteY = e.clientY + document.documentElement.scrollTop;
  var relativeY = absoluteY - getTotalOffset(this.scrollTrough); // relative to trough
  var relativeThumbOffset = Math.round(Math.max(Math.min(relativeY - this.scrollThumb.dragThumbOffsetY, this.scrollTrough.clientHeight - this.scrollThumb.clientHeight), 0));
  var scrollAreaPercent = relativeThumbOffset / (this.scrollTrough.clientHeight - this.scrollThumb.clientHeight);
  var scrollAreaScrollTop = Math.round((this.scrollArea.scrollHeight - this.scrollArea.clientHeight) * scrollAreaPercent);
  this.scrollArea.scrollTop = scrollAreaScrollTop;
  this.scrollThumb.style.top = "" + relativeThumbOffset + "px";
}


function getElementsByClass(searchClass, node, tag) {
  if (!(searchClass instanceof RegExp))
    searchClass = new RegExp("\\b" + searchClass + "\\b");
  var classElements = new Array();
  if (node == null)
    node = document;
  if (tag == null)
    tag = '*';
  var els = node.getElementsByTagName(tag);
  for (i = 0, j = 0; i < els.length; i++) {
    if (searchClass.test(els[i].className)) {
      classElements[j] = els[i];
      j++;
    }
  }
    return classElements;
} /* aliases: */ var getElementsByClassName = getElementsByClass;

var Navigator = {
  _getVersion: function (a, b) {
    var t = navigator.userAgent.split(a)[1];
    return (t) ? t.split(b)[0] : false;
  },
  isOpera: function () {
    return (
      (window.opera) ?
        (document.createElementNS) ?
          (document.createCDATASection) ?
            (document.styleSheets) ? 9 : 8
          : 7
        : 6
      : false
    );
  },
  isSafari: function () {
    return (document.createCDATASection && document.createElementNS) ? Navigator._getVersion('AppleWebKit/', '(') : false;
  },
  isKDE: function () {
    return (document.createCDATASection && document.createElementNS) ? Navigator._getVersion('Konqueror/', ';') : false;
  },
  isGecko: function () {
    return (document.createCDATASection && document.createElementNS) ? Navigator._getVersion('Gecko/', ' ') : false;
  },
  isNN4: function () {
    return (document.layers && typeof document.layers == 'object') ? true : false;
  },
  isWinIE: function () {
    return (
      /*@cc_on @if (@_win64 || @_win32 || @_win16)
      (document.getElementsByTagName) ?
        (@_jscript_version > 5.6) ? 7 :
        (@_jscript_version == 5.6) ? 6 :
        (@_jscript_version == 5.5) ? 5.5 :
        5
      : 4
      @else@*/false/*@end @*/
    );
  },
  isMacIE: function () {
    return (
      /*@cc_on @if (@_mac && (@_PowerPC || @_mc680x0))
        (document.getElementsByTagName) ? 5 : 4
      @else@*/false/*@end @*/
    );
  }
};

var isSafari = Navigator.isSafari();
var isIE = Navigator.isWinIE();

function getTotalOffset(element) {
  var total = 0;
  if (element.offsetParent)
    total += element.offsetTop + getTotalOffset(element.offsetParent);
  return total;
} /* aliases: */ var getOffset = getTotalOffset; var findPosY = getTotalOffset;



function isNodeOrDescendant(node, ancestor) {
  if (!node)
    return false;
  else if (node == ancestor)
    return true;
  else
    return isNodeOrDescendant(node.parentNode, ancestor);
} /* aliases: */ var isNodeOrDescendent = isNodeOrDescendant; var isDescendant = isNodeOrDescendant; var isDescendent = isNodeOrDescendant;
