diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 52f82fee2e6a5e0307811bf95f7c082a1a761466..82d1d80f4f53789bb8a06c21e709fd57ad261a44 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -179,7 +179,7 @@ public class SnarkManager implements Snark.CompleteListener {
         if (!_config.containsKey(PROP_STARTUP_DELAY))
             _config.setProperty(PROP_STARTUP_DELAY, "" + DEFAULT_STARTUP_DELAY);
         if (!_config.containsKey(PROP_THEME))
-            _config.setProperty(PROP_THEME, "" + DEFAULT_THEME);
+            _config.setProperty(PROP_THEME, DEFAULT_THEME);
         updateConfig();
     }
     /**
@@ -198,11 +198,9 @@ public class SnarkManager implements Snark.CompleteListener {
     public String[] getThemes() {
             String[] themes = null;
             // "docs/themes/snark/"
-            String fsc = new String(""+File.separatorChar);
-            String look = _context.getBaseDir() + fsc + "docs" + fsc +"themes" + fsc + "snark" + fsc;
+            File dir = new File(_context.getBaseDir(), "docs/themes/snark");
             FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } };
             // Walk the themes dir, collecting the theme names, and append them to the map
-            File dir = new File(look);
             File[] dirnames = dir.listFiles(fileFilter);
             if (dirnames != null) {
                 themes = new String[dirnames.length];
@@ -271,7 +269,7 @@ public class SnarkManager implements Snark.CompleteListener {
     
     public void updateConfig(String dataDir, boolean autoStart, String startDelay, String seedPct, String eepHost, 
                              String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
-                             String upLimit, String upBW, boolean useOpenTrackers, String openTrackers, String Theme) {
+                             String upLimit, String upBW, boolean useOpenTrackers, String openTrackers, String theme) {
         boolean changed = false;
         //if (eepHost != null) {
         //    // unused, we use socket eepget
@@ -434,10 +432,10 @@ public class SnarkManager implements Snark.CompleteListener {
                 changed = true;
             }
         }
-        if (Theme != null) {
-            if(!Theme.equals(_config.getProperty(PROP_THEME))) {
-                _config.setProperty(PROP_THEME, Theme +"");
-                addMessage (Theme+(_(" theme locked and loaded.")));
+        if (theme != null) {
+            if(!theme.equals(_config.getProperty(PROP_THEME))) {
+                _config.setProperty(PROP_THEME, theme);
+                addMessage(_("{0} theme loaded, return to main i2psnark page to view.", theme));
                 changed = true;
             }
         }
@@ -935,8 +933,8 @@ public class SnarkManager implements Snark.CompleteListener {
 //       , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
 //       , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/"
 //       , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/"
-       "POSTMAN", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/"
-       ,"WELTERDE", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
+       "Postman", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/"
+       ,"Welterde", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
 //       , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/"
     };
     
diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index 81e84c3b9027998fa1e9c293cb5ba275e51cbf26..dddb296f4d6fabbdbad7b5a42ef2317e088bd472 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -31,6 +31,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.util.FileUtil;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
+import net.i2p.util.SecureFileOutputStream;
 
 import org.klomp.snark.MetaInfo;
 import org.klomp.snark.Peer;
@@ -55,6 +56,8 @@ public class I2PSnarkServlet extends Default {
     private SnarkManager _manager;
     private static long _nonce;
     private Resource _resourceBase;
+    private String _themePath;
+    private String _imgPath;
     
     public static final String PROP_CONFIG_FILE = "i2psnark.configFile";
  
@@ -124,11 +127,13 @@ public class I2PSnarkServlet extends Default {
             resp.sendError(HttpResponse.__405_Method_Not_Allowed);
             return;
         }
+        _themePath = "/themes/snark/" + _manager.getTheme() + '/';
+        _imgPath = _themePath + "images/";
         // this is the part after /i2psnark
         String path = req.getServletPath();
         boolean isConfigure = "/configure".equals(path);
         // index.jsp doesn't work, it is grabbed by the war handler before here
-        if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html") || isConfigure)) {
+        if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html") || path.equals("/_post") || isConfigure)) {
             if (path.endsWith("/")) {
                 // bypass the horrid Resource.getListHTML()
                 String pathInfo = req.getPathInfo();
@@ -158,8 +163,12 @@ public class I2PSnarkServlet extends Default {
         resp.setContentType("text/html; charset=UTF-8");
         
         String nonce = req.getParameter("nonce");
-        if ( (nonce != null) && (nonce.equals(String.valueOf(_nonce))) )
-            processRequest(req);
+        if (nonce != null) {
+            if (nonce.equals(String.valueOf(_nonce)))
+                processRequest(req);
+            else  // nonce is constant, shouldn't happen
+                _manager.addMessage("Please retry form submission (bad nonce)");
+        }
         
         String peerParam = req.getParameter("p");
         String peerString;
@@ -170,8 +179,8 @@ public class I2PSnarkServlet extends Default {
         }
 
         PrintWriter out = resp.getWriter();
-        out.write("<html>\n" +
-                  "<head><link rel=\"shortcut icon\" href=\"/themes/snark/" + _manager.getTheme() + "/favicon.ico\">\n" +
+        out.write(DOCTYPE + "<html>\n" +
+                  "<head><link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">\n" +
                   "<title>");
         out.write(_("I2PSnark - Anonymous BitTorrent Client"));
         if ("2".equals(peerParam))
@@ -180,22 +189,22 @@ public class I2PSnarkServlet extends Default {
                                          
         // we want it to go to the base URI so we don't refresh with some funky action= value
         if (!isConfigure)
-            out.write("<meta http-equiv=\"refresh\" content=\"60;" + req.getRequestURI() + peerString + "\">\n");
-        out.write(HEADER_A + _manager.getTheme() + HEADER_B);
+            out.write("<meta http-equiv=\"refresh\" content=\"60;/i2psnark/" + peerString + "\">\n");
+        out.write(HEADER_A + _themePath + HEADER_B);
         out.write("</head><body>");
         out.write("<center>");
         if (isConfigure) {
             out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\"");
             out.write(_("Torrents"));
             out.write("\" class=\"snarkRefresh\">");
-            out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/arrow_refresh.png\"> ");
+            out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;");
             out.write(_("I2PSnark"));
             out.write("</a>");
         } else {
-            out.write("<div class=\"snarknavbar\"><a href=\"" + req.getRequestURI() + peerString + "\" title=\"");
+            out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/" + peerString + "\" title=\"");
             out.write(_("Refresh page"));
             out.write("\" class=\"snarkRefresh\">");
-            out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/arrow_refresh.png\"> ");
+            out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;");
             out.write(_("I2PSnark"));
             out.write("</a> <a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkRefresh\" target=\"_blank\">");
             out.write(_("Forum"));
@@ -244,85 +253,103 @@ public class I2PSnarkServlet extends Default {
         String uri = req.getRequestURI();
         boolean isForm = _manager.util().connected() || !snarks.isEmpty();
         if (isForm) {
-            out.write("<form action=\"");
-            out.write(uri);
-            out.write("\" method=\"POST\">\n");
+            out.write("<form action=\"_post\" method=\"POST\">\n");
             out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
             // don't lose peer setting
             if (peerParam != null)
                 out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n");
         }
         out.write(TABLE_HEADER);
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/status.png\"");
-        out.write(" title=\"");
+        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "status.png\" > ");
         out.write(_("Status"));
-        out.write("\"> ");
-//        out.write(_("Status"));
         if (_manager.util().connected() && !snarks.isEmpty()) {
-            out.write(" <a href=\"");
-            out.write(req.getRequestURI());
+            out.write(" <a href=\"/i2psnark/");
             if (peerParam != null) {
                 out.write("\">");
-                out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/showpeers.png\" title=\"");
-                out.write(_("Hide All Attached Peers [connected/total in swarm]"));
+                out.write("<img border=\"0\" src=\"" + _imgPath + "hidepeers.png\" title=\"");
+                out.write(_("Hide Peers"));
                 out.write("\" alt=\"");
                 out.write(_("Hide Peers"));
                 out.write("\">");
             } else {
                 out.write("?p=1\">");
-                out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/hidepeers.png\" title=\"");
-                out.write(_("Show All Attached Peers [connected/total in swarm]"));
+                out.write("<img border=\"0\" src=\"" + _imgPath + "showpeers.png\" title=\"");
+                out.write(_("Show Peers"));
                 out.write("\" alt=\"");
                 out.write(_("Show Peers"));
                 out.write("\">");
             }
             out.write("</a><br>\n"); 
         }
-        out.write("</th>\n<th align=\"left\">");
-//        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/torrent.png\"\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_torrent.png\" title=\"");
-        out.write(_("Loaded Torrents"));
-        out.write("\">");
-//        out.write(_("Torrent"));
-        out.write("</th>\n<th align=\"center\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_eta.png\" title=\"");
-        out.write(_("Estimated Download Time"));
-        out.write("\">");  // space here would look better but nbsp is too big and thinsp breaks
- //       out.write(_("ETA"));
-        out.write("</th>\n<th align=\"center\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_rx.png\" title=\"");
+        out.write("</th>\n<th colspan=\"3\" align=\"left\">");
+        out.write("<img border=\"0\" src=\"" + _imgPath + "torrent.png\" alt=\"\">");
+        out.write(_("Torrent"));
+        out.write("</th>\n<th align=\"right\">");
+        if (_manager.util().connected() && !snarks.isEmpty()) {
+            out.write("<img border=\"0\" src=\"" + _imgPath + "eta.png\" alt=\"\" title=\"");
+            out.write(_("Estimated time remaining"));
+            out.write("\">");
+            out.write(_("ETA"));
+        }
+        out.write("</th>\n<th align=\"right\">");
+        out.write("<img border=\"0\" src=\"" + _imgPath + "head_rx.png\" alt=\"\" title=\"");
         out.write(_("Downloaded"));
         out.write("\">");
-//        out.write(_("RX"));
-        out.write("</th>\n<th align=\"center\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_tx.png\" title=\"");
-        out.write(_("Uploaded"));
-        out.write("\">");
-//        out.write(_("TX"));
-        out.write("</th>\n<th align=\"center\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_rxspeed.png\" title=\"");
-        out.write(_("Down Rate"));
-        out.write("\">");
-//        out.write(_("Rate"));
+        out.write(_("RX"));
+        out.write("</th>\n<th align=\"right\">");
+        if (_manager.util().connected() && !snarks.isEmpty()) {
+            out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" alt=\"\" title=\"");
+            out.write(_("Uploaded"));
+            out.write("\">");
+            out.write(_("TX"));
+        }
+        out.write("</th>\n<th align=\"right\">");
+        if (_manager.util().connected() && !snarks.isEmpty()) {
+            out.write("<img border=\"0\" src=\"" + _imgPath + "head_rxspeed.png\" title=\"");
+            out.write(_("Down Rate"));
+            out.write("\" alt=\"");
+            out.write(_("RX"));
+            out.write(" \">");
+            out.write(_("Rate"));
+        }
+        out.write("</th>\n<th align=\"right\">");
+        if (_manager.util().connected() && !snarks.isEmpty()) {
+            out.write("<img border=\"0\" src=\"" + _imgPath + "head_txspeed.png\" title=\"");
+            out.write(_("Up Rate"));
+            out.write("\" alt=\"");
+            out.write(_("TX"));
+            out.write(" \">");
+            out.write(_("Rate"));
+        }
         out.write("</th>\n<th align=\"center\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_txspeed.png\" title=\"");
-        out.write(_("Up Rate"));
-        out.write("\">");
-//        out.write(_("Rate"));
-        out.write("</th>\n");
-        out.write("<th align=\"center\">");
+
+        // Opera and text-mode browsers: no &thinsp; and no input type=image values submitted
+        String ua = req.getHeader("User-Agent");
+        boolean isDegraded = ua != null && (ua.startsWith("Opera") || ua.startsWith("Lynx") ||
+                                            ua.startsWith("ELinks") || ua.startsWith("Dillo"));
+
         if (_manager.util().connected()) {
-            out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
+            if (isDegraded)
+                out.write("<a href=\"/i2psnark/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\"");
+            else
+                out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
             out.write(_("Stop all torrents and the I2P tunnel"));
-            out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stop_all.png\" alt=\"");
+            out.write("\" src=\"" + _imgPath + "stop_all.png\" alt=\"");
             out.write(_("Stop All"));
             out.write("\">");
+            if (isDegraded)
+                out.write("</a>");
         } else if (!snarks.isEmpty()) {
-            out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\"");
+            if (isDegraded)
+                out.write("<a href=\"/i2psnark/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
+            else
+                out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\"");
             out.write(_("Start all torrents and the I2P tunnel"));
-            out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/start_all.png\" alt=\"");
+            out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\"");
             out.write(_("Start All"));
             out.write("\">");
+            if (isDegraded)
+                out.write("</a>");
         } else {
             out.write("&nbsp;");
         }
@@ -331,55 +358,35 @@ public class I2PSnarkServlet extends Default {
             Snark snark = (Snark)snarks.get(i);
             boolean showDebug = "2".equals(peerParam);
             boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
-            displaySnark(out, snark, uri, i, stats, showPeers, showDebug);
+            displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, showDebug);
         }
 
         if (snarks.isEmpty()) {
             out.write("<tr class=\"snarkTorrentNoneLoaded\">" +
                       "<td class=\"snarkTorrentNoneLoaded\"" +
-                      " colspan=\"8\"><i>");
+                      " colspan=\"11\"><i>");
             out.write(_("No torrents loaded."));
             out.write("</i></td></tr>\n");
         } else if (snarks.size() > 1) {
             out.write("<tfoot><tr>\n" +
-//                      "    <th align=\"left\" colspan=\"2\">");
-                      "    <th align=\"left\">");
-//            out.write(_("Totals"));
-//            out.write(" &raquo;&nbsp;");
-            out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/status.png\"");
-            out.write(" title=\"");
+                      "    <th align=\"left\" colspan=\"6\">");
             out.write(_("Totals"));
-            out.write("\">");
-            out.write("&thinsp;");
-//            out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4]));
-            out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_peers.png\"");
-            out.write(" title=\"");
+            out.write(":&nbsp;");
+            out.write(ngettext("1 torrent", "{0} torrents", snarks.size()));
+            out.write(", ");
+            out.write(DataHelper.formatSize2(stats[5]) + "B, ");
             out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4]));
-            out.write("\">");
-            out.write(ngettext("1", "{0}", (int) stats[4]));
-            out.write("</th>");
-//            out.write("&nbsp;&nbsp;");
-//            out.write(ngettext("1 torrent", "{0} torrents", snarks.size()));
-            out.write("<th><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_snarks.png\"");
-            out.write(" title=\"");
-            out.write(ngettext("1 torrent loaded", "{0} torrents loaded", snarks.size()));
-            out.write("\">");
-            out.write(ngettext("1", "{0}", snarks.size()));
-            out.write("&nbsp;&nbsp;");
-            out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_loaded.png\"");
-            out.write(" title=\"");
-            out.write(_("Total download size (pre-allocated): "));
-            out.write(DataHelper.formatSize2(stats[5]) + "B");
-            out.write("\">");
-            out.write(DataHelper.formatSize2(stats[5]) + "B");
-            out.write("</th>\n" +
-                      "    <th>&nbsp;</th>\n" +
-                      "    <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" +
+            out.write("</th>\n");
+            if (_manager.util().connected()) {
+                out.write("    <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" +
                       "    <th align=\"right\">" + formatSize(stats[1]) + "</th>\n" +
                       "    <th align=\"right\">" + formatSize(stats[2]) + "ps</th>\n" +
                       "    <th align=\"right\">" + formatSize(stats[3]) + "ps</th>\n" +
-                      "    <th>&nbsp;</th></tr>\n" +
-                      "</tfoot>\n");
+                      "    <th></th>");
+            } else {
+                out.write("<th colspan=\"5\"></th>");
+            }
+            out.write("</tr></tfoot>\n");
         }
         
         out.write("</table>");
@@ -393,14 +400,18 @@ public class I2PSnarkServlet extends Default {
     private void processRequest(HttpServletRequest req) {
         String action = req.getParameter("action");
         if (action == null) {
-            // noop
+            _manager.addMessage("No action specified");
             return;
         }
-        if (!"POST".equals(req.getMethod()))
-            return;
+        // sadly, Opera doesn't send value with input type=image, so we have to use GET there
+        //if (!"POST".equals(req.getMethod())) {
+        //    _manager.addMessage("Action must be with POST");
+        //    return;
+        //}
         if ("Add".equals(action)) {
             String newFile = req.getParameter("newFile");
             String newURL = req.getParameter("newURL");
+         /******
             // NOTE - newFile currently disabled in HTML form - see below
             File f = null;
             if ( (newFile != null) && (newFile.trim().length() > 0) )
@@ -409,6 +420,7 @@ public class I2PSnarkServlet extends Default {
                 _manager.addMessage(_("Torrent file {0} does not exist", newFile));
             }
             if ( (f != null) && (f.exists()) ) {
+                // NOTE - All this is disabled - load from local file disabled
                 File local = new File(_manager.getDataDir(), f.getName());
                 String canonical = null;
                 try {
@@ -431,7 +443,9 @@ public class I2PSnarkServlet extends Default {
                 } catch (IOException ioe) {
                     _log.warn("hrm: " + local, ioe);
                 }
-            } else if (newURL != null) {
+            } else
+          *****/
+            if (newURL != null) {
                 if (newURL.startsWith("http://")) {
                     _manager.addMessage(_("Fetching {0}", urlify(newURL)));
                     I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add");
@@ -616,6 +630,8 @@ public class I2PSnarkServlet extends Default {
                 if (snark.stopped)
                     snark.startTorrent();
             }
+        } else {
+            _manager.addMessage("Unknown POST action: \"" + action + '\"');
         }
     }
     
