diff --git a/README.md b/README.md
index 4830d9303248a1c953833ea4a2808aeacaafe434..a824e90017525e0c65c42c99522337b25d415774 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Go Ethereum comes with several binaries found in
 * `mist` Official Ethereum Browser
 * `ethereum` Ethereum CLI
 * `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit: 
-  `ethtest "`cat myfile.json`"`.
+  `cat file | ethtest`.
 * `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
   10000 -price 0 -dump`. See `-h` for a detailed description.
 
diff --git a/cmd/mist/assets/qml/browser.qml b/cmd/mist/assets/qml/browser.qml
index c8f291e221fe3f16c769f445521f63bb5a96ec19..7056dbbf375787a1b2734b6a0cf59f8006bfbb4a 100644
--- a/cmd/mist/assets/qml/browser.qml
+++ b/cmd/mist/assets/qml/browser.qml
@@ -9,15 +9,16 @@ import Ethereum 1.0
 
 Rectangle {
 	id: window
-	objectName: "browserView"
 	anchors.fill: parent
 	color: "#00000000"
 
-	property var title: "Browser"
+	property var title: "DApps"
 	property var iconSource: "../browser.png"
 	property var menuItem
+    property var hideUrl: true
 
 	property alias url: webview.url
+    property alias windowTitle: webview.title
 	property alias webView: webview
 
 	property var cleanPath: false
@@ -66,8 +67,7 @@ Rectangle {
 		webview.url = "http://etherian.io"
 	}
 
-	signal messages(var messages, int id);
-	onMessages: {
+    function messages(messages, id) {
 		// Bit of a cheat to get proper JSON
 		var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
 		webview.postEvent("eth_changed", id, m);
@@ -164,22 +164,10 @@ Rectangle {
 				id: webview
 				anchors.fill: parent
 
-				function injectJs(js) {
-					webview.experimental.navigatorQtObjectEnabled = true;
-					webview.experimental.evaluateJavaScript(js)
-					webview.experimental.javascriptEnabled = true;
-				}
-
 				function sendMessage(data) {
 					webview.experimental.postMessage(JSON.stringify(data))
 				}
 
-				Component.onCompleted: {
-					for (var i in experimental.preferences) {
-						console.log(i)
-					}
-				}
-
 				experimental.preferences.javascriptEnabled: true
 				experimental.preferences.webAudioEnabled: true
 				experimental.preferences.pluginsEnabled: true
@@ -219,8 +207,7 @@ Rectangle {
 				}
 				experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
 				experimental.onMessageReceived: {
-					console.log("[onMessageReceived]: ", message.data)
-					// TODO move to messaging.js
+					//console.log("[onMessageReceived]: ", message.data)
 					var data = JSON.parse(message.data)
 
 					try {
@@ -350,13 +337,13 @@ Rectangle {
 
 							case "eth_newFilterString":
 							require(1)
-							var id = eth.newFilterString(data.args[0])
+							var id = eth.newFilterString(data.args[0], window)
 							postData(data._id, id);
 							break;
 
 							case "eth_newFilter":
 							require(1)
-							var id = eth.newFilter(data.args[0])
+							var id = eth.newFilter(data.args[0], window)
 
 							postData(data._id, id);
 							break;
@@ -425,11 +412,9 @@ Rectangle {
 					}
 				}
 
-
 				function post(seed, data) {
 					postData(data._id, data)
 				}
-
 				function require(args, num) {
 					if(args.length < num) {
 						throw("required argument count of "+num+" got "+args.length);
@@ -441,12 +426,10 @@ Rectangle {
 				function postEvent(event, id, data) {
 					webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
 				}
-
 				function onWatchedCb(data, id) {
 					var messages = JSON.parse(data)
 					postEvent("watched:"+id, messages)
 				}
-
 				function onNewBlockCb(block) {
 					postEvent("block:new", block)
 				}
@@ -460,7 +443,6 @@ Rectangle {
 			}
 		}
 
-
 		Rectangle {
 			id: sizeGrip
 			color: "gray"
diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml
index 7b207cbcc6ca1f6dfa84f55435ec4e8509fc1a36..c6b52454903113dd444cd5f94b4123891fe5f77e 100644
--- a/cmd/mist/assets/qml/main.qml
+++ b/cmd/mist/assets/qml/main.qml
@@ -13,7 +13,6 @@ ApplicationWindow {
 	id: root
 
 	property var ethx : Eth.ethx
-	property var browser
 
 	width: 1200
 	height: 820
@@ -21,6 +20,7 @@ ApplicationWindow {
 
 	title: "Mist"
 
+    /*
 	// This signal is used by the filter API. The filter API connects using this signal handler from
 	// the different QML files and plugins.
 	signal messages(var messages, int id);
@@ -30,6 +30,7 @@ ApplicationWindow {
 		messages(data, receiverSeed);
 		root.browser.view.messages(data, receiverSeed);
 	}
+    */
 
 	TextField {
 		id: copyElementHax
@@ -45,8 +46,6 @@ ApplicationWindow {
 	// Takes care of loading all default plugins
 	Component.onCompleted: {
 		var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
-		var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true});
-		root.browser = browser;
 		addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 
 		addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
@@ -55,17 +54,17 @@ ApplicationWindow {
 		addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
 		addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
 
-		addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"})
-
 		mainSplit.setView(wallet.view, wallet.menuItem);
 
+        newBrowserTab("http://etherian.io");
+
 		// Command setup
 		gui.sendCommand(0)
 	}
 
 	function activeView(view, menuItem) {
 		mainSplit.setView(view, menuItem)
-		if (view.objectName === "browserView") {
+        if (view.hideUrl) {
 			urlPane.visible = false;
 			mainView.anchors.top = rootView.top
 		} else {
@@ -119,6 +118,13 @@ ApplicationWindow {
 		}
 	}
 
+    function newBrowserTab(url) {
+		var window = addPlugin("./browser.qml", {noAdd: true, close: true, section: "apps", active: true});
+        window.view.url = url;
+        window.menuItem.title = "Browser Tab";
+        activeView(window.view, window.menuItem);
+    }
+
 	menuBar: MenuBar {
 		Menu {
 			title: "File"
@@ -130,13 +136,6 @@ ApplicationWindow {
 				}
 			}
 
-			/*
-			 MenuItem {
-				 text: "Browser"
-				 onTriggered: eth.openBrowser()
-			 }
-			 */
-
 			MenuItem {
 				text: "Add plugin"
 				onTriggered: {
@@ -146,6 +145,14 @@ ApplicationWindow {
 				}
 			}
 
+            MenuItem {
+                text: "New tab"
+                shortcut: "Ctrl+t"
+                onTriggered: {
+                    newBrowserTab("http://etherian.io");
+                }
+            }
+
 			MenuSeparator {}
 
 			MenuItem {
@@ -205,21 +212,6 @@ ApplicationWindow {
 			}
 
 			MenuSeparator {}
-
-			/*
-			 MenuItem {
-				 id: miningSpeed
-				 text: "Mining: Turbo"
-				 onTriggered: {
-					 gui.toggleTurboMining()
-					 if(text == "Mining: Turbo") {
-						 text = "Mining: Normal";
-					 } else {
-						 text = "Mining: Turbo";
-					 }
-				 }
-			 }
-			 */
 		}
 
 		Menu {
@@ -350,9 +342,6 @@ ApplicationWindow {
 				views[i].menuItem.setSelection(false)
 			}
 			view.visible = true
-
-			//menu.border.color = "#CCCCCC"
-			//menu.color = "#FFFFFFFF"
 			menu.setSelection(true)
 		}
 
@@ -512,7 +501,15 @@ ApplicationWindow {
 
 						 this.view.destroy()
 						 this.destroy()
+                         for (var i = 0; i < mainSplit.views.length; i++) {
+                             var view = mainSplit.views[i];
+                             if (view.menuItem === this) {
+                                 mainSplit.views.splice(i, 1);
+                                 break;
+                             }
+                         }
 						 gui.removePlugin(this.path)
+                         activeView(mainSplit.views[0].view, mainSplit.views[0].menuItem);
 					 }
 				 }
 			 }
@@ -576,7 +573,7 @@ ApplicationWindow {
 
 
 				 Text {
-					 text: "APPS"
+					 text: "NET"
 					 font.bold: true
 					 anchors {
 						 left: parent.left
@@ -653,7 +650,7 @@ ApplicationWindow {
 
 					  Keys.onReturnPressed: {
 						  if(/^https?/.test(this.text)) {
-							  activeView(root.browser.view, root.browser.menuItem);
+                              newBrowserTab(this.text);
 						  } else {
 							  addPlugin(this.text, {close: true, section: "apps"})
 						  }
diff --git a/cmd/mist/assets/qml/views/whisper.qml b/cmd/mist/assets/qml/views/whisper.qml
index 029376c4518969a9bf3f18fb9238321a3013a21e..dc097b8061dc26dfc3bea508510b0419d997a252 100644
--- a/cmd/mist/assets/qml/views/whisper.qml
+++ b/cmd/mist/assets/qml/views/whisper.qml
@@ -18,7 +18,6 @@ Rectangle {
 	property var identity: ""
 	Component.onCompleted: {
 		identity = shh.newIdentity()
-		console.log("New identity:", identity)
 
 		var t = shh.watch({}, root)
 	}
diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go
index 596f8442a52c97067cc93de8cb8fdecf46ab4c95..e0321f6dd07907eaae02d4aa1d5dda366dadaf4e 100644
--- a/cmd/mist/ui_lib.go
+++ b/cmd/mist/ui_lib.go
@@ -316,20 +316,15 @@ func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (i
 	filter := qt.NewFilterFromMap(object, self.eth)
 	filter.MessageCallback = func(messages state.Messages) {
 		view.Call("messages", xeth.ToJSMessages(messages), id)
-		//self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id)
 	}
 	id = self.filterManager.InstallFilter(filter)
 	return id
 }
 
-func (self *UiLib) NewFilterString(typ string) (id int) {
+func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
 	filter := core.NewFilter(self.eth)
 	filter.BlockCallback = func(block *types.Block) {
-		if self.win != nil && self.win.Root() != nil {
-			self.win.Root().Call("invokeFilterCallback", "{}", id)
-		} else {
-			fmt.Println("QML is lagging")
-		}
+		view.Call("messages", "{}", id)
 	}
 	id = self.filterManager.InstallFilter(filter)
 	return id
diff --git a/crypto/crypto.go b/crypto/crypto.go
index ac84c6204a7d2729b2643715493d2f0d9e72d294..4b2cc7bb4a693a9be763f475130d173e6a1c3511 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -1,11 +1,20 @@
 package crypto
 
 import (
+	"crypto/aes"
+	"crypto/cipher"
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/sha256"
+	"fmt"
 
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+
+	"code.google.com/p/go-uuid/uuid"
+	"code.google.com/p/go.crypto/pbkdf2"
 	"code.google.com/p/go.crypto/ripemd160"
 	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 	"github.com/ethereum/go-ethereum/crypto/sha3"
@@ -101,7 +110,11 @@ func SigToPub(hash, sig []byte) *ecdsa.PublicKey {
 }
 
 func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
-	sig, err = secp256k1.Sign(hash, prv.D.Bytes())
+	if len(hash) != 32 {
+		return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
+	}
+
+	sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8))
 	return
 }
 
@@ -113,3 +126,100 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
 	key := ecies.ImportECDSA(prv)
 	return key.Decrypt(rand.Reader, ct, nil, nil)
 }
+
+// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
+func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key, error) {
+	key, err := decryptPreSaleKey(keyJSON, password)
+	if err != nil {
+		return nil, err
+	}
+	id := uuid.NewRandom()
+	key.Id = &id
+	err = keyStore.StoreKey(key, password)
+	return key, err
+}
+
+func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
+	preSaleKeyStruct := struct {
+		EncSeed string
+		EthAddr string
+		Email   string
+		BtcAddr string
+	}{}
+	err = json.Unmarshal(fileContent, &preSaleKeyStruct)
+	if err != nil {
+		return nil, err
+	}
+	encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
+	iv := encSeedBytes[:16]
+	cipherText := encSeedBytes[16:]
+	/*
+		See https://github.com/ethereum/pyethsaletool
+
+		pyethsaletool generates the encryption key from password by
+		2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
+		16 byte key length within PBKDF2 and resulting key is used as AES key
+	*/
+	passBytes := []byte(password)
+	derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
+	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
+	ethPriv := Sha3(plainText)
+	ecKey := ToECDSA(ethPriv)
+	key = &Key{
+		Id:         nil,
+		PrivateKey: ecKey,
+	}
+	derivedAddr := ethutil.Bytes2Hex(key.Address())
+	expectedAddr := preSaleKeyStruct.EthAddr
+	if derivedAddr != expectedAddr {
+		err = errors.New("decrypted addr not equal to expected addr")
+	}
+	return key, err
+}
+
+func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) {
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return plainText, err
+	}
+	decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
+	paddedPlainText := make([]byte, len(cipherText))
+	decrypter.CryptBlocks(paddedPlainText, cipherText)
+	plainText = PKCS7Unpad(paddedPlainText)
+	if plainText == nil {
+		err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
+	}
+	return plainText, err
+}
+
+// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
+func PKCS7Pad(in []byte) []byte {
+	padding := 16 - (len(in) % 16)
+	if padding == 0 {
+		padding = 16
+	}
+	for i := 0; i < padding; i++ {
+		in = append(in, byte(padding))
+	}
+	return in
+}
+
+func PKCS7Unpad(in []byte) []byte {
+	if len(in) == 0 {
+		return nil
+	}
+
+	padding := in[len(in)-1]
+	if int(padding) > len(in) || padding > aes.BlockSize {
+		return nil
+	} else if padding == 0 {
+		return nil
+	}
+
+	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
+		if in[i] != padding {
+			return nil
+		}
+	}
+	return in[:len(in)-int(padding)]
+}
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index 349bc31ae48862c46b725578a66345477aeb5343..441733f93c79c6d35655477ace54a342cb796839 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -52,7 +52,7 @@ func BenchmarkSha3(b *testing.B) {
 }
 
 func Test0Key(t *testing.T) {
-
+	t.Skip()
 	key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111")
 
 	p, err := secp256k1.GeneratePubKey(key)
@@ -60,3 +60,15 @@ func Test0Key(t *testing.T) {
 	fmt.Printf("%x\n", p)
 	fmt.Printf("%v %x\n", err, addr)
 }
+
+func TestInvalidSign(t *testing.T) {
+	_, err := Sign(make([]byte, 1), nil)
+	if err == nil {
+		t.Errorf("expected sign with hash 1 byte to error")
+	}
+
+	_, err = Sign(make([]byte, 33), nil)
+	if err == nil {
+		t.Errorf("expected sign with hash 33 byte to error")
+	}
+}
diff --git a/crypto/key.go b/crypto/key.go
index d371ad4dc9ae24580071a0ebfb026c601c312ab5..ca29b691ff0fc5b234bc0dfe9c78f542a1c8af53 100644
--- a/crypto/key.go
+++ b/crypto/key.go
@@ -57,7 +57,7 @@ type encryptedKeyJSON struct {
 
 func (k *Key) Address() []byte {
 	pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
-	return Sha3(pubBytes)[12:]
+	return Sha3(pubBytes[1:])[12:]
 }
 
 func (k *Key) MarshalJSON() (j []byte, err error) {
@@ -99,9 +99,10 @@ func NewKey(rand io.Reader) *Key {
 	privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
 	privateKeyECDSA := ToECDSA(privateKeyMarshalled)
 
-	key := new(Key)
 	id := uuid.NewRandom()
-	key.Id = &id
-	key.PrivateKey = privateKeyECDSA
+	key := &Key{
+		Id:         &id,
+		PrivateKey: privateKeyECDSA,
+	}
 	return key
 }
diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go
index e30a0a785f4685cafcfd69b26c8396fadd283025..80bf49d68a4846a997a5497846dfa8b2af37d2cf 100644
--- a/crypto/key_store_passphrase.go
+++ b/crypto/key_store_passphrase.go
@@ -178,22 +178,10 @@ func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes
 	if err != nil {
 		return nil, err
 	}
-
-	AES256Block, err := aes.NewCipher(derivedKey)
+	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
 	if err != nil {
 		return nil, err
 	}
-
-	AES256CBCDecrypter := cipher.NewCBCDecrypter(AES256Block, iv)
-	paddedPlainText := make([]byte, len(cipherText))
-	AES256CBCDecrypter.CryptBlocks(paddedPlainText, cipherText)
-
-	plainText := PKCS7Unpad(paddedPlainText)
-	if plainText == nil {
-		err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
-		return nil, err
-	}
-
 	keyBytes = plainText[:len(plainText)-32]
 	keyBytesHash := plainText[len(plainText)-32:]
 	if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
@@ -211,35 +199,3 @@ func getEntropyCSPRNG(n int) []byte {
 	}
 	return mainBuff
 }
-
-// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
-func PKCS7Pad(in []byte) []byte {
-	padding := 16 - (len(in) % 16)
-	if padding == 0 {
-		padding = 16
-	}
-	for i := 0; i < padding; i++ {
-		in = append(in, byte(padding))
-	}
-	return in
-}
-
-func PKCS7Unpad(in []byte) []byte {
-	if len(in) == 0 {
-		return nil
-	}
-
-	padding := in[len(in)-1]
-	if int(padding) > len(in) || padding > aes.BlockSize {
-		return nil
-	} else if padding == 0 {
-		return nil
-	}
-
-	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
-		if in[i] != padding {
-			return nil
-		}
-	}
-	return in[:len(in)-int(padding)]
-}
diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go
index 16c0e476d47496f381d621ea7f8e6cfd2895737e..54efc739a2e036407ac6fcee0623c6da9d6bb016 100644
--- a/crypto/key_store_test.go
+++ b/crypto/key_store_test.go
@@ -83,3 +83,16 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestImportPreSaleKey(t *testing.T) {
+	// file content of a presale key file generated with:
+	// python pyethsaletool.py genwallet
+	// with password "foo"
+	fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
+	ks := NewKeyStorePassphrase(DefaultDataDir())
+	pass := "foo"
+	_, err := ImportPreSaleKey(ks, []byte(fileContent), pass)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/whisper/peer.go b/whisper/peer.go
index f82cc6e3e7c5e5762c1b0731191f8f40a8294849..332ddd22a43cac37e730601c600482637fb65fd2 100644
--- a/whisper/peer.go
+++ b/whisper/peer.go
@@ -81,7 +81,7 @@ func (self *peer) broadcast(envelopes []*Envelope) error {
 		if err := self.ws.WriteMsg(msg); err != nil {
 			return err
 		}
-		self.peer.Infoln("broadcasted", i, "message(s)")
+		self.peer.DebugDetailln("broadcasted", i, "message(s)")
 	}
 
 	return nil