// Generated by CoffeeScript 1.12.7
(function() {
  var Frame, GrabBackFocus, NormalMode, bgLog, checkEnabledAfterURLChange, checkIfEnabledForUrl, enterFindMode, findAndFocus, findAndFollowLink, findAndFollowRel, flashFrame, focusFoundLink, focusThisFrame, followLink, frameId, getLinkFromSelection, handleEnterForFindMode, handleEscapeForFindMode, initializeOnDomReady, initializeOnEnabledStateKnown, initializePreDomReady, installListener, installListeners, installModes, isEnabledForUrl, isIncognitoMode, normalMode, onFocus, performBackwardsFind, performFind, root, selectFoundInputElement, setScrollPosition, textInputXPath, windowIsFocused,
    slice = [].slice,
    extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  isEnabledForUrl = true;

  isIncognitoMode = chrome.extension.inIncognitoContext;

  normalMode = null;

  windowIsFocused = (function() {
    var windowHasFocus;
    windowHasFocus = null;
    DomUtils.documentReady(function() {
      return windowHasFocus = document.hasFocus();
    });
    window.addEventListener("focus", forTrusted(function(event) {
      if (event.target === window) {
        windowHasFocus = true;
      }
      return true;
    }));
    window.addEventListener("blur", forTrusted(function(event) {
      if (event.target === window) {
        windowHasFocus = false;
      }
      return true;
    }));
    return function() {
      return windowHasFocus;
    };
  })();

  textInputXPath = (function() {
    var inputElements, textInputTypes;
    textInputTypes = ["text", "search", "email", "url", "number", "password", "date", "tel"];
    inputElements = [
      "input[" + "(" + textInputTypes.map(function(type) {
        return '@type="' + type + '"';
      }).join(" or ") + "or not(@type))" + " and not(@disabled or @readonly)]", "textarea", "*[@contenteditable='' or translate(@contenteditable, 'TRUE', 'true')='true']"
    ];
    return DomUtils.makeXPath(inputElements);
  })();

  frameId = null;

  bgLog = function() {
    var arg, args;
    args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
    args = (function() {
      var j, len, results;
      results = [];
      for (j = 0, len = args.length; j < len; j++) {
        arg = args[j];
        results.push(arg.toString());
      }
      return results;
    })();
    return Frame.postMessage("log", {
      message: args.join(" ")
    });
  };

  GrabBackFocus = (function(superClass) {
    extend1(GrabBackFocus, superClass);

    function GrabBackFocus() {
      var exitEventHandler, listener;
      exitEventHandler = (function(_this) {
        return function() {
          return _this.alwaysContinueBubbling(function() {
            _this.exit();
            return chrome.runtime.sendMessage({
              handler: "sendMessageToFrames",
              message: {
                name: "userIsInteractingWithThePage"
              }
            });
          });
        };
      })(this);
      GrabBackFocus.__super__.constructor.call(this, {
        name: "grab-back-focus",
        keydown: exitEventHandler
      });
      this.push({
        _name: "grab-back-focus-mousedown",
        mousedown: exitEventHandler
      });
      Settings.use("grabBackFocus", (function(_this) {
        return function(grabBackFocus) {
          if (_this.modeIsActive) {
            if (grabBackFocus) {
              _this.push({
                _name: "grab-back-focus-focus",
                focus: function(event) {
                  return _this.grabBackFocus(event.target);
                }
              });
              if (document.activeElement) {
                return _this.grabBackFocus(document.activeElement);
              }
            } else {
              return _this.exit();
            }
          }
        };
      })(this));
      chrome.runtime.onMessage.addListener(listener = (function(_this) {
        return function(arg1) {
          var name;
          name = arg1.name;
          if (name === "userIsInteractingWithThePage") {
            chrome.runtime.onMessage.removeListener(listener);
            if (_this.modeIsActive) {
              _this.exit();
            }
          }
          return false;
        };
      })(this));
    }

    GrabBackFocus.prototype.grabBackFocus = function(element) {
      if (!DomUtils.isFocusable(element)) {
        return this.continueBubbling;
      }
      element.blur();
      return this.suppressEvent;
    };

    return GrabBackFocus;

  })(Mode);

  handlerStack.push({
    _name: "GrabBackFocus-pushState-monitor",
    click: function(event) {
      var ref, target;
      if (DomUtils.isFocusable(document.activeElement)) {
        return true;
      }
      target = event.target;
      while (target) {
        if (target.tagName === "A" && target.origin === document.location.origin && (target.pathName !== document.location.pathName || target.search !== document.location.search) && (((ref = target.target) === "" || ref === "_self") || (target.target === "_parent" && window.parent === window) || (target.target === "_top" && window.top === window))) {
          return new GrabBackFocus();
        } else {
          target = target.parentElement;
        }
      }
      return true;
    }
  });

  NormalMode = (function(superClass) {
    extend1(NormalMode, superClass);

    function NormalMode(options) {
      var defaults;
      if (options == null) {
        options = {};
      }
      defaults = {
        name: "normal",
        indicator: false,
        commandHandler: this.commandHandler.bind(this)
      };
      NormalMode.__super__.constructor.call(this, extend(defaults, options));
      chrome.storage.local.get("normalModeKeyStateMapping", (function(_this) {
        return function(items) {
          return _this.setKeyMapping(items.normalModeKeyStateMapping);
        };
      })(this));
      chrome.storage.onChanged.addListener((function(_this) {
        return function(changes, area) {
          var ref;
          if (area === "local" && ((ref = changes.normalModeKeyStateMapping) != null ? ref.newValue : void 0)) {
            return _this.setKeyMapping(changes.normalModeKeyStateMapping.newValue);
          }
        };
      })(this));
    }

    NormalMode.prototype.commandHandler = function(arg1) {
      var count, ref, registryEntry, sourceFrameId;
      registryEntry = arg1.command, count = arg1.count;
      count *= (ref = registryEntry.options.count) != null ? ref : 1;
      if (registryEntry.noRepeat) {
        count = 1;
      }
      if ((registryEntry.repeatLimit != null) && registryEntry.repeatLimit < count) {
        if (!confirm("You have asked Vimium to perform " + count + " repetitions of the command: " + registryEntry.description + ".\n\nAre you sure you want to continue?")) {
          return;
        }
      }
      if (registryEntry.topFrame) {
        sourceFrameId = window.isVimiumUIComponent ? 0 : frameId;
        return chrome.runtime.sendMessage({
          handler: "sendMessageToFrames",
          message: {
            name: "runInTopFrame",
            sourceFrameId: sourceFrameId,
            registryEntry: registryEntry
          }
        });
      } else if (registryEntry.background) {
        return chrome.runtime.sendMessage({
          handler: "runBackgroundCommand",
          registryEntry: registryEntry,
          count: count
        });
      } else {
        return Utils.invokeCommandString(registryEntry.command, count, {
          registryEntry: registryEntry
        });
      }
    };

    return NormalMode;

  })(KeyHandlerMode);

  installModes = function() {
    normalMode = new NormalMode;
    Scroller.init();
    FindModeHistory.init();
    new InsertMode({
      permanent: true
    });
    if (isEnabledForUrl) {
      new GrabBackFocus;
    }
    return normalMode;
  };

  initializeOnEnabledStateKnown = function(isEnabledForUrl) {
    if (!normalMode) {
      installModes();
    }
    if (isEnabledForUrl) {
      if (DomUtils.isTopFrame()) {
        DomUtils.documentComplete(Vomnibar.init.bind(Vomnibar));
      }
      return initializeOnEnabledStateKnown = function() {};
    }
  };

  initializePreDomReady = function() {
    var requestHandlers;
    installListeners();
    Frame.init();
    checkIfEnabledForUrl(document.hasFocus());
    requestHandlers = {
      focusFrame: function(request) {
        if (frameId === request.frameId) {
          return focusThisFrame(request);
        }
      },
      getScrollPosition: function(ignoredA, ignoredB, sendResponse) {
        if (frameId === 0) {
          return sendResponse({
            scrollX: window.scrollX,
            scrollY: window.scrollY
          });
        }
      },
      setScrollPosition: setScrollPosition,
      frameFocused: function() {},
      checkEnabledAfterURLChange: checkEnabledAfterURLChange,
      runInTopFrame: function(arg1) {
        var registryEntry, sourceFrameId;
        sourceFrameId = arg1.sourceFrameId, registryEntry = arg1.registryEntry;
        if (DomUtils.isTopFrame()) {
          return Utils.invokeCommandString(registryEntry.command, sourceFrameId, registryEntry);
        }
      },
      linkHintsMessage: function(request) {
        return HintCoordinator[request.messageType](request);
      }
    };
    return chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
      var ref, ref1;
      if (!(request.handler && !request.name)) {
        if ((ref = request.name) !== "userIsInteractingWithThePage") {
          if (isEnabledForUrl || ((ref1 = request.name) === "checkEnabledAfterURLChange" || ref1 === "runInTopFrame")) {
            requestHandlers[request.name](request, sender, sendResponse);
          }
        }
      }
      return false;
    });
  };

  installListener = function(element, event, callback) {
    return element.addEventListener(event, forTrusted(function() {
      if (isEnabledForUrl) {
        return callback.apply(this, arguments);
      } else {
        return true;
      }
    }), true);
  };

  installListeners = Utils.makeIdempotent(function() {
    var fn, j, len, ref, type;
    ref = ["keydown", "keypress", "keyup", "click", "focus", "blur", "mousedown", "scroll"];
    fn = function(type) {
      return installListener(window, type, function(event) {
        return handlerStack.bubbleEvent(type, event);
      });
    };
    for (j = 0, len = ref.length; j < len; j++) {
      type = ref[j];
      fn(type);
    }
    return installListener(document, "DOMActivate", function(event) {
      return handlerStack.bubbleEvent('DOMActivate', event);
    });
  });

  onFocus = forTrusted(function(event) {
    if (event.target === window) {
      chrome.runtime.sendMessage({
        handler: "frameFocused"
      });
      return checkIfEnabledForUrl(true);
    }
  });

  window.addEventListener("focus", onFocus);

  window.addEventListener("hashchange", checkEnabledAfterURLChange);

  initializeOnDomReady = function() {
    return Frame.postMessage("domReady");
  };

  Frame = {
    port: null,
    listeners: {},
    addEventListener: function(handler, callback) {
      return this.listeners[handler] = callback;
    },
    postMessage: function(handler, request) {
      if (request == null) {
        request = {};
      }
      return this.port.postMessage(extend(request, {
        handler: handler
      }));
    },
    linkHintsMessage: function(request) {
      return HintCoordinator[request.messageType](request);
    },
    registerFrameId: function(arg1) {
      var chromeFrameId, focusHandler, postRegisterFrame, resizeHandler;
      chromeFrameId = arg1.chromeFrameId;
      frameId = window.frameId = chromeFrameId;
      if (windowIsFocused() || !DomUtils.windowIsTooSmall()) {
        return Frame.postMessage("registerFrame");
      } else {
        postRegisterFrame = function() {
          window.removeEventListener("focus", focusHandler);
          window.removeEventListener("resize", resizeHandler);
          return Frame.postMessage("registerFrame");
        };
        window.addEventListener("focus", focusHandler = forTrusted(function(event) {
          if (event.target === window) {
            return postRegisterFrame();
          }
        }));
        return window.addEventListener("resize", resizeHandler = forTrusted(function(event) {
          if (!DomUtils.windowIsTooSmall()) {
            return postRegisterFrame();
          }
        }));
      }
    },
    init: function() {
      var disconnect;
      this.port = chrome.runtime.connect({
        name: "frames"
      });
      this.port.onMessage.addListener((function(_this) {
        return function(request) {
          var ref;
          return ((ref = _this.listeners[request.handler]) != null ? ref : _this[request.handler])(request);
        };
      })(this));
      this.port.onDisconnect.addListener(disconnect = Utils.makeIdempotent((function(_this) {
        return function() {
          return _this.disconnect();
        };
      })(this)));
      return window.addEventListener("unload", forTrusted(disconnect));
    },
    disconnect: function() {
      try {
        this.postMessage("unregisterFrame");
      } catch (error) {}
      try {
        this.port.disconnect();
      } catch (error) {}
      this.postMessage = this.disconnect = function() {};
      this.port = null;
      this.listeners = {};
      HintCoordinator.exit({
        isSuccess: false
      });
      handlerStack.reset();
      isEnabledForUrl = false;
      window.removeEventListener("focus", onFocus);
      return window.removeEventListener("hashchange", onFocus);
    }
  };

  setScrollPosition = function(arg1) {
    var scrollX, scrollY;
    scrollX = arg1.scrollX, scrollY = arg1.scrollY;
    return DomUtils.documentReady(function() {
      if (DomUtils.isTopFrame()) {
        window.focus();
        document.body.focus();
        if (0 < scrollX || 0 < scrollY) {
          Marks.setPreviousPosition();
          return window.scrollTo(scrollX, scrollY);
        }
      }
    });
  };

  flashFrame = function() {};

  DomUtils.documentReady(function() {
    var _frameEl, _shadowDOM, _styleSheet, highlightedFrameElement, ref;
    highlightedFrameElement = DomUtils.createElement("div");
    _shadowDOM = (ref = typeof highlightedFrameElement.createShadowRoot === "function" ? highlightedFrameElement.createShadowRoot() : void 0) != null ? ref : highlightedFrameElement;
    _styleSheet = DomUtils.createElement("style");
    _styleSheet.innerHTML = "@import url(\"" + (chrome.runtime.getURL("content_scripts/vimium.css")) + "\");";
    _shadowDOM.appendChild(_styleSheet);
    _frameEl = DomUtils.createElement("div");
    _frameEl.className = "vimiumReset vimiumHighlightedFrame";
    _shadowDOM.appendChild(_frameEl);
    return flashFrame = function() {
      document.documentElement.appendChild(highlightedFrameElement);
      return setTimeout((function() {
        return highlightedFrameElement.remove();
      }), 200);
    };
  });

  focusThisFrame = function(request) {
    var ref;
    if (!request.forceFocusThisFrame) {
      if (DomUtils.windowIsTooSmall() || ((ref = document.body) != null ? ref.tagName.toLowerCase() : void 0) === "frameset") {
        chrome.runtime.sendMessage({
          handler: "nextFrame"
        });
        return;
      }
    }
    window.focus();
    if (document.activeElement.tagName.toLowerCase() === "iframe") {
      document.activeElement.blur();
    }
    if (request.highlight) {
      return flashFrame();
    }
  };

  extend(window, {
    scrollToBottom: function() {
      Marks.setPreviousPosition();
      return Scroller.scrollTo("y", "max");
    },
    scrollToTop: function(count) {
      Marks.setPreviousPosition();
      return Scroller.scrollTo("y", (count - 1) * Settings.get("scrollStepSize"));
    },
    scrollToLeft: function() {
      return Scroller.scrollTo("x", 0);
    },
    scrollToRight: function() {
      return Scroller.scrollTo("x", "max");
    },
    scrollUp: function(count) {
      return Scroller.scrollBy("y", -1 * Settings.get("scrollStepSize") * count);
    },
    scrollDown: function(count) {
      return Scroller.scrollBy("y", Settings.get("scrollStepSize") * count);
    },
    scrollPageUp: function(count) {
      return Scroller.scrollBy("y", "viewSize", -1 / 2 * count);
    },
    scrollPageDown: function(count) {
      return Scroller.scrollBy("y", "viewSize", 1 / 2 * count);
    },
    scrollFullPageUp: function(count) {
      return Scroller.scrollBy("y", "viewSize", -1 * count);
    },
    scrollFullPageDown: function(count) {
      return Scroller.scrollBy("y", "viewSize", 1 * count);
    },
    scrollLeft: function(count) {
      return Scroller.scrollBy("x", -1 * Settings.get("scrollStepSize") * count);
    },
    scrollRight: function(count) {
      return Scroller.scrollBy("x", Settings.get("scrollStepSize") * count);
    }
  });

  extend(window, {
    reload: function() {
      return window.location.reload();
    },
    goBack: function(count) {
      return history.go(-count);
    },
    goForward: function(count) {
      return history.go(count);
    },
    goUp: function(count) {
      var url, urlsplit;
      url = window.location.href;
      if (url[url.length - 1] === "/") {
        url = url.substring(0, url.length - 1);
      }
      urlsplit = url.split("/");
      if (urlsplit.length > 3) {
        urlsplit = urlsplit.slice(0, Math.max(3, urlsplit.length - count));
        return window.location.href = urlsplit.join('/');
      }
    },
    goToRoot: function() {
      return window.location.href = window.location.origin;
    },
    mainFrame: function() {
      return focusThisFrame({
        highlight: true,
        forceFocusThisFrame: true
      });
    },
    toggleViewSource: function() {
      return chrome.runtime.sendMessage({
        handler: "getCurrentTabUrl"
      }, function(url) {
        if (url.substr(0, 12) === "view-source:") {
          url = url.substr(12, url.length - 12);
        } else {
          url = "view-source:" + url;
        }
        return chrome.runtime.sendMessage({
          handler: "openUrlInNewTab",
          url: url
        });
      });
    },
    copyCurrentUrl: function() {
      return chrome.runtime.sendMessage({
        handler: "getCurrentTabUrl"
      }, function(url) {
        chrome.runtime.sendMessage({
          handler: "copyToClipboard",
          data: url
        });
        if (28 < url.length) {
          url = url.slice(0, 26) + "....";
        }
        return HUD.showForDuration("Yanked " + url, 2000);
      });
    },
    enterInsertMode: function() {
      return new InsertMode({
        global: true,
        exitOnFocus: true
      });
    },
    enterVisualMode: function() {
      return new VisualMode({
        userLaunchedMode: true
      });
    },
    enterVisualLineMode: function() {
      return new VisualLineMode({
        userLaunchedMode: true
      });
    },
    passNextKey: function(count, options) {
      if (options.registryEntry.options.normal) {
        return enterNormalMode(count);
      } else {
        return new PassNextKeyMode(count);
      }
    },
    enterNormalMode: function(count) {
      return new NormalMode({
        indicator: "Normal mode (pass keys disabled)",
        exitOnEscape: true,
        singleton: "enterNormalMode",
        count: count
      });
    },
    focusInput: (function() {
      var recentlyFocusedElement;
      recentlyFocusedElement = null;
      window.addEventListener("focus", forTrusted(function(event) {
        if (DomUtils.isEditable(event.target)) {
          return recentlyFocusedElement = event.target;
        }
      }), true);
      return function(count) {
        var FocusSelector, element, elements, hint, hints, i, mode, resultSet, selectedInputIndex, tuple, visibleInputs;
        mode = InsertMode;
        resultSet = DomUtils.evaluateXPath(textInputXPath, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
        visibleInputs = (function() {
          var j, ref, results;
          results = [];
          for (i = j = 0, ref = resultSet.snapshotLength; j < ref; i = j += 1) {
            element = resultSet.snapshotItem(i);
            if (!DomUtils.getVisibleClientRect(element, true)) {
              continue;
            }
            results.push({
              element: element,
              rect: Rect.copy(element.getBoundingClientRect())
            });
          }
          return results;
        })();
        if (visibleInputs.length === 0) {
          HUD.showForDuration("There are no inputs to focus.", 1000);
          return;
        }
        if (window.isVimiumOptionsPage) {
          if (recentlyFocusedElement == null) {
            recentlyFocusedElement = document.getElementById("keyMappings");
          }
        }
        selectedInputIndex = count === 1 ? (elements = visibleInputs.map(function(visibleInput) {
          return visibleInput.element;
        }), Math.max(0, elements.indexOf(recentlyFocusedElement))) : Math.min(count, visibleInputs.length) - 1;
        hints = (function() {
          var j, len, results;
          results = [];
          for (j = 0, len = visibleInputs.length; j < len; j++) {
            tuple = visibleInputs[j];
            hint = DomUtils.createElement("div");
            hint.className = "vimiumReset internalVimiumInputHint vimiumInputHint";
            hint.style.left = (tuple.rect.left - 1) + window.scrollX + "px";
            hint.style.top = (tuple.rect.top - 1) + window.scrollY + "px";
            hint.style.width = tuple.rect.width + "px";
            hint.style.height = tuple.rect.height + "px";
            results.push(hint);
          }
          return results;
        })();
        return new (FocusSelector = (function(superClass) {
          extend1(FocusSelector, superClass);

          function FocusSelector() {
            FocusSelector.__super__.constructor.call(this, {
              name: "focus-selector",
              exitOnClick: true,
              keydown: (function(_this) {
                return function(event) {
                  if (event.key === "Tab") {
                    hints[selectedInputIndex].classList.remove('internalVimiumSelectedInputHint');
                    selectedInputIndex += hints.length + (event.shiftKey ? -1 : 1);
                    selectedInputIndex %= hints.length;
                    hints[selectedInputIndex].classList.add('internalVimiumSelectedInputHint');
                    DomUtils.simulateSelect(visibleInputs[selectedInputIndex].element);
                    return _this.suppressEvent;
                  } else if (event.key !== "Shift") {
                    _this.exit();
                    return _this.restartBubbling;
                  }
                };
              })(this)
            });
            this.hintContainingDiv = DomUtils.addElementList(hints, {
              id: "vimiumInputMarkerContainer",
              className: "vimiumReset"
            });
            DomUtils.simulateSelect(visibleInputs[selectedInputIndex].element);
            if (visibleInputs.length === 1) {
              this.exit();
              return;
            } else {
              hints[selectedInputIndex].classList.add('internalVimiumSelectedInputHint');
            }
          }

          FocusSelector.prototype.exit = function() {
            FocusSelector.__super__.exit.call(this);
            DomUtils.removeElement(this.hintContainingDiv);
            if (mode && document.activeElement && DomUtils.isEditable(document.activeElement)) {
              return new mode({
                singleton: "post-find-mode/focus-input",
                targetElement: document.activeElement,
                indicator: false
              });
            }
          };

          return FocusSelector;

        })(Mode));
      };
    })()
  });

  checkIfEnabledForUrl = (function() {
    Frame.addEventListener("isEnabledForUrl", function(response) {
      var frameIsFocused, isFirefox, passKeys;
      isEnabledForUrl = response.isEnabledForUrl, passKeys = response.passKeys, frameIsFocused = response.frameIsFocused, isFirefox = response.isFirefox;
      Utils.isFirefox = function() {
        return isFirefox;
      };
      initializeOnEnabledStateKnown(isEnabledForUrl);
      normalMode.setPassKeys(passKeys);
      if (!isEnabledForUrl) {
        return HUD.hide(true, false);
      }
    });
    return function(frameIsFocused) {
      if (frameIsFocused == null) {
        frameIsFocused = windowIsFocused();
      }
      return Frame.postMessage("isEnabledForUrl", {
        frameIsFocused: frameIsFocused,
        url: window.location.toString()
      });
    };
  })();

  checkEnabledAfterURLChange = forTrusted(function() {
    if (windowIsFocused()) {
      return checkIfEnabledForUrl();
    }
  });

  handleEscapeForFindMode = function() {
    var range, selection;
    document.body.classList.remove("vimiumFindMode");
    selection = window.getSelection();
    if (!selection.isCollapsed) {
      range = window.getSelection().getRangeAt(0);
      window.getSelection().removeAllRanges();
      window.getSelection().addRange(range);
    }
    return focusFoundLink() || selectFoundInputElement();
  };

  handleEnterForFindMode = function() {
    focusFoundLink();
    document.body.classList.add("vimiumFindMode");
    return FindMode.saveQuery();
  };

  focusFoundLink = function() {
    var link;
    if (FindMode.query.hasResults) {
      link = getLinkFromSelection();
      if (link) {
        return link.focus();
      }
    }
  };

  selectFoundInputElement = function() {
    var findModeAnchorNode;
    findModeAnchorNode = document.getSelection().anchorNode;
    if (FindMode.query.hasResults && document.activeElement && DomUtils.isSelectable(document.activeElement) && DomUtils.isDOMDescendant(findModeAnchorNode, document.activeElement)) {
      return DomUtils.simulateSelect(document.activeElement);
    }
  };

  findAndFocus = function(backwards) {
    Marks.setPreviousPosition();
    FindMode.query.hasResults = FindMode.execute(null, {
      backwards: backwards
    });
    if (FindMode.query.hasResults) {
      focusFoundLink();
      return new PostFindMode();
    } else {
      return HUD.showForDuration("No matches for '" + FindMode.query.rawQuery + "'", 1000);
    }
  };

  performFind = function(count) {
    var j, ref, results;
    results = [];
    for (j = 0, ref = count; j < ref; j += 1) {
      results.push(findAndFocus(false));
    }
    return results;
  };

  performBackwardsFind = function(count) {
    var j, ref, results;
    results = [];
    for (j = 0, ref = count; j < ref; j += 1) {
      results.push(findAndFocus(true));
    }
    return results;
  };

  getLinkFromSelection = function() {
    var node;
    node = window.getSelection().anchorNode;
    while (node && node !== document.body) {
      if (node.nodeName.toLowerCase() === "a") {
        return node;
      }
      node = node.parentNode;
    }
    return null;
  };

  followLink = function(linkElement) {
    if (linkElement.nodeName.toLowerCase() === "link") {
      return window.location.href = linkElement.href;
    } else {
      linkElement.scrollIntoView();
      return DomUtils.simulateClick(linkElement);
    }
  };

  findAndFollowLink = function(linkStrings) {
    var boundingClientRect, candidateLink, candidateLinks, computedStyle, exactWordRegex, i, j, k, l, len, len1, len2, len3, link, linkMatches, linkString, links, linksXPath, m, n, ref, ref1;
    linksXPath = DomUtils.makeXPath(["a", "*[@onclick or @role='link' or contains(@class, 'button')]"]);
    links = DomUtils.evaluateXPath(linksXPath, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
    candidateLinks = [];
    for (i = j = ref = links.snapshotLength - 1; j >= 0; i = j += -1) {
      link = links.snapshotItem(i);
      boundingClientRect = link.getBoundingClientRect();
      if (boundingClientRect.width === 0 || boundingClientRect.height === 0) {
        continue;
      }
      computedStyle = window.getComputedStyle(link, null);
      if (computedStyle.getPropertyValue("visibility") !== "visible" || computedStyle.getPropertyValue("display") === "none") {
        continue;
      }
      linkMatches = false;
      for (k = 0, len = linkStrings.length; k < len; k++) {
        linkString = linkStrings[k];
        if (link.innerText.toLowerCase().indexOf(linkString) !== -1 || 0 <= ((ref1 = link.value) != null ? typeof ref1.indexOf === "function" ? ref1.indexOf(linkString) : void 0 : void 0)) {
          linkMatches = true;
          break;
        }
      }
      if (!linkMatches) {
        continue;
      }
      candidateLinks.push(link);
    }
    if (candidateLinks.length === 0) {
      return;
    }
    for (l = 0, len1 = candidateLinks.length; l < len1; l++) {
      link = candidateLinks[l];
      link.wordCount = link.innerText.trim().split(/\s+/).length;
    }
    candidateLinks.forEach(function(a, i) {
      return a.originalIndex = i;
    });
    candidateLinks = candidateLinks.sort(function(a, b) {
      if (a.wordCount === b.wordCount) {
        return a.originalIndex - b.originalIndex;
      } else {
        return a.wordCount - b.wordCount;
      }
    }).filter(function(a) {
      return a.wordCount <= candidateLinks[0].wordCount + 1;
    });
    for (m = 0, len2 = linkStrings.length; m < len2; m++) {
      linkString = linkStrings[m];
      exactWordRegex = /\b/.test(linkString[0]) || /\b/.test(linkString[linkString.length - 1]) ? new RegExp("\\b" + linkString + "\\b", "i") : new RegExp(linkString, "i");
      for (n = 0, len3 = candidateLinks.length; n < len3; n++) {
        candidateLink = candidateLinks[n];
        if (exactWordRegex.test(candidateLink.innerText) || (candidateLink.value && exactWordRegex.test(candidateLink.value))) {
          followLink(candidateLink);
          return true;
        }
      }
    }
    return false;
  };

  findAndFollowRel = function(value) {
    var element, elements, j, k, len, len1, relTags, tag;
    relTags = ["link", "a", "area"];
    for (j = 0, len = relTags.length; j < len; j++) {
      tag = relTags[j];
      elements = document.getElementsByTagName(tag);
      for (k = 0, len1 = elements.length; k < len1; k++) {
        element = elements[k];
        if (element.hasAttribute("rel") && element.rel.toLowerCase() === value) {
          followLink(element);
          return true;
        }
      }
    }
  };

  window.goPrevious = function() {
    var previousPatterns, previousStrings;
    previousPatterns = Settings.get("previousPatterns") || "";
    previousStrings = previousPatterns.split(",").filter(function(s) {
      return s.trim().length;
    });
    return findAndFollowRel("prev") || findAndFollowLink(previousStrings);
  };

  window.goNext = function() {
    var nextPatterns, nextStrings;
    nextPatterns = Settings.get("nextPatterns") || "";
    nextStrings = nextPatterns.split(",").filter(function(s) {
      return s.trim().length;
    });
    return findAndFollowRel("next") || findAndFollowLink(nextStrings);
  };

  enterFindMode = function() {
    Marks.setPreviousPosition();
    return new FindMode();
  };

  window.showHelp = function(sourceFrameId) {
    return HelpDialog.toggle({
      sourceFrameId: sourceFrameId,
      showAllCommandDetails: false
    });
  };

  if (window.HelpDialog == null) {
    window.HelpDialog = {
      helpUI: null,
      isShowing: function() {
        var ref;
        return (ref = this.helpUI) != null ? ref.showing : void 0;
      },
      abort: function() {
        if (this.isShowing()) {
          return this.helpUI.hide(false);
        }
      },
      toggle: function(request) {
        DomUtils.documentComplete((function(_this) {
          return function() {
            return _this.helpUI != null ? _this.helpUI : _this.helpUI = new UIComponent("pages/help_dialog.html", "vimiumHelpDialogFrame", function() {});
          };
        })(this));
        if ((this.helpUI != null) && this.isShowing()) {
          return this.helpUI.hide();
        } else if (this.helpUI != null) {
          return this.helpUI.activate(extend(request, {
            name: "activate",
            focus: true
          }));
        }
      }
    };
  }

  initializePreDomReady();

  DomUtils.documentReady(initializeOnDomReady);

  root = typeof exports !== "undefined" && exports !== null ? exports : window;

  root.handlerStack = handlerStack;

  root.frameId = frameId;

  root.Frame = Frame;

  root.windowIsFocused = windowIsFocused;

  root.bgLog = bgLog;

  extend(root, {
    handleEscapeForFindMode: handleEscapeForFindMode,
    handleEnterForFindMode: handleEnterForFindMode,
    performFind: performFind,
    performBackwardsFind: performBackwardsFind,
    enterFindMode: enterFindMode,
    focusThisFrame: focusThisFrame
  });

  extend(root, {
    installModes: installModes
  });

}).call(this);