@@ -676,8 +692,9 @@ public class I2PSnarkServlet extends Default {
     }
 
     private static final int MAX_DISPLAYED_FILENAME_LENGTH = 50;
-    private static final int MAX_DISPLAYED_ERROR_LENGTH = 6;
-    private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, boolean showDebug) throws IOException {
+    private static final int MAX_DISPLAYED_ERROR_LENGTH = 43;
+    private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers,
+                              boolean isDegraded, boolean showDebug) throws IOException {
         String filename = snark.torrent;
         File f = new File(filename);
         filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
@@ -731,97 +748,69 @@ public class I2PSnarkServlet extends Default {
             knownPeers = Math.max(curPeers, snark.coordinator.trackerSeenPeers);
         }
         
-        String statusString = _("Unknown");
+        String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
+        String statusString;
         if (err != null) {
             if (isRunning && curPeers > 0 && !showPeers)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/trackererror.png\" title=\"" + _("Tracker Error") +
-                               "\"><a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
-                               ngettext("1", "{0}", knownPeers) + "</a>";
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/trackererror.png\" title=\"" + _("Tracker Error") +
-                               "\">" + ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
-                               ngettext("1", "{0}", knownPeers) + "</a>";
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
+                               ": " + curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers);
             else {
                 if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
                     err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "&hellip;";
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/trackererror.png\" title=\"" + _("Tracker Error") +
-                "\"> " + err + "</a>";
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
+                "<br>" + err;
             }
         } else if (remaining <= 0) {
             if (isRunning && curPeers > 0 && !showPeers)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/seeding.png\" title=\"" + _("Seeding") + "\">" +
-                               "<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
-                               ngettext("1", "{0}", knownPeers) + "</a>";
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/seeding.png\" title=\"" + _("Seeding") + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers)  + "</a>";
-                               ngettext("1", "{0}", knownPeers)  + "</a>";
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
+                               ": " + curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers);
             else
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/complete.png\" title=\"" + _("Complete") + "\"> " + _("Complete");
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete");
         } else {
             if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/downloading.png\" title=\"" + _("Downloading") + "\">" +
-                               "<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                             //  ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
-                               ngettext("1", "{0}", knownPeers) + "</a>";
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning && curPeers > 0 && downBps > 0)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/downloading.png\" title=\"" + _("Downloading") + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               ngettext("1", "{0}", knownPeers);
-                              //  ngettext("1 peer", "{0} peers", knownPeers);
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
+                               ": " + curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers);
             else if (isRunning && curPeers > 0 && !showPeers)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stalled.png\" title=\"" + _("Stalled") + "\">" +
