diff --git a/apps/BOB/src/net/i2p/BOB/I2Plistener.java b/apps/BOB/src/net/i2p/BOB/I2Plistener.java
index 3bb94e0b37582344111d946e4b9ceaf38b4d0281..caaadc76d515aa31503bd41dc892fdb077f52cab 100644
--- a/apps/BOB/src/net/i2p/BOB/I2Plistener.java
+++ b/apps/BOB/src/net/i2p/BOB/I2Plistener.java
@@ -25,6 +25,8 @@ package net.i2p.BOB;
 
 import java.net.ConnectException;
 import java.net.SocketTimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import net.i2p.I2PException;
 import net.i2p.client.streaming.I2PServerSocket;
 import net.i2p.client.streaming.I2PSocket;
@@ -78,51 +80,59 @@ public class I2Plistener implements Runnable {
 	public void run() {
 		boolean g = false;
 		I2PSocket sessSocket = null;
+		int conn = 0;
+		try {
+			die:
+			{
 
-die:		{
+				serverSocket.setSoTimeout(50);
+				boolean spin = true;
+				while (spin) {
 
-			serverSocket.setSoTimeout(50);
-			boolean spin = true;
-			while (spin) {
-
-				try {
-					rlock();
-				} catch (Exception e) {
-					break die;
-				}
-				try {
-					spin = info.get("RUNNING").equals(Boolean.TRUE);
-				} catch (Exception e) {
 					try {
-						runlock();
-					} catch (Exception e2) {
+						rlock();
+					} catch (Exception e) {
 						break die;
 					}
-					break die;
-				}
-				try {
 					try {
-						sessSocket = serverSocket.accept();
-						g = true;
-					} catch (ConnectException ce) {
-						g = false;
-					} catch (SocketTimeoutException ste) {
-						g = false;
-					}
-					if (g) {
-						g = false;
-						// toss the connection to a new thread.
-						I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database);
-						Thread t = new Thread(conn_c, "BOBI2PtoTCP");
-						t.start();
+						spin = info.get("RUNNING").equals(Boolean.TRUE);
+					} catch (Exception e) {
+						try {
+							runlock();
+						} catch (Exception e2) {
+							break die;
+						}
+						break die;
 					}
+					try {
+						try {
+							sessSocket = serverSocket.accept();
+							g = true;
+						} catch (ConnectException ce) {
+							g = false;
+						} catch (SocketTimeoutException ste) {
+							g = false;
+						}
+						if (g) {
+							g = false;
+							conn++;
+							// toss the connection to a new thread.
+							I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database);
+							Thread t = new Thread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn);
+							t.start();
+						}
 
-				} catch (Exception e) {
-					//	System.out.println("Exception " + e);
+					} catch (Exception e) {
+						//	System.out.println("Exception " + e);
+					}
 				}
 			}
-		}
+		} finally {
+			try {
+				serverSocket.close();
+			} catch (I2PException ex) {
+			}
 		// System.out.println("I2Plistener: Close");
-	// System.out.println("I2Plistener: Done.");
+		}
 	}
 }
diff --git a/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java b/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java
index ad5e2701b494bbe9486bbc6b1b6731903a1110a7..73e936c61b3cf7b77970820a63dbcdd9c8eb01bf 100644
--- a/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java
+++ b/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java
@@ -70,90 +70,99 @@ public class I2PtoTCP implements Runnable {
 		String host;
 		int port;
 		boolean tell;
-die:            {
-			try {
-				try {
-					rlock();
-				} catch(Exception e) {
-					break die;
-				}
-				try {
-					host = info.get("OUTHOST").toString();
-					port = Integer.parseInt(info.get("OUTPORT").toString());
-					tell = info.get("QUIET").equals(Boolean.FALSE);
-				} catch(Exception e) {
-					runlock();
-					break die;
-				}
+		InputStream in = null;
+		OutputStream out = null;
+		InputStream Iin = null;
+		OutputStream Iout = null;
+		try {
+			die:
+			{
 				try {
-					runlock();
-				} catch(Exception e) {
-					break die;
-				}
-				sock = new Socket(host, port);
-				// make readers/writers
-				InputStream in = sock.getInputStream();
-				OutputStream out = sock.getOutputStream();
-				InputStream Iin = I2P.getInputStream();
-				OutputStream Iout = I2P.getOutputStream();
-				I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
-
-				if(tell) {
-					// tell who is connecting
-					out.write(I2P.getPeerDestination().toBase64().getBytes());
-					out.write(10); // nl
-					out.flush(); // not really needed, but...
-				}
-				// setup to cross the streams
-				TCPio conn_c = new TCPio(in, Iout /*, info, database */ ); // app -> I2P
-				TCPio conn_a = new TCPio(Iin, out /* , info, database */); // I2P -> app
-				Thread t = new Thread(conn_c, "TCPioA");
-				Thread q = new Thread(conn_a, "TCPioB");
-				// Fire!
-				t.start();
-				q.start();
-				while(t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
 					try {
-						Thread.sleep(10); //sleep for 10 ms
-					} catch(InterruptedException e) {
-						try {
-							in.close();
-						} catch(Exception ex) {
-						}
-						try {
-							out.close();
-						} catch(Exception ex) {
-						}
-						try {
-							Iin.close();
-						} catch(Exception ex) {
-						}
+						rlock();
+					} catch (Exception e) {
+						break die;
+					}
+					try {
+						host = info.get("OUTHOST").toString();
+						port = Integer.parseInt(info.get("OUTPORT").toString());
+						tell = info.get("QUIET").equals(Boolean.FALSE);
+					} catch (Exception e) {
+						runlock();
+						break die;
+					}
+					try {
+						runlock();
+					} catch (Exception e) {
+						break die;
+					}
+					sock = new Socket(host, port);
+					// make readers/writers
+					in = sock.getInputStream();
+					out = sock.getOutputStream();
+					Iin = I2P.getInputStream();
+					Iout = I2P.getOutputStream();
+					I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
+
+					if (tell) {
+						// tell who is connecting
+						out.write(I2P.getPeerDestination().toBase64().getBytes());
+						out.write(10); // nl
+						out.flush(); // not really needed, but...
+					}
+					// setup to cross the streams
+					TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
+					TCPio conn_a = new TCPio(Iin, out /* , info, database */); // I2P -> app
+					Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPioA");
+					Thread q = new Thread(conn_a, Thread.currentThread().getName() + " TCPioB");
+					// Fire!
+					t.start();
+					q.start();
+					while (t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
 						try {
-							Iout.close();
-						} catch(Exception ex) {
+							Thread.sleep(10); //sleep for 10 ms
+						} catch (InterruptedException e) {
+							break die;
 						}
 					}
-				}
 				// System.out.println("I2PtoTCP: Going away...");
-			} catch(Exception e) {
-				// System.out.println("I2PtoTCP: Owch! damn!");
-				break die;
+				} catch (Exception e) {
+					// System.out.println("I2PtoTCP: Owch! damn!");
+					break die;
+				}
+			} // die
+		} finally {
+			try {
+				in.close();
+			} catch (Exception ex) {
+			}
+			try {
+				out.close();
+			} catch (Exception ex) {
+			}
+			try {
+				Iin.close();
+			} catch (Exception ex) {
+			}
+			try {
+				Iout.close();
+			} catch (Exception ex) {
+			}
+			try {
+				// System.out.println("I2PtoTCP: Close I2P");
+				I2P.close();
+			} catch (Exception e) {
+				tell = false;
+			}
+			//System.out.println("I2PtoTCP: Closed I2P");
+			try {
+				// System.out.println("I2PtoTCP: Close sock");
+				sock.close();
+			} catch (Exception e) {
+				tell = false;
 			}
-		} // die
-		try {
-			// System.out.println("I2PtoTCP: Close I2P");
-			I2P.close();
-		} catch(Exception e) {
-			tell = false;
-		}
-		//System.out.println("I2PtoTCP: Closed I2P");
-		try {
-			// System.out.println("I2PtoTCP: Close sock");
-			sock.close();
-		} catch(Exception e) {
-			tell = false;
-		}
 		// System.out.println("I2PtoTCP: Done");
 
+		}
 	}
 }
diff --git a/apps/BOB/src/net/i2p/BOB/MUXlisten.java b/apps/BOB/src/net/i2p/BOB/MUXlisten.java
index 776dbf28acc2be094f55e052458d5fa2c2e33d89..91028e7cb8ff21bda6b4f88d5139f2f107f739ac 100644
--- a/apps/BOB/src/net/i2p/BOB/MUXlisten.java
+++ b/apps/BOB/src/net/i2p/BOB/MUXlisten.java
@@ -29,8 +29,6 @@ import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.util.Properties;
 import net.i2p.I2PException;
-import net.i2p.client.I2PSession;
-import net.i2p.client.I2PSessionException;
 import net.i2p.client.streaming.I2PServerSocket;
 import net.i2p.client.streaming.I2PSocketManager;
 import net.i2p.client.streaming.I2PSocketManagerFactory;
