From 96966ca83f96ed1babcd2bd23aa68feb63fbb7a7 Mon Sep 17 00:00:00 2001
From: Einar Egilsson
Date: Tue, 15 Sep 2009 21:41:06 +0000
Subject: Total restructuring of files. Unescape matches fully working Export
 of redirects working.

git-svn-id: http://einaregilsson.googlecode.com/svn/mozilla/redirector/trunk@249 119bf307-c92d-0410-89bd-8f53e6181181
---
 chrome/content/code/browserOverlay.xul.js   | 137 ++++++++++++
 chrome/content/code/editRedirect.xul.js     |  86 +++++++
 chrome/content/code/redirectList.xul.js     | 193 ++++++++++++++++
 chrome/content/code/redirector.prototype.js | 333 ++++++++++++++++++++++++++++
 chrome/content/help.html                    | 173 ---------------
 chrome/content/images/redirector.png        | Bin 0 -> 1462 bytes
 chrome/content/images/statusactive.PNG      | Bin 0 -> 360 bytes
 chrome/content/images/statusinactive.PNG    | Bin 0 -> 396 bytes
 chrome/content/overlay.js                   | 142 ------------
 chrome/content/overlay.xul                  |  38 ----
 chrome/content/redirect.js                  |  86 -------
 chrome/content/redirect.xul                 |  53 -----
 chrome/content/redirectList.js              | 158 -------------
 chrome/content/redirectList.xul             |  54 -----
 chrome/content/redirector.png               | Bin 1462 -> 0 bytes
 chrome/content/redirector.prototype.js      | 272 -----------------------
 chrome/content/statusactive.PNG             | Bin 360 -> 0 bytes
 chrome/content/statusinactive.PNG           | Bin 396 -> 0 bytes
 chrome/content/ui/browserOverlay.xul        |  38 ++++
 chrome/content/ui/editRedirect.xul          |  53 +++++
 chrome/content/ui/help.html                 | 173 +++++++++++++++
 chrome/content/ui/redirectList.xul          |  54 +++++
 chrome/content/unittest/run.html            |  87 ++++++++
 chrome/content/unittest/testcases.js        |  39 ++++
 chrome/content/unittests.html               |  86 -------
 chrome/content/unittests.js                 |  39 ----
 26 files changed, 1193 insertions(+), 1101 deletions(-)
 create mode 100644 chrome/content/code/browserOverlay.xul.js
 create mode 100644 chrome/content/code/editRedirect.xul.js
 create mode 100644 chrome/content/code/redirectList.xul.js
 create mode 100644 chrome/content/code/redirector.prototype.js
 delete mode 100644 chrome/content/help.html
 create mode 100644 chrome/content/images/redirector.png
 create mode 100644 chrome/content/images/statusactive.PNG
 create mode 100644 chrome/content/images/statusinactive.PNG
 delete mode 100644 chrome/content/overlay.js
 delete mode 100644 chrome/content/overlay.xul
 delete mode 100644 chrome/content/redirect.js
 delete mode 100644 chrome/content/redirect.xul
 delete mode 100644 chrome/content/redirectList.js
 delete mode 100644 chrome/content/redirectList.xul
 delete mode 100644 chrome/content/redirector.png
 delete mode 100644 chrome/content/redirector.prototype.js
 delete mode 100644 chrome/content/statusactive.PNG
 delete mode 100644 chrome/content/statusinactive.PNG
 create mode 100644 chrome/content/ui/browserOverlay.xul
 create mode 100644 chrome/content/ui/editRedirect.xul
 create mode 100644 chrome/content/ui/help.html
 create mode 100644 chrome/content/ui/redirectList.xul
 create mode 100644 chrome/content/unittest/run.html
 create mode 100644 chrome/content/unittest/testcases.js
 delete mode 100644 chrome/content/unittests.html
 delete mode 100644 chrome/content/unittests.js

(limited to 'chrome/content')