-                               "<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
-                               ngettext("1", "{0}", knownPeers) + "</a>";                               
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning && curPeers > 0)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stalled.png\" title=\"" + _("Stalled") + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers);
-                               ngettext("1", "{0}", knownPeers);
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
+                               ": " + curPeers + thinsp(isDegraded) +
+                               ngettext("1 peer", "{0} peers", knownPeers);
+            else if (isRunning && knownPeers > 0)
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") +
+                               ": 0&thinsp;/&thinsp;" + knownPeers ;
             else if (isRunning)
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/nopeers.png\" title=\"" + _("No Peers") + "\">" +
-                               ' ' + curPeers + "&thinsp;/&thinsp;" +
-                               // ngettext("1 peer", "{0} peers", knownPeers);
-                               ngettext("1", "{0}", knownPeers);
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers");
             else
-                statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stopped.png\" title=\"" + _("Stopped") + "\"> " + _("Stopped");
+                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stopped.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stopped");
         }
         
-        String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
         out.write("<tr class=\"" + rowClass + "\">");
-        out.write("<td align=\"center\" class=\"snarkTorrentStatus " + rowClass + "\">");
+        out.write("<td class=\"center " + rowClass + "\">");
         out.write(statusString + "</td>\n\t");
-        out.write("<td align=\"left\" class=\"snarkTorrentName " + rowClass + "\">");
-        
-        if (remaining == 0 || snark.meta.getFiles() != null) {
-            out.write("<a href=\"" + snark.storage.getBaseName());
-            if (snark.meta.getFiles() != null)
-                out.write("/");
-            out.write("\" title=\"");
-            if (snark.meta.getFiles() != null)
-                out.write(_("View files"));
-            else
-                out.write(_("Open file"));
-            out.write("\">");
-        }
-        String icon;
-        if (snark.meta.getFiles() != null)
-            icon = "folder";
-        else
-            icon = toIcon(snark.meta.getName());
-        out.write(toImg(icon));
-        out.write(filename);
-        if (remaining == 0 || snark.meta.getFiles() != null)
-            out.write("</a>");
+
+        out.write("<td class=\"" + rowClass + "\">");
         // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash
         String announce = snark.meta.getAnnounce();
         if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
@@ -839,28 +828,62 @@ public class I2PSnarkServlet extends Default {
                 if (e < 0)
                     continue;
                 baseURL = baseURL.substring(e + 1);
-                out.write("&nbsp;<a href=\"" + baseURL + "details.php?dllist=1&filelist=1&info_hash=");
+                out.write("<a href=\"" + baseURL + "details.php?dllist=1&amp;filelist=1&amp;info_hash=");
                 out.write(TrackerClient.urlencode(snark.meta.getInfoHash()));
-                out.write("\" title=\"" + name + ' ' + _("Tracker") + "\" target=\"_blank\">");
-                out.write("<div class=\"infoz\"><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/details.png\"></div>");
+                out.write("\" title=\"" + _("Details at {0} tracker", name) + "\" target=\"_blank\">");
+                out.write("<img alt=\"" + _("Info") + "\" border=\"0\" src=\"" + _imgPath + "details.png\">");
                 out.write("</a>");
                 break;
             }
         }
-        out.write("</td>\n\t");
-        
-        out.write("<td align=\"center\" class=\"snarkTorrentETA " + rowClass + "\">");
+
+        out.write("</td>\n<td class=\"" + rowClass + "\">");
+        StringBuilder buf = null;
+        if (remaining == 0 || snark.meta.getFiles() != null) {
+            buf = new StringBuilder(128);
+            buf.append("<a href=\"").append(snark.storage.getBaseName());
+            if (snark.meta.getFiles() != null)
+                buf.append('/');
+            buf.append("\" title=\"");
+            if (snark.meta.getFiles() != null)
+                buf.append(_("View files"));
+            else
+                buf.append(_("Open file"));
+            buf.append("\">");
+            out.write(buf.toString());
+        }
+        String icon;
+        if (snark.meta.getFiles() != null)
+            icon = "folder";
+        else
+            icon = toIcon(snark.meta.getName());
+        if (remaining == 0 || snark.meta.getFiles() != null) {
+            out.write(toImg(icon, _("Open")));
+            out.write("</a>");
+        } else {
+            out.write(toImg(icon));
+        }
+        out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">");
+        if (remaining == 0 || snark.meta.getFiles() != null)
+            out.write(buf.toString());
+        out.write(filename);
+        if (remaining == 0 || snark.meta.getFiles() != null)
+            out.write("</a>");
+
+        out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
         if(isRunning && remainingSeconds > 0)
             out.write(DataHelper.formatDuration2(remainingSeconds*1000)); // (eta 6h)
         out.write("</td>\n\t");
         out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
         if (remaining > 0)
-            out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB; remove thin space so line does _not_ break. We don't want a break here.
+            out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total));
         else
             out.write(formatSize(total)); // 3GB
         out.write("</td>\n\t");
-        out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass 
-                  + "\">" + formatSize(uploaded) + "</td>\n\t");
+        out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass + "\">");
+        if(isRunning)
+           out.write(formatSize(uploaded));
+        out.write("</td>\n\t");
         out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
         if(isRunning && remaining > 0)
             out.write(formatSize(downBps) + "ps");
@@ -875,27 +898,34 @@ public class I2PSnarkServlet extends Default {
         if (showPeers)
             parameters = parameters + "&p=1";
         if (isRunning) {
-            out.write("<input type=\"image\" name=\"action\" value=\"Stop_");
-            out.write(b64);
-            out.write("\" title=\"");
+            if (isDegraded)
+                out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
+            else
+                out.write("<input type=\"image\" name=\"action\" value=\"Stop_" + b64 + "\" title=\"");
             out.write(_("Stop the torrent"));
-            out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stop.png\" alt=\"");
+            out.write("\" src=\"" + _imgPath + "stop.png\" alt=\"");
             out.write(_("Stop"));
             out.write("\">");
+            if (isDegraded)
+                out.write("</a>");
         } else {
             if (isValid) {
-                out.write("<input type=\"image\" name=\"action\" value=\"Start_");
-                out.write(b64);
-                out.write("\" title=\"");
+                if (isDegraded)
+                    out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
+                else
+                    out.write("<input type=\"image\" name=\"action\" value=\"Start_" + b64 + "\" title=\"");
                 out.write(_("Start the torrent"));
-                out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/start.png\" alt=\"");
+                out.write("\" src=\"" + _imgPath + "start.png\" alt=\"");
                 out.write(_("Start"));
                 out.write("\">");
+                if (isDegraded)
+                    out.write("</a>");
             }
 
-            out.write("<input type=\"image\" name=\"action\" value=\"Remove_");
-            out.write(b64);
-            out.write("\" title=\"");
+            if (isDegraded)
+                out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
+            else
+                out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
             out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
             out.write("\" onclick=\"if (!confirm('");
             // Can't figure out how to escape double quotes inside the onclick string.