@@ -50,7 +48,7 @@ public class MUXlisten implements Runnable {
 	private ByteArrayInputStream prikey;
 	private ThreadGroup tg;
 	private String N;
-	private ServerSocket listener;
+	private ServerSocket listener = null;
 	private int backlog = 50; // should this be more? less?
 	boolean go_out;
 	boolean come_in;
@@ -133,187 +131,162 @@ public class MUXlisten implements Runnable {
 	 */
 	public void run() {
 		I2PServerSocket SS = null;
-		int ticks = 100; // Allow 10 seconds, no more.
+		Thread t = null;
+		Thread q = null;
 		try {
-			wlock();
 			try {
-				info.add("RUNNING", new Boolean(true));
+				wlock();
+				try {
+					info.add("RUNNING", new Boolean(true));
+				} catch (Exception e) {
+					wunlock();
+					return;
+				}
 			} catch (Exception e) {
+				return;
+			}
+			try {
 				wunlock();
+			} catch (Exception e) {
 				return;
 			}
-		} catch (Exception e) {
-			return;
-		}
-		try {
-			wunlock();
-		} catch (Exception e) {
-			return;
-		}
 //		socketManager.addDisconnectListener(new DisconnectListener());
 
-		quit:
-		{
-			try {
-				tg = new ThreadGroup(N);
-				die:
-				{
-					// toss the connections to a new threads.
-					// will wrap with TCP and UDP when UDP works
+			quit:
+			{
+				try {
+					tg = new ThreadGroup(N);
+					die:
+					{
+						// toss the connections to a new threads.
+						// will wrap with TCP and UDP when UDP works
 
-					if (go_out) {
-						// I2P -> TCP
-						SS = socketManager.getServerSocket();
-						I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log);
-						Thread t = new Thread(tg, conn, "BOBI2Plistener " + N);
-						t.start();
-					}
+						if (go_out) {
+							// I2P -> TCP
+							SS = socketManager.getServerSocket();
+							I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log);
+							t = new Thread(tg, conn, "BOBI2Plistener " + N);
+							t.start();
+						}
 
-					if (come_in) {
-						// TCP -> I2P
-						TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log);
-						Thread q = new Thread(tg, conn, "BOBTCPlistener" + N);
-						q.start();
-					}
+						if (come_in) {
+							// TCP -> I2P
+							TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log);
+							q = new Thread(tg, conn, "BOBTCPlistener " + N);
+							q.start();
+						}
 
-					try {
-						wlock();
 						try {
-							info.add("STARTING", new Boolean(false));
+							wlock();
+							try {
+								info.add("STARTING", new Boolean(false));
+							} catch (Exception e) {
+								wunlock();
+								break die;
+							}
 						} catch (Exception e) {
-							wunlock();
 							break die;
 						}
-					} catch (Exception e) {
-						break die;
-					}
-					try {
-						wunlock();
-					} catch (Exception e) {
-						break die;
-					}
-					boolean spin = true;
-					while (spin) {
 						try {
-							Thread.sleep(1000); //sleep for 1 second
-						} catch (InterruptedException e) {
+							wunlock();
+						} catch (Exception e) {
 							break die;
 						}
-						try {
-							rlock();
+						boolean spin = true;
+						while (spin) {
 							try {
-								spin = info.get("STOPPING").equals(Boolean.FALSE);
+								Thread.sleep(1000); //sleep for 1 second
+							} catch (InterruptedException e) {
+								break die;
+							}
+							try {
+								rlock();
+								try {
+									spin = info.get("STOPPING").equals(Boolean.FALSE);
+								} catch (Exception e) {
+									runlock();
+									break die;
+								}
 							} catch (Exception e) {
+								break die;
+							}
+							try {
 								runlock();
+							} catch (Exception e) {
 								break die;
 							}
-						} catch (Exception e) {
-							break die;
 						}
+
 						try {
-							runlock();
+							wlock();
+							try {
+								info.add("RUNNING", new Boolean(false));
+							} catch (Exception e) {
+								wunlock();
+								break die;
+							}
 						} catch (Exception e) {
 							break die;
 						}
-					}
-
-					try {
-						wlock();
 						try {
-							info.add("RUNNING", new Boolean(false));
-						} catch (Exception e) {
 							wunlock();
+						} catch (Exception e) {
 							break die;
 						}
-					} catch (Exception e) {
-						break die;
-					}
-					try {
-						wunlock();
-					} catch (Exception e) {
-						break die;
-					}
-				} // die
-
-				if (SS != null) {
-					try {
-						SS.close();
-					} catch (I2PException ex) {
-						//Logger.getLogger(MUXlisten.class.getName()).log(Level.SEVERE, null, ex);
-					}
-				}
-				if (this.come_in) {
-					try {
-						listener.close();
-					} catch (IOException e) {
-					}
-				}
+					} // die
 
-				I2PSession session = socketManager.getSession();
-				if (session != null) {
-					// System.out.println("I2Plistener: destroySession");
-					try {
-						session.destroySession();
-					} catch (I2PSessionException ex) {
-						// nop
-					}
+				// I2PSession session = socketManager.getSession();
+				// if (session != null) {
+				// System.out.println("I2Plistener: destroySession");
+				//	try {
+				//		session.destroySession();
+				//	} catch (I2PSessionException ex) {
+				// nop
+				//	}
+				// }
+				// try {
+				//	socketManager.destroySocketManager();
+				//} catch (Exception e) {
+				// nop
+				//}
+				} catch (Exception e) {
+					// System.out.println("MUXlisten: Caught an exception" + e);
+					break quit;
 				}
+			} // quit
+		} finally {
+			// allow threads above this one to catch the stop signal.
+			try {
+				Thread.sleep(250);
+			} catch (InterruptedException ex) {
+			}
+			// zero out everything.
+			try {
+				wlock();
 				try {
-					socketManager.destroySocketManager();
+					info.add("STARTING", new Boolean(false));
+					info.add("STOPPING", new Boolean(false));
+					info.add("RUNNING", new Boolean(false));
 				} catch (Exception e) {
-					// nop
+					wunlock();
+					return;
 				}
-				// Wait for child threads and thread groups to die
-				// System.out.println("MUXlisten: waiting for children");
-				// if (tg.activeCount() + tg.activeGroupCount() != 0) {
-				//	tg.interrupt(); // give my stuff a small smack.
-				//	while ((tg.activeCount() + tg.activeGroupCount() != 0) && ticks != 0) {
-				//		ticks--;
-				//		try {
-				//			Thread.sleep(100); //sleep for 100 ms (One tenth second)
-				//		} catch (InterruptedException ex) {
-				//			break quit;
-				//		}
-				//	}
-				//	if (tg.activeCount() + tg.activeGroupCount() != 0) {
-				//		break quit; // Uh-oh.
-				//	}
-				//}
-				//tg.destroy();
-				// Zap reference to the ThreadGroup so the JVM can GC it.
-				//tg = null;
+				wunlock();
 			} catch (Exception e) {
-				// System.out.println("MUXlisten: Caught an exception" + e);
-				break quit;
 			}
-		} // quit
 
-		// zero out everything.
-		try {
-			wlock();
-			try {
-				info.add("STARTING", new Boolean(false));
-				info.add("STOPPING", new Boolean(false));
-				info.add("RUNNING", new Boolean(false));
-			} catch (Exception e) {
-				wunlock();
-				return;
-			}
-			wunlock();
-		} catch (Exception e) {
-		}
+			//try {
+			//	Thread.sleep(1000 * 20); // how long?? is this even needed??
+			//} catch (InterruptedException ex) {
+			//}
 
-		// This is here to catch when something fucks up REALLY bad, like those annoying stuck threads!
-		if (tg != null) {
-			// tg.interrupt(); // give my stuff a small smack again.
 			if (SS != null) {
 				try {
 					SS.close();
 				} catch (I2PException ex) {
-					//Logger.getLogger(MUXlisten.class.getName()).log(Level.SEVERE, null, ex);
 				}
 			}
-			if (this.come_in) {
+			if (listener != null) {
 				try {
 					listener.close();
 				} catch (IOException e) {
@@ -323,50 +296,46 @@ public class MUXlisten implements Runnable {
 				socketManager.destroySocketManager();
 			} catch (Exception e) {
 				// nop
-			}
-			if (tg.activeCount() + tg.activeGroupCount() != 0) {
-				int foo = tg.activeCount() + tg.activeGroupCount();
-				int bar = foo;
+				}
+			// This is here to catch when something fucks up REALLY bad, like those annoying stuck threads!
+			if (tg != null) {
 				String boner = tg.getName();
-				System.out.println("BOB: MUXlisten: Waiting on threads for " + boner);
-				System.out.println("\n\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
-				visit(tg, 0, boner);
-				System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n\n");
-				// Happily spin forever :-(
-				while ((tg.activeCount() + tg.activeGroupCount() != 0)) {
-					foo = tg.activeCount() + tg.activeGroupCount();
-					if (foo != bar) {
-						System.out.println("\n\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
-						visit(tg, 0, boner);
-						System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n\n");
-					}
-					bar = foo;
-					try {
+				// tg.interrupt(); // give my stuff a small smack again.
+				if (tg.activeCount() + tg.activeGroupCount() != 0) {
+					int foo = tg.activeCount() + tg.activeGroupCount();
+					int bar = foo;
+					// hopefully no longer needed!
+					// System.out.println("BOB: MUXlisten: Waiting on threads for " + boner);
+					// System.out.println("\n\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
+					// visit(tg, 0, boner);
+					// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n\n");
+					// Happily spin forever :-(
+					while ((tg.activeCount() + tg.activeGroupCount() != 0)) {
+						foo = tg.activeCount() + tg.activeGroupCount();
+						//	if (foo != bar) {
+						//		System.out.println("\n\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
+						//		visit(tg, 0, boner);
+						//		System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n\n");
+						//	}
+						bar = foo;
 						try {
-							socketManager.destroySocketManager();
-						} catch (Exception e) {
+							Thread.sleep(100); //sleep for 100 ms (One tenth second)
+						} catch (InterruptedException ex) {
 							// nop
 						}
-					} catch (Exception e) {
-						// nop
-					}
-					try {
-						Thread.sleep(100); //sleep for 100 ms (One tenth second)
-					} catch (InterruptedException ex) {
-						// nop
 					}
 				}
 				System.out.println("BOB: MUXlisten: Threads went away. Success: " + boner);
+				tg.destroy();
+				// Zap reference to the ThreadGroup so the JVM can GC it.
+				tg = null;
 			}
-			tg.destroy();
-			// Zap reference to the ThreadGroup so the JVM can GC it.
-			tg = null;
 		}
 	}
 
 
 	// Debugging...
-	/** 
+	/**
 	 *	Find the root thread group and print them all.
 	 *
 	 */
diff --git a/apps/BOB/src/net/i2p/BOB/TCPlistener.java b/apps/BOB/src/net/i2p/BOB/TCPlistener.java
index 4ce888090bc6d0dc84a1815f417a9d060945c323..0ac67d277b8919d685ed335f2126c438260b6e19 100644
--- a/apps/BOB/src/net/i2p/BOB/TCPlistener.java
+++ b/apps/BOB/src/net/i2p/BOB/TCPlistener.java
@@ -29,6 +29,8 @@ import java.net.Socket;
 import java.net.SocketTimeoutException;
 // import net.i2p.client.I2PSession;
 // import net.i2p.client.I2PSessionException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import net.i2p.client.streaming.I2PServerSocket;
 import net.i2p.client.streaming.I2PSocketManager;
 import net.i2p.util.Log;
@@ -80,71 +82,80 @@ public class TCPlistener implements Runnable {
 	public void run() {
 		boolean g = false;
 		boolean spin = true;
-
-die:		{
-			try {
-				rlock();
-			} catch (Exception e) {
-				break die;
-			}
-			try {
-				if (info.exists("OUTPORT")) {
-					tgwatch = 2;
-				}
-			} catch (Exception e) {
+		int conn = 0;
+		try {
+			die:
+			{
 				try {
-					runlock();
-				} catch (Exception e2) {
+					rlock();
+				} catch (Exception e) {
 					break die;
 				}
-				break die;
-			}
-			try {
-				runlock();
-			} catch (Exception e) {
-				break die;
-			}
-			try {
-				Socket server = new Socket();
-				listener.setSoTimeout(50); // We don't block, we cycle and check.
-				while (spin) {
+				try {
+					if (info.exists("OUTPORT")) {
+						tgwatch = 2;
+					}
+				} catch (Exception e) {
 					try {
-						rlock();
-					} catch (Exception e) {
+						runlock();
+					} catch (Exception e2) {
 						break die;
 					}
-					try {
-						spin = info.get("RUNNING").equals(Boolean.TRUE);
-					} catch (Exception e) {
+					break die;
+				}
+				try {
+					runlock();
+				} catch (Exception e) {
+					break die;
+				}
+				try {
+					Socket server = new Socket();
+					listener.setSoTimeout(50); // We don't block, we cycle and check.
+					while (spin) {
 						try {
-							runlock();
-						} catch (Exception e2) {
+							rlock();
+						} catch (Exception e) {
 							break die;
 						}
-						break die;
+						try {
+							spin = info.get("RUNNING").equals(Boolean.TRUE);
+						} catch (Exception e) {
+							try {
+								runlock();
+							} catch (Exception e2) {
+								break die;
+							}
+							break die;
+						}
+						try {
+							server = listener.accept();
+							g = true;
+						} catch (SocketTimeoutException ste) {
+							g = false;
+						}
+						if (g) {
+							conn++;
+							// toss the connection to a new thread.
+							TCPtoI2P conn_c = new TCPtoI2P(socketManager, server);
+							Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn);
+							t.start();
+							g = false;
+						}
 					}
+					listener.close();
+				} catch (IOException ioe) {
 					try {
-						server = listener.accept();
-						g = true;
-					} catch (SocketTimeoutException ste) {
-						g = false;
-					}
-					if (g) {
-						// toss the connection to a new thread.
-						TCPtoI2P conn_c = new TCPtoI2P(socketManager, server);
-						Thread t = new Thread(conn_c, "BOBTCPtoI2P");
-						t.start();
-						g = false;
+						listener.close();
+					} catch (IOException e) {
 					}
 				}
+			}
+		} finally {
+			try {
 				listener.close();
-			} catch (IOException ioe) {
-				try {
-					listener.close();
-				} catch (IOException e) {
-				}
+			} catch (IOException ex) {
 			}
+		//System.out.println("TCPlistener: " + Thread.currentThread().getName() +  "Done.");
 		}
-	//System.out.println("TCPlistener: Done.");
 	}
 }
diff --git a/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java b/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java
index 5fefae017852e2e58e1b98934b48a4845ca316f9..f3f2c74456ed3e3d1d6e4ccc7b07d99505ce0942 100644
--- a/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java
+++ b/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java
@@ -64,17 +64,17 @@ public class TCPtoI2P implements Runnable {
 
 		S = new String();
 
-		while(true) {
+		while (true) {
 			b = in.read();
-			if(b == 13) {
+			if (b == 13) {
 				//skip CR
 				continue;
 			}
-			if(b < 20 || b > 126) {
+			if (b < 20 || b > 126) {
 				// exit on anything not legal
 				break;
 			}
-			c = (char)(b & 0x7f); // We only really give a fuck about ASCII
+			c = (char) (b & 0x7f); // We only really give a fuck about ASCII
 			S = new String(S + c);
 		}
 		return S;
@@ -118,85 +118,87 @@ public class TCPtoI2P implements Runnable {
 		OutputStream Iout = null;
 		InputStream in = null;
 		OutputStream out = null;
-
 		try {
-
-			in = sock.getInputStream();
-			out = sock.getOutputStream();
 			try {
-				line = lnRead(in);
-				input = line.toLowerCase();
-				Destination dest = null;
-
-				if(input.endsWith(".i2p")) {
-					dest = I2PTunnel.destFromName(input);
-					line = dest.toBase64();
-				}
-				dest = new Destination();
-				dest.fromBase64(line);
 
+				in = sock.getInputStream();
+				out = sock.getOutputStream();
 				try {
-					// get a client socket
-					I2P = socketManager.connect(dest);
-					I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
-					// make readers/writers
-					Iin = I2P.getInputStream();
-					Iout = I2P.getOutputStream();
-					// setup to cross the streams
-					TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
-					TCPio conn_a = new TCPio(Iin, out /*, info, database */); // I2P -> app
-					Thread t = new Thread(conn_c, "TCPioA");
-					Thread q = new Thread(conn_a, "TCPioB");
-					// Fire!
-					t.start();
-					q.start();
-					while(t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
+					line = lnRead(in);
+					input = line.toLowerCase();
+					Destination dest = null;
+
+					if (input.endsWith(".i2p")) {
+						dest = I2PTunnel.destFromName(input);
+						line = dest.toBase64();
+					}
+					dest = new Destination();
+					dest.fromBase64(line);
+
+					try {
+						// get a client socket
+						I2P = socketManager.connect(dest);
+						I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
+						// make readers/writers
+						Iin = I2P.getInputStream();
+						Iout = I2P.getOutputStream();
+						// setup to cross the streams
+						TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
+						TCPio conn_a = new TCPio(Iin, out /*, info, database */); // I2P -> app
+						Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPioA");
+						Thread q = new Thread(conn_a, Thread.currentThread().getName() + " TCPioB");
+						// Fire!
+						t.start();
+						q.start();
+						while (t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
 							Thread.sleep(10); //sleep for 10 ms
+						}
+
+					} catch (I2PException e) {
+						Emsg("ERROR " + e.toString(), out);
+					} catch (ConnectException e) {
+						Emsg("ERROR " + e.toString(), out);
+					} catch (NoRouteToHostException e) {
+						Emsg("ERROR " + e.toString(), out);
+					} catch (InterruptedIOException e) {
+						// We're breaking away.
 					}
 
-				} catch(I2PException e) {
-					Emsg("ERROR " + e.toString(), out);
-				} catch(ConnectException e) {
+				} catch (Exception e) {
 					Emsg("ERROR " + e.toString(), out);
-				} catch(NoRouteToHostException e) {
-					Emsg("ERROR " + e.toString(), out);
-				} catch(InterruptedIOException e) {
-					// We're breaking away.
 				}
-
-			} catch(Exception e) {
-				Emsg("ERROR " + e.toString(), out);
+			} catch (Exception e) {
+				// bail on anything else
+			}
+		} finally {
+			try {
+				in.close();
+			} catch (Exception e) {
+			}
+			try {
+				out.close();
+			} catch (Exception e) {
+			}
+			try {
+				Iin.close();
+			} catch (Exception e) {
+			}
+			try {
+				Iout.close();
+			} catch (Exception e) {
+			}
+			try {
+				// System.out.println("TCPtoI2P: Close I2P");
+				I2P.close();
+			} catch (Exception e) {
 			}
-		} catch(Exception e) {
-			// bail on anything else
-		}
-		try {
-			in.close();
-		} catch(Exception e) {
-		}
-		try {
-			out.close();
-		} catch(Exception e) {
-		}
-		try {
-			Iin.close();
-		} catch(Exception e) {
-		}
-		try {
-			Iout.close();
-		} catch(Exception e) {
-		}
-		try {
-			// System.out.println("TCPtoI2P: Close I2P");
-			I2P.close();
-		} catch(Exception e) {
-		}
 
-		try {
-			// System.out.println("TCPtoI2P: Close sock");
-			sock.close();
-		} catch(Exception e) {
+			try {
+				// System.out.println("TCPtoI2P: Close sock");
+				sock.close();
+			} catch (Exception e) {
+			}
 		}
-		// System.out.println("TCPtoI2P: Done.");
+	// System.out.println("TCPtoI2P: Done.");
 	}
 }
diff --git a/apps/addressbook/java/src/addressbook/Servlet.java b/apps/addressbook/java/src/addressbook/Servlet.java
index 50bc1eb6dba4c5b9d3cad995e5f235cd2dfec3e7..34af69c1ce657eff17985538aba3c8e8bf867a2f 100644
--- a/apps/addressbook/java/src/addressbook/Servlet.java
+++ b/apps/addressbook/java/src/addressbook/Servlet.java
@@ -54,9 +54,10 @@ public class Servlet extends GenericServlet {
         args[0] = config.getInitParameter("home");
         DaemonThread thread = new DaemonThread(args);
         thread.setDaemon(true);
+        thread.setName("Addressbook");
         thread.start();
         System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
         System.out.println("INFO: config root under " + args[0]);
     }
 
-}
\ No newline at end of file
+}
diff --git a/apps/desktopgui/nbproject/build-impl.xml b/apps/desktopgui/nbproject/build-impl.xml
index f8fea458d1f346442380fd849ea37ea18712ff34..039f8788f1ca19268562c37f54c28030b53894f8 100644
--- a/apps/desktopgui/nbproject/build-impl.xml
+++ b/apps/desktopgui/nbproject/build-impl.xml
@@ -152,7 +152,7 @@ is divided into following sections:
             <attribute default="${includes}" name="includes"/>
             <attribute default="${excludes}" name="excludes"/>
             <attribute default="${javac.debug}" name="debug"/>
-            <attribute default="" name="sourcepath"/>
+            <attribute default="/does/not/exist" name="sourcepath"/>
             <element name="customize" optional="true"/>
             <sequential>
                 <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
@@ -218,13 +218,13 @@ is divided into following sections:
             </sequential>
         </macrodef>
     </target>
-    <target name="-init-macrodef-nbjpda">
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
         <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
             <attribute default="${main.class}" name="name"/>
             <attribute default="${debug.classpath}" name="classpath"/>
             <attribute default="" name="stopclassname"/>
             <sequential>
-                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
                     <classpath>
                         <path path="@{classpath}"/>
                     </classpath>
@@ -255,6 +255,12 @@ is divided into following sections:
         <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
             <istrue value="${have-jdk-older-than-1.4}"/>
         </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
     </target>
     <target depends="-init-debug-args" name="-init-macrodef-debug">
         <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
@@ -264,7 +270,7 @@ is divided into following sections:
             <sequential>
                 <java classname="@{classname}" dir="${work.dir}" fork="true">
                     <jvmarg line="${debug-args-line}"/>
-                    <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
                     <jvmarg line="${run.jvmargs}"/>
                     <classpath>
                         <path path="@{classpath}"/>
@@ -311,6 +317,13 @@ is divided into following sections:
                 ===================
             -->
     <target depends="init" name="deps-jar" unless="no.deps"/>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
     <target depends="init,deps-jar" name="-pre-pre-compile">
         <mkdir dir="${build.classes.dir}"/>
     </target>
@@ -331,7 +344,7 @@ is divided into following sections:
         <!-- Empty placeholder for easier customization. -->
         <!-- You can override this target in the ../build.xml file. -->
     </target>
-    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
     <target name="-pre-compile-single">
         <!-- Empty placeholder for easier customization. -->
         <!-- You can override this target in the ../build.xml file. -->
@@ -345,7 +358,7 @@ is divided into following sections:
         <!-- Empty placeholder for easier customization. -->
         <!-- You can override this target in the ../build.xml file. -->
     </target>
-    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
     <!--
                 ====================
                 JAR BUILDING SECTION
diff --git a/apps/desktopgui/nbproject/genfiles.properties b/apps/desktopgui/nbproject/genfiles.properties
index 1b326007c72e7a85df4b7923826955a2cbbe1fd3..20e01e830ba018780074c5f99ab74c1da137da83 100644
--- a/apps/desktopgui/nbproject/genfiles.properties
+++ b/apps/desktopgui/nbproject/genfiles.properties
@@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=be360661
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
 nbproject/build-impl.xml.data.CRC32=c4b345cd
-nbproject/build-impl.xml.script.CRC32=74d3fda2
-nbproject/build-impl.xml.stylesheet.CRC32=487672f9
+nbproject/build-impl.xml.script.CRC32=8c02c081
+nbproject/build-impl.xml.stylesheet.CRC32=65b8de21
diff --git a/apps/desktopgui/src/desktopgui/GUIVersion.java b/apps/desktopgui/src/desktopgui/GUIVersion.java
index 7bde544de8d05d1b0dbaecbf613f2d3667ce97c5..d90713bc86531bbe163a00a21c7e2e74bb321c03 100644
--- a/apps/desktopgui/src/desktopgui/GUIVersion.java
+++ b/apps/desktopgui/src/desktopgui/GUIVersion.java
@@ -10,5 +10,5 @@ package desktopgui;
  * @author mathias
  */
 public class GUIVersion {
-    public static final String VERSION = "0.0.1.1";
+    public static final String VERSION = "0.0.1.2";
 }
diff --git a/apps/desktopgui/src/gui/GeneralConfiguration.form b/apps/desktopgui/src/gui/GeneralConfiguration.form
index df02e3d967a24a23edea625e7fb33f3f4bc76984..1b70c5adf77284750e69b0a37d122828be661532 100644
--- a/apps/desktopgui/src/gui/GeneralConfiguration.form
+++ b/apps/desktopgui/src/gui/GeneralConfiguration.form
@@ -1,8 +1,13 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 
 <Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.ButtonGroup" name="buttonGroup1">
+    </Component>
+  </NonVisualComponents>
   <Properties>
     <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" resourceKey="Form.title"/>
     <Property name="name" type="java.lang.String" value="Form" noResource="true"/>
   </Properties>
   <SyntheticProperties>
@@ -22,27 +27,27 @@
   <Layout>
     <DimensionLayout dim="0">
       <Group type="103" groupAlignment="0" attributes="0">
-          <Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
+          <Component id="applyPanel" alignment="0" max="32767" attributes="0"/>
           <Group type="102" attributes="0">
               <EmptySpace min="12" pref="12" max="12" attributes="0"/>
-              <Component id="jTabbedPane1" pref="566" max="32767" attributes="0"/>
+              <Component id="settingsPanel" pref="566" max="32767" attributes="0"/>
           </Group>
       </Group>
     </DimensionLayout>
     <DimensionLayout dim="1">
       <Group type="103" groupAlignment="0" attributes="0">
           <Group type="102" alignment="1" attributes="0">
-              <Component id="jTabbedPane1" max="32767" attributes="0"/>
+              <Component id="settingsPanel" max="32767" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
-              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+              <Component id="applyPanel" min="-2" max="-2" attributes="0"/>
           </Group>
       </Group>
     </DimensionLayout>
   </Layout>
   <SubComponents>
-    <Container class="javax.swing.JPanel" name="jPanel1">
+    <Container class="javax.swing.JPanel" name="applyPanel">
       <Properties>
-        <Property name="name" type="java.lang.String" value="jPanel1" noResource="true"/>
+        <Property name="name" type="java.lang.String" value="applyPanel" noResource="true"/>
       </Properties>
 
       <Layout>
@@ -84,21 +89,21 @@
         </Component>
       </SubComponents>
     </Container>
-    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
+    <Container class="javax.swing.JTabbedPane" name="settingsPanel">
       <Properties>
-        <Property name="name" type="java.lang.String" value="jTabbedPane1" noResource="true"/>
+        <Property name="name" type="java.lang.String" value="settingsPanel" noResource="true"/>
       </Properties>
 
       <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
       <SubComponents>
-        <Container class="javax.swing.JPanel" name="jPanel2">
+        <Container class="javax.swing.JPanel" name="speedPanel">
           <Properties>
-            <Property name="name" type="java.lang.String" value="jPanel2" noResource="true"/>
+            <Property name="name" type="java.lang.String" value="speedPanel" noResource="true"/>
           </Properties>
           <Constraints>
             <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
               <JTabbedPaneConstraints tabName="Speed">
-                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel2.TabConstraints.tabTitle"/>
+                <Property name="tabTitle" type="java.lang.String" resourceKey="speedPanel.TabConstraints.tabTitle"/>
               </JTabbedPaneConstraints>
             </Constraint>
           </Constraints>
@@ -107,10 +112,10 @@
             <Property name="useNullLayout" type="boolean" value="true"/>
           </Layout>
           <SubComponents>
-            <Component class="javax.swing.JLabel" name="jLabel1">
+            <Component class="javax.swing.JLabel" name="uploadSpeedLabel">
               <Properties>
-                <Property name="text" type="java.lang.String" resourceKey="jLabel1.text"/>
-                <Property name="name" type="java.lang.String" value="jLabel1" noResource="true"/>
+                <Property name="text" type="java.lang.String" resourceKey="uploadSpeedLabel.text"/>
+                <Property name="name" type="java.lang.String" value="uploadSpeedLabel" noResource="true"/>
               </Properties>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
@@ -118,10 +123,10 @@
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JLabel" name="jLabel2">
+            <Component class="javax.swing.JLabel" name="downloadSpeedLabel">
               <Properties>
-                <Property name="text" type="java.lang.String" resourceKey="jLabel2.text"/>
-                <Property name="name" type="java.lang.String" value="jLabel2" noResource="true"/>
+                <Property name="text" type="java.lang.String" resourceKey="downloadSpeedLabel.text"/>
+                <Property name="name" type="java.lang.String" value="downloadSpeedLabel" noResource="true"/>
               </Properties>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
@@ -129,58 +134,66 @@
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JTextField" name="jTextField1">
+            <Component class="javax.swing.JTextField" name="uploadspeed">
               <Properties>
-                <Property name="text" type="java.lang.String" resourceKey="jTextField1.text"/>
-                <Property name="name" type="java.lang.String" value="jTextField1" noResource="true"/>
+                <Property name="text" type="java.lang.String" resourceKey="uploadspeed.text"/>
+                <Property name="name" type="java.lang.String" value="uploadspeed" noResource="true"/>
               </Properties>
+              <Events>
+                <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="speedKeyTyped"/>
+              </Events>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
                   <AbsoluteConstraints x="160" y="20" width="-1" height="-1"/>
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JTextField" name="jTextField2">
+            <Component class="javax.swing.JTextField" name="downloadspeed">
               <Properties>
-                <Property name="text" type="java.lang.String" resourceKey="jTextField2.text"/>
-                <Property name="name" type="java.lang.String" value="jTextField2" noResource="true"/>
+                <Property name="text" type="java.lang.String" resourceKey="downloadspeed.text"/>
+                <Property name="name" type="java.lang.String" value="downloadspeed" noResource="true"/>
               </Properties>
+              <Events>
+                <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="speedKeyTyped"/>
+              </Events>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
                   <AbsoluteConstraints x="160" y="60" width="-1" height="-1"/>
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JComboBox" name="jComboBox1">
+            <Component class="javax.swing.JComboBox" name="uploadkbps">
               <Properties>
                 <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
-                  <StringArray count="4">
-                    <StringItem index="0" value="Item 1"/>
-                    <StringItem index="1" value="Item 2"/>
-                    <StringItem index="2" value="Item 3"/>
-                    <StringItem index="3" value="Item 4"/>
+                  <StringArray count="2">
+                    <StringItem index="0" value="kbps"/>
+                    <StringItem index="1" value="kBps"/>
                   </StringArray>
                 </Property>
-                <Property name="name" type="java.lang.String" value="jComboBox1" noResource="true"/>
+                <Property name="name" type="java.lang.String" value="uploadkbps" noResource="true"/>
               </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="uploadkbpsActionPerformed"/>
+              </Events>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
                   <AbsoluteConstraints x="240" y="20" width="-1" height="-1"/>
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JComboBox" name="jComboBox2">
+            <Component class="javax.swing.JComboBox" name="downloadkbps">
               <Properties>
                 <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
-                  <StringArray count="4">
-                    <StringItem index="0" value="Item 1"/>
-                    <StringItem index="1" value="Item 2"/>
-                    <StringItem index="2" value="Item 3"/>
-                    <StringItem index="3" value="Item 4"/>
+                  <StringArray count="2">
+                    <StringItem index="0" value="kbps"/>
+                    <StringItem index="1" value="kBps"/>
                   </StringArray>
                 </Property>
-                <Property name="name" type="java.lang.String" value="jComboBox2" noResource="true"/>
+                <Property name="name" type="java.lang.String" value="downloadkbps" noResource="true"/>
               </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="downloadkbpsActionPerformed"/>
+              </Events>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
                   <AbsoluteConstraints x="240" y="60" width="-1" height="-1"/>
@@ -209,22 +222,28 @@
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JTextField" name="jTextField3">
+            <Component class="javax.swing.JTextField" name="uploadgb">
               <Properties>
-                <Property name="text" type="java.lang.String" resourceKey="jTextField3.text"/>
-                <Property name="name" type="java.lang.String" value="jTextField3" noResource="true"/>
+                <Property name="text" type="java.lang.String" resourceKey="uploadgb.text"/>
+                <Property name="name" type="java.lang.String" value="uploadgb" noResource="true"/>
               </Properties>
+              <Events>
+                <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="uploadgbKeyTyped"/>
+              </Events>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
                   <AbsoluteConstraints x="440" y="20" width="60" height="-1"/>
                 </Constraint>
               </Constraints>
             </Component>
-            <Component class="javax.swing.JTextField" name="jTextField4">
+            <Component class="javax.swing.JTextField" name="downloadgb">
               <Properties>
-                <Property name="text" type="java.lang.String" resourceKey="jTextField4.text"/>
-                <Property name="name" type="java.lang.String" value="jTextField4" noResource="true"/>
+                <Property name="text" type="java.lang.String" resourceKey="downloadgb.text"/>
+                <Property name="name" type="java.lang.String" value="downloadgb" noResource="true"/>
               </Properties>
+              <Events>
+                <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="downloadgbKeyTyped"/>
+              </Events>
               <Constraints>
                 <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
                   <AbsoluteConstraints x="440" y="60" width="60" height="-1"/>
@@ -266,14 +285,14 @@
             </Component>
           </SubComponents>
         </Container>
-        <Container class="javax.swing.JPanel" name="jPanel3">
+        <Container class="javax.swing.JPanel" name="updatesPanel">
           <Properties>
-            <Property name="name" type="java.lang.String" value="jPanel3" noResource="true"/>
+            <Property name="name" type="java.lang.String" value="updatesPanel" noResource="true"/>
           </Properties>
           <Constraints>
             <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
               <JTabbedPaneConstraints tabName="Updates">
-                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel3.TabConstraints.tabTitle"/>
+                <Property name="tabTitle" type="java.lang.String" resourceKey="updatesPanel.TabConstraints.tabTitle"/>
               </JTabbedPaneConstraints>
             </Constraint>
           </Constraints>
@@ -344,18 +363,27 @@
             </Component>
             <Component class="javax.swing.JRadioButton" name="jRadioButton1">
               <Properties>
+                <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+                  <ComponentRef name="buttonGroup1"/>
+                </Property>
                 <Property name="text" type="java.lang.String" resourceKey="jRadioButton1.text"/>
                 <Property name="name" type="java.lang.String" value="jRadioButton1" noResource="true"/>
               </Properties>
             </Component>
             <Component class="javax.swing.JRadioButton" name="jRadioButton2">
               <Properties>
+                <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+                  <ComponentRef name="buttonGroup1"/>
+                </Property>
                 <Property name="text" type="java.lang.String" resourceKey="jRadioButton2.text"/>
                 <Property name="name" type="java.lang.String" value="jRadioButton2" noResource="true"/>
               </Properties>
             </Component>
             <Component class="javax.swing.JRadioButton" name="jRadioButton3">
               <Properties>
+                <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+                  <ComponentRef name="buttonGroup1"/>
+                </Property>
                 <Property name="text" type="java.lang.String" resourceKey="jRadioButton3.text"/>
                 <Property name="name" type="java.lang.String" value="jRadioButton3" noResource="true"/>
               </Properties>
@@ -380,14 +408,14 @@
             </Component>
           </SubComponents>
         </Container>
-        <Container class="javax.swing.JPanel" name="jPanel4">
+        <Container class="javax.swing.JPanel" name="tunnelPanel">
           <Properties>
-            <Property name="name" type="java.lang.String" value="jPanel4" noResource="true"/>
+            <Property name="name" type="java.lang.String" value="tunnelPanel" noResource="true"/>
           </Properties>
           <Constraints>
             <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
               <JTabbedPaneConstraints tabName="Tunnels/Services">
-                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel4.TabConstraints.tabTitle"/>
+                <Property name="tabTitle" type="java.lang.String" resourceKey="tunnelPanel.TabConstraints.tabTitle"/>
               </JTabbedPaneConstraints>
             </Constraint>
           </Constraints>
@@ -461,14 +489,14 @@
             </Component>
           </SubComponents>
         </Container>
-        <Container class="javax.swing.JPanel" name="jPanel5">
+        <Container class="javax.swing.JPanel" name="networkPanel">
           <Properties>
-            <Property name="name" type="java.lang.String" value="jPanel5" noResource="true"/>
+            <Property name="name" type="java.lang.String" value="networkPanel" noResource="true"/>
           </Properties>
           <Constraints>
             <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
               <JTabbedPaneConstraints tabName="Network">
-                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel5.TabConstraints.tabTitle"/>
+                <Property name="tabTitle" type="java.lang.String" resourceKey="networkPanel.TabConstraints.tabTitle"/>
               </JTabbedPaneConstraints>
             </Constraint>
           </Constraints>
@@ -486,14 +514,14 @@
             </DimensionLayout>
           </Layout>
         </Container>
-        <Container class="javax.swing.JPanel" name="jPanel6">
+        <Container class="javax.swing.JPanel" name="advancedPanel">
           <Properties>
-            <Property name="name" type="java.lang.String" value="jPanel6" noResource="true"/>
+            <Property name="name" type="java.lang.String" value="advancedPanel" noResource="true"/>
           </Properties>
           <Constraints>
             <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
               <JTabbedPaneConstraints tabName="Advanced">
-                <Property name="tabTitle" type="java.lang.String" resourceKey="jPanel6.TabConstraints.tabTitle"/>
+                <Property name="tabTitle" type="java.lang.String" resourceKey="advancedPanel.TabConstraints.tabTitle"/>
               </JTabbedPaneConstraints>
             </Constraint>
           </Constraints>
diff --git a/apps/desktopgui/src/gui/GeneralConfiguration.java b/apps/desktopgui/src/gui/GeneralConfiguration.java
index 912026bf12d218bb5703a1b850180df7772355f3..d1ff4bbe721a192b6fe88417213d6f0eb119e45c 100644
--- a/apps/desktopgui/src/gui/GeneralConfiguration.java
+++ b/apps/desktopgui/src/gui/GeneralConfiguration.java
@@ -6,6 +6,8 @@
 
 package gui;
 
+import router.configuration.SpeedHelper;
+
 /**
  *
  * @author  mathias
@@ -15,9 +17,14 @@ public class GeneralConfiguration extends javax.swing.JFrame {
     /** Creates new form GeneralConfiguration */
     public GeneralConfiguration() {
         initComponents();
+        extraInitComponents();
         this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
         this.setVisible(true);
     }
+    
+    private void extraInitComponents() {
+        downloadspeed.setText(SpeedHelper.getInboundBandwidth());
+    }
 
     /** This method is called from within the constructor to
      * initialize the form.
@@ -28,25 +35,26 @@ public class GeneralConfiguration extends javax.swing.JFrame {
     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
     private void initComponents() {
 
-        jPanel1 = new javax.swing.JPanel();
+        buttonGroup1 = new javax.swing.ButtonGroup();
+        applyPanel = new javax.swing.JPanel();
         cancel = new javax.swing.JToggleButton();
         ok = new javax.swing.JToggleButton();
-        jTabbedPane1 = new javax.swing.JTabbedPane();
-        jPanel2 = new javax.swing.JPanel();
-        jLabel1 = new javax.swing.JLabel();
-        jLabel2 = new javax.swing.JLabel();
-        jTextField1 = new javax.swing.JTextField();
-        jTextField2 = new javax.swing.JTextField();
-        jComboBox1 = new javax.swing.JComboBox();
-        jComboBox2 = new javax.swing.JComboBox();
+        settingsPanel = new javax.swing.JTabbedPane();
+        speedPanel = new javax.swing.JPanel();
+        uploadSpeedLabel = new javax.swing.JLabel();
+        downloadSpeedLabel = new javax.swing.JLabel();
+        uploadspeed = new javax.swing.JTextField();
+        downloadspeed = new javax.swing.JTextField();
+        uploadkbps = new javax.swing.JComboBox();
+        downloadkbps = new javax.swing.JComboBox();
         jLabel3 = new javax.swing.JLabel();
         jLabel4 = new javax.swing.JLabel();
-        jTextField3 = new javax.swing.JTextField();
-        jTextField4 = new javax.swing.JTextField();
+        uploadgb = new javax.swing.JTextField();
+        downloadgb = new javax.swing.JTextField();
         jLabel5 = new javax.swing.JLabel();
         jLabel6 = new javax.swing.JLabel();
         jLabel7 = new javax.swing.JLabel();
-        jPanel3 = new javax.swing.JPanel();
+        updatesPanel = new javax.swing.JPanel();
         jLabel8 = new javax.swing.JLabel();
         jRadioButton1 = new javax.swing.JRadioButton();
         jRadioButton2 = new javax.swing.JRadioButton();
@@ -54,130 +62,164 @@ public class GeneralConfiguration extends javax.swing.JFrame {
         jToggleButton1 = new javax.swing.JToggleButton();
         jToggleButton2 = new javax.swing.JToggleButton();
         jToggleButton3 = new javax.swing.JToggleButton();
-        jPanel4 = new javax.swing.JPanel();
+        tunnelPanel = new javax.swing.JPanel();
         jScrollPane1 = new javax.swing.JScrollPane();
         jScrollPane2 = new javax.swing.JScrollPane();
         jLabel9 = new javax.swing.JLabel();
         jLabel10 = new javax.swing.JLabel();
         jLabel11 = new javax.swing.JLabel();
-        jPanel5 = new javax.swing.JPanel();
-        jPanel6 = new javax.swing.JPanel();
+        networkPanel = new javax.swing.JPanel();
+        advancedPanel = new javax.swing.JPanel();
 
         setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(GeneralConfiguration.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
         setName("Form"); // NOI18N
 
-        jPanel1.setName("jPanel1"); // NOI18N
+        applyPanel.setName("applyPanel"); // NOI18N
 
-        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(GeneralConfiguration.class);
         cancel.setText(resourceMap.getString("cancel.text")); // NOI18N
         cancel.setName("cancel"); // NOI18N
 
         ok.setText(resourceMap.getString("ok.text")); // NOI18N
         ok.setName("ok"); // NOI18N
 
-        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
-        jPanel1.setLayout(jPanel1Layout);
-        jPanel1Layout.setHorizontalGroup(
-            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+        javax.swing.GroupLayout applyPanelLayout = new javax.swing.GroupLayout(applyPanel);
+        applyPanel.setLayout(applyPanelLayout);
+        applyPanelLayout.setHorizontalGroup(
+            applyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, applyPanelLayout.createSequentialGroup()
                 .addContainerGap(475, Short.MAX_VALUE)
                 .addComponent(ok)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(cancel)
                 .addContainerGap())
         );
-        jPanel1Layout.setVerticalGroup(
-            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(jPanel1Layout.createSequentialGroup()
-                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+        applyPanelLayout.setVerticalGroup(
+            applyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(applyPanelLayout.createSequentialGroup()
+                .addGroup(applyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(cancel)
                     .addComponent(ok))
                 .addContainerGap(14, Short.MAX_VALUE))
         );
 
-        jTabbedPane1.setName("jTabbedPane1"); // NOI18N
-
-        jPanel2.setName("jPanel2"); // NOI18N
-        jPanel2.setLayout(null);
-
-        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
-        jLabel1.setName("jLabel1"); // NOI18N
-        jPanel2.add(jLabel1);
-        jLabel1.setBounds(20, 20, 140, 30);
-
-        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
-        jLabel2.setName("jLabel2"); // NOI18N
-        jPanel2.add(jLabel2);
-        jLabel2.setBounds(20, 60, 140, 30);
-
-        jTextField1.setText(resourceMap.getString("jTextField1.text")); // NOI18N
-        jTextField1.setName("jTextField1"); // NOI18N
-        jPanel2.add(jTextField1);
-        jTextField1.setBounds(160, 20, 77, 27);
-
-        jTextField2.setText(resourceMap.getString("jTextField2.text")); // NOI18N
-        jTextField2.setName("jTextField2"); // NOI18N
-        jPanel2.add(jTextField2);
-        jTextField2.setBounds(160, 60, 77, 27);
-
-        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
-        jComboBox1.setName("jComboBox1"); // NOI18N
-        jPanel2.add(jComboBox1);
-        jComboBox1.setBounds(240, 20, 78, 27);
-
-        jComboBox2.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
-        jComboBox2.setName("jComboBox2"); // NOI18N
-        jPanel2.add(jComboBox2);
-        jComboBox2.setBounds(240, 60, 78, 27);
+        settingsPanel.setName("settingsPanel"); // NOI18N
+
+        speedPanel.setName("speedPanel"); // NOI18N
+        speedPanel.setLayout(null);
+
+        uploadSpeedLabel.setText(resourceMap.getString("uploadSpeedLabel.text")); // NOI18N
+        uploadSpeedLabel.setName("uploadSpeedLabel"); // NOI18N
+        speedPanel.add(uploadSpeedLabel);
+        uploadSpeedLabel.setBounds(20, 20, 140, 30);
+
+        downloadSpeedLabel.setText(resourceMap.getString("downloadSpeedLabel.text")); // NOI18N
+        downloadSpeedLabel.setName("downloadSpeedLabel"); // NOI18N
+        speedPanel.add(downloadSpeedLabel);
+        downloadSpeedLabel.setBounds(20, 60, 140, 30);
+
+        uploadspeed.setText(resourceMap.getString("uploadspeed.text")); // NOI18N
+        uploadspeed.setName("uploadspeed"); // NOI18N
+        uploadspeed.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyTyped(java.awt.event.KeyEvent evt) {
+                speedKeyTyped(evt);
+            }
+        });
+        speedPanel.add(uploadspeed);
+        uploadspeed.setBounds(160, 20, 77, 27);
+
+        downloadspeed.setText(resourceMap.getString("downloadspeed.text")); // NOI18N
+        downloadspeed.setName("downloadspeed"); // NOI18N
+        downloadspeed.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyTyped(java.awt.event.KeyEvent evt) {
+                speedKeyTyped(evt);
+            }
+        });
+        speedPanel.add(downloadspeed);
+        downloadspeed.setBounds(160, 60, 77, 27);
+
+        uploadkbps.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" }));
+        uploadkbps.setName("uploadkbps"); // NOI18N
+        uploadkbps.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                uploadkbpsActionPerformed(evt);
+            }
+        });
+        speedPanel.add(uploadkbps);
+        uploadkbps.setBounds(240, 20, 68, 27);
+
+        downloadkbps.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" }));
+        downloadkbps.setName("downloadkbps"); // NOI18N
+        downloadkbps.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                downloadkbpsActionPerformed(evt);
+            }
+        });
+        speedPanel.add(downloadkbps);
+        downloadkbps.setBounds(240, 60, 68, 27);
 
         jLabel3.setText(resourceMap.getString("jLabel3.text")); // NOI18N
         jLabel3.setName("jLabel3"); // NOI18N
-        jPanel2.add(jLabel3);
+        speedPanel.add(jLabel3);
         jLabel3.setBounds(330, 20, 97, 30);
 
         jLabel4.setText(resourceMap.getString("jLabel4.text")); // NOI18N
         jLabel4.setName("jLabel4"); // NOI18N
-        jPanel2.add(jLabel4);
+        speedPanel.add(jLabel4);
         jLabel4.setBounds(330, 60, 97, 30);
 
-        jTextField3.setText(resourceMap.getString("jTextField3.text")); // NOI18N
-        jTextField3.setName("jTextField3"); // NOI18N
-        jPanel2.add(jTextField3);
-        jTextField3.setBounds(440, 20, 60, 27);
-
-        jTextField4.setText(resourceMap.getString("jTextField4.text")); // NOI18N
-        jTextField4.setName("jTextField4"); // NOI18N
-        jPanel2.add(jTextField4);
-        jTextField4.setBounds(440, 60, 60, 27);
+        uploadgb.setText(resourceMap.getString("uploadgb.text")); // NOI18N
+        uploadgb.setName("uploadgb"); // NOI18N
+        uploadgb.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyTyped(java.awt.event.KeyEvent evt) {
+                uploadgbKeyTyped(evt);
+            }
+        });
+        speedPanel.add(uploadgb);
+        uploadgb.setBounds(440, 20, 60, 27);
+
+        downloadgb.setText(resourceMap.getString("downloadgb.text")); // NOI18N
+        downloadgb.setName("downloadgb"); // NOI18N
+        downloadgb.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyTyped(java.awt.event.KeyEvent evt) {
+                downloadgbKeyTyped(evt);
+            }
+        });
+        speedPanel.add(downloadgb);
+        downloadgb.setBounds(440, 60, 60, 27);
 
         jLabel5.setText(resourceMap.getString("jLabel5.text")); // NOI18N
         jLabel5.setName("jLabel5"); // NOI18N
-        jPanel2.add(jLabel5);
+        speedPanel.add(jLabel5);
         jLabel5.setBounds(510, 20, 19, 30);
 
         jLabel6.setText(resourceMap.getString("jLabel6.text")); // NOI18N
         jLabel6.setName("jLabel6"); // NOI18N
-        jPanel2.add(jLabel6);
+        speedPanel.add(jLabel6);
         jLabel6.setBounds(510, 60, 19, 30);
 
         jLabel7.setText(resourceMap.getString("jLabel7.text")); // NOI18N
         jLabel7.setName("jLabel7"); // NOI18N
-        jPanel2.add(jLabel7);
+        speedPanel.add(jLabel7);
         jLabel7.setBounds(20, 100, 520, 70);
 
-        jTabbedPane1.addTab(resourceMap.getString("jPanel2.TabConstraints.tabTitle"), jPanel2); // NOI18N
+        settingsPanel.addTab(resourceMap.getString("speedPanel.TabConstraints.tabTitle"), speedPanel); // NOI18N
 
-        jPanel3.setName("jPanel3"); // NOI18N
+        updatesPanel.setName("updatesPanel"); // NOI18N
 
         jLabel8.setText(resourceMap.getString("jLabel8.text")); // NOI18N
         jLabel8.setName("jLabel8"); // NOI18N
 
+        buttonGroup1.add(jRadioButton1);
         jRadioButton1.setText(resourceMap.getString("jRadioButton1.text")); // NOI18N
         jRadioButton1.setName("jRadioButton1"); // NOI18N
 
+        buttonGroup1.add(jRadioButton2);
         jRadioButton2.setText(resourceMap.getString("jRadioButton2.text")); // NOI18N
         jRadioButton2.setName("jRadioButton2"); // NOI18N
 
+        buttonGroup1.add(jRadioButton3);
         jRadioButton3.setText(resourceMap.getString("jRadioButton3.text")); // NOI18N
         jRadioButton3.setName("jRadioButton3"); // NOI18N
 
@@ -190,35 +232,35 @@ public class GeneralConfiguration extends javax.swing.JFrame {
         jToggleButton3.setText(resourceMap.getString("jToggleButton3.text")); // NOI18N
         jToggleButton3.setName("jToggleButton3"); // NOI18N
 
-        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
-        jPanel3.setLayout(jPanel3Layout);
-        jPanel3Layout.setHorizontalGroup(
-            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(jPanel3Layout.createSequentialGroup()
-                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addGroup(jPanel3Layout.createSequentialGroup()
+        javax.swing.GroupLayout updatesPanelLayout = new javax.swing.GroupLayout(updatesPanel);
+        updatesPanel.setLayout(updatesPanelLayout);
+        updatesPanelLayout.setHorizontalGroup(
+            updatesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(updatesPanelLayout.createSequentialGroup()
+                .addGroup(updatesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(updatesPanelLayout.createSequentialGroup()
                         .addGap(20, 20, 20)
-                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                        .addGroup(updatesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                             .addComponent(jLabel8)
-                            .addGroup(jPanel3Layout.createSequentialGroup()
+                            .addGroup(updatesPanelLayout.createSequentialGroup()
                                 .addComponent(jToggleButton1)
                                 .addGap(18, 18, 18)
                                 .addComponent(jToggleButton2))))
-                    .addGroup(jPanel3Layout.createSequentialGroup()
+                    .addGroup(updatesPanelLayout.createSequentialGroup()
                         .addGap(40, 40, 40)
-                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                        .addGroup(updatesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                             .addComponent(jRadioButton2)
                             .addComponent(jRadioButton1)
                             .addComponent(jRadioButton3))))
                 .addGap(9, 9, 9))
-            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, updatesPanelLayout.createSequentialGroup()
                 .addContainerGap(339, Short.MAX_VALUE)
                 .addComponent(jToggleButton3)
                 .addContainerGap())
         );
-        jPanel3Layout.setVerticalGroup(
-            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(jPanel3Layout.createSequentialGroup()
+        updatesPanelLayout.setVerticalGroup(
+            updatesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(updatesPanelLayout.createSequentialGroup()
                 .addContainerGap()
                 .addComponent(jLabel8)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
@@ -228,7 +270,7 @@ public class GeneralConfiguration extends javax.swing.JFrame {
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jRadioButton3)
                 .addGap(18, 18, 18)
-                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                .addGroup(updatesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(jToggleButton1)
                     .addComponent(jToggleButton2))
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 181, Short.MAX_VALUE)
@@ -236,9 +278,9 @@ public class GeneralConfiguration extends javax.swing.JFrame {
                 .addContainerGap())
         );
 
-        jTabbedPane1.addTab(resourceMap.getString("jPanel3.TabConstraints.tabTitle"), jPanel3); // NOI18N
+        settingsPanel.addTab(resourceMap.getString("updatesPanel.TabConstraints.tabTitle"), updatesPanel); // NOI18N
 
-        jPanel4.setName("jPanel4"); // NOI18N
+        tunnelPanel.setName("tunnelPanel"); // NOI18N
 
         jScrollPane1.setName("jScrollPane1"); // NOI18N
 
@@ -253,13 +295,13 @@ public class GeneralConfiguration extends javax.swing.JFrame {
         jLabel11.setText(resourceMap.getString("jLabel11.text")); // NOI18N
         jLabel11.setName("jLabel11"); // NOI18N
 
-        javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
-        jPanel4.setLayout(jPanel4Layout);
-        jPanel4Layout.setHorizontalGroup(
-            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(jPanel4Layout.createSequentialGroup()
+        javax.swing.GroupLayout tunnelPanelLayout = new javax.swing.GroupLayout(tunnelPanel);
+        tunnelPanel.setLayout(tunnelPanelLayout);
+        tunnelPanelLayout.setHorizontalGroup(
+            tunnelPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(tunnelPanelLayout.createSequentialGroup()
                 .addContainerGap()
-                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                .addGroup(tunnelPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 538, Short.MAX_VALUE)
                     .addComponent(jLabel9, javax.swing.GroupLayout.DEFAULT_SIZE, 538, Short.MAX_VALUE)
                     .addComponent(jLabel10)
@@ -267,9 +309,9 @@ public class GeneralConfiguration extends javax.swing.JFrame {
                     .addComponent(jLabel11))
                 .addContainerGap())
         );
-        jPanel4Layout.setVerticalGroup(
-            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addGroup(jPanel4Layout.createSequentialGroup()
+        tunnelPanelLayout.setVerticalGroup(
+            tunnelPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(tunnelPanelLayout.createSequentialGroup()
                 .addContainerGap()
                 .addComponent(jLabel10)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@@ -283,67 +325,110 @@ public class GeneralConfiguration extends javax.swing.JFrame {
                 .addContainerGap())
         );
 
-        jTabbedPane1.addTab(resourceMap.getString("jPanel4.TabConstraints.tabTitle"), jPanel4); // NOI18N
+        settingsPanel.addTab(resourceMap.getString("tunnelPanel.TabConstraints.tabTitle"), tunnelPanel); // NOI18N
 
-        jPanel5.setName("jPanel5"); // NOI18N
+        networkPanel.setName("networkPanel"); // NOI18N
 
-        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
-        jPanel5.setLayout(jPanel5Layout);
-        jPanel5Layout.setHorizontalGroup(
-            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+        javax.swing.GroupLayout networkPanelLayout = new javax.swing.GroupLayout(networkPanel);
+        networkPanel.setLayout(networkPanelLayout);
+        networkPanelLayout.setHorizontalGroup(
+            networkPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGap(0, 562, Short.MAX_VALUE)
         );
-        jPanel5Layout.setVerticalGroup(
-            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+        networkPanelLayout.setVerticalGroup(
+            networkPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGap(0, 388, Short.MAX_VALUE)
         );
 
-        jTabbedPane1.addTab(resourceMap.getString("jPanel5.TabConstraints.tabTitle"), jPanel5); // NOI18N
+        settingsPanel.addTab(resourceMap.getString("networkPanel.TabConstraints.tabTitle"), networkPanel); // NOI18N
 
-        jPanel6.setName("jPanel6"); // NOI18N
+        advancedPanel.setName("advancedPanel"); // NOI18N
 
-        javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
-        jPanel6.setLayout(jPanel6Layout);
-        jPanel6Layout.setHorizontalGroup(
-            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+        javax.swing.GroupLayout advancedPanelLayout = new javax.swing.GroupLayout(advancedPanel);
+        advancedPanel.setLayout(advancedPanelLayout);
+        advancedPanelLayout.setHorizontalGroup(
+            advancedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGap(0, 562, Short.MAX_VALUE)
         );
-        jPanel6Layout.setVerticalGroup(
-            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+        advancedPanelLayout.setVerticalGroup(
+            advancedPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGap(0, 388, Short.MAX_VALUE)
         );
 
-        jTabbedPane1.addTab(resourceMap.getString("jPanel6.TabConstraints.tabTitle"), jPanel6); // NOI18N
+        settingsPanel.addTab(resourceMap.getString("advancedPanel.TabConstraints.tabTitle"), advancedPanel); // NOI18N
 
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
         getContentPane().setLayout(layout);
         layout.setHorizontalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(applyPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
             .addGroup(layout.createSequentialGroup()
                 .addGap(12, 12, 12)
-                .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 566, Short.MAX_VALUE))
+                .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 566, Short.MAX_VALUE))
         );
         layout.setVerticalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
-                .addComponent(jTabbedPane1)
+                .addComponent(settingsPanel)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addComponent(applyPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
         );
 
         pack();
     }// </editor-fold>//GEN-END:initComponents
 
+private void speedKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_speedKeyTyped
+    try {
+        String upload = "";
+        if(uploadkbps.getSelectedIndex() == KILOBIT)
+            upload = "" + Integer.parseInt(uploadspeed.getText())/8;
+        else
+            upload = uploadspeed.getText();
+        String download = "";
+        if(downloadkbps.getSelectedIndex() == KILOBIT)
+            download = "" + Integer.parseInt(downloadspeed.getText())/8;
+        else
+            download = downloadspeed.getText();
+        initUsage(upload, download);
+    }
+    catch(NumberFormatException e) {
+        e.printStackTrace();
+        return;
+    }
+}//GEN-LAST:event_speedKeyTyped
+
+private void uploadkbpsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_uploadkbpsActionPerformed
+    // TODO add your handling code here:
+}//GEN-LAST:event_uploadkbpsActionPerformed
+
+private void downloadkbpsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadkbpsActionPerformed
+    // TODO add your handling code here:
+}//GEN-LAST:event_downloadkbpsActionPerformed
+
+private void uploadgbKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_uploadgbKeyTyped
+    // TODO add your handling code here:
+}//GEN-LAST:event_uploadgbKeyTyped
+
+private void downloadgbKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_downloadgbKeyTyped
+    // TODO add your handling code here:
+}//GEN-LAST:event_downloadgbKeyTyped
+
+    protected void initUsage(String upload, String download) {
+        uploadgb.setText("" + SpeedHelper.calculateMonthlyUsage(Integer.parseInt(upload)));
+        downloadgb.setText("" + SpeedHelper.calculateMonthlyUsage(Integer.parseInt(download)));
+    }
 
     // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JPanel advancedPanel;
+    private javax.swing.JPanel applyPanel;
+    private javax.swing.ButtonGroup buttonGroup1;
     private javax.swing.JToggleButton cancel;
-    private javax.swing.JComboBox jComboBox1;
-    private javax.swing.JComboBox jComboBox2;
-    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel downloadSpeedLabel;
+    private javax.swing.JTextField downloadgb;
+    private javax.swing.JComboBox downloadkbps;
+    private javax.swing.JTextField downloadspeed;
     private javax.swing.JLabel jLabel10;
     private javax.swing.JLabel jLabel11;
-    private javax.swing.JLabel jLabel2;
     private javax.swing.JLabel jLabel3;
     private javax.swing.JLabel jLabel4;
     private javax.swing.JLabel jLabel5;
@@ -351,26 +436,26 @@ public class GeneralConfiguration extends javax.swing.JFrame {
     private javax.swing.JLabel jLabel7;
     private javax.swing.JLabel jLabel8;
     private javax.swing.JLabel jLabel9;
-    private javax.swing.JPanel jPanel1;
-    private javax.swing.JPanel jPanel2;
-    private javax.swing.JPanel jPanel3;
-    private javax.swing.JPanel jPanel4;
-    private javax.swing.JPanel jPanel5;
-    private javax.swing.JPanel jPanel6;
     private javax.swing.JRadioButton jRadioButton1;
     private javax.swing.JRadioButton jRadioButton2;
     private javax.swing.JRadioButton jRadioButton3;
     private javax.swing.JScrollPane jScrollPane1;
     private javax.swing.JScrollPane jScrollPane2;
-    private javax.swing.JTabbedPane jTabbedPane1;
-    private javax.swing.JTextField jTextField1;
-    private javax.swing.JTextField jTextField2;
-    private javax.swing.JTextField jTextField3;
-    private javax.swing.JTextField jTextField4;
     private javax.swing.JToggleButton jToggleButton1;
     private javax.swing.JToggleButton jToggleButton2;
     private javax.swing.JToggleButton jToggleButton3;
+    private javax.swing.JPanel networkPanel;
     private javax.swing.JToggleButton ok;
+    private javax.swing.JTabbedPane settingsPanel;
+    private javax.swing.JPanel speedPanel;
+    private javax.swing.JPanel tunnelPanel;
+    private javax.swing.JPanel updatesPanel;
+    private javax.swing.JLabel uploadSpeedLabel;
+    private javax.swing.JTextField uploadgb;
+    private javax.swing.JComboBox uploadkbps;
+    private javax.swing.JTextField uploadspeed;
     // End of variables declaration//GEN-END:variables
 
+    public static final int KILOBIT = 0;
+    public static final int KILOBYTE = 1;
 }
diff --git a/apps/desktopgui/src/gui/JPopupTrayIcon.java b/apps/desktopgui/src/gui/JPopupTrayIcon.java
index 83872e4a51958c1b9b5ca094800ec731392574a3..1b0ae1f8612220dc1c500138f9ad4056329df1ca 100644
--- a/apps/desktopgui/src/gui/JPopupTrayIcon.java
+++ b/apps/desktopgui/src/gui/JPopupTrayIcon.java
@@ -37,13 +37,12 @@ import java.awt.Window;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JWindow;
 import javax.swing.RootPaneContainer;
 import javax.swing.event.PopupMenuEvent;
 import javax.swing.event.PopupMenuListener;
+import java.util.Date;
 
 
 
@@ -63,6 +62,10 @@ public class JPopupTrayIcon extends TrayIcon {
     
     private final static boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows");
 
+    private static MouseEvent previous = null;
+    private static Date previousTime = new Date();
+    private static Date time = new Date();
+
     public JPopupTrayIcon(Image image) {
         super(image);
         init();
@@ -92,12 +95,12 @@ public class JPopupTrayIcon extends TrayIcon {
 
             @Override
             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
-//                System.out.println("popupMenuWillBecomeVisible");
+                //System.out.println("popupMenuWillBecomeVisible");
             }
 
             @Override
             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
-//                System.out.println("popupMenuWillBecomeInvisible");
+                //System.out.println("popupMenuWillBecomeInvisible");
                 if(window != null) {
                     window.dispose();
                     window = null;
@@ -117,21 +120,27 @@ public class JPopupTrayIcon extends TrayIcon {
         addMouseListener(new MouseAdapter() {
             @Override
             public void mousePressed(MouseEvent e) {
-//                System.out.println(e.getPoint());
-                showJPopupMenu(e);
+                //System.out.println("Pressed " + e.getPoint());
+                showJPopupMenu(e, previous);
+                previous = e;
+                previousTime = time;
+                time = new Date();
             }
 
             @Override
             public void mouseReleased(MouseEvent e) {
-//                System.out.println(e.getPoint());
-                showJPopupMenu(e);
+                //System.out.println("Released " + e.getPoint());
+                showJPopupMenu(e, previous);
+                previous = e;
+                previousTime = time;
+                time = new Date();
             }
         });
 
     }
 
-    private final void showJPopupMenu(MouseEvent e) {
-        if(e.isPopupTrigger() && menu != null) {
+    private final void showJPopupMenu(MouseEvent e, MouseEvent previous) {
+        if((e.isPopupTrigger() || previous.isPopupTrigger()) && (time.getTime() - previousTime.getTime() < 1000) && menu != null) {
             if (window == null) {
 
                 if(IS_WINDOWS) {
diff --git a/apps/desktopgui/src/gui/LogViewer.form b/apps/desktopgui/src/gui/LogViewer.form
index b53b410bac2305d27ef38ff74014877dace14fdc..ce012006819a87176e2d7037718fcd5f456cdf5a 100644
--- a/apps/desktopgui/src/gui/LogViewer.form
+++ b/apps/desktopgui/src/gui/LogViewer.form
@@ -3,6 +3,7 @@
 <Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
   <Properties>
     <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" resourceKey="Form.title"/>
     <Property name="name" type="java.lang.String" value="Form" noResource="true"/>
   </Properties>
   <SyntheticProperties>
diff --git a/apps/desktopgui/src/gui/LogViewer.java b/apps/desktopgui/src/gui/LogViewer.java
index 2dad70c1fc242ecabc02401c3ac10c83908dbddf..e08a38f7ed72235dc9e48c60625fa17ecef736c4 100644
--- a/apps/desktopgui/src/gui/LogViewer.java
+++ b/apps/desktopgui/src/gui/LogViewer.java
@@ -73,6 +73,8 @@ public class LogViewer extends javax.swing.JFrame {
         clearButton = new javax.swing.JButton();
 
         setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(LogViewer.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
         setName("Form"); // NOI18N
 
         textScroll.setName("textScroll"); // NOI18N
@@ -82,7 +84,6 @@ public class LogViewer extends javax.swing.JFrame {
         logText.setName("logText"); // NOI18N
         textScroll.setViewportView(logText);
 
-        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(LogViewer.class);
         explanationText.setText(resourceMap.getString("explanationText.text")); // NOI18N
         explanationText.setName("explanationText"); // NOI18N
 
diff --git a/apps/desktopgui/src/gui/SpeedSelector3.form b/apps/desktopgui/src/gui/SpeedSelector3.form
index b295c45938c70d6d1a1a54dba4a00d3e55e3f747..8e4aa5b4e8d19b460b4eb3a21575ac3a309fa496 100644
--- a/apps/desktopgui/src/gui/SpeedSelector3.form
+++ b/apps/desktopgui/src/gui/SpeedSelector3.form
@@ -16,6 +16,7 @@
   <AuxValues>
     <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
     <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
     <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
     <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
     <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
@@ -318,7 +319,7 @@
       </Properties>
       <Constraints>
         <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
-          <AbsoluteConstraints x="580" y="150" width="-1" height="30"/>
+          <AbsoluteConstraints x="580" y="150" width="40" height="30"/>
         </Constraint>
       </Constraints>
     </Component>
diff --git a/apps/desktopgui/src/gui/SpeedSelector3.java b/apps/desktopgui/src/gui/SpeedSelector3.java
index 8c6407f629d55dea655d5e63961420f40b39ab8c..bd26a9a759286f322b8055ae346923af6fdb87c5 100644
--- a/apps/desktopgui/src/gui/SpeedSelector3.java
+++ b/apps/desktopgui/src/gui/SpeedSelector3.java
@@ -231,7 +231,7 @@ public class SpeedSelector3 extends javax.swing.JFrame {
         downloadGB.setText(resourceMap.getString("downloadUsageLabel.text")); // NOI18N
         downloadGB.setName("downloadUsageLabel"); // NOI18N
         getContentPane().add(downloadGB);
-        downloadGB.setBounds(580, 150, 19, 30);
+        downloadGB.setBounds(580, 150, 40, 30);
 
         explanation.setText(resourceMap.getString("explanation.text")); // NOI18N
         explanation.setName("explanation"); // NOI18N
diff --git a/apps/desktopgui/src/gui/Version.form b/apps/desktopgui/src/gui/Version.form
index 20df8621a0c244ba59e834ca5543fcf3731bf219..27d9161dc2fabbb2ab5b8bf597b05bf2f3555a55 100644
--- a/apps/desktopgui/src/gui/Version.form
+++ b/apps/desktopgui/src/gui/Version.form
@@ -3,6 +3,7 @@
 <Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
   <Properties>
     <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" resourceKey="Form.title"/>
     <Property name="name" type="java.lang.String" value="Form" noResource="true"/>
   </Properties>
   <SyntheticProperties>
@@ -22,24 +23,24 @@
   <Layout>
     <DimensionLayout dim="0">
       <Group type="103" groupAlignment="0" attributes="0">
-          <Group type="102" alignment="0" attributes="0">
+          <Group type="102" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
-              <Group type="103" groupAlignment="1" max="-2" attributes="0">
-                  <Component id="I2Plabel" alignment="0" max="32767" attributes="0"/>
-                  <Component id="GUILabel" alignment="0" max="32767" attributes="1"/>
-              </Group>
-              <EmptySpace type="separate" max="-2" attributes="0"/>
               <Group type="103" groupAlignment="0" attributes="0">
-                  <Component id="I2PVersion" pref="126" max="32767" attributes="0"/>
-                  <Component id="GUIVersion" pref="126" max="32767" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                          <Component id="I2Plabel" alignment="0" max="32767" attributes="0"/>
+                          <Component id="GUILabel" alignment="0" max="32767" attributes="1"/>
+                      </Group>
+                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="I2PVersion" pref="126" max="32767" attributes="0"/>
+                          <Component id="GUIVersion" pref="126" max="32767" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <Component id="okButton" alignment="1" min="-2" max="-2" attributes="0"/>
               </Group>
               <EmptySpace max="-2" attributes="0"/>
           </Group>
-          <Group type="102" alignment="1" attributes="0">
-              <EmptySpace pref="294" max="32767" attributes="0"/>
-              <Component id="okButton" min="-2" max="-2" attributes="0"/>
-              <EmptySpace max="-2" attributes="0"/>
-          </Group>
       </Group>
     </DimensionLayout>
     <DimensionLayout dim="1">
diff --git a/apps/desktopgui/src/gui/Version.java b/apps/desktopgui/src/gui/Version.java
index 3e5a478c59a15f5c5ef6576e5f5261830f2a05f1..b7e275df1afeb77eeef0965463a2690409a8260a 100644
--- a/apps/desktopgui/src/gui/Version.java
+++ b/apps/desktopgui/src/gui/Version.java
@@ -46,9 +46,10 @@ public class Version extends javax.swing.JDialog {
         GUIVersion = new javax.swing.JLabel();
 
         setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(Version.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
         setName("Form"); // NOI18N
 
-        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(Version.class);
         okButton.setText(resourceMap.getString("okButton.text")); // NOI18N
         okButton.setName("okButton"); // NOI18N
         okButton.addActionListener(new java.awt.event.ActionListener() {
@@ -75,17 +76,16 @@ public class Version extends javax.swing.JDialog {
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
-                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
-                    .addComponent(I2Plabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                    .addComponent(GUILabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                .addGap(18, 18, 18)
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addComponent(I2PVersion, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)
-                    .addComponent(GUIVersion, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE))
-                .addContainerGap())
-            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
-                .addContainerGap(294, Short.MAX_VALUE)
-                .addComponent(okButton)
+                    .addGroup(layout.createSequentialGroup()
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                            .addComponent(I2Plabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(GUILabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                        .addGap(18, 18, 18)
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(I2PVersion, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)
+                            .addComponent(GUIVersion, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)))
+                    .addComponent(okButton, javax.swing.GroupLayout.Alignment.TRAILING))
                 .addContainerGap())
         );
         layout.setVerticalGroup(
diff --git a/apps/desktopgui/src/gui/resources/GeneralConfiguration.properties b/apps/desktopgui/src/gui/resources/GeneralConfiguration.properties
index 3dc629a9715ac76d59515d7e02df719a4cb41375..6387ce274fc2bf640435ac7046a480efc366e4e9 100644
--- a/apps/desktopgui/src/gui/resources/GeneralConfiguration.properties
+++ b/apps/desktopgui/src/gui/resources/GeneralConfiguration.properties
@@ -1,19 +1,7 @@
-
-jPanel2.TabConstraints.tabTitle=Speed
-jPanel3.TabConstraints.tabTitle=Updates
-jPanel4.TabConstraints.tabTitle=Tunnels/Services
-jPanel5.TabConstraints.tabTitle=Network
-jPanel6.TabConstraints.tabTitle=Advanced
 cancel.text=Cancel
 ok.text=OK
-jLabel1.text=Upload speed:
-jLabel2.text=Download speed:
-jTextField1.text=jTextField1
-jTextField2.text=jTextField2
 jLabel3.text=Monthly usage:
 jLabel4.text=Monthly usage:
-jTextField3.text=jTextField3
-jTextField4.text=jTextField4
 jLabel5.text=GB
 jLabel6.text=GB
 jLabel7.text=Explanation ...
@@ -27,3 +15,15 @@ jToggleButton3.text=Advanced update configuration
 jLabel9.text=Tunnel explanation
 jLabel10.text=Client tunnels:
 jLabel11.text=Server tunnels:
+Form.title=General Configuration
+speedPanel.TabConstraints.tabTitle=Speed
+updatesPanel.TabConstraints.tabTitle=Updates
+tunnelPanel.TabConstraints.tabTitle=Tunnels/Services
+networkPanel.TabConstraints.tabTitle=Network
+advancedPanel.TabConstraints.tabTitle=Advanced
+uploadSpeedLabel.text=Upload speed:
+downloadSpeedLabel.text=Download speed:
+uploadspeed.text=jTextField1
+downloadspeed.text=jTextField2
+uploadgb.text=jTextField3
+downloadgb.text=jTextField4
diff --git a/apps/desktopgui/src/gui/resources/LogViewer.properties b/apps/desktopgui/src/gui/resources/LogViewer.properties
index 8cb0e620913951f63269300844bf5f732f5f550f..d4ef5bf0e0c6c495848c2cd8f8988133c684121e 100644
--- a/apps/desktopgui/src/gui/resources/LogViewer.properties
+++ b/apps/desktopgui/src/gui/resources/LogViewer.properties
@@ -1,3 +1,4 @@
 refreshButton.text=Refresh
 clearButton.text=Clear
 explanationText.text=Explanation ...
+Form.title=View Logs
diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector3.properties b/apps/desktopgui/src/gui/resources/SpeedSelector3.properties
index 5b338348cf2e778a6a37fc3109aac5a169747a9e..6dca3ca51603dd9a6667aea2588bda0812aecd5f 100644
--- a/apps/desktopgui/src/gui/resources/SpeedSelector3.properties
+++ b/apps/desktopgui/src/gui/resources/SpeedSelector3.properties
@@ -5,8 +5,8 @@ uploadLabel.text=Upload Speed:
 uploadBurstLabel.text=Burst Upload Speed:
 downloadLabel.text=Download Speed:
 downloadBurstLabel.text=Burst Download Speed:
-uploadUsageLabel.text=Monthly usage:
-downloadUsageLabel.text=Monthly usage:
+uploadUsageLabel.text=GB
+downloadUsageLabel.text=GB
 uploadField.text=jTextField1
 uploadBurstField.text=jTextField2
 downloadField.text=jTextField4
diff --git a/apps/desktopgui/src/gui/resources/Version.properties b/apps/desktopgui/src/gui/resources/Version.properties
index 91ee786ad12716094d21e405f0619bf11676ea82..c2030bb2d838b6859ded31c3fee5ef30beeba8f0 100644
--- a/apps/desktopgui/src/gui/resources/Version.properties
+++ b/apps/desktopgui/src/gui/resources/Version.properties
@@ -3,3 +3,4 @@ I2Plabel.text=<html><h1>I2P Version:</h1></html>
 GUILabel.text=<html><h1>GUI Version:</h1></html>
 I2PVersion.text=jLabel3
 GUIVersion.text=jLabel4
+Form.title=Version
diff --git a/apps/desktopgui/src/router/configuration/SpeedHelper.java b/apps/desktopgui/src/router/configuration/SpeedHelper.java
index acad2adb146d65403c3c497b9b7364c139f3dc09..bba361cf632e51e96b733ade308d5b1239aaafe2 100644
--- a/apps/desktopgui/src/router/configuration/SpeedHelper.java
+++ b/apps/desktopgui/src/router/configuration/SpeedHelper.java
@@ -1,5 +1,8 @@
 package router.configuration;
 
+import net.i2p.router.transport.FIFOBandwidthRefiller;
+import router.RouterHelper;
+
 /**
  *
  * @author mathias
@@ -29,4 +32,8 @@ public class SpeedHelper {
     public static int calculateSpeed(int gigabytes) {
         return (int) (((long)gigabytes)*1000000/31/24/3600);
     }
+    
+    public static String getInboundBandwidth() {
+        return RouterHelper.getContext().router().getConfigSetting(FIFOBandwidthRefiller.PROP_INBOUND_BANDWIDTH);
+    }
 }
diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index 915da5db965b43943a75d9538f4efa58e379110d..4f0a5a3385fb62bf25920a41920113fcbba883a5 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -284,6 +284,7 @@
                 <input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />                
             </div>
                  
+         <% if (!"streamrclient".equals(tunnelType)) { // streamr client sends pings so it will never be idle %>
             <div class="subdivider">
                 <hr />
             </div>
@@ -362,6 +363,7 @@
                 </label>
                 <input value="1" type="checkbox" id="startOnLoad" name="delayOpen" title="Delay Tunnel Open"<%=(editBean.getDelayOpen(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />                
             </div>
+         <% } // !streamrclient %>
                  
             <div class="subdivider">
                 <hr />
diff --git a/apps/routerconsole/jsp/summaryframe.jsp b/apps/routerconsole/jsp/summaryframe.jsp
index 627fe328c8ad5888d96c3bf464b029f1ca443680..54126ef722d1715e8ffd4d639de4953c94ca9751 100644
--- a/apps/routerconsole/jsp/summaryframe.jsp
+++ b/apps/routerconsole/jsp/summaryframe.jsp
@@ -16,7 +16,9 @@
     // try hard to avoid an error page in the iframe after shutdown
     String action = request.getParameter("action");
     String d = request.getParameter("refresh");
-    boolean shutdownSoon = "shutdownImmediate".equals(action) || "restartImmediate".equals(action);
+    // Normal browsers send value, IE sends button label
+    boolean shutdownSoon = "shutdownImmediate".equals(action) || "restartImmediate".equals(action) ||
+                           "Shutdown immediately".equals(action) || "Restart immediately".equals(action);
     if (!shutdownSoon) {
         if (d == null || "".equals(d)) {
             d = System.getProperty("routerconsole.summaryRefresh");
@@ -30,6 +32,14 @@
         if (!"0".equals(d)) {
             // doesn't work for restart or shutdown with no expl. tunnels,
             // since the call to ConfigRestartBean.renderStatus() hasn't happened yet...
+            // So we delay slightly
+            if ("restart".equalsIgnoreCase(action) || "shutdown".equalsIgnoreCase(action)) {
+                synchronized(this) {
+                    try {
+                        wait(1000);
+                    } catch(InterruptedException ie) {}
+                }
+            }
             long timeleft = net.i2p.router.web.ConfigRestartBean.getRestartTimeRemaining();
             long delay = 60;
             try { delay = Long.parseLong(d); } catch (NumberFormatException nfe) {}
diff --git a/build.xml b/build.xml
index 6ed84ca7342ec9807598e7c8c1773c6f3e102044..fc251a40a99bb0d477ab5bd4f74ca99487b23cd9 100644
--- a/build.xml
+++ b/build.xml
@@ -25,6 +25,10 @@
         <echo message="  javadoc:   generate javadoc for the entire project into ./build/javadoc" />
         <echo message="  slackpkg:  generate Slackware packages in ./Slackware/i2p and ./Slackware/i2p-base" />
         <echo message="  debianhowto: instructions on building Debian packages" />
+        <echo message="  updaterWithDesktopgui: tar the built files and desktopgui in an i2pupdate.zip" />
+        <echo message="  pkgWithDesktopgui: distclean then package everything up with the desktopgui" />
+        <echo message="  distWithDesktopgui: pkgWithDesktopgui and javadoc" />
+        <echo message="  distcleanWithDesktopgui: clean up all derived files (including desktopgui files)" />
     </target>
     <target name="debianhowto">
         <echo message="To build debian packages, you must run dpkg-buildpackage as root in the source directory. It will then run ant for you. dpkg-buildpackage is found in the 'dpkg-dev' package. Also it should work fine to use the 'fakeroot' package with dpkg-buildpackage, if you don't want to run as root. Please read 'man dpkg-buildpackage' before building any packages yourself." />
diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java
index eda48e75444cb6b1c190825a877642d6f0f58cf0..aeef4e38eaa420789ecd9de2b855ebc458cfd71e 100644
--- a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java
+++ b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java
@@ -202,20 +202,23 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
         private LinkedBlockingQueue<MsgData> _msgs;
         private AtomicBoolean _alive = new AtomicBoolean(false);
         private static final int POISON_SIZE = -99999;
- 
+        private AtomicBoolean stopping = new AtomicBoolean(false);
+
         public MuxedAvailabilityNotifier() {
             _msgs = new LinkedBlockingQueue();
         }
 
         @Override
         public void stopNotifying() {
+            if(stopping.get()) return;
+            stopping.set(true);
             boolean again = true;
-            _msgs.clear();
+            // _msgs.clear();
             // Thread.yield();
             if (_alive.get()) {
                 // System.out.println("I2PSessionMuxedImpl.stopNotifying()");
+                _msgs.clear();
                 while(again) {
-                    _msgs.clear();
                     try {
                         _msgs.put(new MsgData(0, POISON_SIZE, 0, 0, 0));
                         again = false;
@@ -226,6 +229,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
                 }
             }
             _alive.set(false);
+            stopping.set(false); // Do we need this?
         }
         
         /** unused */
diff --git a/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java b/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java
index 5c79d94f3c70ca356c0e2a8918451299953fe761..461c4b08a4f9dbf25de23be53c896e406e818540 100644
--- a/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java
+++ b/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java
@@ -115,8 +115,8 @@ public class I2CPMessageReader {
     }
 
     private class I2CPMessageReaderRunner implements Runnable {
-        private boolean _doRun;
-        private boolean _stayAlive;
+        private volatile boolean _doRun;
+        private volatile boolean _stayAlive;
 
         public I2CPMessageReaderRunner() {
             _doRun = true;
diff --git a/history.txt b/history.txt
index 102aef63247614e2a224b210488ac16498dd32b6..c27842cae7cf9c856e7dbd851952b9b4b47332a8 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,25 @@
+2009-05-07 zzz
+    * Add nibble.i2p to proxy list and hosts.txt
+
+2009-05-07 zzz
+    * Addressbook: Name the thread
+    * Console:
+      - More IE button fixes, try harder to not refresh the iframe after shutdown
+      - Disable idle options for streamr client, it will never be
+        idle because it pings the server
+    * Floodfill Monitor: Slow down the volunteers
+    * Throttle: Throttle at 90% so we throttle before we WRED
+
+2009-05-06 Mathiasdm
+    * Improvements to popup menu rightclick action
+    * Added general configuration options (still not available by default)
+    * General fixes
+    * Added ant build options (irc says eche|on would like that ;))
+
+2009-05-06 sponge
+    * Hopefully the last fixes for BOB.
+    * Fixes to prevent race in client-side I2CP and Notifier.
+
 2009-05-03 sponge
     * More hopeful fixes for BOB.
     * Added new Robert ID to snark
@@ -46,6 +68,7 @@
     * RouterConsole: iframe tweaks
     * StatisticsManager: Cleanup
     * Streaming: Don't let jrandom yell so loud
+    * Tunnel Pool: Don't self-destruct if more than 6 IB tunnels configured
 
 2009-04-25 sponge
     * I2PSessionMuxedImpl atomic fixes
diff --git a/hosts.txt b/hosts.txt
index b015d95c6793539d5f5da0d46de74070a351f7c0..44cdacd754d4b9955406c02e4760761ed9d57e5c 100644
--- a/hosts.txt
+++ b/hosts.txt
@@ -314,3 +314,4 @@ codevoid.i2p=tV-4GJjgYIoCDTTJ91nfDbhSnT8B2o3v-TUfHtiAAjJJdroCAEDbmJWFPUQJEEispvr
 echelon.i2p=w6zK9m4fqSfvJck9EGIR1wRIbWsEQ2DkjZ-VI57ESFqLqbTIA1cD5nOfSSbpELqPyhjifdrNiBNAsSdyil3C0a2B7CGtwUcTS2dCG0tKf2nAbvpsbcCK17nI4Xbu5KqZU0y3hJ~l7rcJqQBR0nfV5cU30ZDrpQV6VL875cihGlnmwLFq6qSzNcEb88Nw6wFG~FIgB2PJ6A3jJyuTnLrdiMvwqgD6nSyeOylOgBCsNxXh8-drrhASjladfNrwjlGRCZTiQ~H92HIyOwiabDiG3TUugMaFWs87yuXnZ~ni9jgjoAMFo8xV8Od2BiRgCxkZoMU07FhgUjew9qtXNa04wkexf3gx77nVPhqE0GHqCuwHwmBVf92RdYEys76u~akaOMq5UhayDpCBCaHiYLkKDNqmh47tfMCwxf6z8VIcR4zv25QfJDIWPs~RA~9U7m4raytiAs5PvYZBn4B3SqOL8XdkL9sDT54sQXbsYCJr3olu6ieMtNWlmos0uohYXNUyAAAA
 crstrack.i2p=b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA
 tracker2.postman.i2p=lnQ6yoBTxQuQU8EQ1FlF395ITIQF-HGJxUeFvzETLFnoczNjQvKDbtSB7aHhn853zjVXrJBgwlB9sO57KakBDaJ50lUZgVPhjlI19TgJ-CxyHhHSCeKx5JzURdEW-ucdONMynr-b2zwhsx8VQCJwCEkARvt21YkOyQDaB9IdV8aTAmP~PUJQxRwceaTMn96FcVenwdXqleE16fI8CVFOV18jbJKrhTOYpTtcZKV4l1wNYBDwKgwPx5c0kcrRzFyw5~bjuAKO~GJ5dR7BQsL7AwBoQUS4k1lwoYrG1kOIBeDD3XF8BWb6K3GOOoyjc1umYKpur3G~FxBuqtHAsDRICkEbKUqJ9mPYQlTSujhNxiRIW-oLwMtvayCFci99oX8MvazPS7~97x0Gsm-onEK1Td9nBdmq30OqDxpRtXBimbzkLbR1IKObbg9HvrKs3L-kSyGwTUmHG9rSQSoZEvFMA-S0EXO~o4g21q1oikmxPMhkeVwQ22VHB0-LZJfmLr4SAAAA
+nibble.i2p=V2XQ31BQWcwLcBNz2ywb4xy0Q1GMjdziQyjKql-lGdYPOX7w9g3j8IkA1jfW6YYwNi5QZc0JurjrSNH1yx6Y1goI8SB1l-yWdzst73fGWo6B1UtL45XrfXPg5k34RpktCNa4KoeIsUnGnxHQESSj5hw389hvexKXlkAHXQg9eUfbBYyzZc~~Kt4YdYX4cfMpXXjg443kyEiwKisOaRuiEN-YjqZ8pJTyAQsOKNg8hL3e15XFNPfAAkCSsALPAqj0~HZDwCZDeV0Cp4iaCGjw8tsNQ7xBeSjnhOeMoZKtrPAbbK4vNh7OIcakcVu16ykfEf-FcqbPQQe9rjilMy8V-BcjhggjUcZmtWj9qE7RMfUFpbAIfNHgWXTl5yR5V~brqxxuBxHQWn4oyB5NpY02dBkvvxXwdk~XFzXlSz~uEZKVswvI8rUHR4a2N3YDss5iQ~uscvKwNvsTZiDUaN66~CacZLYU9BtDBNnAxClz9LSu5b9CiunKeacbH6l5qrPpAAAA
diff --git a/installer/resources/i2ptunnel.config b/installer/resources/i2ptunnel.config
index 48d18b95ec10335d88de0240203fadfd12de4241..c0dd002dbddf6460999aad737b6eb97fdfb7e007 100644
--- a/installer/resources/i2ptunnel.config
+++ b/installer/resources/i2ptunnel.config
@@ -5,7 +5,7 @@ tunnel.0.type=httpclient
 tunnel.0.sharedClient=true
 tunnel.0.interface=127.0.0.1
 tunnel.0.listenPort=4444
-tunnel.0.proxyList=false.i2p
+tunnel.0.proxyList=false.i2p,nibble.i2p
 tunnel.0.i2cpHost=127.0.0.1
 tunnel.0.i2cpPort=7654
 tunnel.0.option.inbound.nickname=shared clients
diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java
index fc38b16958aaba4ae35e04c3bbb55175b18ac0db..acab90a6490ee18b8ed494d522d09e0b3ff8cb27 100644
--- a/router/java/src/net/i2p/router/RouterThrottleImpl.java
+++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java
@@ -262,6 +262,7 @@ class RouterThrottleImpl implements RouterThrottle {
     }
 
     private static final int DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE = 40; // .067KBps
+    /** also limited to 90% - see below */
     private static final int MIN_AVAILABLE_BPS = 4*1024; // always leave at least 4KBps free when allowing
     private static final String LIMIT_STR = "Rejecting tunnels: Bandwidth limit";
     
@@ -282,8 +283,11 @@ class RouterThrottleImpl implements RouterThrottle {
         int used1mOut = _context.router().get1mRate(true);
 
         // Check the inbound and outbound total bw available (separately)
-        int availBps = (maxKBpsIn*1024) - usedIn;
-        availBps = Math.min(availBps, (maxKBpsOut*1024) - usedOut);
+        // We block all tunnels when share bw is over (max * 0.9) - 4KB
+        // This gives reasonable growth room for existing tunnels on both low and high
+        // bandwidth routers. We want to be rejecting tunnels more aggressively than
+        // dropping packets with WRED
+        int availBps = Math.min((maxKBpsIn*1024*9/10) - usedIn, (maxKBpsOut*1024*9/10) - usedOut);
         if (availBps < MIN_AVAILABLE_BPS) {
             if (_log.shouldLog(Log.WARN)) _log.warn("Reject, avail (" + availBps + ") less than min");
             setTunnelStatus(LIMIT_STR);
@@ -303,8 +307,7 @@ class RouterThrottleImpl implements RouterThrottle {
         _context.statManager().addRateData("router.throttleTunnelBytesAllowed", availBps, (long)bytesAllocated);
 
         // Now see if 1m rates are too high
-        long overage = used1mIn - (maxKBpsIn*1024);
-        overage = Math.max(overage, used1mOut - (maxKBpsOut*1024));
+        long overage = Math.max(used1mIn - (maxKBpsIn*1024), used1mOut - (maxKBpsOut*1024));
         if ( (overage > 0) && 
              ((overage/(float)(maxKBps*1024f)) > _context.random().nextFloat()) ) {
             if (_log.shouldLog(Log.WARN)) _log.warn("Reject tunnel, 1m rate (" + overage + " over) indicates overload.");
@@ -312,7 +315,8 @@ class RouterThrottleImpl implements RouterThrottle {
             return false;
         }
 
-            float maxBps = maxKBps * 1024f;
+            // limit at 90% - 4KBps (see above)
+            float maxBps = (maxKBps * 1024f * 0.9f) - MIN_AVAILABLE_BPS;
             float pctFull = (maxBps - availBps) / (maxBps);
             double probReject = Math.pow(pctFull, 16); // steep curve 
             double rand = _context.random().nextFloat();
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 4ab27b06c8d04d29f293b3abde69e23a53fd5a74..28c3a9575a814009758d422c053f34b4058788ed 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
     /** deprecated */
     public final static String ID = "Monotone";
     public final static String VERSION = CoreVersion.VERSION;
-    public final static long BUILD = 7;
+    public final static long BUILD = 9;
     /** for example "-test" */
     public final static String EXTRA = "";
     public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java
index 26eaa2fada01b1dd971ccc84bb7bb54fa4fe9920..a1a74fc868fb337edd6fad9bba9f059c6d34a7e3 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java
@@ -46,7 +46,12 @@ class FloodfillMonitorJob extends JobImpl {
             getContext().router().rebuildRouterInfo();
         if (_log.shouldLog(Log.INFO))
             _log.info("Should we be floodfill? " + ff);
-        requeue((REQUEUE_DELAY / 2) + getContext().random().nextInt(REQUEUE_DELAY));
+        int delay = (REQUEUE_DELAY / 2) + getContext().random().nextInt(REQUEUE_DELAY);
+        // there's a lot of eligible non-floodfills, keep them from all jumping in at once
+        // To do: somehow assess the size of the network to make this adaptive?
+        if (!ff)
+            delay *= 3;
+        requeue(delay);
     }
 
     private boolean shouldBeFloodfill() {