diff --git a/chrome/content/code/browserOverlay.xul.js b/chrome/content/code/browserOverlay.xul.js
new file mode 100644
index 0000000..636c02b
--- /dev/null
+++ b/chrome/content/code/browserOverlay.xul.js
@@ -0,0 +1,137 @@
+//// $Id$
+
+var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
+
+var RedirectorOverlay = {
+
+    id          : "redirector@einaregilsson.com",
+    name        : "Redirector",
+    initialized : false,
+    strings     : null,
+
+    onLoad : function(event) {
+        try {
+
+            // initialization code
+            Redirector.debug("Initializing...");
+            document.getElementById('contentAreaContextMenu')
+                .addEventListener("popupshowing", function(e) { RedirectorOverlay.showContextMenu(e); }, false);
+            
+            if (!Redirector.getBoolPref('showContextMenu')) {
+                document.getElementById('redirector-context').hidden = true;
+            }
+            if (!Redirector.getBoolPref('showStatusBarIcon')) {
+                document.getElementById('redirector-status').hidden = true;
+            }
+            this.strings = document.getElementById("redirector-strings");
+            this.prefObserver.register();
+            this.setStatusBarImg();
+
+            Redirector.debug("Finished initialization");
+            this.initialized = true;
+
+        } catch(e) {
+            if (this.strings) {
+                alert(this.strings.getFormattedString("initError", [this.name]) + "\n\n" + e);
+            } else {
+                alert(e);
+            }
+        }
+    },
+    
+    onUnload : function(event) {
+        RedirectorOverlay.prefObserver.unregister();
+        Redirector.debug("Finished cleanup");
+    },
+
+    showContextMenu : function(event) {
+        if (gContextMenu.onLink) {
+            document.getElementById("redirector-context").label = this.strings.getString('addLinkUrl');
+        } else {
+            document.getElementById("redirector-context").label = this.strings.getString('addCurrentUrl');
+        }
+    },
+
+    onContextMenuCommand: function(event) {
+
+        var item = { exampleUrl : window.content.location.href, pattern: window.content.location.href};
+        if (gContextMenu.onLink) {
+            item.redirectUrl = gContextMenu.link.toString();
+        }
+
+        window.openDialog("chrome://redirector/content/ui/editRedirect.xul",
+                    "redirect",
+                    "chrome,dialog,modal,centerscreen", item);
+
+        if (item.saved) {
+            Redirector.addRedirect(item);
+        }
+    },
+
+    onMenuItemCommand: function(event) {
+        this.openSettings();
+    },
+
+    toggleEnabled : function(event) {
+        Redirector.setEnabled(!Redirector.enabled);
+    },
+
+    openSettings : function() {
+        var windowName = "redirectorSettings";
+        var windowsMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
+        var win = windowsMediator.getMostRecentWindow(windowName);
+        if (win) {
+            win.focus();
+        } else {
+            window.openDialog("chrome://redirector/content/ui/redirectList.xul",
+                    windowName,
+                    "chrome,dialog,resizable=no,centerscreen", this);
+        }
+    
+    },
+    
+    statusBarClick : function(event) {
+        var LEFT = 0, RIGHT = 2;
+
+        if (event.button == LEFT) {
+            RedirectorOverlay.toggleEnabled();
+        } else if (event.button == RIGHT) {
+            this.openSettings();
+        }
+    },
+
+    setStatusBarImg : function() {
+        var statusImg = document.getElementById('redirector-statusbar-img');
+
+        if (Redirector.enabled) {
+            statusImg.src = 'chrome://redirector/content/images/statusactive.PNG'
+            statusImg.setAttribute('tooltiptext', this.strings.getString('enabledTooltip'));
+        } else {
+            statusImg.src = 'chrome://redirector/content/images/statusinactive.PNG'
+            statusImg.setAttribute('tooltiptext', this.strings.getString('disabledTooltip'));
+        }
+    },
+    
+    prefObserver : {
+
+        getService : function() {
+            return Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranchInternal);
+        },
+
+        register: function() {
+            this.getService().addObserver('extensions.redirector', this, false);
+        },
+
+        unregister: function() {
+            this.getService().removeObserver('extensions.redirector', this);
+        },
+
+        observe : function(subject, topic, data) {
+            if (topic == 'nsPref:changed' && data == 'extensions.redirector.enabled') {
+                RedirectorOverlay.setStatusBarImg();
+            }
+        }
+    }
+};
+window.addEventListener("load", function(event) { RedirectorOverlay.onLoad(event); }, false);
+window.addEventListener("unload", function(event) { RedirectorOverlay.onUnload(event); }, false);
diff --git a/chrome/content/code/editRedirect.xul.js b/chrome/content/code/editRedirect.xul.js
new file mode 100644
index 0000000..6e981d2
--- /dev/null
+++ b/chrome/content/code/editRedirect.xul.js
@@ -0,0 +1,86 @@
+//// $Id$
+
+const kRedirectorWildcard = 'W';
+const kRedirectorRegex= 'R';
+var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
+
+function $(id) {
+    return document.getElementById(id);
+}
+
+var EditRedirect = {
+
+    onLoad : function() {
+        var item = window.arguments[0];
+        item.saved = false;
+        $('txtExampleUrl').value = item.exampleUrl;
+        $('txtPattern').value = item.pattern;
+        $('txtRedirectUrl').value = item.redirectUrl || '';
+        $('txtExcludePattern').value = item.excludePattern || '';
+        $('chkUnescapeMatches').setAttribute('checked', !!item.unescapeMatches);
+
+        $('txtPattern').focus();
+        this.strings = document.getElementById("redirector-strings");
+
+        if (item.patternType == kRedirectorRegex) {
+            $('rdoRegex').setAttribute('selected', true);
+            $('rdoWildcard').setAttribute('selected', false);
+        }
+    },
+
+    onAccept : function() {
+        var item = window.arguments[0];
+
+        item.pattern = $('txtPattern').value;
+        if ($('rdoRegex').selected) {
+            item.patternType = kRedirectorRegex;
+        } else {
+            item.patternType = kRedirectorWildcard;
+        }
+        item.exampleUrl = $('txtExampleUrl').value;
+        item.redirectUrl = $('txtRedirectUrl').value;
+        item.excludePattern = $('txtExcludePattern').value;
+        item.unescapeMatches = $('chkUnescapeMatches').hasAttribute('checked') && $('chkUnescapeMatches').getAttribute('checked');
+        item.saved = true;
+
+        return true;
+    },
+
+    msgBox : function(title, text) {
+        Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+            .getService(Components.interfaces.nsIPromptService)
+                .alert(window, title, text);
+    },
+    
+    testPattern : function() {
+        var redirectUrl, pattern, excludePattern, example, extName, isExcluded, unescapeMatches;
+        redirectUrl = $('txtRedirectUrl').value;
+        pattern = $('txtPattern').value;
+        excludePattern = $('txtExcludePattern').value;
+        example = $('txtExampleUrl').value;
+		unescapeMatches = $('chkUnescapeMatches').checked;
+		
+        extName = this.strings.getString('extensionName');
+
+        if ($('rdoRegex').selected) {
+            redirectUrl = Redirector.regexMatch(pattern, example, redirectUrl, unescapeMatches);
+            if (excludePattern) {
+                isExcluded = Redirector.regexMatch(excludePattern, example, 'exclude');
+            }
+        } else {
+            redirectUrl = Redirector.wildcardMatch(pattern, example, redirectUrl, unescapeMatches);
+            if (excludePattern) {
+                isExcluded = Redirector.wildcardMatch(excludePattern, example, 'exclude');
+            }
+        }
+
+        var isRedirectMatch = redirectUrl || (redirectUrl === '' && $('txtRedirectUrl').value === '');
+        if (isRedirectMatch && !isExcluded) {
+            this.msgBox(extName, this.strings.getFormattedString('testPatternSuccess', [pattern, example, redirectUrl]));
+        } else if (isExcluded) {
+            this.msgBox(extName, this.strings.getFormattedString('testPatternExclude', [example, excludePattern]));
+        } else {
+            this.msgBox(extName, this.strings.getFormattedString('testPatternFailure', [pattern, example]));
+        }
+    }
+};
\ No newline at end of file
diff --git a/chrome/content/code/redirectList.xul.js b/chrome/content/code/redirectList.xul.js
new file mode 100644
index 0000000..65957b4
--- /dev/null
+++ b/chrome/content/code/redirectList.xul.js
@@ -0,0 +1,193 @@
+//// $Id$ 
+
+var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function $(id) {
+    return document.getElementById(id);
+}
+
+var RedirectList = {
+
+    id          : "redirector@einaregilsson.com",
+    name        : "Redirector",
+    lstRedirects: null,
+    btnDelete   : null,
+    btnEdit     : null,
+
+    addItemsToListBox : function(items) {
+
+        var list = $('lstRedirects');
+        var item, row, value, newItem;
+        
+        for each (item in items) {
+            newItem = this.template.cloneNode(true);
+
+            newItem.getElementsByAttribute('name', 'dscrIncludePattern')[0].setAttribute('value', item.pattern);
+            newItem.getElementsByAttribute('name', 'dscrExcludePattern')[0].setAttribute('value', item.excludePattern);
+            newItem.getElementsByAttribute('name', 'dscrRedirectTo')[0].setAttribute('value', item.redirectUrl);
+            newItem.item = item;
+            list.appendChild(newItem);
+            newItem.setAttribute("selected", false);
+        }
+        
+    },
+
+    onLoad : function() {
+        try {
+            this.lstRedirects = $('lstRedirects');
+            this.lstRedirects.selType = 'single'; 
+            this.template = document.getElementsByTagName('richlistitem')[0];
+            this.lstRedirects.removeChild(this.template);
+            this.btnDelete = $('btnDelete');
+            this.btnEdit = $('btnEdit');
+            this.addItemsToListBox(Redirector.list);
+        } catch(e) {
+            alert(e);
+        }
+    },
+
+    openHelp : function() {
+        var windowName = "redirectorHelp";
+        var windowsMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+        var win;
+        var iter = windowsMediator.getEnumerator(null);
+        while (iter.hasMoreElements()) {
+            win = iter.getNext();
+            if (win.name == windowName) {
+                win.focus();
+                return;
+            }
+        }
+        window.openDialog("chrome://redirector/content/ui/help.html", windowName, "chrome,dialog,resizable=yes,location=0,toolbar=0,status=0,width=800px,height=600px,centerscreen", this);
+    },
+    
+    close : function() {
+        window.close();
+    },
+    
+    moveUp : function(){
+        if (this.lstRedirects.selectedIndex <= 0) {
+            return;
+        }
+        this.switchItems(this.lstRedirects.selectedIndex-1);
+    },
+
+    moveDown : function() {
+        if (this.lstRedirects.selectedIndex == Redirector.list.length-1) {
+            return;
+        }
+        this.switchItems(this.lstRedirects.selectedIndex);
+    },
+
+    switchItems : function(firstIndex) {
+        var first = Redirector.list[firstIndex];
+        var second = Redirector.list[firstIndex+1];
+        Redirector.list[firstIndex] = second;
+        Redirector.list[firstIndex+1] = first;
+        this.setListItemValues(this.lstRedirects.children[firstIndex+1], first);
+        this.setListItemValues(this.lstRedirects.children[firstIndex], second);
+        this.lstRedirects.selectedIndex -= 1;
+        Redirector.save();
+    }, 
+    
+    setListItemValues : function(listItem, item){
+        listItem.getElementsByAttribute('name', 'dscrIncludePattern')[0].setAttribute('value', item.pattern);
+        listItem.getElementsByAttribute('name', 'dscrExcludePattern')[0].setAttribute('value', item.excludePattern);
+        listItem.getElementsByAttribute('name', 'dscrRedirectTo')[0].setAttribute('value', item.redirectUrl);
+    },
+    
+    addRedirect : function() {
+
+        var item = { pattern : '', exampleUrl : '', redirectUrl : '', patternType : 'W', unescapeMatches : false};
+
+        window.openDialog("chrome://redirector/content/ui/editRedirect.xul",
+                    "redirect",
+                    "chrome,dialog,modal,centerscreen", item);
+
+        if (item.saved) {
+            this.addItemsToListBox([item]);
+            Redirector.addRedirect(item);
+        }
+
+    },
+
+    editRedirect : function() {
+
+        var listItem = this.lstRedirects.selectedItem;
+
+        if (!listItem) {
+            return;
+        }
+
+        var item = listItem.item;
+
+        window.openDialog("chrome://redirector/content/ui/editRedirect.xul",
+                    "redirect",
+                    "chrome,dialog,modal,centerscreen", item);
+
+        if (item.saved) {
+            this.setListItemValues(listItem, item);
+            Redirector.save();
+        }
+    },
+
+    deleteRedirect : function() {
+        var index = this.lstRedirects.selectedIndex;
+
+        if (index == -1) {
+            return;
+        }
+
+        try {
+            this.lstRedirects.removeChild(this.lstRedirects.children[index]);
+            Redirector.deleteAt(index);
+        } catch(e) {
+            alert(e);
+        }
+    },
+
+    selectionChange : function() {
+        var index = $('lstRedirects').selectedIndex;
+
+        $('btnEdit').disabled = (index == -1);
+        $('btnDelete').disabled = (index == -1);
+    },
+    
+    importExport : function(mode, captionKey, func) {
+	    //Mostly borrowed from Adblock Plus
+		var picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+		picker.init(window, Redirector.getString(captionKey), mode);
+		picker.defaultExtension = ".rdx";
+		var dir = Redirector.getDefaultDir();
+		if (dir) {
+			picker.displayDirectory = dir;
+		}
+		picker.appendFilter(Redirector.getString('redirectorFiles'), '*.rdx');
+	
+		if (picker.show() != picker.returnCancel)
+		{
+			try
+			{
+				func(picker.file);
+			}
+			catch (e)
+			{
+				alert(e);
+			}
+		}
+    },
+    
+    export : function() {
+	    this.importExport(Ci.nsIFilePicker.modeSave, 'exportCaption', function(file) {
+		    Redirector.exportRedirects(file);
+	    });
+    },
+    
+    import : function() {
+	    this.importExport(Ci.nsIFilePicker.modeOpen, 'importCaption', function(file) {
+		    Redirector.importRedirects(file);
+	    });
+    }
+};
diff --git a/chrome/content/code/redirector.prototype.js b/chrome/content/code/redirector.prototype.js
new file mode 100644
index 0000000..24a41ba
--- /dev/null
+++ b/chrome/content/code/redirector.prototype.js
@@ -0,0 +1,333 @@
+//// $Id$
+
+Cc = Components.classes;
+Ci = Components.interfaces;
+Cr = Components.results;
+kRedirectorWildcard = 'W';
+kRedirectorRegex= 'R';
+nsIContentPolicy = Ci.nsIContentPolicy;
+
+
+Redirector.prototype = {
+    prefBranch : null,
+    list : null,
+    strings : null,
+    cout : Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService),
+
+    init : function() {
+	    this.prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("extensions.redirector.");
+	
+	    //Check if we need to update existing redirects
+	
+	    var data = this.prefBranch.getCharPref('redirects');
+	    var version = this.prefBranch.getCharPref('version');
+	    this.debugEnabled = this.prefBranch.getBoolPref('debug');
+	    this.enabled = this.prefBranch.getBoolPref('enabled');
+	    this.loadStrings();
+	    //Here update checks are handled
+	    if (version == 'undefined') { //Either a fresh install of Redirector, or first time install of v2.0
+	        if (data) { //There is some data in redirects, we are upgrading from a previous version, need to upgrade data
+	            var tempList = eval(data);
+	            var arr;
+	            var newArr = []
+	            for each (arr in tempList) {
+	                if (arr.length == 5) {
+	                    arr.push(''); //For those that don't have an exclude pattern. Backwards compatibility is a bitch!
+	                }
+	                arr.splice(3,1); //Remove the "only if link exists" data
+	                newArr.push(arr.join(',,,'));
+	            }
+	            this.prefBranch.setCharPref('redirects', newArr.join(':::'));
+	        }
+	        this.prefBranch.setCharPref('version', '2.0');
+	    }
+	    //Update finished
+	    
+	    //Now get from the new format
+	    data = this.prefBranch.getCharPref('redirects');
+	    var arr;
+	    this.list = [];
+	    if (data != '') {
+	        for each (redirectString in data.split(':::')) {
+	            arr = redirectString.split(',,,');
+	            this.list.push({
+	                exampleUrl          : arr[0],
+	                pattern             : arr[1],
+	                redirectUrl         : arr[2],
+	                patternType         : arr[3],
+	                excludePattern      : arr[4],
+	                unescapeMatches		: arr[5] == 'true' //This might be undefined for those upgrading from 1.7.1 but that's ok
+	            });
+	        }
+	    }
+	    
+    },
+    
+    getDefaultDir : function() {
+		return this.prefBranch.getCharPref('defaultDir');    
+    },
+    
+    setDefaultDir : function(dir) {
+		this.prefBranch.setCharPref('defaultDir', dir.spec);
+    },
+
+    loadStrings : function() {
+        var src = 'chrome://redirector/locale/redirector.properties';
+        var localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
+        var appLocale = localeService.getApplicationLocale();
+        var stringBundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
+        this.strings = stringBundleService.createBundle(src, appLocale);    
+    },    
+    
+    debug : function(msg) {
+        if (this.debugEnabled) {
+            this.cout.logStringMessage('REDIRECTOR: ' + msg);
+        }
+    },
+    
+    // nsIContentPolicy interface implementation
+    shouldLoad: function(contentType, contentLocation, requestOrigin, aContext, mimeTypeGuess, extra) {
+        if (!this.enabled) {
+            return nsIContentPolicy.ACCEPT;
+        }
+        if (contentLocation.scheme != "http" && contentLocation.scheme != "https") {
+            return nsIContentPolicy.ACCEPT;
+        }
+
+        if (contentType != nsIContentPolicy.TYPE_DOCUMENT) {
+            return nsIContentPolicy.ACCEPT;
+        }
+        
+        if (!aContext || !aContext.loadURI) {
+            return nsIContentPolicy.ACCEPT;
+        }
+        this.debug("CHECK: " + contentLocation.spec);
+        
+        var url = contentLocation.spec;
+        
+        for each (var redirect in this.list) {
+            var redirectUrl = this.getRedirectUrl(url, redirect);
+            if (redirectUrl) {
+                redirectUrl = this.makeAbsoluteUrl(url, redirectUrl);
+                this.debug('Redirecting ' + url + ' to ' + redirectUrl);
+                aContext.loadURI(redirectUrl, requestOrigin, null);
+                return nsIContentPolicy.REJECT_REQUEST;
+            }
+        }
+        return nsIContentPolicy.ACCEPT;
+    },
+
+    // nsIContentPolicy interface implementation
+    shouldProcess: function(contentType, contentLocation, requestOrigin, insecNode, mimeType, extra) {
+        return nsIContentPolicy.ACCEPT;
+    },
+
+    setEnabled : function(val) {
+        this.enabled = val;
+        this.prefBranch.setBoolPref('enabled', val);
+    },
+    
+    reload : function() {
+		Cc["@mozilla.org/moz/jssubscript-loader;1"]
+			.getService(Ci.mozIJSSubScriptLoader)
+				.loadSubScript('chrome://redirector/content/code/redirector.prototype.js');
+		
+		for (var key in Redirector.prototype) {
+			this[key] = Redirector.prototype[key];
+		}
+		this.init();
+    }, 
+    
+    addRedirect : function(redirect) {
+        this.list.push(redirect);
+        this.save();
+    },
+
+    deleteAt : function(index) {
+        this.list.splice(index, 1);
+        this.save();
+    },
+    
+    save : function() {
+        this.prefBranch.setCharPref('redirects', this.redirectsAsStrings().join(':::'));
+    },
+    
+    redirectsAsStrings : function() {
+        var r
+          , tempList = [];
+
+        for each (r in this.list) {
+	        this.debug(r.unescapeMatches);
+            tempList.push([r.exampleUrl, r.pattern, r.redirectUrl, r.patternType, r.excludePattern, r.unescapeMatches].join(',,,'));
+        }
+        return tempList;
+    },
+    
+    getBoolPref : function(name) {
+        return this.prefBranch.getBoolPref(name);
+    },
+    
+    regexMatch : function(pattern, text, redirectUrl, unescapeMatches) {
+
+        if (!pattern) {
+            return null;
+        }
+        var strings, rx, match;
+        try {
+            rx = new RegExp(pattern, 'gi');
+            match = rx.exec(text);
+        } catch(e) {
+            this.msgBox(this.strings.GetStringFromName('extensionName'), this.strings.formatStringFromName('regexPatternError', [pattern, e.toString()],2));
+            return null;
+        }
+
+        var rxrepl;
+
+        if (match) {
+            for (var i = 1; i < match.length; i++) {
+                rxrepl = new RegExp('\\$' + i, 'gi');
+                redirectUrl = redirectUrl.replace(rxrepl, unescapeMatches ? unescape(match[i]) : match[i]);
+            }
+            return redirectUrl;
+        }
+
+        return null;
+
+    },
+
+	exportRedirects : function(file) {
+		var fileStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+		const PR_WRONLY      = 0x02;
+		const PR_CREATE_FILE = 0x08;
+		const PR_TRUNCATE    = 0x20;
+
+		fileStream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644, 0);
+		//file.parent.QueryInterface(Ci.nsILocalFile)
+		var stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
+		stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
+		stream.writeString(this.redirectsAsStrings().join('\n'));
+		stream.close();
+	},
+	
+	importRedirects : function(file) {
+		var fileStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
+		fileStream.init(file, 0x01, 0444, 0); //TODO: Find the actual constants for these magic numbers
+
+		var stream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
+		stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
+		stream = stream.QueryInterface(Ci.nsIUnicharLineInputStream);
+
+		var importCount = 0, existsCount = 0;
+		var lines = [];
+		var line = {value: null};
+		while (stream.readLine(line)) {
+			var parts = line.replace('\n', '').split(',,,');
+			if (parts.length < 6) {
+				var redirect = {
+	                exampleUrl          : parts[0],
+	                pattern             : parts[1],
+	                redirectUrl         : parts[2],
+	                patternType         : parts[3],
+	                excludePattern      : parts[4],
+	                unescapeMatches		: parts[5] == 'true' ? true : false 
+                };
+                
+                
+			}
+		}
+		stream.close();
+		this.save();
+	},
+	
+    getString : function(name) {
+	    return this.strings.GetStringFromName(name);
+    },
+    
+    msgBox : function(title, text) {
+        Cc["@mozilla.org/embedcomp/prompt-service;1"]
+            .getService(Ci.nsIPromptService)
+                .alert(null, title, text);
+    },
+
+    getRedirectUrl: function(url, redirect) {
+    
+        if (redirect.patternType == kRedirectorWildcard) {
+            if (this.wildcardMatch(redirect.excludePattern, url, 'whatever')) {
+                this.debug(url + ' matches exclude pattern ' + redirect.excludePattern);
+                return null;
+            }
+            return this.wildcardMatch(redirect.pattern, url, redirect.redirectUrl, redirect.unescapeMatches);
+        } else if (redirect.patternType == kRedirectorRegex) {
+            if (this.regexMatch(redirect.excludePattern, url, 'whatever')) {
+                this.debug(url + ' matches exclude pattern ' + redirect.excludePattern);
+                return null;
+            }
+            return this.regexMatch(redirect.pattern, url, redirect.redirectUrl, redirect.unescapeMatches);
+        }
+        return null;
+    },
+
+    makeAbsoluteUrl : function(currentUrl, relativeUrl) {
+        
+        if (relativeUrl.match(/https?:/)) {
+            return relativeUrl;
+        } 
+        
+        var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+        //this.debug(currentUrl);
+        var uri = ioService.newURI(currentUrl, null, null); 
+        
+        return uri.resolve(relativeUrl);
+    },
+    
+    wildcardMatch : function(pattern, text, redirectUrl, unescapeMatches) {
+
+	    if (!pattern || !text) {
+	    	return null;
+		}
+		if (pattern.indexOf('*') == -1) {
+			return (pattern == text) ? redirectUrl : null;
+		}
+		
+		var parts = pattern.split('*');  
+		var first = parts[0], 
+		    last  = parts[parts.length-1];
+
+		if (first) {
+			if (text.substr(0, first.length) != first) {
+				return null;
+			}
+			text = text.substr(first.length);
+		}
+
+		if (last) {
+			if (text.substr(text.length-last.length) != last) {
+				return null;
+			}
+			text = text.substr(0, text.length-last.length);
+		}
+		
+		if ((first || last) && parts.length == 2) {
+			return redirectUrl.replace('$1', text);
+		}
+		parts.splice(0,1);
+		parts.splice(parts.length-1,1);
+		var pos = 0, lastPos = 0;
+    	var matches = [];
+		for each(part in parts) {
+            pos = text.indexOf(part, lastPos);
+            if (pos == -1) {
+                return null;
+            }
+            var match = text.substr(lastPos, pos-lastPos);
+            matches.push(match);
+            lastPos = pos + part.length;
+        }
+        matches.push(text.substr(lastPos));
+        for (var i = 1; i <= matches.length; i++) {
+            redirectUrl = redirectUrl.replace(new RegExp('\\$' + i, 'gi'), unescapeMatches ? unescape(matches[i-1]) : matches[i-1]);
+        }
+
+        return redirectUrl;
+    }
+};
diff --git a/chrome/content/help.html b/chrome/content/help.html
deleted file mode 100644
index 0ce6769..0000000
--- a/chrome/content/help.html
+++ /dev/null
@@ -1,173 +0,0 @@
-<!-- $Id$ -->
-<html>
-	<head>
-		<title>Redirector Help</title>
-		<style type="text/css">
-			body { font-family: Verdana, Arial; color:black; background-color:white; font-size:0.9em;}
-			a { color:blue; }
-		</style>
-	</head>
-	<body>
-		<h1>Redirector Help</h1>
-		<h3>Table of contents</h3>
-		<ul>
-			<li><a href="#whatisredirector">What is Redirector?</a></li>
-			<li><a href="#basicusage">Basic usage</a>
-				<ul>
-					<li><a href="#exampleurl">Example url</a></li>
-					<li><a href="#includepattern">Include pattern</a></li>
-					<li><a href="#excludepattern">Exclude pattern</a></li>
-					<li><a href="#redirectto">Redirect to</a></li>
-					<li><a href="#patterntype">Pattern type</a></li>
-				</ul>
-			</li>
-			<li><a href="#wildcards">Wildcards</a></li>
-			<li><a href="#regularexpressions">Regular expressions</a></li>
-			<li><a href="#examples">Examples</a>
-				<ol>
-					<li><a href="#ex1">Static redirect</a></li>
-					<li><a href="#ex2">Redirect using query string parameter and wildcards</a></li>
-					<li><a href="#ex3">Redirect using query string parameter and regular expressions</a></li>
-					<li><a href="#ex4">Redirect to a different folder using wildcards</a></li>
-					<li><a href="#ex5">Redirect http to https using wildcards</a></li>
-				</ol>
-			
-			</li>
-		</ul>
-		
-		
-		<a name="whatisredirector"></a>
-		<h4>What is Redirector?</h4>
-		
-		<p>Redirector is an extension for Firefox that allows you to automatically redirect from
-		one webpage to another. For example, every time you visit http://abc.com you will automatically
-		load http://def.com instead. This can be useful for instance to always redirect articles to printer friendly
-		versions, redirect http:// to https:// for sites that support both, bypass advertising pages that appear before
-		being able to view certain pages and more.</p>
-		
-		<a name="basicusage"></a>
-		<h4>Basic usage</h4>
-		<p>To add a new redirect you can go to the <em>Tools</em> menuitem and select <em>Redirector</em>. That will
-		open the <em>Redirector settings</em> window which shows all your redirects. The window can also be opened
-		by right clicking on the <strong>R</strong> icon in your statusbar. 
-		There you can press the <em>Add...</em> button and then you can enter the details for the new redirect. A redirect
-		consists of a few things:
-		<ul>
-			<li><a name="exampleurl"></a><strong>Example url:</strong> This is an example of an url you want to redirect. It is not really used for anything,
-			it's just there to show what types of urls you're targetting. You can leave this out, but then you can't use the <em>Test pattern</em> button.</li>
-			
-			<li><a name="includepattern"></a><strong>Include pattern:</strong> This is pattern for the urls you want to redirect. In the simplest case, where you just want
-			to redirect one specific url to another then this will just be the exact url you want to redirect. For instance, if you just want http://aaa.com to
-			redirect to http://bbb.com then <em>Include pattern</em> will just be http://aaa.com. For more complex patterns that match many
-			urls you can use either <a href="#wildcards">wildcards</a> or <a href="#regularexpressions">regular expressions</a>.</li>
-			
-            <li><a name="excludepattern"></a><strong>Exclude pattern:</strong> Urls that match this pattern will never be redirected. This is not necessary to
-            fill out, but can be useful when you want to redirect all urls that contain some text except if they contain some other text. 
-            Redirects like that can often be done with a complex regular expression, but using an exclude pattern makes it much simpler. The exclude
-            patterns can use wildcard characters or regular expressions like the include patterns.</li>
-
-            <li><a name="redirectto"></a><strong>Redirect to:</strong> This is the url that you will be redirected to when you open any page where the url matches the
-            include pattern. You can use the special signs $1, $2, $3 etc. in the url, they will be replaced by the results of captures with regular
-            expressions or stars with wildcards. For instance, if you have the include pattern <em>http://google.com/*</em>, redirect to <em>http://froogle.com/$1</em>
-            and you open the page http://google.com/foobar, then you will be redireced to http://froogle.com/foobar, since 'foobar' was what the star replaced. $1 is for the
-            first star in the pattern, $2 for the second and so on. For regular expression $1 is for the first parantheses, $2 for the second etc.</li>
-		
-            <li><a name="patterntype"></a><strong>Pattern type:</strong> This specifies how Redirector should interpret the patterns, either as
-            <a href="#wildcards">wildcards</a> or <a href="#regularexpressions#">regular expressions</a>.</li>
-            
-		</ul>
-		</p>
-
-		<a name="wildcards"></a>
-		<h4>Wildcards</h4>
-		
-		<p>Wildcards are the simplest way to specify include and exclude patterns. When you create a wildcard pattern there
-		is just one special character, the asterisk *. An asterisk in your pattern will match zero or more characters and you can
-		have more than one star in your pattern. Some examples:
-			<ul>
-				<li><em>http://example.com/*</em> matches http://example.com/, http://example.com/foo, http://example.com/bar and all other urls that start with http://example.com/.</li>
-				<li><em>http://*.example.com</em> matches all subdomains of example.com, like http://www.example.com, http://mail.example.com.</li>
-				<li><em>http*://example.com</em> matches both http://example.com and https://example.com.</li>
-				<li><em>http://example.com/index.asp*</em> matches http://example.com/index.asp, http://example.com/index.asp?a=b&c=d.</li>
-			</ul>
-		$1, $2, $3 in the redirect urls will match the text that the stars matched. Examples:
-			<ul>
-				<li><em>http://example.com/*</em> matches http://example.com/foobar, $1 is foobar.</li>
-				<li><em>http://*.example.com/*</em> matches http://www.example.com/foobar, $1 is www, $2 is foobar.</li>
-			</ul>
-		</p>
-		
-		<a name="regularexpressions"></a>
-		<h4>Regular expressions</h4>
-		
-		<p>Regular expressions allow for more complicated patterns but they are a lot harder to learn than wildcards. I'm not gonna
-		create a regex tutorial here but normal javascript regex syntax works, look at <a href="http://regular-expressions.info" target="_blank">http://regular-expressions.info</a> for
-		an introduction to regular expressions. $1,$2 etc. can be used in the redirect url and will be replaced with contents of captures in
-		the regular expressions. Captures are specified with parantheses. Example: http://example.com/index.asp\?id=(\d+) will match the url
-		http://example.com/index.asp?id=12345 and $1 will be replaced by 12345. (A common mistake in regex patterns is to forget to escape
-		the ? sign in the querystring of the url. ? is a special character in regular expressions so if you want to match an url with a querystring
-		you should escape it as \?).</p>
-
-		<a name="examples"></a>
-		<h4>Examples</h4>
-		
-		<ol>
-			<li>
-				<strong><a name="ex1"></a>Static redirect</strong><br/>
-				Redirects from http://example.com/foo to http://example.com/bar
-				<p>
-					<strong>Include pattern:</strong> http://example.com/foo<br/>
-					<strong>Exclude pattern:</strong><br/>
-					<strong>Redirect to:</strong> http://example.com/bar<br/>
-					<strong>Pattern type:</strong> Wildcard<br />
-				</p>
-				
-			</li>
-			<li>
-				<strong><a name="ex2"></a>Redirect using query string parameter and wildcards</strong><br/>
-				Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
-				where 12345 could be any number.
-				<p>
-					<strong>Include pattern:</strong> http://example.com/index.php?id=*&a=b<br/>
-					<strong>Exclude pattern:</strong><br/>
-					<strong>Redirect to:</strong> http://example.com/printerfriendly.com?id=$1&a=b<br/>
-					<strong>Pattern type:</strong> Wildcard<br />
-				</p>
-			</li>
-			<li>
-				<strong><a name="ex3"></a>Redirect using query string parameter and regular expressions</strong><br/>
-				Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
-				where 12345 could be any number.
-				<p>
-					<strong>Include pattern:</strong> http://example.com/index.php\?id=(\d+)&a=b<br/>
-					<strong>Exclude pattern:</strong><br/>
-					<strong>Redirect to:</strong> http://example.com/printerfriendly.com?id=$1&a=b<br/>
-					<strong>Pattern type:</strong> Regular Expression<br />
-				</p>
-			</li>
-			<li>
-				<strong><a name="ex4"></a>Redirect to a different folder using wildcards</strong><br/>
-				Redirects from http://example.com/category/fish/index.php to http://example.com/category/cats/index.php
-				where fish could be any word. The exclude pattern makes sure that there is only one
-				folder there, so for instance http://example.com/category/fish/cat/mouse/index.php would not match.
-				<p>
-					<strong>Include pattern:</strong> http://example.com/category/*/index.php<br/>
-					<strong>Exclude pattern:</strong> http://example.com/category/*/*/index.php<br/>
-					<strong>Redirect to:</strong> http://example.com/category/cats/index.php<br/>
-					<strong>Pattern type:</strong> Wildcard<br />
-				</p>
-			</li>
-			<li>
-				<strong><a name="ex5"></a>Redirect http to https using wildcards</strong><br/>
-				Redirects from http://mail.google.com/randomcharacters to https://mail.google.com/randomcharacters
-				where randomcharacters could be anything.
-				<p>
-					<strong>Include pattern:</strong> http://mail.google.com*<br/>
-					<strong>Exclude pattern:</strong><br/>
-					<strong>Redirect to:</strong> https://mail.google.com$1<br/>
-					<strong>Pattern type:</strong> Wildcard<br />
-				</p>
-			</li>
-		</ol>
-	</body>
-</html>
\ No newline at end of file
diff --git a/chrome/content/images/redirector.png b/chrome/content/images/redirector.png
new file mode 100644
index 0000000..f8de12c
Binary files /dev/null and b/chrome/content/images/redirector.png differ
diff --git a/chrome/content/images/statusactive.PNG b/chrome/content/images/statusactive.PNG
new file mode 100644
index 0000000..06ce766
Binary files /dev/null and b/chrome/content/images/statusactive.PNG differ
diff --git a/chrome/content/images/statusinactive.PNG b/chrome/content/images/statusinactive.PNG
new file mode 100644
index 0000000..8b83562
Binary files /dev/null and b/chrome/content/images/statusinactive.PNG differ
diff --git a/chrome/content/overlay.js b/chrome/content/overlay.js
deleted file mode 100644
index 760f828..0000000
--- a/chrome/content/overlay.js
+++ /dev/null
@@ -1,142 +0,0 @@
-//// $Id$
-
-var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
-
-function $(id) {
-    return document.getElementById(id);
-}
-
-var RedirectorOverlay = {
-
-    id          : "redirector@einaregilsson.com",
-    name        : "Redirector",
-    initialized : false,
-    strings     : null,
-
-    onLoad : function(event) {
-        try {
-
-            // initialization code
-            Redirector.debug("Initializing...");
-            $('contentAreaContextMenu')
-                .addEventListener("popupshowing", function(e) { RedirectorOverlay.showContextMenu(e); }, false);
-            
-            if (!Redirector.getBoolPref('showContextMenu')) {
-                $('redirector-context').hidden = true;
-            }
-            if (!Redirector.getBoolPref('showStatusBarIcon')) {
-                $('redirector-status').hidden = true;
-            }
-            this.strings = document.getElementById("redirector-strings");
-            this.prefObserver.register();
-            this.setStatusBarImg();
-
-            Redirector.debug("Finished initialization");
-            this.initialized = true;
-
-        } catch(e) {
-            if (this.strings) {
-                alert(this.strings.getFormattedString("initError", [this.name]) + "\n\n" + e);
-            } else {
-                alert(e);
-            }
-        }
-    },
-    
-    onUnload : function(event) {
-        RedirectorOverlay.prefObserver.unregister();
-        Redirector.debug("Finished cleanup");
-    },
-
-    showContextMenu : function(event) {
-        if (gContextMenu.onLink) {
-            $("redirector-context").label = this.strings.getString('addLinkUrl');
-        } else {
-            $("redirector-context").label = this.strings.getString('addCurrentUrl');
-        }
-    },
-
-    onContextMenuCommand: function(event) {
-
-        var item = { exampleUrl : window.content.location.href, pattern: window.content.location.href};
-        if (gContextMenu.onLink) {
-            item.redirectUrl = gContextMenu.link.toString();
-        }
-
-        window.openDialog("chrome://redirector/content/redirect.xul",
-                    "redirect",
-                    "chrome,dialog,modal,centerscreen", item);
-
-        if (item.saved) {
-            Redirector.addRedirect(item);
-        }
-    },
-
-    onMenuItemCommand: function(event) {
-        this.openSettings();
-    },
-
-    toggleEnabled : function(event) {
-        Redirector.setEnabled(!Redirector.enabled);
-    },
-
-    openSettings : function() {
-        var windowName = "redirectorSettings";
-        var windowsMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
-        var win = windowsMediator.getMostRecentWindow(windowName);
-        if (win) {
-            win.focus();
-        } else {
-            window.openDialog("chrome://redirector/content/redirectList.xul",
-                    windowName,
-                    "chrome,dialog,resizable=no,centerscreen", this);
-        }
-    
-    },
-    
-    statusBarClick : function(event) {
-        var LEFT = 0, RIGHT = 2;
-
-        if (event.button == LEFT) {
-            RedirectorOverlay.toggleEnabled();
-        } else if (event.button == RIGHT) {
-            this.openSettings();
-            //$('redirector-status-popup').showPopup();
-        }
-    },
-
-    setStatusBarImg : function() {
-        var statusImg = $('redirector-statusbar-img');
-
-        if (Redirector.enabled) {
-            statusImg.src = 'chrome://redirector/content/statusactive.PNG'
-            statusImg.setAttribute('tooltiptext', this.strings.getString('enabledTooltip'));
-        } else {
-            statusImg.src = 'chrome://redirector/content/statusinactive.PNG'
-            statusImg.setAttribute('tooltiptext', this.strings.getString('disabledTooltip'));
-        }
-    },
-    
-    prefObserver : {
-
-        getService : function() {
-            return Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranchInternal);
-        },
-
-        register: function() {
-            this.getService().addObserver('extensions.redirector', this, false);
-        },
-
-        unregister: function() {
-            this.getService().removeObserver('extensions.redirector', this);
-        },
-
-        observe : function(subject, topic, data) {
-            if (topic == 'nsPref:changed' && data == 'extensions.redirector.enabled') {
-                RedirectorOverlay.setStatusBarImg();
-            }
-        }
-    }
-};
-window.addEventListener("load", function(event) { RedirectorOverlay.onLoad(event); }, false);
-window.addEventListener("unload", function(event) { RedirectorOverlay.onUnload(event); }, false);
diff --git a/chrome/content/overlay.xul b/chrome/content/overlay.xul
deleted file mode 100644
index 9c4619e..0000000
--- a/chrome/content/overlay.xul
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- $Id$ -->
-<!DOCTYPE overlay SYSTEM "chrome://redirector/locale/redirector.dtd">
-<overlay id="redirector-overlay"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script src="overlay.js"/>
-
-  <stringbundleset id="stringbundleset">
-    <stringbundle id="redirector-strings" src="chrome://redirector/locale/redirector.properties"/>
-  </stringbundleset>
-
-  <menupopup id="menu_ToolsPopup">
-    <menuitem id="redirector-menuitem" label="&RedirectorMenuItem.label;"
-              accesskey="&RedirectorMenuItem.accesskey;"
-              oncommand="RedirectorOverlay.onMenuItemCommand(event);"/>
-  </menupopup>
-  <popup id="contentAreaContextMenu">
-    <menuitem id="redirector-context" label="&RedirectorContext.label;"
-              accesskey="&RedirectorContext.accesskey;"
-              insertafter="context-stop"
-              oncommand="RedirectorOverlay.onContextMenuCommand(event)"/>
-  </popup>
-  <statusbar id="status-bar">
-  <statusbarpanel id="redirector-status">
-      <!-- Put back in later
-      <menupopup id="redirector-status-popup" position="at_pointer">
-        <menuitem label="&RedirectorManageRedirects.label;" accesskey="&RedirectorManageRedirects.accesskey;" oncommand="RedirectorOverlay.openSettings();" />
-        <menuitem label="&RedirectorHelp.label;" accesskey="&RedirectorHelp.accesskey;" oncommand="Redirector.openHelp();" />
-      </menupopup>
-      -->
-      <image id="redirector-statusbar-img" src="chrome://redirector/content/statusactive.PNG"
-             tooltiptext="Redirector is enabled;"
-             style="width:16px; height:16px;"
-             onclick="RedirectorOverlay.statusBarClick(event);" />
-  </statusbarpanel>
-  </statusbar>
-
-</overlay>
\ No newline at end of file
diff --git a/chrome/content/redirect.js b/chrome/content/redirect.js
deleted file mode 100644
index f51e7f2..0000000
--- a/chrome/content/redirect.js
+++ /dev/null
@@ -1,86 +0,0 @@
-//// $Id$
-
-const kRedirectorWildcard = 'W';
-const kRedirectorRegex= 'R';
-var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
-
-function $(id) {
-    return document.getElementById(id);
-}
-
-var Redirect = {
-
-    onLoad : function() {
-        var item = window.arguments[0];
-        item.saved = false;
-        $('txtExampleUrl').value = item.exampleUrl;
-        $('txtPattern').value = item.pattern;
-        $('txtRedirectUrl').value = item.redirectUrl || '';
-        $('txtExcludePattern').value = item.excludePattern || '';
-        $('chkUnescapeMatches').setAttribute('selected', !!item.unescapeMatches);
-
-        $('txtPattern').focus();
-        this.strings = document.getElementById("redirector-strings");
-
-        if (item.patternType == kRedirectorRegex) {
-            $('rdoRegex').setAttribute('selected', true);
-            $('rdoWildcard').setAttribute('selected', false);
-        }
-    },
-
-    onAccept : function() {
-        var item = window.arguments[0];
-
-        item.pattern = $('txtPattern').value;
-        if ($('rdoRegex').selected) {
-            item.patternType = kRedirectorRegex;
-        } else {
-            item.patternType = kRedirectorWildcard;
-        }
-        item.exampleUrl =$('txtExampleUrl').value;
-        item.redirectUrl = $('txtRedirectUrl').value;
-        item.excludePattern = $('txtExcludePattern').value;
-        item.unescapeMatches = $('chkUnescapeMatches').selected;
-        item.saved = true;
-
-        return true;
-    },
-
-    msgBox : function(title, text) {
-        Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
-            .getService(Components.interfaces.nsIPromptService)
-                .alert(window, title, text);
-    },
-    
-    testPattern : function() {
-        var redirectUrl, pattern, excludePattern, example, extName, isExcluded, unescapeMatches;
-        redirectUrl = $('txtRedirectUrl').value;
-        pattern = $('txtPattern').value;
-        excludePattern = $('txtExcludePattern').value;
-        example = $('txtExampleUrl').value;
-		unescapeMatches = $('chkUnescapeMatches').checked;
-		
-        extName = this.strings.getString('extensionName');
-
-        if ($('rdoRegex').selected) {
-            redirectUrl = Redirector.regexMatch(pattern, example, redirectUrl, unescapeMatches);
-            if (excludePattern) {
-                isExcluded = Redirector.regexMatch(excludePattern, example, 'exclude');
-            }
-        } else {
-            redirectUrl = Redirector.wildcardMatch(pattern, example, redirectUrl, unescapeMatches);
-            if (excludePattern) {
-                isExcluded = Redirector.wildcardMatch(excludePattern, example, 'exclude');
-            }
-        }
-
-        var isRedirectMatch = redirectUrl || (redirectUrl === '' && $('txtRedirectUrl').value === '');
-        if (isRedirectMatch && !isExcluded) {
-            this.msgBox(extName, this.strings.getFormattedString('testPatternSuccess', [pattern, example, redirectUrl]));
-        } else if (isExcluded) {
-            this.msgBox(extName, this.strings.getFormattedString('testPatternExclude', [example, excludePattern]));
-        } else {
-            this.msgBox(extName, this.strings.getFormattedString('testPatternFailure', [pattern, example]));
-        }
-    }
-};
\ No newline at end of file
diff --git a/chrome/content/redirect.xul b/chrome/content/redirect.xul
deleted file mode 100644
index d3b0907..0000000
--- a/chrome/content/redirect.xul
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- $Id$ -->
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<!DOCTYPE dialog SYSTEM "chrome://redirector/locale/redirect.dtd">
-<dialog title="&redirectWindow.title;"
-        orient="vertical"
-        autostretch="always"
-        onload="Redirect.onLoad();"
-        buttons="accept,cancel"
-        ondialogaccept="return Redirect.onAccept();"
-        xmlns:nc="http://home.netscape.com/NC-rdf#"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-  <script type="application/x-javascript" src="redirect.js"/>
-  <stringbundleset id="stringbundleset">
-    <stringbundle id="redirector-strings" src="chrome://redirector/locale/redirector.properties"/>
-  </stringbundleset>
-
-  <grid>
-    <rows>
-      <row align="center">
-        <text value="&txtExampleUrl.label;" style="margin-top:6px;"/>
-        <textbox id="txtExampleUrl" style="width:400px;"/>
-      </row>
-      <row align="center">
-        <text value="&txtPattern.label;" style="margin-top:6px;"/>
-        <textbox id="txtPattern" taborder="1"/>
-        <button id="btnTestPattern" label="&btnTestPattern.label;" onclick="Redirect.testPattern();" taborder="2"/>
-      </row>
-      <row align="center">
-        <text value="&txtExcludePattern.label;" style="margin-top:6px;"/>
-        <textbox id="txtExcludePattern" taborder="3"/>
-      </row>
-      <row align="center">
-        <text value="&txtRedirectUrl.label;" style="margin-top:6px;"/>
-        <textbox id="txtRedirectUrl" taborder="4"/>
-      </row>
-      <row align="center">
-        <text value="&rdoPatternTypes.label;"/>
-        <radiogroup>
-          <hbox>
-            <radio id="rdoWildcard" label="&rdoWildcard.label;" accesskey="&rdoWildcard.accessKey;" selected="true" taborder="5"/>
-            <radio id="rdoRegex" label="&rdoRegex.label;"  accesskey="&rdoRegex.accessKey;" taborder="6"/>
-          </hbox>
-        </radiogroup>
-      </row>
-      <row align="center">
-        <text value="&chkUnescapeMatches.label;" />
-        <checkbox id="chkUnescapeMatches" label="" taborder="7"/>
-      </row>
-    </rows>
-  </grid>
-</dialog>
diff --git a/chrome/content/redirectList.js b/chrome/content/redirectList.js
deleted file mode 100644
index b3a3200..0000000
--- a/chrome/content/redirectList.js
+++ /dev/null
@@ -1,158 +0,0 @@
-//// $Id$ 
-
-var Redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-function $(id) {
-    return document.getElementById(id);
-}
-
-var RedirectList = {
-
-    id          : "redirector@einaregilsson.com",
-    name        : "Redirector",
-    lstRedirects: null,
-    btnDelete   : null,
-    btnEdit     : null,
-
-    addItemsToListBox : function(items) {
-
-        var list = $('lstRedirects');
-        var item, row, value, newItem;
-        
-        for each (item in items) {
-            newItem = this.template.cloneNode(true);
-
-            newItem.getElementsByAttribute('name', 'dscrIncludePattern')[0].setAttribute('value', item.pattern);
-            newItem.getElementsByAttribute('name', 'dscrExcludePattern')[0].setAttribute('value', item.excludePattern);
-            newItem.getElementsByAttribute('name', 'dscrRedirectTo')[0].setAttribute('value', item.redirectUrl);
-            newItem.item = item;
-            list.appendChild(newItem);
-            newItem.setAttribute("selected", false);
-        }
-        
-    },
-
-    onLoad : function() {
-        try {
-            this.lstRedirects = $('lstRedirects');
-            this.lstRedirects.selType = 'single'; 
-            this.template = document.getElementsByTagName('richlistitem')[0];
-            this.lstRedirects.removeChild(this.template);
-            this.btnDelete = $('btnDelete');
-            this.btnEdit = $('btnEdit');
-            this.addItemsToListBox(Redirector.list);
-        } catch(e) {
-            alert(e);
-        }
-    },
-
-    openHelp : function() {
-        var windowName = "redirectorHelp";
-        var windowsMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
-        var win;
-        var iter = windowsMediator.getEnumerator(null);
-        while (iter.hasMoreElements()) {
-            win = iter.getNext();
-            if (win.name == windowName) {
-                win.focus();
-                return;
-            }
-        }
-        window.openDialog("chrome://redirector/content/help.html", windowName, "chrome,dialog,resizable=yes,location=0,toolbar=0,status=0,width=800px,height=600px,centerscreen", this);
-    },
-    
-    close : function() {
-        window.close();
-    },
-    
-    moveUp : function(){
-        if (this.lstRedirects.selectedIndex <= 0) {
-            return;
-        }
-        this.switchItems(this.lstRedirects.selectedIndex-1);
-    },
-
-    moveDown : function() {
-        if (this.lstRedirects.selectedIndex == Redirector.list.length-1) {
-            return;
-        }
-        this.switchItems(this.lstRedirects.selectedIndex);
-    },
-
-    switchItems : function(firstIndex) {
-        var first = Redirector.list[firstIndex];
-        var second = Redirector.list[firstIndex+1];
-        Redirector.list[firstIndex] = second;
-        Redirector.list[firstIndex+1] = first;
-        this.setListItemValues(this.lstRedirects.children[firstIndex+1], first);
-        this.setListItemValues(this.lstRedirects.children[firstIndex], second);
-        this.lstRedirects.selectedIndex -= 1;
-        Redirector.save();
-    }, 
-    
-    setListItemValues : function(listItem, item){
-        listItem.getElementsByAttribute('name', 'dscrIncludePattern')[0].setAttribute('value', item.pattern);
-        listItem.getElementsByAttribute('name', 'dscrExcludePattern')[0].setAttribute('value', item.excludePattern);
-        listItem.getElementsByAttribute('name', 'dscrRedirectTo')[0].setAttribute('value', item.redirectUrl);
-    },
-    
-    addRedirect : function() {
-
-        var item = { pattern : '', exampleUrl : '', redirectUrl : '', patternType : 'W'};
-
-        window.openDialog("chrome://redirector/content/redirect.xul",
-                    "redirect",
-                    "chrome,dialog,modal,centerscreen", item);
-
-        if (item.saved) {
-            this.addItemsToListBox([item]);
-            Redirector.addRedirect(item);
-        }
-
-    },
-
-    editRedirect : function() {
-
-        var listItem = this.lstRedirects.selectedItem;
-
-        if (!listItem) {
-            return;
-        }
-
-        var item = listItem.item;
-
-        window.openDialog("chrome://redirector/content/redirect.xul",
-                    "redirect",
-                    "chrome,dialog,modal,centerscreen", item);
-
-        if (item.saved) {
-            this.setListItemValues(listItem, item);
-            Redirector.save();
-        }
-    },
-
-    deleteRedirect : function() {
-        var index = this.lstRedirects.selectedIndex;
-
-        if (index == -1) {
-            return;
-        }
-
-        try {
-            this.lstRedirects.removeChild(this.lstRedirects.children[index]);
-            Redirector.deleteAt(index);
-        } catch(e) {
-            alert(e);
-        }
-    },
-
-    selectionChange : function() {
-        var index = $('lstRedirects').selectedIndex;
-
-        $('btnEdit').disabled = (index == -1);
-        $('btnDelete').disabled = (index == -1);
-    }
-
-};
diff --git a/chrome/content/redirectList.xul b/chrome/content/redirectList.xul
deleted file mode 100644
index 77bbf9b..0000000
--- a/chrome/content/redirectList.xul
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- $Id -->
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<!DOCTYPE dialog SYSTEM "chrome://redirector/locale/redirectList.dtd">
-<window title="&window.title;"
-        orient="vertical"
-        onload="RedirectList.onLoad();"
-        buttons="accept"
-        width="600px"
-        height="400px"
-        windowtype="redirectorSettings"
-		xmlns:nc="http://home.netscape.com/NC-rdf#"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-  <script type="application/x-javascript" src="redirectList.js"/>
-
-  <vbox>
-      <richlistbox seltype="single" id="lstRedirects" style="margin-bottom:5px; border:solid 1px grey;" height="330px" ondblclick="RedirectList.editRedirect();" onselect="RedirectList.selectionChange();">
-        <richlistitem style="border-bottom:dotted 1px grey;" selected="false">
-            <grid>
-			    <cols>
-			    </cols>
-			    <rows>
-				    <row>
-		              <label style="font-weight:bold;" value="&colIncludePattern.label;:" />
-		              <description name="dscrIncludePattern" />
-				    </row>
-				    <row>
-		              <label style="font-weight:bold;" value="&colExcludePattern.label;:" />
-		              <description name="dscrExcludePattern" />
-				    </row>
-				    <row>
-		              <label style="font-weight:bold;" value="&colRedirectTo.label;:" />
-		              <description name="dscrRedirectTo" />
-				    </row>
-			    </rows>
-            </grid>
-        </richlistitem>
-      </richlistbox>
-      <hbox style="align:right;">
-        <button id="btnAdd" onclick="RedirectList.addRedirect();" label="&btnAdd.label;" disabled="false" />
-        <button id="btnEdit" onclick="RedirectList.editRedirect();" label="&btnEdit.label;" disabled="true" />
-        <button id="btnDelete" onclick="RedirectList.deleteRedirect();" label="&btnDelete.label;" disabled="true" />
-        <button id="btnClose" onclick="RedirectList.close();" label="&btnClose.label;"/>
-        <button id="btnHelp" onclick="RedirectList.openHelp();" label="&btnHelp.label;"/>
-        <button id="btnImport" onclick="RedirectList.import();" label="&btnImport.label;"/>
-        <button id="btnExport" onclick="RedirectList.export();" label="&btnExport.label;"/>
-        <!-- TODO: include in v2.0 
-        <button id="btnUp" onclick="RedirectList.moveUp();" label="UP" disabled="false" />
-        <button id="btnDown" onclick="RedirectList.moveDown();" label="Down" />
-        -->
-      </hbox>
-  </vbox>
-</window>
diff --git a/chrome/content/redirector.png b/chrome/content/redirector.png
deleted file mode 100644
index f8de12c..0000000
Binary files a/chrome/content/redirector.png and /dev/null differ
diff --git a/chrome/content/redirector.prototype.js b/chrome/content/redirector.prototype.js
deleted file mode 100644
index d064764..0000000
--- a/chrome/content/redirector.prototype.js
+++ /dev/null
@@ -1,272 +0,0 @@
-//// $Id$
-
-Cc = Components.classes;
-Ci = Components.interfaces;
-Cr = Components.results;
-kRedirectorWildcard = 'W';
-kRedirectorRegex= 'R';
-nsIContentPolicy = Ci.nsIContentPolicy;
-
-
-Redirector.prototype = {
-    prefBranch : null,
-    list : null,
-    strings : null,
-    cout : Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService),
-
-    init : function() {
-	    this.prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("extensions.redirector.");
-	
-	    //Check if we need to update existing redirects
-	
-	    var data = this.prefBranch.getCharPref('redirects');
-	    var version = this.prefBranch.getCharPref('version');
-	    this.debugEnabled = this.prefBranch.getBoolPref('debug');
-	    this.enabled = this.prefBranch.getBoolPref('enabled');
-	    this.loadStrings();
-	    //Here update checks are handled
-	    if (version == 'undefined') { //Either a fresh install of Redirector, or first time install of v2.0
-	        if (data) { //There is some data in redirects, we are upgrading from a previous version, need to upgrade data
-	            var tempList = eval(data);
-	            var arr;
-	            var newArr = []
-	            for each (arr in tempList) {
-	                if (arr.length == 5) {
-	                    arr.push(''); //For those that don't have an exclude pattern. Backwards compatibility is a bitch!
-	                }
-	                arr.splice(3,1); //Remove the "only if link exists" data
-	                newArr.push(arr.join(',,,'));
-	            }
-	            this.prefBranch.setCharPref('redirects', newArr.join(':::'));
-	        }
-	        this.prefBranch.setCharPref('version', '2.0');
-	    }
-	    //Update finished
-	    
-	    //Now get from the new format
-	    data = this.prefBranch.getCharPref('redirects');
-	    var arr;
-	    this.list = [];
-	    if (data != '') {
-	        for each (redirectString in data.split(':::')) {
-	            arr = redirectString.split(',,,');
-	            this.list.push({
-	                exampleUrl          : arr[0],
-	                pattern             : arr[1],
-	                redirectUrl         : arr[2],
-	                patternType         : arr[3],
-	                excludePattern      : arr[4],
-	                unescapeMatches		: !!arr[5] //This might be undefined for those upgrading from 1.7.1 but that's ok
-	            });
-	        }
-	    }
-	    
-    },
-    
-    loadStrings : function() {
-        var src = 'chrome://redirector/locale/redirector.properties';
-        var localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
-        var appLocale = localeService.getApplicationLocale();
-        var stringBundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
-        this.strings = stringBundleService.createBundle(src, appLocale);    
-    },    
-    
-    debug : function(msg) {
-        if (this.debugEnabled) {
-            this.cout.logStringMessage('REDIRECTOR: ' + msg);
-        }
-    },
-    
-    // nsIContentPolicy interface implementation
-    shouldLoad: function(contentType, contentLocation, requestOrigin, aContext, mimeTypeGuess, extra) {
-        if (!this.enabled) {
-            return nsIContentPolicy.ACCEPT;
-        }
-        if (contentLocation.scheme != "http" && contentLocation.scheme != "https") {
-            return nsIContentPolicy.ACCEPT;
-        }
-
-        if (contentType != nsIContentPolicy.TYPE_DOCUMENT) {
-            return nsIContentPolicy.ACCEPT;
-        }
-        
-        if (!aContext || !aContext.loadURI) {
-            return nsIContentPolicy.ACCEPT;
-        }
-        this.debug("CHECK: " + contentLocation.spec);
-        
-        var url = contentLocation.spec;
-        
-        for each (var redirect in this.list) {
-            var redirectUrl = this.getRedirectUrl(url, redirect);
-            if (redirectUrl) {
-                redirectUrl = this.makeAbsoluteUrl(url, redirectUrl);
-                this.debug('Redirecting ' + url + ' to ' + redirectUrl);
-                aContext.loadURI(redirectUrl, requestOrigin, null);
-                return nsIContentPolicy.REJECT_REQUEST;
-            }
-        }
-        return nsIContentPolicy.ACCEPT;
-    },
-
-    // nsIContentPolicy interface implementation
-    shouldProcess: function(contentType, contentLocation, requestOrigin, insecNode, mimeType, extra) {
-        return nsIContentPolicy.ACCEPT;
-    },
-
-    setEnabled : function(val) {
-        this.enabled = val;
-        this.prefBranch.setBoolPref('enabled', val);
-    },
-    
-    reload : function() {
-		Cc["@mozilla.org/moz/jssubscript-loader;1"]
-			.getService(Ci.mozIJSSubScriptLoader)
-				.loadSubScript('chrome://redirector/content/redirector.prototype.js');
-		
-		for (var key in Redirector.prototype) {
-			this[key] = Redirector.prototype[key];
-		}
-		this.init();
-    }, 
-    
-    addRedirect : function(redirect) {
-        this.list.push(redirect);
-        this.save();
-    },
-
-    deleteAt : function(index) {
-        this.list.splice(index, 1);
-        this.save();
-    },
-    
-    save : function() {
-        var r
-          , tempList = [];
-
-        for each (r in this.list) {
-            tempList.push([r.exampleUrl, r.pattern, r.redirectUrl, r.patternType, r.excludePattern, r.unescapeMatches].join(',,,'));
-        }
-        this.prefBranch.setCharPref('redirects', tempList.join(':::'));
-    },
-    
-    getBoolPref : function(name) {
-        return this.prefBranch.getBoolPref(name);
-    },
-    
-    regexMatch : function(pattern, text, redirectUrl, unescapeMatches) {
-
-        if (!pattern) {
-            return null;
-        }
-        var strings, rx, match;
-        try {
-            rx = new RegExp(pattern, 'gi');
-            match = rx.exec(text);
-        } catch(e) {
-            this.msgBox(this.strings.GetStringFromName('extensionName'), this.strings.formatStringFromName('regexPatternError', [pattern, e.toString()],2));
-            return null;
-        }
-
-        var rxrepl;
-
-        if (match) {
-            for (var i = 1; i < match.length; i++) {
-                rxrepl = new RegExp('\\$' + i, 'gi');
-                redirectUrl = redirectUrl.replace(rxrepl, unescapeMatches ? unescape(match[i]) : match[i]);
-            }
-            return redirectUrl;
-        }
-
-        return null;
-
-    },
-
-    msgBox : function(title, text) {
-        Cc["@mozilla.org/embedcomp/prompt-service;1"]
-            .getService(Ci.nsIPromptService)
-                .alert(null, title, text);
-    },
-
-    getRedirectUrl: function(url, redirect) {
-    
-        if (redirect.patternType == kRedirectorWildcard) {
-            if (this.wildcardMatch(redirect.excludePattern, url, 'whatever')) {
-                this.debug(url + ' matches exclude pattern ' + redirect.excludePattern);
-                return null;
-            }
-            return this.wildcardMatch(redirect.pattern, url, redirect.redirectUrl, redirect.unescapeMatches);
-        } else if (redirect.patternType == kRedirectorRegex) {
-            if (this.regexMatch(redirect.excludePattern, url, 'whatever')) {
-                this.debug(url + ' matches exclude pattern ' + redirect.excludePattern);
-                return null;
-            }
-            return this.regexMatch(redirect.pattern, url, redirect.redirectUrl, redirect.unescapeMatches);
-        }
-        return null;
-    },
-
-    makeAbsoluteUrl : function(currentUrl, relativeUrl) {
-        
-        if (relativeUrl.match(/https?:/)) {
-            return relativeUrl;
-        } 
-        
-        var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-        //this.debug(currentUrl);
-        var uri = ioService.newURI(currentUrl, null, null); 
-        
-        return uri.resolve(relativeUrl);
-    },
-    
-    wildcardMatch : function(pattern, text, redirectUrl, unescapeMatches) {
-
-	    if (!pattern || !text) {
-	    	return null;
-		}
-		if (pattern.indexOf('*') == -1) {
-			return (pattern == text) ? redirectUrl : null;
-		}
-		
-		var parts = pattern.split('*');  
-		var first = parts[0], 
-		    last  = parts[parts.length-1];
-
-		if (first) {
-			if (text.substr(0, first.length) != first) {
-				return null;
-			}
-			text = text.substr(first.length);
-		}
-
-		if (last) {
-			if (text.substr(text.length-last.length) != last) {
-				return null;
-			}
-			text = text.substr(0, text.length-last.length);
-		}
-		
-		if ((first || last) && parts.length == 2) {
-			return redirectUrl.replace('$1', text);
-		}
-		parts.splice(0,1);
-		parts.splice(parts.length-1,1);
-		var pos = 0, lastPos = 0;
-    	var matches = [];
-		for each(part in parts) {
-            pos = text.indexOf(part, lastPos);
-            if (pos == -1) {
-                return null;
-            }
-            var match = text.substr(lastPos, pos-lastPos);
-            matches.push(match);
-            lastPos = pos + part.length;
-        }
-        matches.push(text.substr(lastPos));
-        for (var i = 1; i <= matches.length; i++) {
-            redirectUrl = redirectUrl.replace(new RegExp('\\$' + i, 'gi'), unescapeMatches ? unescape(matches[i-1]) : matches[i-1]);
-        }
-
-        return redirectUrl;
-    }
-};
diff --git a/chrome/content/statusactive.PNG b/chrome/content/statusactive.PNG
deleted file mode 100644
index 06ce766..0000000
Binary files a/chrome/content/statusactive.PNG and /dev/null differ
diff --git a/chrome/content/statusinactive.PNG b/chrome/content/statusinactive.PNG
deleted file mode 100644
index 8b83562..0000000
Binary files a/chrome/content/statusinactive.PNG and /dev/null differ
diff --git a/chrome/content/ui/browserOverlay.xul b/chrome/content/ui/browserOverlay.xul
new file mode 100644
index 0000000..9a02332
--- /dev/null
+++ b/chrome/content/ui/browserOverlay.xul
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id$ -->
+<!DOCTYPE overlay SYSTEM "chrome://redirector/locale/browserOverlay.xul.dtd">
+<overlay id="redirector-overlay"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script src="../code/browserOverlay.xul.js"/>
+
+  <stringbundleset id="stringbundleset">
+    <stringbundle id="redirector-strings" src="chrome://redirector/locale/redirector.properties"/>
+  </stringbundleset>
+
+  <menupopup id="menu_ToolsPopup">
+    <menuitem id="redirector-menuitem" label="&RedirectorMenuItem.label;"
+              accesskey="&RedirectorMenuItem.accesskey;"
+              oncommand="RedirectorOverlay.onMenuItemCommand(event);"/>
+  </menupopup>
+  <popup id="contentAreaContextMenu">
+    <menuitem id="redirector-context" label="&RedirectorContext.label;"
+              accesskey="&RedirectorContext.accesskey;"
+              insertafter="context-stop"
+              oncommand="RedirectorOverlay.onContextMenuCommand(event)"/>
+  </popup>
+  <statusbar id="status-bar">
+  <statusbarpanel id="redirector-status">
+      <!-- Put back in later
+      <menupopup id="redirector-status-popup" position="at_pointer">
+        <menuitem label="&RedirectorManageRedirects.label;" accesskey="&RedirectorManageRedirects.accesskey;" oncommand="RedirectorOverlay.openSettings();" />
+        <menuitem label="&RedirectorHelp.label;" accesskey="&RedirectorHelp.accesskey;" oncommand="Redirector.openHelp();" />
+      </menupopup>
+      -->
+      <image id="redirector-statusbar-img" src="chrome://redirector/content/images/statusactive.PNG"
+             tooltiptext="Redirector is enabled;"
+             style="width:16px; height:16px;"
+             onclick="RedirectorOverlay.statusBarClick(event);" />
+  </statusbarpanel>
+  </statusbar>
+
+</overlay>
\ No newline at end of file
diff --git a/chrome/content/ui/editRedirect.xul b/chrome/content/ui/editRedirect.xul
new file mode 100644
index 0000000..afca5b6
--- /dev/null
+++ b/chrome/content/ui/editRedirect.xul
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id$ -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://redirector/locale/editRedirect.xul.dtd">
+<dialog title="&redirectWindow.title;"
+        orient="vertical"
+        autostretch="always"
+        onload="EditRedirect.onLoad();"
+        buttons="accept,cancel"
+        ondialogaccept="return EditRedirect.onAccept();"
+        xmlns:nc="http://home.netscape.com/NC-rdf#"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="../code/editRedirect.xul.js"/>
+  <stringbundleset id="stringbundleset">
+    <stringbundle id="redirector-strings" src="chrome://redirector/locale/redirector.properties"/>
+  </stringbundleset>
+
+  <grid>
+    <rows>
+      <row align="center">
+        <text value="&txtExampleUrl.label;" style="margin-top:6px;"/>
+        <textbox id="txtExampleUrl" style="width:400px;"/>
+      </row>
+      <row align="center">
+        <text value="&txtPattern.label;" style="margin-top:6px;"/>
+        <textbox id="txtPattern" taborder="1"/>
+        <button id="btnTestPattern" label="&btnTestPattern.label;" onclick="EditRedirect.testPattern();" taborder="2"/>
+      </row>
+      <row align="center">
+        <text value="&txtExcludePattern.label;" style="margin-top:6px;"/>
+        <textbox id="txtExcludePattern" taborder="3"/>
+      </row>
+      <row align="center">
+        <text value="&txtRedirectUrl.label;" style="margin-top:6px;"/>
+        <textbox id="txtRedirectUrl" taborder="4"/>
+      </row>
+      <row align="center">
+        <text value="&rdoPatternTypes.label;"/>
+        <radiogroup>
+          <hbox>
+            <radio id="rdoWildcard" label="&rdoWildcard.label;" accesskey="&rdoWildcard.accessKey;" selected="true" taborder="5"/>
+            <radio id="rdoRegex" label="&rdoRegex.label;"  accesskey="&rdoRegex.accessKey;" taborder="6"/>
+          </hbox>
+        </radiogroup>
+      </row>
+      <row align="center">
+        <text value="&chkUnescapeMatches.label;" />
+        <checkbox id="chkUnescapeMatches" label="" taborder="7"/>
+      </row>
+    </rows>
+  </grid>
+</dialog>
diff --git a/chrome/content/ui/help.html b/chrome/content/ui/help.html
new file mode 100644
index 0000000..0ce6769
--- /dev/null
+++ b/chrome/content/ui/help.html
@@ -0,0 +1,173 @@
+<!-- $Id$ -->
+<html>
+	<head>
+		<title>Redirector Help</title>
+		<style type="text/css">
+			body { font-family: Verdana, Arial; color:black; background-color:white; font-size:0.9em;}
+			a { color:blue; }
+		</style>
+	</head>
+	<body>
+		<h1>Redirector Help</h1>
+		<h3>Table of contents</h3>
+		<ul>
+			<li><a href="#whatisredirector">What is Redirector?</a></li>
+			<li><a href="#basicusage">Basic usage</a>
+				<ul>
+					<li><a href="#exampleurl">Example url</a></li>
+					<li><a href="#includepattern">Include pattern</a></li>
+					<li><a href="#excludepattern">Exclude pattern</a></li>
+					<li><a href="#redirectto">Redirect to</a></li>
+					<li><a href="#patterntype">Pattern type</a></li>
+				</ul>
+			</li>
+			<li><a href="#wildcards">Wildcards</a></li>
+			<li><a href="#regularexpressions">Regular expressions</a></li>
+			<li><a href="#examples">Examples</a>
+				<ol>
+					<li><a href="#ex1">Static redirect</a></li>
+					<li><a href="#ex2">Redirect using query string parameter and wildcards</a></li>
+					<li><a href="#ex3">Redirect using query string parameter and regular expressions</a></li>
+					<li><a href="#ex4">Redirect to a different folder using wildcards</a></li>
+					<li><a href="#ex5">Redirect http to https using wildcards</a></li>
+				</ol>
+			
+			</li>
+		</ul>
+		
+		
+		<a name="whatisredirector"></a>
+		<h4>What is Redirector?</h4>
+		
+		<p>Redirector is an extension for Firefox that allows you to automatically redirect from
+		one webpage to another. For example, every time you visit http://abc.com you will automatically
+		load http://def.com instead. This can be useful for instance to always redirect articles to printer friendly
+		versions, redirect http:// to https:// for sites that support both, bypass advertising pages that appear before
+		being able to view certain pages and more.</p>
+		
+		<a name="basicusage"></a>
+		<h4>Basic usage</h4>
+		<p>To add a new redirect you can go to the <em>Tools</em> menuitem and select <em>Redirector</em>. That will
+		open the <em>Redirector settings</em> window which shows all your redirects. The window can also be opened
+		by right clicking on the <strong>R</strong> icon in your statusbar. 
+		There you can press the <em>Add...</em> button and then you can enter the details for the new redirect. A redirect
+		consists of a few things:
+		<ul>
+			<li><a name="exampleurl"></a><strong>Example url:</strong> This is an example of an url you want to redirect. It is not really used for anything,
+			it's just there to show what types of urls you're targetting. You can leave this out, but then you can't use the <em>Test pattern</em> button.</li>
+			
+			<li><a name="includepattern"></a><strong>Include pattern:</strong> This is pattern for the urls you want to redirect. In the simplest case, where you just want
+			to redirect one specific url to another then this will just be the exact url you want to redirect. For instance, if you just want http://aaa.com to
+			redirect to http://bbb.com then <em>Include pattern</em> will just be http://aaa.com. For more complex patterns that match many
+			urls you can use either <a href="#wildcards">wildcards</a> or <a href="#regularexpressions">regular expressions</a>.</li>
+			
+            <li><a name="excludepattern"></a><strong>Exclude pattern:</strong> Urls that match this pattern will never be redirected. This is not necessary to
+            fill out, but can be useful when you want to redirect all urls that contain some text except if they contain some other text. 
+            Redirects like that can often be done with a complex regular expression, but using an exclude pattern makes it much simpler. The exclude
+            patterns can use wildcard characters or regular expressions like the include patterns.</li>
+
+            <li><a name="redirectto"></a><strong>Redirect to:</strong> This is the url that you will be redirected to when you open any page where the url matches the
+            include pattern. You can use the special signs $1, $2, $3 etc. in the url, they will be replaced by the results of captures with regular
+            expressions or stars with wildcards. For instance, if you have the include pattern <em>http://google.com/*</em>, redirect to <em>http://froogle.com/$1</em>
+            and you open the page http://google.com/foobar, then you will be redireced to http://froogle.com/foobar, since 'foobar' was what the star replaced. $1 is for the
+            first star in the pattern, $2 for the second and so on. For regular expression $1 is for the first parantheses, $2 for the second etc.</li>
+		
+            <li><a name="patterntype"></a><strong>Pattern type:</strong> This specifies how Redirector should interpret the patterns, either as
+            <a href="#wildcards">wildcards</a> or <a href="#regularexpressions#">regular expressions</a>.</li>
+            
+		</ul>
+		</p>
+
+		<a name="wildcards"></a>
+		<h4>Wildcards</h4>
+		
+		<p>Wildcards are the simplest way to specify include and exclude patterns. When you create a wildcard pattern there
+		is just one special character, the asterisk *. An asterisk in your pattern will match zero or more characters and you can
+		have more than one star in your pattern. Some examples:
+			<ul>
+				<li><em>http://example.com/*</em> matches http://example.com/, http://example.com/foo, http://example.com/bar and all other urls that start with http://example.com/.</li>
+				<li><em>http://*.example.com</em> matches all subdomains of example.com, like http://www.example.com, http://mail.example.com.</li>
+				<li><em>http*://example.com</em> matches both http://example.com and https://example.com.</li>
+				<li><em>http://example.com/index.asp*</em> matches http://example.com/index.asp, http://example.com/index.asp?a=b&c=d.</li>
+			</ul>
+		$1, $2, $3 in the redirect urls will match the text that the stars matched. Examples:
+			<ul>
+				<li><em>http://example.com/*</em> matches http://example.com/foobar, $1 is foobar.</li>
+				<li><em>http://*.example.com/*</em> matches http://www.example.com/foobar, $1 is www, $2 is foobar.</li>
+			</ul>
+		</p>
+		
+		<a name="regularexpressions"></a>
+		<h4>Regular expressions</h4>
+		
+		<p>Regular expressions allow for more complicated patterns but they are a lot harder to learn than wildcards. I'm not gonna
+		create a regex tutorial here but normal javascript regex syntax works, look at <a href="http://regular-expressions.info" target="_blank">http://regular-expressions.info</a> for
+		an introduction to regular expressions. $1,$2 etc. can be used in the redirect url and will be replaced with contents of captures in
+		the regular expressions. Captures are specified with parantheses. Example: http://example.com/index.asp\?id=(\d+) will match the url
+		http://example.com/index.asp?id=12345 and $1 will be replaced by 12345. (A common mistake in regex patterns is to forget to escape
+		the ? sign in the querystring of the url. ? is a special character in regular expressions so if you want to match an url with a querystring
+		you should escape it as \?).</p>
+
+		<a name="examples"></a>
+		<h4>Examples</h4>
+		
+		<ol>
+			<li>
+				<strong><a name="ex1"></a>Static redirect</strong><br/>
+				Redirects from http://example.com/foo to http://example.com/bar
+				<p>
+					<strong>Include pattern:</strong> http://example.com/foo<br/>
+					<strong>Exclude pattern:</strong><br/>
+					<strong>Redirect to:</strong> http://example.com/bar<br/>
+					<strong>Pattern type:</strong> Wildcard<br />
+				</p>
+				
+			</li>
+			<li>
+				<strong><a name="ex2"></a>Redirect using query string parameter and wildcards</strong><br/>
+				Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
+				where 12345 could be any number.
+				<p>
+					<strong>Include pattern:</strong> http://example.com/index.php?id=*&a=b<br/>
+					<strong>Exclude pattern:</strong><br/>
+					<strong>Redirect to:</strong> http://example.com/printerfriendly.com?id=$1&a=b<br/>
+					<strong>Pattern type:</strong> Wildcard<br />
+				</p>
+			</li>
+			<li>
+				<strong><a name="ex3"></a>Redirect using query string parameter and regular expressions</strong><br/>
+				Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
+				where 12345 could be any number.
+				<p>
+					<strong>Include pattern:</strong> http://example.com/index.php\?id=(\d+)&a=b<br/>
+					<strong>Exclude pattern:</strong><br/>
+					<strong>Redirect to:</strong> http://example.com/printerfriendly.com?id=$1&a=b<br/>
+					<strong>Pattern type:</strong> Regular Expression<br />
+				</p>
+			</li>
+			<li>
+				<strong><a name="ex4"></a>Redirect to a different folder using wildcards</strong><br/>
+				Redirects from http://example.com/category/fish/index.php to http://example.com/category/cats/index.php
+				where fish could be any word. The exclude pattern makes sure that there is only one
+				folder there, so for instance http://example.com/category/fish/cat/mouse/index.php would not match.
+				<p>
+					<strong>Include pattern:</strong> http://example.com/category/*/index.php<br/>
+					<strong>Exclude pattern:</strong> http://example.com/category/*/*/index.php<br/>
+					<strong>Redirect to:</strong> http://example.com/category/cats/index.php<br/>
+					<strong>Pattern type:</strong> Wildcard<br />
+				</p>
+			</li>
+			<li>
+				<strong><a name="ex5"></a>Redirect http to https using wildcards</strong><br/>
+				Redirects from http://mail.google.com/randomcharacters to https://mail.google.com/randomcharacters
+				where randomcharacters could be anything.
+				<p>
+					<strong>Include pattern:</strong> http://mail.google.com*<br/>
+					<strong>Exclude pattern:</strong><br/>
+					<strong>Redirect to:</strong> https://mail.google.com$1<br/>
+					<strong>Pattern type:</strong> Wildcard<br />
+				</p>
+			</li>
+		</ol>
+	</body>
+</html>
\ No newline at end of file
diff --git a/chrome/content/ui/redirectList.xul b/chrome/content/ui/redirectList.xul
new file mode 100644
index 0000000..29d5ceb
--- /dev/null
+++ b/chrome/content/ui/redirectList.xul
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://redirector/locale/redirectList.xul.dtd">
+<window title="&window.title;"
+        orient="vertical"
+        onload="RedirectList.onLoad();"
+        buttons="accept"
+        width="600px"
+        height="400px"
+        windowtype="redirectorSettings"
+		xmlns:nc="http://home.netscape.com/NC-rdf#"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="../code/redirectList.xul.js"/>
+
+  <vbox>
+      <richlistbox seltype="single" id="lstRedirects" style="margin-bottom:5px; border:solid 1px grey;" height="330px" ondblclick="RedirectList.editRedirect();" onselect="RedirectList.selectionChange();">
+        <richlistitem style="border-bottom:dotted 1px grey;" selected="false">
+            <grid>
+			    <cols>
+			    </cols>
+			    <rows>
+				    <row>
+		              <label style="font-weight:bold;" value="&colIncludePattern.label;:" />
+		              <description name="dscrIncludePattern" />
+				    </row>
+				    <row>
+		              <label style="font-weight:bold;" value="&colExcludePattern.label;:" />
+		              <description name="dscrExcludePattern" />
+				    </row>
+				    <row>
+		              <label style="font-weight:bold;" value="&colRedirectTo.label;:" />
+		              <description name="dscrRedirectTo" />
+				    </row>
+			    </rows>
+            </grid>
+        </richlistitem>
+      </richlistbox>
+      <hbox style="align:right;">
+        <button id="btnAdd" onclick="RedirectList.addRedirect();" label="&btnAdd.label;" disabled="false" />
+        <button id="btnEdit" onclick="RedirectList.editRedirect();" label="&btnEdit.label;" disabled="true" />
+        <button id="btnDelete" onclick="RedirectList.deleteRedirect();" label="&btnDelete.label;" disabled="true" />
+        <button id="btnImport" onclick="RedirectList.import();" label="&btnImport.label;"/>
+        <button id="btnExport" onclick="RedirectList.export();" label="&btnExport.label;"/>
+        <button id="btnHelp" onclick="RedirectList.openHelp();" label="&btnHelp.label;"/>
+        <button id="btnClose" onclick="RedirectList.close();" label="&btnClose.label;"/>
+        <!-- TODO: include in v2.0 
+        <button id="btnUp" onclick="RedirectList.moveUp();" label="UP" disabled="false" />
+        <button id="btnDown" onclick="RedirectList.moveDown();" label="Down" />
+        -->
+      </hbox>
+  </vbox>
+</window>
diff --git a/chrome/content/unittest/run.html b/chrome/content/unittest/run.html
new file mode 100644
index 0000000..2c4f968
--- /dev/null
+++ b/chrome/content/unittest/run.html
@@ -0,0 +1,87 @@
+<!-- $Id$ -->
+<html>
+	<head>
+		<title>Redirector Unit Tests</title>
+		<style type="text/css">
+			body { font-family: Verdana, Arial; color:black; background-color:white; font-size:0.8em; width:800px; margin:auto; text-align:center;}
+			a { color:blue; }
+			h1 { text-align:center; margin:10px 0px; }
+			table { margin:auto; border:solid 1px black; width:700px; border-collapse:collapse;}
+			td { border:solid 1px black; padding:3px; }
+			td.result { width:20px; height:20px; padding:0;}
+			td.result div { width:70%; height:70%; margin:auto;  }
+			button { margin:20px auto; }
+		</style>
+		<script type="text/javascript">
+
+		//Global variables
+		var subscriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
+		var redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
+		
+		function setupTest(name, testcase) {
+			var table = document.createElement('table');
+			var row = document.createElement('tr');
+			var cell = document.createElement('th');
+			var testdata;
+			cell.setAttribute('colspan', 2);
+			row.appendChild(cell);
+			table.appendChild(row);
+			cell.innerHTML = name;
+			document.getElementsByTagName('body')[0].appendChild(table);
+			for (var i = 0; i < testcase.tests.length; i++) {
+				var testdata = testcase.tests[i];
+				row = document.createElement('tr');
+				cell = document.createElement('td');
+				cell.setAttribute('class', 'result');
+				var dot = document.createElement('div');
+				dot.setAttribute('id', name + '_' + i);
+				cell.appendChild(dot);
+				
+				row.appendChild(cell);
+				cell = document.createElement('td');
+				cell.innerHTML = testcase.describe(testdata);
+				row.appendChild(cell);
+				table.appendChild(row);
+			}
+		}
+		
+		function setup() {
+			var tables = document.getElementsByTagName('table');
+			for (var i = 0; i < tables.length; i++) {
+				tables[i].parentNode.removeChild(tables[i]);
+			}
+			
+			subscriptLoader.loadSubScript('chrome://redirector/content/unittest/testcases.js');
+			redirector.reload();
+			
+			for (var name in tests) {
+				setupTest(name, tests[name]);
+			}	
+		}
+		
+		function runTests() {
+			for (var testcaseName in tests) {
+				var testcase = tests[testcaseName];
+				for (var i = 0; i < testcase.tests.length; i++) {
+					try {
+						var result = testcase.run(testcase.tests[i]);
+						if (result) {
+							document.getElementById(testcaseName + '_' + i).style.backgroundColor = '#17f816';
+						} else {
+							document.getElementById(testcaseName + '_' + i).style.backgroundColor = '#ff0000';
+						}
+					} catch(e) {
+						document.getElementById(testcaseName + '_' + i).style.backgroundColor = '#ff0000';
+					}
+				}
+			}	
+		}
+		
+		</script>
+	</head>
+	<body onload="setup();">
+		<h1>Redirector Unit Tests</h1>
+		<button onclick="runTests();">Run tests</button>
+		<button onclick="setup();">Reload tests</button>
+	</body>
+</html>
\ No newline at end of file
diff --git a/chrome/content/unittest/testcases.js b/chrome/content/unittest/testcases.js
new file mode 100644
index 0000000..ea6e26b
--- /dev/null
+++ b/chrome/content/unittest/testcases.js
@@ -0,0 +1,39 @@
+//// $Id$
+var tests = {
+	"Wildcard matches" : {
+		run : function(data) { 
+			var pattern = data[0],
+				url = data[1],
+				expected = data[2];
+			var parts = expected.split(',');
+			var redirectUrl = '';
+			if (!(parts.length == 1 && parts[0] == '')) {
+				for (var i in parts) {
+					redirectUrl += '$' + (parseFloat(i)+1) + ',';
+				}
+				redirectUrl = redirectUrl.substr(0, redirectUrl.length-1);
+			}
+			var result = redirector.wildcardMatch(pattern, url, redirectUrl, false); 
+			return result == expected;
+		},
+		
+		describe : function(data) { return data[0] + ' == ' + data[1] + ', matches=' + data[2]; },
+		tests : [
+			['http://foo*', 'http://foobar.is', 'bar.is'],
+			['http://foo*', 'http://foo', ''],
+			['*://foo.is', 'http://foo.is', 'http'],
+			['*http://foo.is', 'http://foo.is', ''],
+			['http*foo*', 'http://foobar.is', '://,bar.is'],
+			['http*foo*', 'http://foo', '://,'],
+			['*://f*.is', 'http://foo.is', 'http,oo'],
+			['*http://f*.is', 'http://foo.is', ',oo'],
+			['*foo*', 'http://foo', 'http://,'],
+			['*foo*', 'foobar.is', ',bar.is'],
+			['*foo*', 'http://foobar.is', 'http://,bar.is'],
+			['http://foo.is', 'http://foo.is', ''],
+			['*', 'http://foo.is', 'http://foo.is'],
+			['*://*oo*bar*', 'http://foo.is/bar/baz', 'http,f,.is/,/baz'],
+			['*://**oo*bar*', 'http://foo.is/bar/baz', 'http,,f,.is/,/baz'],
+		]
+	}
+};
diff --git a/chrome/content/unittests.html b/chrome/content/unittests.html
deleted file mode 100644
index 0989562..0000000
--- a/chrome/content/unittests.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!-- $Id$ -->
-<html>
-	<head>
-		<title>Redirector Unit Tests</title>
-		<style type="text/css">
-			body { font-family: Verdana, Arial; color:black; background-color:white; font-size:0.8em; width:800px; margin:auto; text-align:center;}
-			a { color:blue; }
-			h1 { text-align:center; margin:20px 0px; }
-			table { margin:auto; border:solid 1px black; width:700px; border-collapse:collapse;}
-			td { border:solid 1px black; padding:3px; }
-			td.result { width:20px; height:20px; padding:0;}
-			td.result div { width:70%; height:70%; margin:auto;  }
-		</style>
-		<script type="text/javascript">
-
-		//Global variables
-		var subscriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
-		var redirector = Components.classes["@einaregilsson.com/redirector;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
-		
-		function setupTest(name, testcase) {
-			var table = document.createElement('table');
-			var row = document.createElement('tr');
-			var cell = document.createElement('th');
-			var testdata;
-			cell.setAttribute('colspan', 2);
-			row.appendChild(cell);
-			table.appendChild(row);
-			cell.innerHTML = name;
-			document.getElementsByTagName('body')[0].appendChild(table);
-			for (var i = 0; i < testcase.tests.length; i++) {
-				var testdata = testcase.tests[i];
-				row = document.createElement('tr');
-				cell = document.createElement('td');
-				cell.setAttribute('class', 'result');
-				var dot = document.createElement('div');
-				dot.setAttribute('id', name + '_' + i);
-				cell.appendChild(dot);
-				
-				row.appendChild(cell);
-				cell = document.createElement('td');
-				cell.innerHTML = testcase.describe(testdata);
-				row.appendChild(cell);
-				table.appendChild(row);
-			}
-		}
-		
-		function setup() {
-			var tables = document.getElementsByTagName('table');
-			for (var i = 0; i < tables.length; i++) {
-				tables[i].parentNode.removeChild(tables[i]);
-			}
-			
-			subscriptLoader.loadSubScript('chrome://redirector/content/unittests.js');
-			redirector.reload();
-			
-			for (var name in tests) {
-				setupTest(name, tests[name]);
-			}	
-		}
-		
-		function runTests() {
-			for (var testcaseName in tests) {
-				var testcase = tests[testcaseName];
-				for (var i = 0; i < testcase.tests.length; i++) {
-					try {
-						var result = testcase.run(testcase.tests[i]);
-						if (result) {
-							document.getElementById(testcaseName + '_' + i).style.backgroundColor = '#17f816';
-						} else {
-							document.getElementById(testcaseName + '_' + i).style.backgroundColor = '#ff0000';
-						}
-					} catch(e) {
-						document.getElementById(testcaseName + '_' + i).style.backgroundColor = '#ff0000';
-					}
-				}
-			}	
-		}
-		
-		</script>
-	</head>
-	<body onload="setup();">
-		<h1>Redirector Unit Tests</h1>
-		<button onclick="runTests();">Run tests</button>
-		<button onclick="setup();">Reload tests</button>
-	</body>
-</html>
\ No newline at end of file
diff --git a/chrome/content/unittests.js b/chrome/content/unittests.js
deleted file mode 100644
index ea6e26b..0000000
--- a/chrome/content/unittests.js
+++ /dev/null
@@ -1,39 +0,0 @@
-//// $Id$
-var tests = {
-	"Wildcard matches" : {
-		run : function(data) { 
-			var pattern = data[0],
-				url = data[1],
-				expected = data[2];
-			var parts = expected.split(',');
-			var redirectUrl = '';
-			if (!(parts.length == 1 && parts[0] == '')) {
-				for (var i in parts) {
-					redirectUrl += '$' + (parseFloat(i)+1) + ',';
-				}
-				redirectUrl = redirectUrl.substr(0, redirectUrl.length-1);
-			}
-			var result = redirector.wildcardMatch(pattern, url, redirectUrl, false); 
-			return result == expected;
-		},
-		
-		describe : function(data) { return data[0] + ' == ' + data[1] + ', matches=' + data[2]; },
-		tests : [
-			['http://foo*', 'http://foobar.is', 'bar.is'],
-			['http://foo*', 'http://foo', ''],
-			['*://foo.is', 'http://foo.is', 'http'],
-			['*http://foo.is', 'http://foo.is', ''],
-			['http*foo*', 'http://foobar.is', '://,bar.is'],
-			['http*foo*', 'http://foo', '://,'],
-			['*://f*.is', 'http://foo.is', 'http,oo'],
-			['*http://f*.is', 'http://foo.is', ',oo'],
-			['*foo*', 'http://foo', 'http://,'],
-			['*foo*', 'foobar.is', ',bar.is'],
-			['*foo*', 'http://foobar.is', 'http://,bar.is'],
-			['http://foo.is', 'http://foo.is', ''],
-			['*', 'http://foo.is', 'http://foo.is'],
-			['*://*oo*bar*', 'http://foo.is/bar/baz', 'http,f,.is/,/baz'],
-			['*://**oo*bar*', 'http://foo.is/bar/baz', 'http,,f,.is/,/baz'],
-		]
-	}
-};
-- 
cgit v1.2.3-70-g09d2