@@ -903,13 +933,16 @@ public class I2PSnarkServlet extends Default {
             // Then the remaining single quite must be escaped
             out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
             out.write("')) { return false; }\"");
-            out.write(" src=\"/themes/snark/" + _manager.getTheme() + "/images/remove.png\" alt=\"");
+            out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
             out.write(_("Remove"));
             out.write("\">");
+            if (isDegraded)
+                out.write("</a>");
 
-            out.write("<input type=\"image\" name=\"action\" value=\"Delete_");
-            out.write(b64);
-            out.write("\" title=\"");
+            if (isDegraded)
+                out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
+            else
+                out.write("<input type=\"image\" name=\"action\" value=\"Delete_" + b64 + "\" title=\"");
             out.write(_("Delete the .torrent file and the associated data file(s)"));
             out.write("\" onclick=\"if (!confirm('");
             // Can't figure out how to escape double quotes inside the onclick string.
@@ -917,9 +950,11 @@ public class I2PSnarkServlet extends Default {
             // Then the remaining single quite must be escaped
             out.write(_("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?", fullFilename));
             out.write("')) { return false; }\"");
-            out.write(" src=\"/themes/snark/" + _manager.getTheme() + "/images/delete.png\" alt=\"");
+            out.write(" src=\"" + _imgPath + "delete.png\" alt=\"");
             out.write(_("Delete"));
             out.write("\">");
+            if (isDegraded)
+                out.write("</a>");
         }
         out.write("</td>\n</tr>\n");
 
@@ -930,10 +965,8 @@ public class I2PSnarkServlet extends Default {
             for (Peer peer : peers) {
                 if (!peer.isConnected())
                     continue;
-                out.write("<tr class=\"" + rowClass + "\">");
-                out.write("<td align=\"center\" class=\"snarkTorrentStatus " + rowClass + "\">");
-                out.write("</td>\n\t");
-                out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
+                out.write("<tr class=\"" + rowClass + "\"><td></td>");
+                out.write("<td colspan=\"4\" align=\"right\" class=\"" + rowClass + "\">");
                 String ch = peer.toString().substring(0, 4);
                 String client;
                 if ("AwMD".equals(ch))
@@ -1006,11 +1039,18 @@ public class I2PSnarkServlet extends Default {
                 out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
                 out.write("</td></tr>\n\t");
                 if (showDebug)
-                    out.write("<tr><td colspan=\"8\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">" + peer.getSocket() + "</td></tr>");
+                    out.write("<tr><td></td><td colspan=\"10\" align=\"right\" class=\"" + rowClass + "\">" + peer.getSocket() + "</td></tr>");
             }
         }
     }
     
+    /** @since 0.8.2 */
+    private static String thinsp(boolean disable) {
+        if (disable)
+            return " / ";
+        return ("&thinsp;/&thinsp;");
+    }
+
     /**
      *  Sort by completeness (seeds first), then by ID
      *  @since 0.8.1
@@ -1034,9 +1074,9 @@ public class I2PSnarkServlet extends Default {
         //String newFile = req.getParameter("newFile");
         //if ( (newFile == null) || (newFile.trim().length() <= 0) ) newFile = "";
         
-        out.write("<span class=\"snarkNewTorrent\">\n");
+        out.write("<div class=\"snarkNewTorrent\">\n");
         // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
-        out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
+        out.write("<form action=\"_post\" method=\"POST\">\n");
         out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
         out.write("<input type=\"hidden\" name=\"action\" value=\"Add\" >\n");
         // don't lose peer setting
@@ -1044,7 +1084,7 @@ public class I2PSnarkServlet extends Default {
         if (peerParam != null)
             out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n");
         out.write("<div class=\"addtorrentsection\"><span class=\"snarkConfigTitle\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/add.png\">");
+        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "add.png\"> ");
         out.write(_("Add Torrent"));
         out.write("</span><hr>\n<table border=\"0\"><tr><td>");
         out.write(_("From URL"));
@@ -1062,7 +1102,7 @@ public class I2PSnarkServlet extends Default {
         out.write("\n");
         out.write(_("Removing a .torrent will cause it to stop."));
         out.write("<br></span></table>\n");
-        out.write("</form>\n</span></div>");  
+        out.write("</div></form></div>");  
     }
     
     private void writeSeedForm(PrintWriter out, HttpServletRequest req) throws IOException {
@@ -1073,9 +1113,9 @@ public class I2PSnarkServlet extends Default {
         else
             baseFile = DataHelper.stripHTML(baseFile);    // XSS
         
-        out.write("<div class=\"newtorrentsection\"><span class=\"snarkNewTorrent\">\n");
+        out.write("<div class=\"newtorrentsection\"><div class=\"snarkNewTorrent\">\n");
         // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
-        out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
+        out.write("<form action=\"_post\" method=\"POST\">\n");
         out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
         out.write("<input type=\"hidden\" name=\"action\" value=\"Create\" >\n");
         // don't lose peer setting
@@ -1083,7 +1123,7 @@ public class I2PSnarkServlet extends Default {
         if (peerParam != null)
             out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n");
         out.write("<span class=\"snarkConfigTitle\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/create.png\">");
+        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "create.png\"> ");
         out.write(_("Create Torrent"));
         out.write("</span><hr>\n<table border=\"0\"><tr><td>");
         //out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>\n");
@@ -1116,7 +1156,7 @@ public class I2PSnarkServlet extends Default {
         out.write("<input type=\"submit\" value=\"");
         out.write(_("Create torrent"));
         out.write("\" name=\"foo\" ></table>\n");
-        out.write("</form>\n</span></div>");        
+        out.write("</form></div></div>");        
     }
     
     private void writeConfigForm(PrintWriter out, HttpServletRequest req) throws IOException {
@@ -1127,31 +1167,18 @@ public class I2PSnarkServlet extends Default {
         String openTrackers = _manager.util().getOpenTrackerString();
         //int seedPct = 0;
        
-        out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
-        out.write("<div class=\"configsectionpanel\"><span class=\"snarkConfig\">\n");
+        out.write("<form action=\"/i2psnark/configure\" method=\"POST\">\n");
+        out.write("<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n");
         out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
         out.write("<input type=\"hidden\" name=\"action\" value=\"Save\" >\n");
         out.write("<span class=\"snarkConfigTitle\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/config.png\">");
+        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> ");
         out.write(_("Configuration"));
         out.write("</span><hr>\n");
         out.write("<table border=\"0\"><tr><td>");
 
-        out.write(_("Theme"));
-        out.write(": <td><select name='theme'>");
-        String theme = _manager.getTheme();
-        String[] themes = _manager.getThemes();
-        for(int i = 0; i < themes.length; i++) {
-            if(themes[i].equals(theme))
-                out.write("\n<OPTION value='" + themes[i] + "' SELECTED>" + themes[i]);
-            else
-                out.write("\n<OPTION value='" + themes[i] + "'>" + themes[i]);
-        }
-        out.write("\n</select>\n<tr><td>");
-
-
         out.write(_("Data directory"));
-        out.write(": <td><code>" + dataDir + "</code> (");
+        out.write(": <td><code>" + dataDir + "</code> <i>(");
         out.write(_("Edit i2psnark.config and restart to change"));
         out.write(")</i><br>\n");
 
@@ -1163,6 +1190,19 @@ public class I2PSnarkServlet extends Default {
         out.write(_("If checked, automatically start torrents that are added"));
         out.write("\" >");
 
+        out.write("<tr><td>");
+        out.write(_("Theme"));
+        out.write(": <td><select name='theme'>");
+        String theme = _manager.getTheme();
+        String[] themes = _manager.getThemes();
+        for(int i = 0; i < themes.length; i++) {
+            if(themes[i].equals(theme))
+                out.write("\n<OPTION value=\"" + themes[i] + "\" SELECTED>" + themes[i]);
+            else
+                out.write("\n<OPTION value=\"" + themes[i] + "\">" + themes[i]);
+        }
+        out.write("</select>\n");
+
         out.write("<tr><td>");
         out.write(_("Startup delay"));
         out.write(": <td><input name=\"startupDelay\" size=\"3\" class=\"r\" value=\"" + _manager.util().getStartupDelay() + "\"> ");
@@ -1263,14 +1303,13 @@ public class I2PSnarkServlet extends Default {
         out.write("<tr><td>&nbsp;<td><input type=\"submit\" value=\"");
         out.write(_("Save configuration"));
         out.write("\" name=\"foo\" >\n");
-        out.write("</table></span>\n");
-        out.write("</form></div>");
+        out.write("</table></div></div></form>");
     }
     
     private void writeConfigLink(PrintWriter out) throws IOException {
         out.write("<div class=\"configsection\"><span class=\"snarkConfig\">\n");
         out.write("<span class=\"snarkConfigTitle\"><a href=\"configure\">");
-        out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/config.png\">");
+        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> ");
         out.write(_("Configuration"));
         out.write("</a></span></span></div>\n");
     }
@@ -1346,15 +1385,16 @@ public class I2PSnarkServlet extends Default {
         return buf.toString();
     }
 
-    private static final String HEADER_A = "<link href=\"/themes/snark/";
-    private static final String HEADER_B = "/snark.css\" rel=\"stylesheet\" type=\"text/css\" >";
+    private static final String DOCTYPE = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
+    private static final String HEADER_A = "<link href=\"";
+    private static final String HEADER_B = "snark.css\" rel=\"stylesheet\" type=\"text/css\" >";
 
 
-    private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" cellpadding=\"0 10px\">\n" +
+    private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" >\n" +
                                                "<thead>\n" +
-                                               "<tr><th align=\"center\">";
+                                               "<tr><th colspan=\"2\">";
 
-    private static final String FOOTER = "</div></div></div></center></body></html>";
+    private static final String FOOTER = "</div></center></body></html>";
 
     /**
      * Modded heavily from the Jetty version in Resource.java,
@@ -1398,7 +1438,7 @@ public class I2PSnarkServlet extends Default {
         Arrays.sort(ls, Collator.getInstance());
         
         StringBuilder buf=new StringBuilder(4096);
-        buf.append("<HTML><HEAD><TITLE>");
+        buf.append(DOCTYPE + "<HTML><HEAD><TITLE>");
         String title = URI.decodePath(base);
         if (title.startsWith("/i2psnark/"))
             title = title.substring("/i2psnark/".length());
@@ -1419,36 +1459,32 @@ public class I2PSnarkServlet extends Default {
             title = title.substring(0, title.length() - 1);
         title = _("Torrent") + ": " + title;
         buf.append(title);
-        buf.append("</TITLE>").append(HEADER_A).append(_manager.getTheme()).append(HEADER_B).append("<link rel=\"shortcut icon\" href=\"/themes/snark/" + _manager.getTheme() + "/favicon.ico\"></HEAD><BODY>\n<center><div class=\"snarknavbar\"> <a href=\"/i2psnark/\" title=\"Torrents\"");
-        buf.append(" class=\"snarkRefresh\"><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/arrow_refresh.png\"> I2PSnark</a>").append("</div>");
+        buf.append("</TITLE>").append(HEADER_A).append(_themePath).append(HEADER_B).append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">" +
+             "</HEAD><BODY>\n<center><div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\"Torrents\"");
+        buf.append(" class=\"snarkRefresh\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;I2PSnark</a></div></center>\n");
         
-        if (parent)
-            buf.append("</div><div class=\"page\"><div class=\"mainsection\">");
-            boolean showPriority = snark != null && !snark.storage.complete();
+        if (parent)  // always true
+            buf.append("<div class=\"page\"><div class=\"mainsection\">");
+        boolean showPriority = snark != null && !snark.storage.complete();
         if (showPriority)
             buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
-            buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" cellpadding=\"5px 10px\">" +
+        buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" >" +
             "<thead><tr><th>")
-            .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/file.png\" title=\"")
-            .append(_("File")).append("\" alt=\"").append(_("File")).append("\">&nbsp;")
+            .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" >&nbsp;")
             .append(title).append("</th><th align=\"right\">")
-            .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/size.png\" title=\"")
-//            .append(_("FileSize")).append("\" alt=\"").append(_("FileSize")).append("\">").append(_("Size"));
-            .append(_("FileSize")).append("\" alt=\"").append(_("FileSize")).append("\">");
-            buf.append("</th><th class=\"headerstatus\">")
-            .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/status.png\" title=\"")
-//            .append(_("Download Status")).append("\">").append(_("Status")).append("</th>");
-            .append(_("Download Status")).append("\">").append("</th>");
+            .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "size.png\" >&nbsp;")
+            .append(_("Size"));
+        buf.append("</th><th class=\"headerstatus\">")
+            .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "status.png\" >&nbsp;")
+            .append(_("Status")).append("</th>");
         if (showPriority)
             buf.append("<th class=\"headerpriority\">")
-            .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/priority.png\" title=\"")
-            .append(_("Priority")).append("\">").append("</th>");
-//            .append(_("Priority")).append("</th>");
-//            .append("</th>");
-            buf.append("</tr></thead>\n");
-            buf.append("<tr><td colspan=\"4\" class=\"ParentDir\"><A HREF=\"");
-            buf.append(URI.addPaths(base,"../"));
-            buf.append("\"><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/up.png\"> ")
+            .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "priority.png\" >&nbsp;")
+            .append(_("Priority")).append("</th>");
+        buf.append("</tr></thead>\n");
+        buf.append("<tr><td colspan=\"" + (showPriority ? '4' : '3') + "\" class=\"ParentDir\"><A HREF=\"");
+        buf.append(URI.addPaths(base,"../"));
+        buf.append("\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "up.png\"> ")
             .append(_("Up to higher level directory")).append("</A></td></tr>\n");
 
 
@@ -1474,12 +1510,12 @@ public class I2PSnarkServlet extends Default {
             long length = item.length();
             if (item.isDirectory()) {
                 complete = true;
-                status = toImg("tick") + _("Directory");
+                status = toImg("tick") + ' ' + _("Directory");
             } else {
                 if (snark == null) {
                     // Assume complete, perhaps he removed a completed torrent but kept a bookmark
                     complete = true;
-                    status = toImg("cancel") + _("Torrent not found?");
+                    status = toImg("cancel") + ' ' + _("Torrent not found?");
                 } else {
                     try {
                         File f = item.getFile();
@@ -1487,10 +1523,10 @@ public class I2PSnarkServlet extends Default {
                             long remaining = snark.storage.remaining(f.getCanonicalPath());
                             if (remaining < 0) {
                                 complete = true;
-                                status = toImg("cancel") + _("File not found in torrent?");
+                                status = toImg("cancel") + ' ' + _("File not found in torrent?");
                             } else if (remaining == 0 || length <= 0) {
                                 complete = true;
-                                status = toImg("tick") + _("Complete");
+                                status = toImg("tick") + ' ' + _("Complete");
                             } else {
                                 int priority = snark.storage.getPriority(f.getCanonicalPath());
                                 if (priority < 0)
@@ -1499,7 +1535,7 @@ public class I2PSnarkServlet extends Default {
                                     status = toImg("clock");
                                 else
                                     status = toImg("clock_red");
-                                status +=
+                                status += " " +
                                          (100 * (length - remaining) / length) + "% " + _("complete") +
                                          " (" + DataHelper.formatSize2(remaining) + _("bytes remaining") + ")";
                             }
@@ -1526,13 +1562,13 @@ public class I2PSnarkServlet extends Default {
                     buf.append("<img alt=\"\" border=\"0\" class=\"thumb\" src=\"")
                        .append(path).append("\"></a> ");
                 } else {
-                    buf.append(toImg(icon));
+                    buf.append(toImg(icon, _("Open"))).append("</a> ");
                 }
                 buf.append("<A HREF=\"");
                 buf.append(path);
                 buf.append("\">");
             } else {
-                buf.append(toImg(icon));
+                buf.append(toImg(icon)).append(' ');
             }
             buf.append(ls[i]);
             if (complete)
@@ -1640,7 +1676,12 @@ public class I2PSnarkServlet extends Default {
     
     /** @since 0.7.14 */
     private static String toImg(String icon) {
-        return "<img alt=\"\" height=\"16\" width=\"16\" src=\"/i2psnark/_icons/" + icon + ".png\"> ";
+        return "<img alt=\"\" height=\"16\" width=\"16\" src=\"/i2psnark/_icons/" + icon + ".png\">";
+    }
+
+    /** @since 0.8.2 */
+    private static String toImg(String icon, String altText) {
+        return "<img alt=\"" + altText + "\" height=\"16\" width=\"16\" src=\"/i2psnark/_icons/" + icon + ".png\">";
     }
 
     /** @since 0.8.1 */
@@ -1702,8 +1743,13 @@ private static class FetchAndAdd implements Runnable {
                         else
                             _manager.addMessage(_("Torrent already in the queue: {0}", name));
                     } else {
-                        FileUtil.copy(file.getAbsolutePath(), canonical, true);
-                        _manager.addTorrent(canonical);
+                        boolean success = FileUtil.copy(file.getAbsolutePath(), canonical, false);
+                        if (success) {
+                            SecureFileOutputStream.setPerms(torrentFile);
+                            _manager.addTorrent(canonical);
+                        } else {
+                            _manager.addMessage(_("Failed to copy torrent file to {0}", canonical));
+                        }
                     }
                 } catch (IOException ioe) {
                     _manager.addMessage(_("Torrent at {0} was not valid", urlify(_url)) + ": " + ioe.getMessage());
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
index bc7e4ab9056a0425a43d6611bec3f824268ed338..921d8992bf731d3cba65673e0b0d7f1fc3822e97 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
@@ -15,6 +15,7 @@ import java.util.Properties;
 import java.util.zip.GZIPOutputStream;
 
 import net.i2p.client.streaming.I2PSocket;
+import net.i2p.I2PAppContext;
 import net.i2p.data.DataHelper;
 import net.i2p.util.EventDispatcher;
 import net.i2p.util.I2PAppThread;
@@ -36,6 +37,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
     private static final String HASH_HEADER = "X-I2P-DestHash";
     private static final String DEST64_HEADER = "X-I2P-DestB64";
     private static final String DEST32_HEADER = "X-I2P-DestB32";
+    private static final String[] CLIENT_SKIPHEADERS = {HASH_HEADER, DEST64_HEADER, DEST32_HEADER};
+    private static final String SERVER_HEADER = "Server";
+    private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER};
 
     public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
         super(host, port, privData, l, notifyThis, tunnel);
@@ -75,7 +79,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
             InputStream in = socket.getInputStream();
 
             StringBuilder command = new StringBuilder(128);
-            Properties headers = readHeaders(in, command);
+            Properties headers = readHeaders(in, command,
+                CLIENT_SKIPHEADERS, getTunnel().getContext());
             headers.setProperty(HASH_HEADER, socket.getPeerDestination().calculateHash().toBase64());
             headers.setProperty(DEST32_HEADER, Base32.encode(socket.getPeerDestination().calculateHash().getData()) + ".b32.i2p" );
             headers.setProperty(DEST64_HEADER, socket.getPeerDestination().toBase64());
@@ -118,7 +123,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
                 useGZIP = true;
             
             if (allowGZIP && useGZIP) {
-                I2PAppThread req = new I2PAppThread(new CompressedRequestor(s, socket, modifiedHeader), Thread.currentThread().getName()+".hc");
+                I2PAppThread req = new I2PAppThread(
+                    new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext()),
+                        Thread.currentThread().getName()+".hc");
                 req.start();
             } else {
                 new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
@@ -155,10 +162,12 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
         private Socket _webserver;
         private I2PSocket _browser;
         private String _headers;
-        public CompressedRequestor(Socket webserver, I2PSocket browser, String headers) {
+        private I2PAppContext _ctx;
+        public CompressedRequestor(Socket webserver, I2PSocket browser, String headers, I2PAppContext ctx) {
             _webserver = webserver;
             _browser = browser;
             _headers = headers;
+            _ctx = ctx;
         }
         public void run() {
             if (_log.shouldLog(Log.INFO))
@@ -200,8 +209,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
 
                 //Change headers to protect server identity
                 StringBuilder command = new StringBuilder(128);
-                Properties headers = readHeaders(serverin, command);
-                headers.setProperty("Server", "I2PServer");
+                Properties headers = readHeaders(serverin, command,
+                    SERVER_SKIPHEADERS, _ctx);
                 String modifiedHeaders = formatHeaders(headers, command);
                 compressedOut.write(modifiedHeaders.getBytes());
 
@@ -336,7 +345,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
     /** ridiculously long, just to prevent OOM DOS @since 0.7.13 */
     private static final int MAX_HEADERS = 60;
 
-    private static Properties readHeaders(InputStream in, StringBuilder command) throws IOException {
+    private static Properties readHeaders(InputStream in, StringBuilder command, String[] skipHeaders, I2PAppContext ctx) throws IOException {
         Properties headers = new Properties();
         StringBuilder buf = new StringBuilder(128);
         
@@ -356,8 +365,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
                 }
             }
         }
-        //if (trimmed > 0)
-        //    getTunnel().getContext().statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed, 0);
+        if (trimmed > 0)
+            ctx.statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed, 0);
         
         int i = 0;
         while (true) {
@@ -379,16 +388,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
                     value = buf.substring(split+1).trim(); // ":"
                 else
                     value = "";
+
                 if ("Accept-encoding".equalsIgnoreCase(name))
                     name = "Accept-encoding";
                 else if ("X-Accept-encoding".equalsIgnoreCase(name))
                     name = "X-Accept-encoding";
-                else if (HASH_HEADER.equalsIgnoreCase(name))
-                    continue;     // Prevent spoofing
-                else if (DEST64_HEADER.equalsIgnoreCase(name))
-                    continue;     // Prevent spoofing
-                else if (DEST32_HEADER.equalsIgnoreCase(name))
-                    continue;     // Prevent spoofing
+
+                //We want to remove certain headers to improve anonymity
+                boolean skip = false;
+                for (String skipHeader: skipHeaders) {
+                    if (skipHeader.equalsIgnoreCase(name)) {
+                        skip = true;
+                        break;
+                    }
+                }
+                if(skip) {
+                    continue;
+                }
+
                 headers.setProperty(name, value);
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("Read the header [" + name + "] = [" + value + "]");
diff --git a/build.xml b/build.xml
index 5d1567ea97f3c1bb5025497ad0a51862bd03ca91..7c75e857aeaa5d2e1dbe523463552a89bcafff2a 100644
--- a/build.xml
+++ b/build.xml
@@ -23,9 +23,10 @@
         <echo message="  dist:      pkg and javadoc" />
         <echo message="  installer: build the GUI installer" />
         <echo message="  tarball:   tar the full install into i2p.tar.bz2 (extracts to build a new clean install)" />
-        <echo message="  updater:   tar the built i2p specific files into an i2pupdate.zip (extracts safely over existing installs)" />
+        <echo message="  updater:   Package the built files in i2pupdate.zip (extracts safely over existing installs)" />
+        <echo message="  updater200: Updater compressed with pack200 (creates i2pupdate200.zip, 60% smaller)" />
         <echo message="  updaterWithJavadoc: updater including the javadocs, for display in the console" />
-        <echo message="  updaterWithJetty:   tar the built i2p specific files and jetty into an i2pupdate.zip (extracts safely over existing installs)" />
+        <echo message="  updaterWithJetty: Updater including Jetty" />
         <echo message="  updaterWithJettyFixes: updater including local jetty patches" />
         <echo message="  updaterWithGeoIP: updater including GeoIP Files" />
         <echo message="  updaterWithJettyFixesAndGeoIP" />
@@ -199,7 +200,8 @@
         <copy file="installer/lib/jbigi/jbigi.jar" todir="build" />
         <copy file="apps/addressbook/dist/addressbook.war" todir="build/" />
     </target>
-    <target name="poupdate">
+    <!-- the apps need to compile the jsps to poupdate -->
+    <target name="poupdate" depends="buildRouter, buildStreaming, buildSystray, buildJetty" >
         <ant dir="apps/routerconsole/java/" target="poupdate" />
         <ant dir="apps/i2psnark/java/" target="poupdate" />
         <ant dir="apps/i2ptunnel/java/" target="poupdate" />
diff --git a/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java b/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java
index 7309a849b3933ccd97eb1d825b1b7931c9d6094e..28d211fa557720eb4f165d8970711bdb4c804591 100644
--- a/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java
+++ b/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java
@@ -38,8 +38,13 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
             l.messageAvailable(session, msgId, size, proto, fromport, toport);
         else {
             // no listener, throw it out
-            _log.error("No listener found for proto: " + proto + " port: " + toport + "msg id: " + msgId +
-                       " from pool of " + _listeners.size() + " listeners");
+            if (_listeners.isEmpty()) {
+                if (_log.shouldLog(Log.WARN))
+                    _log.warn("No listeners for incoming message");
+            } else {
+                _log.error("No listener found for proto: " + proto + " port: " + toport + " msg id: " + msgId +
+                           " from pool of " + _listeners.size() + " listeners");
+            }
             try {
                 session.receiveMessage(msgId);
             } catch (I2PSessionException ise) {}
diff --git a/core/java/src/net/i2p/crypto/TrustedUpdate.java b/core/java/src/net/i2p/crypto/TrustedUpdate.java
index 11f267712f88cc0ba15c3c288c83960d2a4bdd13..fdf63697dfbdfc1b2ccc620faff132e778e9a1d0 100644
--- a/core/java/src/net/i2p/crypto/TrustedUpdate.java
+++ b/core/java/src/net/i2p/crypto/TrustedUpdate.java
@@ -176,23 +176,30 @@ JXQAnA28vDmMMMH/WPbC5ixmJeGGNUiR
     /**
      *  Duplicate keys or names rejected,
      *  except that duplicate empty names are allowed
+     *  @param key 172 character base64 string
+     *  @param name non-null but "" ok
      *  @since 0.7.12
      *  @return true if successful
      */
     public boolean addKey(String key, String name) {
+        String oldName = _trustedKeys.get(key);
+        // already there?
+        if (name.equals(oldName))
+            return true;
+        if (oldName != null && !oldName.equals("")) {
+            _log.error("Key for " + name + " already stored for different name " + oldName + " : " + key);
+            return false;
+        }
         SigningPublicKey signingPublicKey = new SigningPublicKey();
         try {
-            // fromBase64() won't reject a string that is too long
-            if (key.length() != KEYSIZE_B64_BYTES)
-                throw new DataFormatException("x");
+            // fromBase64() will throw a DFE if length is not right
             signingPublicKey.fromBase64(key);
         } catch (DataFormatException dfe) {
-            _log.error("Bad signing key for " + name + " : " + key);
+            _log.error("Invalid signing key for " + name + " : " + key, dfe);
             return false;
         }
-        if (_trustedKeys.containsKey(signingPublicKey) ||
-            ((!name.equals("")) && _trustedKeys.containsValue(name))) {
-            _log.error("Duplicate signing key for " + name + " : " + key);
+        if ((!name.equals("")) && _trustedKeys.containsValue(name)) {
+            _log.error("Key mismatch for " + name + ", spoof attempt? : " + key);
             return false;
         }
         _trustedKeys.put(signingPublicKey, name);
diff --git a/core/java/src/net/i2p/util/LogRecordFormatter.java b/core/java/src/net/i2p/util/LogRecordFormatter.java
index 84a1cb6b8cf7a5acbec2e786d4e687de67525047..52583b63c393290f4da98836635d731219d4cefc 100644
--- a/core/java/src/net/i2p/util/LogRecordFormatter.java
+++ b/core/java/src/net/i2p/util/LogRecordFormatter.java
@@ -29,6 +29,14 @@ class LogRecordFormatter {
     private final static int MAX_PRIORITY_LENGTH = 5;
 
     public static String formatRecord(LogManager manager, LogRecord rec) {
+        return formatRecord(manager, rec, true);
+    }
+
+    /**
+     *  @param showDate if false, skip any date in the format (use when writing to wrapper log)
+     *  @since 0.8.2
+     */
+    static String formatRecord(LogManager manager, LogRecord rec, boolean showDate) {
         int size = 128 + rec.getMessage().length();
         if (rec.getThrowable() != null)
             size += 512;
@@ -37,7 +45,10 @@ class LogRecordFormatter {
         for (int i = 0; i < format.length; ++i) {
             switch (format[i]) {
             case LogManager.DATE:
-                buf.append(getWhen(manager, rec));
+                if (showDate)
+                    buf.append(getWhen(manager, rec));
+                else if (i+1 < format.length && format[i+1] == ' ')
+                    i++;  // skip following space
                 break;
             case LogManager.CLASS:
                 buf.append(getWhere(rec));
diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java
index f68249ba7a759822047413460eb524faf5d0e60c..51108e18b8841207d06d0f9f1d76654df5f212c2 100644
--- a/core/java/src/net/i2p/util/LogWriter.java
+++ b/core/java/src/net/i2p/util/LogWriter.java
@@ -17,8 +17,6 @@ import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.Queue;
 
-import net.i2p.I2PAppContext;
-
 /**
  * Log writer thread that pulls log records from the LogManager, writes them to
  * the current logfile, and rotates the logs as necessary.  This also periodically
@@ -112,7 +110,7 @@ class LogWriter implements Runnable {
     }
 
     private void writeRecord(LogRecord rec) {
-        String val = LogRecordFormatter.formatRecord(_manager, rec);
+        String val = LogRecordFormatter.formatRecord(_manager, rec, true);
         writeRecord(val);
 
         // we always add to the console buffer, but only sometimes write to stdout
@@ -121,7 +119,11 @@ class LogWriter implements Runnable {
             _manager.getBuffer().addCritical(val);
         if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) {
             if (_manager.displayOnScreen()) {
-                System.out.print(val);
+                // wrapper log already does time stamps, so reformat without the date
+                if (System.getProperty("wrapper.version") != null)
+                    System.out.print(LogRecordFormatter.formatRecord(_manager, rec, false));
+                else
+                    System.out.print(val);
             }
         }
     }
@@ -199,7 +201,7 @@ class LogWriter implements Runnable {
         File f = new File(pattern);
         File base = null;
         if (!f.isAbsolute())
-            base = I2PAppContext.getGlobalContext().getLogDir();
+            base = _manager.getContext().getLogDir();
 
         if ( (pattern.indexOf('#') < 0) && (pattern.indexOf('@') <= 0) ) {
             if (base != null)
diff --git a/history.txt b/history.txt
index a31619ba8d2999a325210ad4c23e1389103d3c15..9450ccca9545576173c2aa4107121d480699b719 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,29 @@
+2010-12-11 zzz
+    * Build: Fix 'ant distclean poupdate' again
+    * I2CP: Change a log error to a warning (ticket #353)
+    * i2psnark:
+      - Restore text (ticket #273)
+      - Fix several HTML errors (ticket #273)
+      - Fix HTML error causing info links to be unclickable in dillo (tiicket #273)
+      - Fix alt text duplicated or looking bad in text browsers (ticket #273)
+      - Fix Opera button errors (ticket #332)
+      - Fix POST resubmission errors (ticket #334)
+      - Catch FetchAndAdd copy error (ticket #352)
+      - Set permissions on downloaded torrent files
+      - Hide some columns when not running
+      - Lots of spacing cleanups
+      - Rename images so users don't end up with unused files
+      - Remove ~15 unused images
+      - Clean up theme selection speed-coding exercise
+      - Indent fixes
+    * Log: Don't double-timestamp CRITS in wrapper.log
+    * News: XML fixes (ticket #350)
+    * Plugins: Better handling of signing keys (Ticket #351)
+    * TunnelPoolManager: Fix rare startup NPE (http://forum.i2p/viewtopic.php?t=5192)
+
+2010-12-10 Mathiasdm
+    * I2PTunnel: Fixed up security fix.
+
 2010-12-07 Mathiasdm
     * I2PTunnel: Security fix: change server reply
       to return 'I2PServer' instead of the actual servername.
diff --git a/installer/resources/checklist.txt b/installer/resources/checklist.txt
index 2527d69cdec2bc320cbb2b93cfaca8cb1a551554..da8b54386f4004be5a0441da27caf49d9bc96a06 100644
--- a/installer/resources/checklist.txt
+++ b/installer/resources/checklist.txt
@@ -8,7 +8,6 @@ Deploy the Jetty archive, a clean checkout lacks it
 
 Change revision in:
 	history.txt
-	installer/resources/initialNews.xml
 	installer/install.xml
 	installer/resources/news.xml
 	router/java/src/net/i2p/router/RouterVersion.java
@@ -21,7 +20,7 @@ Review the complete diff from the last release:
 
 Verify that no untrusted revisions were inadvertently
 blessed by a trusted party:
-        mtn log --brief --no-graph --to t:i2p-0.7.(xx-1) | cut -d ' ' -f 2- | sort
+        mtn log --brief --no-graph --to t:i2p-0.8.(xx-1) | cut -d ' ' -f 2 | sort | uniq -c
 
 NOTE: Most tasks below here are now automated by 'ant release'
 
diff --git a/installer/resources/initialNews/initialNews.xml b/installer/resources/initialNews/initialNews.xml
index d69d6c644a6a6f1cedd43b2eab61bf82b9cd6dfb..49f8a012a5bd73fd1b023cd5c170c86be5bcf025 100644
--- a/installer/resources/initialNews/initialNews.xml
+++ b/installer/resources/initialNews/initialNews.xml
@@ -1,5 +1,5 @@
 <div lang="en">
-<h4><ul><li>Congratulations on getting I2P installed!</li></ul></h4>
+<h3>Congratulations on getting I2P installed!</h3>
 <p>
 <b>Welcome to I2P!</b>
 Please <b>have patience</b> as I2P boots up and finds peers.
diff --git a/installer/resources/initialNews/initialNews_de.xml b/installer/resources/initialNews/initialNews_de.xml
index 38b037fc50a465d6f8e61961c2605a83665a2ea2..6b48359c2645e0b08e052c9e4dc9da0687e24c5e 100644
--- a/installer/resources/initialNews/initialNews_de.xml
+++ b/installer/resources/initialNews/initialNews_de.xml
@@ -1,5 +1,5 @@
 <div lang="de">
-<h4><ul><li>Wir gratulieren zur erfolgreichen Installation von I2P!</li></ul></h4>
+<h3>Wir gratulieren zur erfolgreichen Installation von I2P!</h3>
 <p>
 <b>Willkommen im I2P!</b>
 Hab noch <b>etwas Geduld</b>, w&auml;hrend I2P startet und weitere I2P-Router findet.
diff --git a/installer/resources/initialNews/initialNews_es.xml b/installer/resources/initialNews/initialNews_es.xml
index eca5e4918781a71ad4ec30a44ef7aabcdec6e8d2..7fca2669ebc2074bb4506c2240af51dcf7ca6f50 100644
--- a/installer/resources/initialNews/initialNews_es.xml
+++ b/installer/resources/initialNews/initialNews_es.xml
@@ -1,5 +1,5 @@
 <div lang="es">
-<h4><ul><li>&iexcl;Felicidades!, has instalado el enrutador I2P con &eacute;xito.</li></ul></h4>
+<h3>&iexcl;Felicidades!, has instalado el enrutador I2P con &eacute;xito.</h3>
 <p>
 <b>&iexcl;Bienvenido a I2P!</b><br>
 &iexcl;Ten todav&iacute;a <b>paciencia</b> mientras I2P est&eacute; arrancando y encontrando otros enrutadores I2P!
diff --git a/installer/resources/initialNews/initialNews_nl.xml b/installer/resources/initialNews/initialNews_nl.xml
index a968236d580570ebd10838b7c61a5e145b2dc44b..b888fb2966c47ec0ba6472d3904e88aa1a283695 100644
--- a/installer/resources/initialNews/initialNews_nl.xml
+++ b/installer/resources/initialNews/initialNews_nl.xml
@@ -1,5 +1,5 @@
 <div lang="nl">
-<h4><ul><li>Gefeliciteerd met de installatie van I2P!</li></ul></h4>
+<h3>Gefeliciteerd met de installatie van I2P!</h3>
 <p>
 <b>Welkom bij I2P!</b>
 Heb <b>wat geduld</b> terwijl I2P opstart en peers zoekt.
diff --git a/installer/resources/initialNews/initialNews_pt.xml b/installer/resources/initialNews/initialNews_pt.xml
index 2fe0ea2561611eab456cc9e6958f1fe6a83d1f80..76b553e2dbbd3e76f7e36165eca8400971044523 100644
--- a/installer/resources/initialNews/initialNews_pt.xml
+++ b/installer/resources/initialNews/initialNews_pt.xml
@@ -1,5 +1,5 @@
 <div lang="pt">
-<h4><ul><li>Parabéns, você instalou o roteador I2P com êxito!</li></ul></h4>
+<h3>Parabéns, você instalou o roteador I2P com êxito!</h3>
 <p>
 <b>Bem-vindo ao I2P!</b><br>
 Seja <b>paciente</b> enquanto I2P ainda está iniciando-se e enquanto continuam sendo encontrados outros roteadores I2P!
diff --git a/installer/resources/initialNews/initialNews_ru.xml b/installer/resources/initialNews/initialNews_ru.xml
index 93eb2fd7a87a67f36f0d77e3d44ceae412f7b74e..f82df2c7f730fbfd7ea90bbf4f5d10291d08c8e4 100644
--- a/installer/resources/initialNews/initialNews_ru.xml
+++ b/installer/resources/initialNews/initialNews_ru.xml
@@ -1,5 +1,5 @@
 <div lang="ru">
-<h4><ul><li>Поздравляем с успешным завершением установки I2P!</li></ul></h4>
+<h3>Поздравляем с успешным завершением установки I2P!</h3>
 <p>
 <b>Добро пожаловать в I2P!</b> Немного терпения! I2P-маршрутизатору потребуется пара минут для запуска модулей и первого подключения к сети I2P. 
 </p>
diff --git a/installer/resources/news.xml b/installer/resources/news.xml
index 91cdd52a97fc906b2811260be2c199d3f0fb2732..ae6b780c0191064a1b6e6013304c5bebe847dce0 100644
--- a/installer/resources/news.xml
+++ b/installer/resources/news.xml
@@ -3,7 +3,7 @@
 <i2p.release version="0.8.1" date="2010/11/15" minVersion="0.6" />
 -->
 <div lang="en">
-<h4><ul><li>2010-11-15: <b>0.8.1 <a href="http://www.i2p2.i2p/release-0.8.1.html">Released</a></b></li></ul></h4>
+<h3>2010-11-15: <b>0.8.1 <a href="http://www.i2p2.i2p/release-0.8.1.html">Released</a></b></h3>
 <p>
 The 0.8.1 release contains the usual collection of bug fixes,
 and a newly colorful i2psnark theme by dr|zed.
diff --git a/installer/resources/themes/snark/ubergine/images/details_nolink.png b/installer/resources/themes/snark/ubergine/images/details_nolink.png
deleted file mode 100644
index 79fd2b72a774a6e7999829dd9ea83b03603c3529..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/details_nolink.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/eta.png b/installer/resources/themes/snark/ubergine/images/eta.png
index f4c3f99d90440da920da4cce9ad8b5a21e0bdc59..197bbdd01ee9928724cd54d8a17db42399473f6e 100644
Binary files a/installer/resources/themes/snark/ubergine/images/eta.png and b/installer/resources/themes/snark/ubergine/images/eta.png differ
diff --git a/installer/resources/themes/snark/ubergine/images/head_eta.png b/installer/resources/themes/snark/ubergine/images/head_eta.png
deleted file mode 100644
index 197bbdd01ee9928724cd54d8a17db42399473f6e..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/head_eta.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/head_loaded.png b/installer/resources/themes/snark/ubergine/images/head_loaded.png
deleted file mode 100644
index 91f92b39b809bf0e54ac669f8148f62975643849..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/head_loaded.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/head_peers.png b/installer/resources/themes/snark/ubergine/images/head_peers.png
deleted file mode 100644
index 3fc97172f0dd3ba572e4fcbaf4f91e549271bb27..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/head_peers.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/head_snarks.png b/installer/resources/themes/snark/ubergine/images/head_snarks.png
deleted file mode 100644
index 9aac1c2ce94fcd922f9e929f21d96f994deae5ed..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/head_snarks.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/head_torrent.png b/installer/resources/themes/snark/ubergine/images/head_torrent.png
deleted file mode 100644
index d2a0d59d1101899649162fdea985da262d629115..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/head_torrent.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/snark_thead.png b/installer/resources/themes/snark/ubergine/images/snark_thead.png
deleted file mode 100644
index ead40efeac7cebfaf0fed362aadc323c1d61a528..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/ubergine/images/snark_thead.png and /dev/null differ
diff --git a/installer/resources/themes/snark/ubergine/images/torrent.png b/installer/resources/themes/snark/ubergine/images/torrent.png
index 5894d66cbff96a62c4c14136975c28dd6d2dcbcc..d2a0d59d1101899649162fdea985da262d629115 100644
Binary files a/installer/resources/themes/snark/ubergine/images/torrent.png and b/installer/resources/themes/snark/ubergine/images/torrent.png differ
diff --git a/installer/resources/themes/snark/ubergine/snark.css b/installer/resources/themes/snark/ubergine/snark.css
index 7d4ef2c333da6ca3999438d7ea9994231ebca432..95b529f1957c4080c390e0a9e499a934fb5063e7 100644
--- a/installer/resources/themes/snark/ubergine/snark.css
+++ b/installer/resources/themes/snark/ubergine/snark.css
@@ -155,7 +155,6 @@ th {
      border-bottom: 1px inset #101;
      color: #ddd;
      whitespace: nowrap;
-     font-variant: small-caps !important;
      letter-spacing: 0.05em;
 }
 
@@ -238,6 +237,10 @@ td:first-child {
      font-size: 9.5pt;
 }
 
+.center {
+     text-align: center !important;
+}
+
 .snarkTorrentName {
      text-shadow:1px 1px #550000;
      padding: 2px 0 0;
@@ -268,7 +271,6 @@ td:first-child {
 }
 
 .snarkTorrentEven {
-     background: #545;
      font-size: 8pt;
      background: #202;
 }
@@ -323,7 +325,6 @@ td:first-child {
 }
 
 .snarkTorrentOdd {
-     background: #656;
      background: #351933;
      font-size: 8pt;
      border: 0px inset #101 !important;
diff --git a/installer/resources/themes/snark/vanilla/images/eta.png b/installer/resources/themes/snark/vanilla/images/eta.png
index f4c3f99d90440da920da4cce9ad8b5a21e0bdc59..8eba678b7022fb00bab64e6537155eb80e56cda4 100644
Binary files a/installer/resources/themes/snark/vanilla/images/eta.png and b/installer/resources/themes/snark/vanilla/images/eta.png differ
diff --git a/installer/resources/themes/snark/vanilla/images/head_eta.png b/installer/resources/themes/snark/vanilla/images/head_eta.png
deleted file mode 100644
index 8eba678b7022fb00bab64e6537155eb80e56cda4..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/head_eta.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/head_loaded.png b/installer/resources/themes/snark/vanilla/images/head_loaded.png
deleted file mode 100644
index 46fc281ffe61828f29cadfdb6613eac975f6d1e4..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/head_loaded.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/head_peers.png b/installer/resources/themes/snark/vanilla/images/head_peers.png
deleted file mode 100644
index 8d1918acb6a4bfa80fc7aab84dd724bdb84da2e5..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/head_peers.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/head_snarks.png b/installer/resources/themes/snark/vanilla/images/head_snarks.png
deleted file mode 100644
index 10d909e25f48d9364b951862d6a7718df2a023e6..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/head_snarks.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/head_torrent.png b/installer/resources/themes/snark/vanilla/images/head_torrent.png
deleted file mode 100644
index c0ec7d2b0434894ba28ea9436098cb391569bb5c..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/head_torrent.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/link.png b/installer/resources/themes/snark/vanilla/images/link.png
deleted file mode 100644
index 25eacb7c2524142262d68bf729c5e2b61adfd6d4..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/link.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/snark_thead.png b/installer/resources/themes/snark/vanilla/images/snark_thead.png
deleted file mode 100644
index a0ecfb1a78e338cc1d0bc72f0850054809fabb59..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/snark_thead.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/tile3.png b/installer/resources/themes/snark/vanilla/images/tile3.png
deleted file mode 100644
index 43aa314de17776c283b2d8d48b5c88beb75f1b68..0000000000000000000000000000000000000000
Binary files a/installer/resources/themes/snark/vanilla/images/tile3.png and /dev/null differ
diff --git a/installer/resources/themes/snark/vanilla/images/torrent.png b/installer/resources/themes/snark/vanilla/images/torrent.png
index 5894d66cbff96a62c4c14136975c28dd6d2dcbcc..c0ec7d2b0434894ba28ea9436098cb391569bb5c 100644
Binary files a/installer/resources/themes/snark/vanilla/images/torrent.png and b/installer/resources/themes/snark/vanilla/images/torrent.png differ
diff --git a/installer/resources/themes/snark/vanilla/snark.css b/installer/resources/themes/snark/vanilla/snark.css
index 7ddfb7a7a9c4d4d270bad2e05f5702b891d146ec..8d31ca99136eb8fef9de3ed9e706a0640ee96596 100644
--- a/installer/resources/themes/snark/vanilla/snark.css
+++ b/installer/resources/themes/snark/vanilla/snark.css
@@ -139,7 +139,6 @@ tr {
 }
 
 thead, tfoot {
-     text-shadow: 0px 1px 1px #707;
      background: url("images/bling2.png") repeat-x scroll center center #867;
      font-weight: bold;
      color: #503;
@@ -161,7 +160,6 @@ th {
      border-top: 1px outset #604;
      border-bottom: 1px inset #604;
      whitespace: nowrap;
-     font-variant: small-caps !important;
      letter-spacing: 0.05em;
 }
 
@@ -244,6 +242,10 @@ td:first-child {
      font-size: 9.5pt;
 }
 
+.center {
+     text-align: center !important;
+}
+
 .snarkTorrentName {
 /*     text-shadow:1px 1px #540;*/
      padding: 3px 0 0;
@@ -270,7 +272,6 @@ td:first-child {
 }
 
 .snarkTorrentEven {
-     background: #fef;
      font-size: 8pt;
      background: #feb;
 }
@@ -328,7 +329,6 @@ td:first-child {
 }
 
 .snarkTorrentOdd {
-     background: #656;
      background: #fed;
      font-size: 8pt;
      border: 0px inset #fff !important;
@@ -490,7 +490,6 @@ input {
 
 input.r {
      text-align: right;
-     background: /*url('/themes/snark/ubergine/images/graytile.png')*/;
 }
 
 input[type=submit] {
@@ -524,7 +523,7 @@ input[type=image] {
      border-radius: 0px;
      border: medium none;
      margin: 0 2px;
-     opacity: 0.9 !important;
+     opacity: 0.8 !important;
 }
 
 input[type=image]:hover {
@@ -561,7 +560,7 @@ select:hover, textarea:hover {
 }
 
 textarea {
-     background: #fff; /*/*url('/themes/snark/ubergine/images/graytile.png')*/;*/
+     background: #fff; /*url('/themes/snark/ubergine/images/graytile.png');*/
      color: #f60;
      font-weight: bold;
      padding: 1px 4px 0px;
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
index d246679f34bde1d6b755a37b66b7bb5a91743fb3..3a53be55268765cad58df32105b17e70ac0e0dc0 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
@@ -131,10 +131,14 @@ public class TunnelPoolManager implements TunnelManagerFacade {
                 if (info != null)
                     return info;
         }
-        info = _inboundExploratory.getTunnel(id);
-        if (info != null) return info;
-        info = _outboundExploratory.getTunnel(id);
-        if (info != null) return info;
+        if (_inboundExploratory != null) {
+            info = _inboundExploratory.getTunnel(id);
+            if (info != null) return info;
+        }
+        if (_outboundExploratory != null) {
+            info = _outboundExploratory.getTunnel(id);
+            if (info != null) return info;
+        }
         return null;
     }