function AdfGeckoAgent(version, domWindow) {
  if(arguments.length) {
    this.Init(version, domWindow)
  }
}
AdfObject.createSubclass(AdfGeckoAgent, AdfAgent);
AdfGeckoAgent.InitClass = function() {
  AdfGeckoAgent._NBSP_STRING = String.fromCharCode(160)
};
AdfGeckoAgent.__getAgentVersion = function(userAgent) {
  return AdfAgent.__parseFloatVersion(userAgent, /rv:(\d+[.]\d+)/)
};
AdfGeckoAgent.__getSupported = function(userAgent, version) {
  if(userAgent.indexOf("Firefox/") == -1) {
    return false
  }
  if(AdfAgent._MIN_FIREFOX_VERSION == 0) {
    return true
  }
  return version >= AdfAgent._MIN_FIREFOX_VERSION
};
AdfGeckoAgent.__getSpecificAgentClassName = function(userAgent, version) {
  var agentClassName;
  if(version >= 6) {
    agentClassName = "AdfGeckoAgent"
  }else {
    if(version >= 5) {
      agentClassName = "AdfGecko5Agent"
    }else {
      if(version >= 1.9) {
        agentClassName = "AdfGecko19Agent"
      }else {
        if(version >= 1.8) {
          agentClassName = "AdfGecko18Agent"
        }else {
          if(version >= 1) {
            agentClassName = "AdfGecko17Agent"
          }else {
            agentClassName = "AdfGeckoAgent"
          }
        }
      }
    }
  }
  return agentClassName
};
AdfGeckoAgent.prototype.Init = function(version, domWindow) {
  AdfGeckoAgent.superclass.Init.call(this, AdfAgent.GECKO_PLATFORM, AdfAgent.guessOS(), version, domWindow);
  this._ID_TO_DOM_MAP = new Object
};
AdfGeckoAgent.prototype.getElementById = function(id) {
  if(id == null) {
    return null
  }
  if(AdfAssert.DEBUG) {
    var cachedDom = this._ID_TO_DOM_MAP[id];
    var elementById = this.getDomDocument().getElementById(id);
    if(cachedDom != elementById) {
      AdfAssert.assert(false, "document.getElementById('" + id + "')\x3d\x3d" + elementById + " not " + cachedDom)
    }
  }
  return this._ID_TO_DOM_MAP[id]
};
AdfGeckoAgent.prototype._getSessionStorageKey = function(propKey) {
  var domWindow = this.getDomWindow();
  var protocol = domWindow.location.protocol;
  if(protocol) {
    return protocol + "_" + propKey
  }
  return propKey
};
AdfGeckoAgent.prototype.elementsRemoved = function(node) {
  var idToDomMap = this._ID_TO_DOM_MAP;
  var targetId = node.id;
  if(targetId != null) {
    delete idToDomMap[targetId]
  }
  if(node.firstChild) {
    var idNodes = this.getDomDocument().evaluate(".//*[@id]", node, null, XPathResult.ANY_TYPE, null);
    var currNode = idNodes.iterateNext();
    while(currNode) {
      var currId = currNode.getAttribute("id");
      if(currId) {
        delete idToDomMap[currId]
      }
      currNode = idNodes.iterateNext()
    }
  }
};
AdfGeckoAgent.prototype.allElementsRemoved = function() {
  this._ID_TO_DOM_MAP = new Object;
  this.elementsAdded(this.getDomDocument())
};
AdfGeckoAgent.prototype.elementsAdded = function(node) {
  var idToDomMap = this._ID_TO_DOM_MAP;
  var targetId = node.id;
  if(targetId != null) {
    idToDomMap[targetId] = node
  }
  if(node.firstChild) {
    var idNodes = this.getDomDocument().evaluate(".//*[@id]", node, null, XPathResult.ANY_TYPE, null);
    var currNode = idNodes.iterateNext();
    while(currNode) {
      var currId = currNode.getAttribute("id");
      if(currId) {
        idToDomMap[currId] = currNode
      }
      currNode = idNodes.iterateNext()
    }
  }
};
AdfGeckoAgent.prototype.setButtonTextContent = function(node, newText) {
  AdfAssert.assertDomNode(node);
  if(newText === null || newText.length == 0) {
    newText = AdfGeckoAgent._NBSP_STRING
  }
  node.textContent = newText
};
AdfGeckoAgent.prototype.disableUserSelect = function(element) {
  element.style.MozUserSelect = "none"
};
AdfGeckoAgent.prototype.enableUserSelect = function(element) {
  element.style.MozUserSelect = ""
};
AdfGeckoAgent.prototype.CreateUIInputEvent = function(component, type, nativeEvent) {
  if(nativeEvent.type == "click" && nativeEvent.button == 2) {
    return null
  }
  return new AdfGeckoUIInputEvent(component, type, nativeEvent)
};
AdfGeckoAgent.prototype.CreateDefaultLogWriter = function(nativeLogWriter) {
  var domWindow = this.getDomWindow();
  if(domWindow.console && domWindow.console["firebug"]) {
    return new AdfFireBugLogWriter(domWindow, nativeLogWriter)
  }else {
    return AdfGeckoAgent.superclass.CreateDefaultLogWriter.call(this, nativeLogWriter)
  }
};
AdfGeckoAgent.prototype.CreateNativeLogWriter = function() {
  return new AdfGeckoLogWriter
};
AdfGeckoAgent.prototype.getNodeType = function(element) {
  if(element) {
    try {
      return element.nodeType
    }catch(e) {
    }
  }
  return undefined
};
AdfGeckoAgent.prototype.getWindowClientWidth = function(domWindow) {
  return domWindow.innerWidth
};
AdfGeckoAgent.prototype.getWindowClientHeight = function(domWindow) {
  return domWindow.innerHeight
};
AdfGeckoAgent.prototype.pointInElementOrChildBounds = function(element, pageX, pageY) {
  if(this.pointInElementBounds(element, pageX, pageY)) {
    return true
  }
  if(!element.clientHeight && !element.clientWidth) {
    for(var parent = element.parentNode;parent;parent = parent.parentNode) {
      if(parent.clientWidth || parent.clientHeight) {
        if(this.pointInElementBounds(parent, pageX, pageY)) {
          break
        }
        return false
      }
    }
    for(var node = element.firstChild;node;node = node.nextSibling) {
      if(node.nodeType == 1) {
        if(node.style.position != "absolute") {
          if(this.pointInElementOrChildBounds(node, pageX, pageY)) {
            return true
          }
        }
      }
    }
  }
  return false
};
AdfGeckoAgent.prototype.isChromeEvent = function(domEvent) {
  try {
    domEvent.originalTarget.localName;
    return false
  }catch(e) {
    return true
  }
};
AdfGeckoAgent.prototype.setImageSource = function(img, src) {
  img.setAttribute("src", src);
  this._needsReset = true
};
AdfGeckoAgent.prototype.setImageTooltip = function(img, tooltip) {
  img.title = tooltip
};
AdfGeckoAgent.prototype.addEventBubbles = function(node, listener) {
  AdfGeckoAgent.superclass.addEventBubbles.call(this, node, listener);
  AdfGeckoAgent.superclass.addEventBubbles.call(this, node, AdfGeckoAgent._resetThrobber)
};
AdfGeckoAgent.prototype.removeEventBubbles = function(node, listener) {
  AdfGeckoAgent.superclass.addEventBubbles.call(this, node, listener);
  AdfGeckoAgent.superclass.removeEventBubbles.call(this, node, AdfGeckoAgent._resetThrobber)
};
AdfGeckoAgent.prototype.addKeyEventListener = function(node, listener) {
  AdfAssert.assertDomNode(node);
  AdfAssert.assertFunction(listener);
  node.addEventListener("keypress", listener, false)
};
AdfGeckoAgent.prototype.removeKeyEventListener = function(node, listener) {
  AdfAssert.assertDomNode(node);
  AdfAssert.assertFunction(listener);
  node.removeEventListener("keypress", listener, false)
};
AdfGeckoAgent._resetThrobber = function(event) {
  var gecko = AdfAgent.AGENT;
  if(gecko._needsReset) {
    gecko._needsReset = false;
    var ownerDocument = gecko.getDomDocument();
    var element = ownerDocument.documentElement;
    var frame = ownerDocument.createElement("iframe");
    frame.frameBorder = "0";
    frame.scrolling = "no";
    frame.style.zIndex = 900;
    frame.style.position = "absolute";
    frame.style.borderStyle = "none";
    frame.style.top = element.style.top;
    frame.style.left = element.style.left;
    frame.style.width = element.offsetWidth + "px";
    frame.style.height = element.offsetHeight + "px";
    ownerDocument.body.appendChild(frame);
    ownerDocument.body.removeChild(frame)
  }
};
AdfGeckoAgent.prototype.showBusyCursor = function(ownerDocument, show) {
  AdfGeckoAgent.superclass.showBusyCursor(ownerDocument, show);
  this.forceCursorChange(ownerDocument)
};
AdfGeckoAgent.prototype.isLeftButtonClick = function(evt) {
  return evt.type == "click" && evt.button == 0
};
AdfGeckoAgent.prototype.isFunctionKey = function(keyEvent) {
  return keyEvent.which == 0
};
AdfGeckoAgent.prototype.getKeyCode = function(keyEvent) {
  if(this.isFunctionKey(keyEvent)) {
    return keyEvent.keyCode
  }else {
    var code = keyEvent.which;
    if(code >= 97 && code <= 122) {
      return code - 32
    }else {
      return code
    }
  }
};
AdfGeckoAgent.prototype.isElementHTML = function(element) {
  AdfAssert.assertDomNode(element);
  return element instanceof HTMLElement
};
AdfGeckoAgent.prototype.removeIdsFromDomSubTree = function(subTreeRoot) {
  var id = subTreeRoot.id;
  if(id != null && id != "") {
    subTreeRoot.id = ""
  }
  if(subTreeRoot.firstChild) {
    var idNodes = this.getDomDocument().evaluate(".//*[@id]", subTreeRoot, null, XPathResult.ANY_TYPE, null);
    var currNode = idNodes.iterateNext();
    while(currNode) {
      var currId = currNode.id;
      if(currId != null && currId != "") {
        currNode.id = ""
      }
      currNode = idNodes.iterateNext()
    }
  }
};
AdfGeckoAgent.prototype.GetCssToDomPropertyNameMap = function() {
  return AdfGeckoAgent._CSS_TO_DOM_MAP
};
AdfGeckoAgent.prototype.getBoxSizing = function(element, currentStyle) {
  if(!currentStyle) {
    currentStyle = this.getComputedStyle(element)
  }
  return currentStyle.getPropertyValue("-moz-box-sizing")
};
AdfGeckoAgent._CSS_TO_DOM_MAP = {"float":"cssFloat"};
AdfGeckoAgent._MOZ_USER_DEFINED = "_moz-userdefined";
AdfGeckoAgent._FAKE_MOUSEMOVE_EVENT = undefined;
AdfGeckoAgent._getBoxObjectFor = function(elem) {
  var doc = elem.ownerDocument;
  if(doc.getBoxObjectFor) {
    return doc.getBoxObjectFor(elem)
  }
  var boundingRect = elem.getBoundingClientRect();
  var elemTop = Math.round(boundingRect.top);
  var elemLeft = Math.round(boundingRect.left);
  var elemWidth = Math.round(boundingRect.width);
  var elemHeight = Math.round(boundingRect.height);
  return{x:elemLeft, y:elemTop, width:elemWidth, height:elemHeight}
};
AdfGeckoAgent.prototype.atLeast = function(platform, version) {
  if(typeof version == "number") {
    return AdfGeckoAgent.superclass.atLeast.call(this, platform, version)
  }else {
    if(version && platform && platform == this.getPlatform()) {
      var agentName = navigator.userAgent.toLowerCase();
      var geckoVersionDigits = agentName.match(/rv:(\d+)\.(\d+)\.?(\d+)?\.?(\d+)?/);
      AdfAssert.assertArray(geckoVersionDigits, "parse gecko version string");
      geckoVersionDigits.splice(0, 1);
      var versionDigits = version.split(".");
      var maxLen = Math.max(versionDigits.length, geckoVersionDigits.length);
      for(var i = 0;i < maxLen;i++) {
        var geckoDigit = parseInt(geckoVersionDigits[i] ? geckoVersionDigits[i] : 0);
        var versionDigit = parseInt(versionDigits[i] ? versionDigits[i] : 0);
        if(versionDigit == geckoDigit) {
          continue
        }else {
          if(versionDigit < geckoDigit) {
            return true
          }else {
            return false
          }
        }
      }
    }else {
      return false
    }
  }
  return true
};
AdfGeckoAgent.prototype.pointInElementBounds = function(element, pageX, pageY) {
  var boundingRect = element.getBoundingClientRect();
  var documentElement = element.ownerDocument.documentElement;
  var clientX = pageX - documentElement.scrollLeft;
  var clientY = pageY - documentElement.scrollTop;
  return clientY >= boundingRect.top && clientY <= boundingRect.bottom && clientX >= boundingRect.left && clientX <= boundingRect.right
};
AdfGeckoAgent.prototype.slice = function(file, startByte, stopByte) {
  if(typeof Blob === "undefined" || typeof Blob.prototype.slice === "undefined" && typeof Blob.prototype.mozSlice === "undefined") {
    return undefined
  }
  if(file == null) {
    return null
  }
  if(file.slice) {
    return file.slice(startByte, stopByte)
  }else {
    if(file.mozSlice) {
      return file.mozSlice(startByte, stopByte)
    }
  }
  return undefined
};
AdfGeckoAgent.prototype.cloneEvent = function(event, newTarget) {
  if(this.isKeyboardEvent(event)) {
    var eventType = event.type;
    var newEvent = this._copyKeyboardEvent(event, eventType, newTarget);
    var targetNode = newTarget ? newTarget : event.target;
    var targetDocument = targetNode.ownerDocument;
    targetDocument.addEventListener(eventType, this.stopPropagation, true);
    try {
      targetNode.dispatchEvent(newEvent)
    }finally {
      targetDocument.removeEventListener(eventType, this.stopPropagation, true)
    }
    return newEvent
  }else {
    return AdfGeckoAgent.superclass.cloneEvent.call(this, event, newTarget)
  }
};
AdfGeckoAgent.prototype._copyKeyboardEvent = function(event, eventType, newTarget) {
  var targetNode = newTarget ? newTarget : event.target;
  var targetDocument = targetNode.ownerDocument;
  var newEvent = targetDocument.createEvent("KeyboardEvent");
  newEvent.initKeyEvent(eventType, true, true, targetDocument.contentWindow, event.ctrlKey, event.altKey, event.shiftKey, event.metaKey, event.keyCode, event.charCode);
  return newEvent
};
AdfGeckoAgent.prototype.isDragPrepEvent = function(componentEvent) {
  if(AdfGeckoAgent.superclass.isDragPrepEvent.call(this, componentEvent)) {
    var nativeEvent = componentEvent.getNativeEvent();
    var originalTarget = nativeEvent["originalTarget"];
    var explicitOriginalTarget = nativeEvent["explicitOriginalTarget"];
    if(explicitOriginalTarget === originalTarget) {
      return true
    }else {
      return explicitOriginalTarget.nodeType != 1
    }
  }
  return false
};
