diff --git a/background.js b/background.js
new file mode 100644
index 0000000..f53e79f
--- /dev/null
+++ b/background.js
@@ -0,0 +1,125 @@
+// This event is fired each time the user updates the text in the omnibox,
+// as long as the extension's keyword mode is still active.
+var FF_MAX_SUGGESTIONS = 20;
+var FF_MAX_MATCHLENGTH = 1000;
+var FF_DEBUGGING = !false;
+var FF_HISTORY = [];
+
+function ffGetDomain(url) {
+ var a = document.createElement ('a');
+ ; a.href = url;
+ return a.hostname;
+}
+
+function ffSearchFor(text, callback) {
+ chrome.tabs.query({}, function(array_of_tabs) {
+ var fuzzy_query = new RegExp(text.split('').join('.*'), 'i');
+ var exact_query = new RegExp(text, 'i');
+ var exact_query_hl = new RegExp("(" + text + ")", 'ig');
+ callback(
+ array_of_tabs.
+ map(function(tab) {
+
+ if(FF_DEBUGGING) { console.debug("tab", tab); }
+
+ switch (true) {
+ case !!tab.title.match(exact_query):
+ tab.score = 40;
+ tab.score += 1 - 1.0 * exact_query.exec(tab.title).index / FF_MAX_MATCHLENGTH;
+ tab.title = tab.title.replace(exact_query_hl, "$1")
+ break;
+ case !!tab.url.match(exact_query):
+ tab.score = 40;
+ tab.score += 1 - 1.0 * exact_query.exec(tab.url).index / FF_MAX_MATCHLENGTH;
+ break;
+ case !!tab.title.match(fuzzy_query):
+ tab.title = tab.title.replace(fuzzy_query, function(m) { return "" + m + ""; })
+ tab.score = 20;
+ tab.score += 1 - 1.0 * tab.title.match(fuzzy_query)[0].length / FF_MAX_MATCHLENGTH;
+ break;
+ case !!tab.url.match(fuzzy_query):
+ tab.score = 20;
+ tab.score += 1 - 1.0 * tab.url.match(fuzzy_query)[0].length / FF_MAX_MATCHLENGTH;
+ break;
+ default:
+ tab.score = 0;
+ }
+
+ if(tab.pinned) { tab.score += 1; }
+
+ return tab;
+ }).
+ filter(function(tab) {
+ return tab.score >= 10;
+ }).
+ sort(function(tab1, tab2) {
+ if(tab1.score < tab2.score) return 1;
+ if(tab1.score > tab2.score) return -1;
+ return 0;
+ }).
+ slice(0, FF_MAX_SUGGESTIONS).
+ map(function(tab) {
+
+ var content = JSON.stringify({tabId: tab.id, windowId: tab.windowId});
+ var desc = tab.title + " " + ffGetDomain(tab.url) + "";
+ if(FF_DEBUGGING) { desc = "score:" + tab.score + " - " + desc; }
+
+ if(tab.status !== "complete") desc = "[" + tab.status + "] " + desc;
+ if(tab.incognito) desc = "[incognito] " + desc;
+ if(tab.pinned) desc = "[pinned] " + desc;
+ if(tab.audible) desc = "[audible] " + desc;
+
+ return {content: content, description: desc};
+ })
+ );
+ });
+}
+
+chrome.omnibox.onInputChanged.addListener(
+ function(text, suggest) { ffSearchFor(text, suggest); }
+);
+
+function ffActivateTag(tabId, windowId) {
+ if(tabId) {
+ chrome.tabs.update(tabId, {active: true});
+ }
+ if(windowId) {
+ chrome.windows.update(windowId, {focused: true});
+ }
+}
+
+chrome.omnibox.onInputEntered.addListener(
+ function(text) {
+ if(FF_DEBUGGING) {
+ console.debug("entered:", text);
+ console.debug("history:", FF_HISTORY);
+ }
+
+ var selected = {};
+
+ if(text.length === 0) {
+ if(FF_HISTORY.length >= 2) {
+ selected = FF_HISTORY[FF_HISTORY.length - 2];
+ } else {
+ return;
+ }
+ } else {
+ try {
+ selected = JSON.parse(text);
+ } catch(e) {
+ // User probably typed something but selected the first default option,
+ // i.e., "Run ff command: query"
+ ffSearchFor(text, function(suggestions) {
+ if(suggestions.length === 0) { return; }
+ var selected = JSON.parse(suggestions[0].content);
+ FF_HISTORY.push(selected);
+ ffActivateTag(selected.tabId, selected.windowId)
+ });
+ return;
+ }
+ }
+
+ FF_HISTORY.push(selected);
+ ffActivateTag(selected.tabId, selected.windowId)
+ }
+);
diff --git a/ff.png b/ff.png
new file mode 100644
index 0000000..25deba7
Binary files /dev/null and b/ff.png differ
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..3572e9d
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+
+ "name": "FF (Fuzzy Finder)",
+ "description": "Omnibox Fuzzy Finder for Chrome. Type 'ff' in your address bar and search for your tabs.",
+ "version": "1.0",
+ "author": "Sina Siadat ",
+ "homepage_url": "https://github.com/siadat/chrome-ff",
+ "permissions": [ "tabs", "activeTab" ],
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "omnibox": { "keyword" : "ff" },
+ "icons": {
+ "16": "ff.png"
+ }
+}