From 3cd0ae0e8ba8d7cb10760be2d8caf92633e39022 Mon Sep 17 00:00:00 2001
From: pointbiz <d>
Date: Sun, 16 Aug 2015 17:16:17 -0400
Subject: [PATCH] v2.9.11 add status icons

add status icons for checking the URI protocol used, support for
window.crypto.getRandomValues and run the synchronous unit tests after
entropy collection. Thanks @cantonbecker for the ideas.
---
 CHANGELOG.txt           |   5 +
 CHANGELOG.txt.asc       |  19 +-
 Gruntfile.js            |   2 +
 bitaddress.org.html     | 606 +++++++++++++++++++++++++++++++---------
 bitaddress.org.html.sig |  14 +-
 package.json            |   6 +-
 src/bitaddress-ui.html  |  47 ++++
 src/main.css            |   7 +
 src/ninja.misc.js       | 240 +++-------------
 src/ninja.onload.js     |   2 +-
 src/ninja.qrcode.js     |  94 +++++++
 src/ninja.seeder.js     | 112 ++++++++
 src/ninja.translator.js | 245 +++++++++++++++-
 src/ninja.unittests.js  |  22 +-
 14 files changed, 1073 insertions(+), 348 deletions(-)
 create mode 100644 src/ninja.qrcode.js
 create mode 100644 src/ninja.seeder.js

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 7ed70ce..fe4b758 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -28,6 +28,11 @@ END USER NOTES:
 
 Here is a signed list of file names and version history.
 
+2015-08-16: status ACTIVE
+bitaddress.org-v2.9.11-SHA256-40376eddc790a63d9afcfb72c0a45002827da965f3bfe6ba8c330e697bf188b2.html
+ - add status icons for checking the URI protocol used, support for window.crypto.getRandomValues
+   and run the synchronous unit tests after entropy collection.
+
 2015-07-18: status ACTIVE
 bitaddress.org-v2.9.10-SHA256-445e44cfd04c8f1ea8f732c3ae7277b0166fdb3e2109251c54e4b367983fe04d.html
  - add Portuguese. Thanks rhcastilhos.
diff --git a/CHANGELOG.txt.asc b/CHANGELOG.txt.asc
index eb50b5b..444319c 100644
--- a/CHANGELOG.txt.asc
+++ b/CHANGELOG.txt.asc
@@ -31,6 +31,11 @@ END USER NOTES:
 
 Here is a signed list of file names and version history.
 
+2015-08-16: status ACTIVE
+bitaddress.org-v2.9.11-SHA256-40376eddc790a63d9afcfb72c0a45002827da965f3bfe6ba8c330e697bf188b2.html
+ - add status icons for checking the URI protocol used, support for window.crypto.getRandomValues
+   and run the synchronous unit tests after entropy collection.
+
 2015-07-18: status ACTIVE
 bitaddress.org-v2.9.10-SHA256-445e44cfd04c8f1ea8f732c3ae7277b0166fdb3e2109251c54e4b367983fe04d.html
  - add Portuguese. Thanks rhcastilhos.
@@ -293,11 +298,11 @@ bitaddress.org-v0.1-SHA1-f40e706490f3eb2be56c31ddbf4c8646cd51ef40.html
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (MingW32)
 
-iQEcBAEBAgAGBQJVqvCZAAoJEIdJe5Fjl09aiCMIAJe62QQZ0Y0L0KaJAetUXB8R
-5BFPC1KiMclipjU0avNTKa1lm6bEell1suyL0D8yZiuDy22DLqekc3RG6fYy2a1I
-O/eobk3S5rBTIFiAm+U4s7sQV6/vZ2DgYyu/909gn5ziF3nguHq77SEA7bKWtT94
-EwFhTwblBCT4ib/OvQ0sb4cYF3VdbKtn7kzjzy/HeadYNVOfbIALbCySTRakvX5Z
-qB++gQTFusXk8aptHmW19Fc9o0FMtAMHW8sdPtqTq1DW6HYetU9mmZmiuQdfFGLR
-M8rwTwJX4kAkaSy5baSQowojDPR1EiDvMsnqRFGXv/B2H61baF4cB9gdcIW3clc=
-=TyF6
+iQEcBAEBAgAGBQJV0Pu2AAoJEIdJe5Fjl09avHcH/31ABkos0xmXJ6E1PC2P7SUN
+SiX6ehnKVTnMzbu1APhyJ2hlUrpSOBS0bbRhlHc9M6X2z8aqBT5izRba6V3LnxJ7
+dxtPPv++ieJR/5s6EIrbn1I1f+eoCxKCtuFabmqq/Pmc+ChMbjsWbTz/Nx1lwjSq
+F/a1k5RqEL3qMPHTc2eCwT4UdlcNr5YKm/8bJTbRKFygWGfj7U0ryX87h+xI3D2s
+jO69dtU6hiQ490574Hl1w9cDMbAdNkhXP5TXZ9Tl7Lqs1SMgHZ9Shi+8xjiOyUSM
+7hnRbGyK+r2DbpyLzFnayvez1Zu3oELa5qKNgIq1rS3XLZzxPXId+0li/MRSn1c=
+=5DkH
 -----END PGP SIGNATURE-----
diff --git a/Gruntfile.js b/Gruntfile.js
index bdd0a92..f77957a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -30,6 +30,8 @@ module.exports = function (grunt) {
 					{ token: "//ninja.key.js", file: "./src/ninja.key.js" },
 					{ token: "//ninja.misc.js", file: "./src/ninja.misc.js" },
 					{ token: "//ninja.onload.js", file: "./src/ninja.onload.js" },
+					{ token: "//ninja.qrcode.js", file: "./src/ninja.qrcode.js" },
+					{ token: "//ninja.seeder.js", file: "./src/ninja.seeder.js" },
 					{ token: "//ninja.unittests.js", file: "./src/ninja.unittests.js" },
 					{ token: "//ninja.translator.js", file: "./src/ninja.translator.js" },
 					{ token: "//ninja.singlewallet.js", file: "./src/ninja.singlewallet.js" },
diff --git a/bitaddress.org.html b/bitaddress.org.html
index 51c7c04..518252a 100644
--- a/bitaddress.org.html
+++ b/bitaddress.org.html
@@ -6321,6 +6321,7 @@ body, html { height: 99%; }
 .question:hover, .expandable:hover { color: #77777A; }
 .answer { padding: 0 15px 10px 25px; text-align: left; display: none; font-size: 80%; }
 .faq { border: 0; border-top: 2px solid #009900; }
+.button {}
 
 #wallets { clear: both; }
 #btcaddress, #btcprivwif, #detailaddress, #detailaddresscomp, #detailprivwif, #detailprivwifcomp { font-family: monospace; font-size: 1.25em; }
@@ -6510,6 +6511,12 @@ body, html { height: 99%; }
 	.footer .authorpgp span.item { text-align: right; display: block; padding: 0 20px; }
 	.footer .copyright { font-size: 80%; clear: both; padding: 5px 0; }
 	.footer .copyright span { padding: 10px 2px; }
+    .footer .tooltip { display: none; text-align: left; border: 2px solid green; background-color: #FFFFF6; margin: 5px; padding: 10px; top: 0px; position: relative;  }
+	.footer .statusgood { color: green; font-weight: bold; }
+    .footer .statuswarn { color: orange; font-weight: bold; }
+	.footer .statusbad { color: red; font-weight: bold; }
+    .footer .statusicon { background-color: none; font-size: 120%; padding: 1px 2px; }
+    .footer .statusicon:hover { background-color: green; cursor: pointer; }
 }
 @media print
 {
@@ -6882,17 +6889,58 @@ body, html { height: 99%; }
 
 
 		<div id="footer" class="footer">
+			<div class="tooltips">
+				<div class="tooltip" id="statuscryptogood">
+					<span class="statusgood" id="statuslabelcryptogood">&#10004; Good!</span>
+					<span id="statuslabelcryptogood1">Your browser can generate cryptographically random keys using window.crypto.getRandomValues</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokcryptogood" onclick="document.getElementById('statuscryptogood').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statuscryptobad">
+					<span class="statusbad" id="statuslabelcryptobad">&times; Oh no!</span>
+					<span id="statuslabelcryptobad1">Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokcryptobad" onclick="document.getElementById('statuscryptobad').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusunittestsgood">
+					<span class="statusgood" id="statuslabelunittestsgood">&#10004; Good!</span>
+					<span id="statuslabelunittestsgood1">All synchronous unit tests passed.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokunittestsgood" onclick="document.getElementById('statusunittestsgood').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusunittestsbad">
+					<span class="statusbad" id="statuslabelunittestsbad">&times; Oh no!</span>
+					<span id="statuslabelunittestsbad1">Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokunittestsbad" onclick="document.getElementById('statusunittestsbad').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusprotocolgood">
+					<span class="statusgood" id="statuslabelprotocolgood">&#10004; Good!</span>
+					<span id="statuslabelprotocolgood1">You are running this generator from your local computer. <br />Tip: Double check you are offline by trying </span>
+					<a href="http://www.google.com" target="_blank">www.google.com</a>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokprotocolgood" onclick="document.getElementById('statusprotocolgood').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusprotocolbad">
+					<span class="statuswarn" id="statuslabelprotocolbad">&#9888; Think twice!</span>
+					<span id="statuslabelprotocolbad1">You appear to be running this generator online from a live website. For valuable wallets it is recommended to</span>
+					<a id="statuslabelprotocolbad2" href="https://github.com/pointbiz/bitaddress.org/archive/v2.9.11.zip">download</a>
+					<span id="statuslabelprotocolbad3">the zip file from GitHub and run this generator offline as a local html file.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokprotocolbad" onclick="document.getElementById('statusprotocolbad').style.display = 'none';" />
+				</div>
+			</div>
+
 			<div class="authorbtc">
 				<div>
+					<span class="item">
+						<span class="statusicon" id="statusprotocol" onclick="ninja.status.showProtocol();">...</span>
+						<span class="statusicon" id="statuscrypto" onclick="ninja.status.showCrypto();">...</span>
+						<span class="statusicon" id="statusunittests" onclick="ninja.status.showUnitTests();">...</span>
+					</span>
 					<span class="item"><span id="footerlabeldonations">Donations:</span> <b>1NiNja</b>1bUmhSoTXozBRBEtR8LeF9TGbZBN</span>
 					<span class="item" id="footerlabeltranslatedby"></span>
 					<span class="item"><a href="https://github.com/pointbiz/bitaddress.org" target="_blank" id="footerlabelgithub">GitHub Repository</a> 
-						(<a href="https://github.com/pointbiz/bitaddress.org/archive/v2.9.10.zip" target="_blank" id="footerlabelgithubzip">zip</a>)</span>
+						(<a href="https://github.com/pointbiz/bitaddress.org/archive/v2.9.11.zip" target="_blank" id="footerlabelgithubzip">zip</a>)</span>
 				</div>
 			</div>
 			<div class="authorpgp">
 				<span class="item">
-					<a href="CHANGELOG.txt.asc" target="_blank"><span id="footerlabelversion">Version History</span> (2.9.10)</a>
+					<a href="CHANGELOG.txt.asc" target="_blank"><span id="footerlabelversion">Version History</span> (2.9.11)</a>
 					
 				</span>
 				<span class="item">527B 5C82 B1F6 B2DB 72A0<br />ECBF 8749 7B91 6397 4F5A</span>
@@ -7261,7 +7309,7 @@ ninja.publicKey = {
 };
 	</script>
 	<script type="text/javascript">
-ninja.seeder = {
+ninja.seeder = {
 	init: (function () {
 		document.getElementById("generatekeyinput").value = "";
 	})(),
@@ -7284,10 +7332,10 @@ ninja.seeder = {
 		var timeStamp = new Date().getTime();
 		// seeding is over now we generate and display the address
 		if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
-		    ninja.seeder.seedCount++;
-		    ninja.seeder.seedingOver();
+			ninja.seeder.seedCount++;
+			ninja.seeder.seedingOver();
 		}
-		// seed mouse position X and Y when mouse movements are greater than 40ms apart.
+			// seed mouse position X and Y when mouse movements are greater than 40ms apart.
 		else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
 			SecureRandom.seedTime();
 			SecureRandom.seedInt16((evt.clientX * evt.clientY));
@@ -7303,10 +7351,10 @@ ninja.seeder = {
 		if (!evt) var evt = window.event;
 		// seeding is over now we generate and display the address
 		if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
-		    ninja.seeder.seedCount++;
-		    ninja.seeder.seedingOver();
+			ninja.seeder.seedCount++;
+			ninja.seeder.seedingOver();
 		}
-		// seed key press character
+			// seed key press character
 		else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
 			var timeStamp = new Date().getTime();
 			// seed a bunch (minimum seedLimit) of times
@@ -7323,19 +7371,19 @@ ninja.seeder = {
 	showPool: function () {
 		var poolHex;
 		if (SecureRandom.poolCopyOnInit != null) {
-		    poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
-		    document.getElementById("seedpool").innerHTML = poolHex;
-		    document.getElementById("seedpooldisplay").innerHTML = poolHex;
+			poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
+			document.getElementById("seedpool").innerHTML = poolHex;
+			document.getElementById("seedpooldisplay").innerHTML = poolHex;
 		}
 		else {
-		    poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
-		    document.getElementById("seedpool").innerHTML = poolHex;
-		    document.getElementById("seedpooldisplay").innerHTML = poolHex;
+			poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
+			document.getElementById("seedpool").innerHTML = poolHex;
+			document.getElementById("seedpooldisplay").innerHTML = poolHex;
 		}
 		var percentSeeded = Math.round((ninja.seeder.seedCount / ninja.seeder.seedLimit) * 100) + "%";
 		document.getElementById("mousemovelimit").innerHTML = percentSeeded;
 		for (var wIndex in ninja.seeder.seederDependentWallets) {
-		    document.getElementById(ninja.seeder.seederDependentWallets[wIndex]).innerHTML = percentSeeded;
+			document.getElementById(ninja.seeder.seederDependentWallets[wIndex]).innerHTML = percentSeeded;
 		}
 	},
 
@@ -7356,113 +7404,176 @@ ninja.seeder = {
 	},
 
 	seedingOver: function () {
-	    ninja.seeder.isStillSeeding = false;
-	    var walletType = ninja.tab.whichIsOpen();
-	    if (walletType == null) {
-	        ninja.tab.select("singlewallet");
-	    } else {
-	        ninja.tab.select(walletType)
-	    }
-	    document.getElementById("generate").style.display = "none";
-	    // update labels for dependent wallets
-	    var culture = (ninja.getQueryString()["culture"] == null ? "en" : ninja.getQueryString()["culture"]);
-	    ninja.translator.translate(culture);
-	    ninja.seeder.removePoints();
+		ninja.seeder.isStillSeeding = false;
+		// run sync unit tests
+		ninja.status.unitTests();
+		// open selected tab
+		var walletType = ninja.tab.whichIsOpen();
+		if (walletType == null) {
+			ninja.tab.select("singlewallet");
+		} else {
+			ninja.tab.select(walletType)
+		}
+		document.getElementById("generate").style.display = "none";
+		// update labels for dependent wallets
+		var culture = (ninja.getQueryString()["culture"] == null ? "en" : ninja.getQueryString()["culture"]);
+		ninja.translator.translate(culture);
+		ninja.seeder.removePoints();
 	}
 };
 
-ninja.qrCode = {
-	// determine which type number is big enough for the input text length
-	getTypeNumber: function (text) {
-		var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
-		if (lengthCalculation < 72) { return 1; }
-		else if (lengthCalculation < 128) { return 2; }
-		else if (lengthCalculation < 208) { return 3; }
-		else if (lengthCalculation < 288) { return 4; }
-		else if (lengthCalculation < 368) { return 5; }
-		else if (lengthCalculation < 480) { return 6; }
-		else if (lengthCalculation < 528) { return 7; }
-		else if (lengthCalculation < 688) { return 8; }
-		else if (lengthCalculation < 800) { return 9; }
-		else if (lengthCalculation < 976) { return 10; }
-		return null;
-	},
+	</script>
+	<script type="text/javascript">
+ (function (ninja) {
+	var qrC = ninja.qrCode = {
+		// determine which type number is big enough for the input text length
+		getTypeNumber: function (text) {
+			var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
+			if (lengthCalculation < 72) { return 1; }
+			else if (lengthCalculation < 128) { return 2; }
+			else if (lengthCalculation < 208) { return 3; }
+			else if (lengthCalculation < 288) { return 4; }
+			else if (lengthCalculation < 368) { return 5; }
+			else if (lengthCalculation < 480) { return 6; }
+			else if (lengthCalculation < 528) { return 7; }
+			else if (lengthCalculation < 688) { return 8; }
+			else if (lengthCalculation < 800) { return 9; }
+			else if (lengthCalculation < 976) { return 10; }
+			return null;
+		},
 
-	createCanvas: function (text, sizeMultiplier) {
-		sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
-		// create the qrcode itself
-		var typeNumber = ninja.qrCode.getTypeNumber(text);
-		var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
-		qrcode.addData(text);
-		qrcode.make();
-		var width = qrcode.getModuleCount() * sizeMultiplier;
-		var height = qrcode.getModuleCount() * sizeMultiplier;
-		// create canvas element
-		var canvas = document.createElement('canvas');
-		var scale = 10.0;
-		canvas.width = width * scale;
-		canvas.height = height * scale;
-		canvas.style.width = width + 'px';
-		canvas.style.height = height + 'px';
-		var ctx = canvas.getContext('2d');
-		ctx.scale(scale, scale);
-		// compute tileW/tileH based on width/height
-		var tileW = width / qrcode.getModuleCount();
-		var tileH = height / qrcode.getModuleCount();
-		// draw in the canvas
-		for (var row = 0; row < qrcode.getModuleCount(); row++) {
-			for (var col = 0; col < qrcode.getModuleCount(); col++) {
-				ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
-				ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
-			}
-		}
-		// return just built canvas
-		return canvas;
-	},
-
-	// generate a QRCode and return it's representation as an Html table 
-	createTableHtml: function (text) {
-		var typeNumber = ninja.qrCode.getTypeNumber(text);
-		var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
-		qr.addData(text);
-		qr.make();
-		var tableHtml = "<table class='qrcodetable'>";
-		for (var r = 0; r < qr.getModuleCount(); r++) {
-			tableHtml += "<tr>";
-			for (var c = 0; c < qr.getModuleCount(); c++) {
-				if (qr.isDark(r, c)) {
-					tableHtml += "<td class='qrcodetddark'/>";
-				} else {
-					tableHtml += "<td class='qrcodetdlight'/>";
+		createCanvas: function (text, sizeMultiplier) {
+			sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
+			// create the qrcode itself
+			var typeNumber = qrC.getTypeNumber(text);
+			var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
+			qrcode.addData(text);
+			qrcode.make();
+			var width = qrcode.getModuleCount() * sizeMultiplier;
+			var height = qrcode.getModuleCount() * sizeMultiplier;
+			// create canvas element
+			var canvas = document.createElement('canvas');
+			var scale = 10.0;
+			canvas.width = width * scale;
+			canvas.height = height * scale;
+			canvas.style.width = width + 'px';
+			canvas.style.height = height + 'px';
+			var ctx = canvas.getContext('2d');
+			ctx.scale(scale, scale);
+			// compute tileW/tileH based on width/height
+			var tileW = width / qrcode.getModuleCount();
+			var tileH = height / qrcode.getModuleCount();
+			// draw in the canvas
+			for (var row = 0; row < qrcode.getModuleCount() ; row++) {
+				for (var col = 0; col < qrcode.getModuleCount() ; col++) {
+					ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
+					ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
 				}
 			}
-			tableHtml += "</tr>";
-		}
-		tableHtml += "</table>";
-		return tableHtml;
-	},
+			// return just built canvas
+			return canvas;
+		},
 
-	// show QRCodes with canvas OR table (IE8)
-	// parameter: keyValuePair 
-	// example: { "id1": "string1", "id2": "string2"}
-	//		"id1" is the id of a div element where you want a QRCode inserted.
-	//		"string1" is the string you want encoded into the QRCode.
-	showQrCode: function (keyValuePair, sizeMultiplier) {
-		for (var key in keyValuePair) {
-			var value = keyValuePair[key];
-			try {
-				if (document.getElementById(key)) {
-					document.getElementById(key).innerHTML = "";
-					document.getElementById(key).appendChild(ninja.qrCode.createCanvas(value, sizeMultiplier));
+		// generate a QRCode and return it's representation as an Html table 
+		createTableHtml: function (text) {
+			var typeNumber = qrC.getTypeNumber(text);
+			var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
+			qr.addData(text);
+			qr.make();
+			var tableHtml = "<table class='qrcodetable'>";
+			for (var r = 0; r < qr.getModuleCount() ; r++) {
+				tableHtml += "<tr>";
+				for (var c = 0; c < qr.getModuleCount() ; c++) {
+					if (qr.isDark(r, c)) {
+						tableHtml += "<td class='qrcodetddark'/>";
+					} else {
+						tableHtml += "<td class='qrcodetdlight'/>";
+					}
+				}
+				tableHtml += "</tr>";
+			}
+			tableHtml += "</table>";
+			return tableHtml;
+		},
+
+		// show QRCodes with canvas OR table (IE8)
+		// parameter: keyValuePair 
+		// example: { "id1": "string1", "id2": "string2"}
+		//		"id1" is the id of a div element where you want a QRCode inserted.
+		//		"string1" is the string you want encoded into the QRCode.
+		showQrCode: function (keyValuePair, sizeMultiplier) {
+			for (var key in keyValuePair) {
+				var value = keyValuePair[key];
+				try {
+					if (document.getElementById(key)) {
+						document.getElementById(key).innerHTML = "";
+						document.getElementById(key).appendChild(qrC.createCanvas(value, sizeMultiplier));
+					}
+				}
+				catch (e) {
+					// for browsers that do not support canvas (IE8)
+					document.getElementById(key).innerHTML = qrC.createTableHtml(value);
 				}
 			}
-			catch (e) {
-				// for browsers that do not support canvas (IE8)
-				document.getElementById(key).innerHTML = ninja.qrCode.createTableHtml(value);
-			}
 		}
-	}
-};
+	};
+})(ninja);
+	</script>
+	<script type="text/javascript">
+(function (ninja) {
+	var status = ninja.status = function() {
+		var cryptoCase = "";
+		if (window.crypto && window.crypto.getRandomValues) {
+			document.getElementById("statuscrypto").innerHTML = "&#10004;"; //✔
+			cryptoCase = "good";
+		}
+		else {
+			document.getElementById("statuscrypto").innerHTML = "&times;"; //×
+			cryptoCase = "bad";
+		}
+
+		var protocolCase = "";
+		switch (window.location.protocol) {
+			case 'file:':
+				document.getElementById("statusprotocol").innerHTML = "&#10004;"; //✔
+				protocolCase = "good";
+				break;
+			case 'http:':
+			case 'https:':
+				document.getElementById("statusprotocol").innerHTML = "&#9888;"; //⚠
+				protocolCase = "bad";
+				break;
+			default:
+		}
+
+		var unitTestsCase = "";
+		var unitTests = function () {
+			var result = ninja.unitTests.runSynchronousTests();
+			if (result.passCount == result.testCount) {
+				document.getElementById("statusunittests").innerHTML = "&#10004;"; //✔
+				unitTestsCase = "good";
+			}
+			else {
+				document.getElementById("statusunittests").innerHTML = "&times;"; //×
+				unitTestsCase = "bad";
+			}
+		};
+
+		var showCrypto = function () {
+			document.getElementById('statuscrypto' + cryptoCase).style.display = 'block';
+		};
+
+		var showProtocol = function () {
+			document.getElementById('statusprotocol' + protocolCase).style.display = 'block';
+		};
+
+		var showUnitTests = function () {
+			if(unitTestsCase != "") document.getElementById('statusunittests' + unitTestsCase).style.display = 'block';
+		};
+
+		return { unitTests: unitTests, showCrypto: showCrypto, showProtocol: showProtocol, showUnitTests: showUnitTests };
+	}();
+})(ninja);
 
 ninja.tab = {
     select: function (walletTab) {
@@ -7674,6 +7785,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Copyright del código JavaScript: en el fuente.",
 			"footerlabelnowarranty": "Sin garantía.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Generar dirección",
 			"singleprint": "Imprimir",
@@ -7812,7 +7945,29 @@ ninja.translator = {
 			"footerlabelcopyright1": "Copyright bitaddress.org.",
 			"footerlabelcopyright2": "Les droits d'auteurs JavaScript sont inclus dans le code source.",
 			"footerlabelnowarranty": "Aucune garantie.",
-			
+
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Générer Une Nouvelle Adresse",
 			"singleprint": "Imprimer",
@@ -7826,7 +7981,6 @@ ninja.translator = {
 			"singleshare": "PARTAGER",
 			"singlesecret": "SECRET",
 
-
 			// paper wallet html
 			"paperlabelhideart": "Enlever l'image ?",
 			"paperlabeladdressesperpage": "Adresses par page:",
@@ -7953,6 +8107,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Τα πνευματικά δικαιώματα της JavaScript περιλαμβάνονται στον κώδικα.",
 			"footerlabelnowarranty": "Καμία εγγύηση.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Δημιουργία μιας νέας Διεύθυνσης",
 			"singleprint": "Εκτύπωση",
@@ -8092,6 +8268,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Le note di copyright dei file JavaScript sono inclusi nei sorgenti stessi.",
 			"footerlabelnowarranty": "Nessuna garanzia.",
 
+	    	// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Genera un Nuovo Indirizzo",
 			"singleprint": "Stampa",
@@ -8231,6 +8429,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "JavaScript-Copyrights sind im Quelltext enthalten.",
 			"footerlabelnowarranty": "Ohne Gew&auml;hr.",
 
+	    	// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Neues Wallet erstellen",
 			"singleprint": "Drucken",
@@ -8370,6 +8590,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Copyright JavaScriptu je uveden ve zdrojovém kódu.",
 			"footerlabelnowarranty": "Bez záruky.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Vytvořit novou adresu",
 			"singleprint": "Tisk",
@@ -8509,6 +8751,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Az egyes JavaScript kódok szerzőinek jogai a forráskódon belül találhatók meg.",
 			"footerlabelnowarranty": "Garancia nincs.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Új cím előállítása",
 			"singleprint": "Nyomtatás",
@@ -8654,6 +8918,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "JavaScriptのコピーライト情報はソースに含まれています。",
 			"footerlabelnowarranty": "保障はありません。",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "新アドレス生成",
 			"singleprint": "印刷",
@@ -8800,6 +9086,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Copyright do código JavaScript: no código-fonte.",
 			"footerlabelnowarranty": "Sem garantia.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Gerar endereço",
 			"singleprint": "Imprimir",
@@ -8939,6 +9247,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "JavaScript的版权信息已经包含在源代码中。",
 			"footerlabelnowarranty": "No warranty",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "生成新地址",
 			"singleprint": "打印",
@@ -9084,6 +9414,28 @@ ninja.translator = {
             "footerlabelcopyright2": "Информация о копирайте на JavaScript в исходниках.",
             "footerlabelnowarranty": "Без гарантий.",
 
+        	// status html
+            "statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+            "statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+            "statusokcryptogood": "OK", //TODO: please translate
+            "statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+            "statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+            "statusokcryptobad": "OK", //TODO: please translate
+            "statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+            "statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+            "statusokunittestsgood": "OK", //TODO: please translate
+            "statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+            "statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+            "statusokunittestsbad": "OK", //TODO: please translate
+            "statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+            "statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+            "statusokprotocolgood": "OK", //TODO: please translate
+            "statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+            "statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+            "statuslabelprotocolbad2": "download", //TODO: please translate
+            "statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+            "statusokprotocolbad": "OK", //TODO: please translate
+
             // single wallet html
             "newaddress": "Сгенерировать новый адрес",
             "singleprint": "Распечатать",
@@ -10048,11 +10400,13 @@ ninja.wallets.splitwallet = {
 	<script type="text/javascript">
 (function (ninja) {
 	var ut = ninja.unitTests = {
-		runSynchronousTests: function () {
-			document.getElementById("busyblock").className = "busy";
-			var div = document.createElement("div");
-			div.setAttribute("class", "unittests");
-			div.setAttribute("id", "unittests");
+		runSynchronousTests: function (showOutput) {
+			if (showOutput) {
+				document.getElementById("busyblock").className = "busy";
+				var div = document.createElement("div");
+				div.setAttribute("class", "unittests");
+				div.setAttribute("id", "unittests");
+			}
 			var testResults = "";
 			var passCount = 0;
 			var testCount = 0;
@@ -10079,10 +10433,12 @@ ninja.wallets.splitwallet = {
 			if (passCount < testCount) {
 				testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
 			}
-			div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
-			document.body.appendChild(div);
-			document.getElementById("busyblock").className = "";
-
+			if (showOutput) {
+				div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
+				document.body.appendChild(div);
+				document.getElementById("busyblock").className = "";
+			}
+			return { passCount: passCount, testCount: testCount };
 		},
 
 		runAsynchronousTests: function () {
@@ -10751,7 +11107,7 @@ ninja.wallets.splitwallet = {
 	<script type="text/javascript">
 // run unit tests
 if (ninja.getQueryString()["unittests"] == "true" || ninja.getQueryString()["unittests"] == "1") {
-	ninja.unitTests.runSynchronousTests();
+	ninja.unitTests.runSynchronousTests(true);
 	ninja.translator.showEnglishJson();
 }
 // run async unit tests
diff --git a/bitaddress.org.html.sig b/bitaddress.org.html.sig
index 6aadf76..e5831f2 100644
--- a/bitaddress.org.html.sig
+++ b/bitaddress.org.html.sig
@@ -1,11 +1,11 @@
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (MingW32)
 
-iQEcBAABAgAGBQJVqvCxAAoJEIdJe5Fjl09alIkIAND7ROpaQKzYrPPGD0qo8uUm
-RGLhOliUw91llOy279BXzIuz0j9mj/8WNSVXevLADyy7Wpwo3WQcSQywkSvh33d5
-H891SWTwjil+G/TxZW9qCD+Lq0qz79gwsXf8x0wJ81aa2u+uW3JAb2BVNnDXMQWV
-XRI66CnP+zWNj9AKr+wEvJ0OuWIu9DlZXbcJsHR9CxzGizVLNWzVyb5oawqiwa2J
-I79/rx7+Tcu6cEam+QgkQwN4nZI62dGlwSFNdHOV6z4njegrrnPwGdNM3nhDPxF9
-eO620nDetccu2AWrFtG5cBvwiu/rRbWuNCboTIb4khU1JYa9oxMmgs1mJ4HyQGs=
-=2DVR
+iQEcBAABAgAGBQJV0PvPAAoJEIdJe5Fjl09aUz8IAIen68xsU8MnU56fHx+/KDbx
+fiYz88OU7I6PnB+0hlVc5TW5VH4RD8Tzfpc1+31+RyPJ+Va/PUdh68FptcthBsuL
+byv3+rrwxRDy/00stIQh1HBd0JJ+mX0DBCqnJ79NdGJJqEHW8D5VgfSnxaqvconi
+U5Q1RvzdArb/HcbQ5BvNTXRgHP+TzQBJ3hHyoCxtwOpa3Qd/w5FzkB2TN52mvEiw
+U1X0KrT4ntyLYAy4eJb+ecLYHi1dn92BTq8fqkj0mN+inBWb5J0zuZd/aBcqqvRM
+qBBPMHBjbXETOunM0PmQ/ENiOugIuN/3JqL0yqVHP1cZxqtLPK5Iw7AVUchPe+E=
+=O+Y0
 -----END PGP SIGNATURE-----
diff --git a/package.json b/package.json
index bce0b39..05313f3 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
   "name": "bitaddress.org",
-  "version": "2.9.10",
-  "sha1sum": "a4c9a05cb374859d4c50c5f73b9548bf33296661",
-  "sha256sum": "445e44cfd04c8f1ea8f732c3ae7277b0166fdb3e2109251c54e4b367983fe04d",
+  "version": "2.9.11",
+  "sha1sum": "7232900c98e3af634a46374cd7178ce5e33cb96f",
+  "sha256sum": "40376eddc790a63d9afcfb72c0a45002827da965f3bfe6ba8c330e697bf188b2",
   "description": "Open Source JavaScript Client-Side Bitcoin Wallet Generator",
   "main": "Gruntfile.js",
   "dependencies": {
diff --git a/src/bitaddress-ui.html b/src/bitaddress-ui.html
index e95d2c9..2d39d19 100644
--- a/src/bitaddress-ui.html
+++ b/src/bitaddress-ui.html
@@ -463,8 +463,49 @@
 
 
 		<div id="footer" class="footer">
+			<div class="tooltips">
+				<div class="tooltip" id="statuscryptogood">
+					<span class="statusgood" id="statuslabelcryptogood">&#10004; Good!</span>
+					<span id="statuslabelcryptogood1">Your browser can generate cryptographically random keys using window.crypto.getRandomValues</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokcryptogood" onclick="document.getElementById('statuscryptogood').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statuscryptobad">
+					<span class="statusbad" id="statuslabelcryptobad">&times; Oh no!</span>
+					<span id="statuslabelcryptobad1">Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokcryptobad" onclick="document.getElementById('statuscryptobad').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusunittestsgood">
+					<span class="statusgood" id="statuslabelunittestsgood">&#10004; Good!</span>
+					<span id="statuslabelunittestsgood1">All synchronous unit tests passed.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokunittestsgood" onclick="document.getElementById('statusunittestsgood').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusunittestsbad">
+					<span class="statusbad" id="statuslabelunittestsbad">&times; Oh no!</span>
+					<span id="statuslabelunittestsbad1">Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokunittestsbad" onclick="document.getElementById('statusunittestsbad').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusprotocolgood">
+					<span class="statusgood" id="statuslabelprotocolgood">&#10004; Good!</span>
+					<span id="statuslabelprotocolgood1">You are running this generator from your local computer. <br />Tip: Double check you are offline by trying </span>
+					<a href="http://www.google.com" target="_blank">www.google.com</a>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokprotocolgood" onclick="document.getElementById('statusprotocolgood').style.display = 'none';" />
+				</div>
+				<div class="tooltip" id="statusprotocolbad">
+					<span class="statuswarn" id="statuslabelprotocolbad">&#9888; Think twice!</span>
+					<span id="statuslabelprotocolbad1">You appear to be running this generator online from a live website. For valuable wallets it is recommended to</span>
+					<a id="statuslabelprotocolbad2" href="https://github.com/pointbiz/bitaddress.org/archive/v//version.zip">download</a>
+					<span id="statuslabelprotocolbad3">the zip file from GitHub and run this generator offline as a local html file.</span>
+					<br /><br /><input type="button" value="OK" class="button" id="statusokprotocolbad" onclick="document.getElementById('statusprotocolbad').style.display = 'none';" />
+				</div>
+			</div>
+
 			<div class="authorbtc">
 				<div>
+					<span class="item">
+						<span class="statusicon" id="statusprotocol" onclick="ninja.status.showProtocol();">...</span>
+						<span class="statusicon" id="statuscrypto" onclick="ninja.status.showCrypto();">...</span>
+						<span class="statusicon" id="statusunittests" onclick="ninja.status.showUnitTests();">...</span>
+					</span>
 					<span class="item"><span id="footerlabeldonations">Donations:</span> <b>1NiNja</b>1bUmhSoTXozBRBEtR8LeF9TGbZBN</span>
 					<span class="item" id="footerlabeltranslatedby"></span>
 					<span class="item"><a href="https://github.com/pointbiz/bitaddress.org" target="_blank" id="footerlabelgithub">GitHub Repository</a> 
@@ -493,6 +534,12 @@
 //ninja.key.js
 	</script>
 	<script type="text/javascript">
+//ninja.seeder.js
+	</script>
+	<script type="text/javascript">
+ //ninja.qrcode.js
+	</script>
+	<script type="text/javascript">
 //ninja.misc.js
 	</script>
 	<script type="text/javascript">
diff --git a/src/main.css b/src/main.css
index 6988dba..4b4d822 100644
--- a/src/main.css
+++ b/src/main.css
@@ -23,6 +23,7 @@ body, html { height: 99%; }
 .question:hover, .expandable:hover { color: #77777A; }
 .answer { padding: 0 15px 10px 25px; text-align: left; display: none; font-size: 80%; }
 .faq { border: 0; border-top: 2px solid #009900; }
+.button {}
 
 #wallets { clear: both; }
 #btcaddress, #btcprivwif, #detailaddress, #detailaddresscomp, #detailprivwif, #detailprivwifcomp { font-family: monospace; font-size: 1.25em; }
@@ -212,6 +213,12 @@ body, html { height: 99%; }
 	.footer .authorpgp span.item { text-align: right; display: block; padding: 0 20px; }
 	.footer .copyright { font-size: 80%; clear: both; padding: 5px 0; }
 	.footer .copyright span { padding: 10px 2px; }
+    .footer .tooltip { display: none; text-align: left; border: 2px solid green; background-color: #FFFFF6; margin: 5px; padding: 10px; top: 0px; position: relative;  }
+	.footer .statusgood { color: green; font-weight: bold; }
+    .footer .statuswarn { color: orange; font-weight: bold; }
+	.footer .statusbad { color: red; font-weight: bold; }
+    .footer .statusicon { background-color: none; font-size: 120%; padding: 1px 2px; }
+    .footer .statusicon:hover { background-color: green; cursor: pointer; }
 }
 @media print
 {
diff --git a/src/ninja.misc.js b/src/ninja.misc.js
index 177743c..0d17b4e 100644
--- a/src/ninja.misc.js
+++ b/src/ninja.misc.js
@@ -1,205 +1,57 @@
-ninja.seeder = {
-	init: (function () {
-		document.getElementById("generatekeyinput").value = "";
-	})(),
-
-	// number of mouse movements to wait for
-	seedLimit: (function () {
-		var num = Crypto.util.randomBytes(12)[11];
-		return 200 + Math.floor(num);
-	})(),
-
-	seedCount: 0, // counter
-	lastInputTime: new Date().getTime(),
-	seedPoints: [],
-	isStillSeeding: true,
-	seederDependentWallets: ["singlewallet", "paperwallet", "bulkwallet", "vanitywallet", "splitwallet"],
-
-	// seed function exists to wait for mouse movement to add more entropy before generating an address
-	seed: function (evt) {
-		if (!evt) var evt = window.event;
-		var timeStamp = new Date().getTime();
-		// seeding is over now we generate and display the address
-		if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
-		    ninja.seeder.seedCount++;
-		    ninja.seeder.seedingOver();
-		}
-		// seed mouse position X and Y when mouse movements are greater than 40ms apart.
-		else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
-			SecureRandom.seedTime();
-			SecureRandom.seedInt16((evt.clientX * evt.clientY));
-			ninja.seeder.showPoint(evt.clientX, evt.clientY);
-			ninja.seeder.seedCount++;
-			ninja.seeder.lastInputTime = new Date().getTime();
-			ninja.seeder.showPool();
-		}
-	},
-
-	// seed function exists to wait for mouse movement to add more entropy before generating an address
-	seedKeyPress: function (evt) {
-		if (!evt) var evt = window.event;
-		// seeding is over now we generate and display the address
-		if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
-		    ninja.seeder.seedCount++;
-		    ninja.seeder.seedingOver();
-		}
-		// seed key press character
-		else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
-			var timeStamp = new Date().getTime();
-			// seed a bunch (minimum seedLimit) of times
-			SecureRandom.seedTime();
-			SecureRandom.seedInt8(evt.which);
-			var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
-			SecureRandom.seedInt8(keyPressTimeDiff);
-			ninja.seeder.seedCount++;
-			ninja.seeder.lastInputTime = new Date().getTime();
-			ninja.seeder.showPool();
-		}
-	},
-
-	showPool: function () {
-		var poolHex;
-		if (SecureRandom.poolCopyOnInit != null) {
-		    poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
-		    document.getElementById("seedpool").innerHTML = poolHex;
-		    document.getElementById("seedpooldisplay").innerHTML = poolHex;
+(function (ninja) {
+	var status = ninja.status = function() {
+		var cryptoCase = "";
+		if (window.crypto && window.crypto.getRandomValues) {
+			document.getElementById("statuscrypto").innerHTML = "&#10004;"; //✔
+			cryptoCase = "good";
 		}
 		else {
-		    poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
-		    document.getElementById("seedpool").innerHTML = poolHex;
-		    document.getElementById("seedpooldisplay").innerHTML = poolHex;
+			document.getElementById("statuscrypto").innerHTML = "&times;"; //×
+			cryptoCase = "bad";
 		}
-		var percentSeeded = Math.round((ninja.seeder.seedCount / ninja.seeder.seedLimit) * 100) + "%";
-		document.getElementById("mousemovelimit").innerHTML = percentSeeded;
-		for (var wIndex in ninja.seeder.seederDependentWallets) {
-		    document.getElementById(ninja.seeder.seederDependentWallets[wIndex]).innerHTML = percentSeeded;
+
+		var protocolCase = "";
+		switch (window.location.protocol) {
+			case 'file:':
+				document.getElementById("statusprotocol").innerHTML = "&#10004;"; //✔
+				protocolCase = "good";
+				break;
+			case 'http:':
+			case 'https:':
+				document.getElementById("statusprotocol").innerHTML = "&#9888;"; //⚠
+				protocolCase = "bad";
+				break;
+			default:
 		}
-	},
 
-	showPoint: function (x, y) {
-		var div = document.createElement("div");
-		div.setAttribute("class", "seedpoint");
-		div.style.top = y + "px";
-		div.style.left = x + "px";
-		document.body.appendChild(div);
-		ninja.seeder.seedPoints.push(div);
-	},
-
-	removePoints: function () {
-		for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
-			document.body.removeChild(ninja.seeder.seedPoints[i]);
-		}
-		ninja.seeder.seedPoints = [];
-	},
-
-	seedingOver: function () {
-	    ninja.seeder.isStillSeeding = false;
-	    var walletType = ninja.tab.whichIsOpen();
-	    if (walletType == null) {
-	        ninja.tab.select("singlewallet");
-	    } else {
-	        ninja.tab.select(walletType)
-	    }
-	    document.getElementById("generate").style.display = "none";
-	    // update labels for dependent wallets
-	    var culture = (ninja.getQueryString()["culture"] == null ? "en" : ninja.getQueryString()["culture"]);
-	    ninja.translator.translate(culture);
-	    ninja.seeder.removePoints();
-	}
-};
-
-ninja.qrCode = {
-	// determine which type number is big enough for the input text length
-	getTypeNumber: function (text) {
-		var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
-		if (lengthCalculation < 72) { return 1; }
-		else if (lengthCalculation < 128) { return 2; }
-		else if (lengthCalculation < 208) { return 3; }
-		else if (lengthCalculation < 288) { return 4; }
-		else if (lengthCalculation < 368) { return 5; }
-		else if (lengthCalculation < 480) { return 6; }
-		else if (lengthCalculation < 528) { return 7; }
-		else if (lengthCalculation < 688) { return 8; }
-		else if (lengthCalculation < 800) { return 9; }
-		else if (lengthCalculation < 976) { return 10; }
-		return null;
-	},
-
-	createCanvas: function (text, sizeMultiplier) {
-		sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
-		// create the qrcode itself
-		var typeNumber = ninja.qrCode.getTypeNumber(text);
-		var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
-		qrcode.addData(text);
-		qrcode.make();
-		var width = qrcode.getModuleCount() * sizeMultiplier;
-		var height = qrcode.getModuleCount() * sizeMultiplier;
-		// create canvas element
-		var canvas = document.createElement('canvas');
-		var scale = 10.0;
-		canvas.width = width * scale;
-		canvas.height = height * scale;
-		canvas.style.width = width + 'px';
-		canvas.style.height = height + 'px';
-		var ctx = canvas.getContext('2d');
-		ctx.scale(scale, scale);
-		// compute tileW/tileH based on width/height
-		var tileW = width / qrcode.getModuleCount();
-		var tileH = height / qrcode.getModuleCount();
-		// draw in the canvas
-		for (var row = 0; row < qrcode.getModuleCount(); row++) {
-			for (var col = 0; col < qrcode.getModuleCount(); col++) {
-				ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
-				ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
+		var unitTestsCase = "";
+		var unitTests = function () {
+			var result = ninja.unitTests.runSynchronousTests();
+			if (result.passCount == result.testCount) {
+				document.getElementById("statusunittests").innerHTML = "&#10004;"; //✔
+				unitTestsCase = "good";
 			}
-		}
-		// return just built canvas
-		return canvas;
-	},
+			else {
+				document.getElementById("statusunittests").innerHTML = "&times;"; //×
+				unitTestsCase = "bad";
+			}
+		};
 
-	// generate a QRCode and return it's representation as an Html table 
-	createTableHtml: function (text) {
-		var typeNumber = ninja.qrCode.getTypeNumber(text);
-		var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
-		qr.addData(text);
-		qr.make();
-		var tableHtml = "<table class='qrcodetable'>";
-		for (var r = 0; r < qr.getModuleCount(); r++) {
-			tableHtml += "<tr>";
-			for (var c = 0; c < qr.getModuleCount(); c++) {
-				if (qr.isDark(r, c)) {
-					tableHtml += "<td class='qrcodetddark'/>";
-				} else {
-					tableHtml += "<td class='qrcodetdlight'/>";
-				}
-			}
-			tableHtml += "</tr>";
-		}
-		tableHtml += "</table>";
-		return tableHtml;
-	},
+		var showCrypto = function () {
+			document.getElementById('statuscrypto' + cryptoCase).style.display = 'block';
+		};
 
-	// show QRCodes with canvas OR table (IE8)
-	// parameter: keyValuePair 
-	// example: { "id1": "string1", "id2": "string2"}
-	//		"id1" is the id of a div element where you want a QRCode inserted.
-	//		"string1" is the string you want encoded into the QRCode.
-	showQrCode: function (keyValuePair, sizeMultiplier) {
-		for (var key in keyValuePair) {
-			var value = keyValuePair[key];
-			try {
-				if (document.getElementById(key)) {
-					document.getElementById(key).innerHTML = "";
-					document.getElementById(key).appendChild(ninja.qrCode.createCanvas(value, sizeMultiplier));
-				}
-			}
-			catch (e) {
-				// for browsers that do not support canvas (IE8)
-				document.getElementById(key).innerHTML = ninja.qrCode.createTableHtml(value);
-			}
-		}
-	}
-};
+		var showProtocol = function () {
+			document.getElementById('statusprotocol' + protocolCase).style.display = 'block';
+		};
+
+		var showUnitTests = function () {
+			if(unitTestsCase != "") document.getElementById('statusunittests' + unitTestsCase).style.display = 'block';
+		};
+
+		return { unitTests: unitTests, showCrypto: showCrypto, showProtocol: showProtocol, showUnitTests: showUnitTests };
+	}();
+})(ninja);
 
 ninja.tab = {
     select: function (walletTab) {
diff --git a/src/ninja.onload.js b/src/ninja.onload.js
index 1962561..6856a23 100644
--- a/src/ninja.onload.js
+++ b/src/ninja.onload.js
@@ -1,6 +1,6 @@
 // run unit tests
 if (ninja.getQueryString()["unittests"] == "true" || ninja.getQueryString()["unittests"] == "1") {
-	ninja.unitTests.runSynchronousTests();
+	ninja.unitTests.runSynchronousTests(true);
 	ninja.translator.showEnglishJson();
 }
 // run async unit tests
diff --git a/src/ninja.qrcode.js b/src/ninja.qrcode.js
new file mode 100644
index 0000000..d53d181
--- /dev/null
+++ b/src/ninja.qrcode.js
@@ -0,0 +1,94 @@
+(function (ninja) {
+	var qrC = ninja.qrCode = {
+		// determine which type number is big enough for the input text length
+		getTypeNumber: function (text) {
+			var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
+			if (lengthCalculation < 72) { return 1; }
+			else if (lengthCalculation < 128) { return 2; }
+			else if (lengthCalculation < 208) { return 3; }
+			else if (lengthCalculation < 288) { return 4; }
+			else if (lengthCalculation < 368) { return 5; }
+			else if (lengthCalculation < 480) { return 6; }
+			else if (lengthCalculation < 528) { return 7; }
+			else if (lengthCalculation < 688) { return 8; }
+			else if (lengthCalculation < 800) { return 9; }
+			else if (lengthCalculation < 976) { return 10; }
+			return null;
+		},
+
+		createCanvas: function (text, sizeMultiplier) {
+			sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
+			// create the qrcode itself
+			var typeNumber = qrC.getTypeNumber(text);
+			var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
+			qrcode.addData(text);
+			qrcode.make();
+			var width = qrcode.getModuleCount() * sizeMultiplier;
+			var height = qrcode.getModuleCount() * sizeMultiplier;
+			// create canvas element
+			var canvas = document.createElement('canvas');
+			var scale = 10.0;
+			canvas.width = width * scale;
+			canvas.height = height * scale;
+			canvas.style.width = width + 'px';
+			canvas.style.height = height + 'px';
+			var ctx = canvas.getContext('2d');
+			ctx.scale(scale, scale);
+			// compute tileW/tileH based on width/height
+			var tileW = width / qrcode.getModuleCount();
+			var tileH = height / qrcode.getModuleCount();
+			// draw in the canvas
+			for (var row = 0; row < qrcode.getModuleCount() ; row++) {
+				for (var col = 0; col < qrcode.getModuleCount() ; col++) {
+					ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
+					ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
+				}
+			}
+			// return just built canvas
+			return canvas;
+		},
+
+		// generate a QRCode and return it's representation as an Html table 
+		createTableHtml: function (text) {
+			var typeNumber = qrC.getTypeNumber(text);
+			var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
+			qr.addData(text);
+			qr.make();
+			var tableHtml = "<table class='qrcodetable'>";
+			for (var r = 0; r < qr.getModuleCount() ; r++) {
+				tableHtml += "<tr>";
+				for (var c = 0; c < qr.getModuleCount() ; c++) {
+					if (qr.isDark(r, c)) {
+						tableHtml += "<td class='qrcodetddark'/>";
+					} else {
+						tableHtml += "<td class='qrcodetdlight'/>";
+					}
+				}
+				tableHtml += "</tr>";
+			}
+			tableHtml += "</table>";
+			return tableHtml;
+		},
+
+		// show QRCodes with canvas OR table (IE8)
+		// parameter: keyValuePair 
+		// example: { "id1": "string1", "id2": "string2"}
+		//		"id1" is the id of a div element where you want a QRCode inserted.
+		//		"string1" is the string you want encoded into the QRCode.
+		showQrCode: function (keyValuePair, sizeMultiplier) {
+			for (var key in keyValuePair) {
+				var value = keyValuePair[key];
+				try {
+					if (document.getElementById(key)) {
+						document.getElementById(key).innerHTML = "";
+						document.getElementById(key).appendChild(qrC.createCanvas(value, sizeMultiplier));
+					}
+				}
+				catch (e) {
+					// for browsers that do not support canvas (IE8)
+					document.getElementById(key).innerHTML = qrC.createTableHtml(value);
+				}
+			}
+		}
+	};
+})(ninja);
\ No newline at end of file
diff --git a/src/ninja.seeder.js b/src/ninja.seeder.js
new file mode 100644
index 0000000..14a0659
--- /dev/null
+++ b/src/ninja.seeder.js
@@ -0,0 +1,112 @@
+ninja.seeder = {
+	init: (function () {
+		document.getElementById("generatekeyinput").value = "";
+	})(),
+
+	// number of mouse movements to wait for
+	seedLimit: (function () {
+		var num = Crypto.util.randomBytes(12)[11];
+		return 200 + Math.floor(num);
+	})(),
+
+	seedCount: 0, // counter
+	lastInputTime: new Date().getTime(),
+	seedPoints: [],
+	isStillSeeding: true,
+	seederDependentWallets: ["singlewallet", "paperwallet", "bulkwallet", "vanitywallet", "splitwallet"],
+
+	// seed function exists to wait for mouse movement to add more entropy before generating an address
+	seed: function (evt) {
+		if (!evt) var evt = window.event;
+		var timeStamp = new Date().getTime();
+		// seeding is over now we generate and display the address
+		if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
+			ninja.seeder.seedCount++;
+			ninja.seeder.seedingOver();
+		}
+			// seed mouse position X and Y when mouse movements are greater than 40ms apart.
+		else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
+			SecureRandom.seedTime();
+			SecureRandom.seedInt16((evt.clientX * evt.clientY));
+			ninja.seeder.showPoint(evt.clientX, evt.clientY);
+			ninja.seeder.seedCount++;
+			ninja.seeder.lastInputTime = new Date().getTime();
+			ninja.seeder.showPool();
+		}
+	},
+
+	// seed function exists to wait for mouse movement to add more entropy before generating an address
+	seedKeyPress: function (evt) {
+		if (!evt) var evt = window.event;
+		// seeding is over now we generate and display the address
+		if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
+			ninja.seeder.seedCount++;
+			ninja.seeder.seedingOver();
+		}
+			// seed key press character
+		else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
+			var timeStamp = new Date().getTime();
+			// seed a bunch (minimum seedLimit) of times
+			SecureRandom.seedTime();
+			SecureRandom.seedInt8(evt.which);
+			var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
+			SecureRandom.seedInt8(keyPressTimeDiff);
+			ninja.seeder.seedCount++;
+			ninja.seeder.lastInputTime = new Date().getTime();
+			ninja.seeder.showPool();
+		}
+	},
+
+	showPool: function () {
+		var poolHex;
+		if (SecureRandom.poolCopyOnInit != null) {
+			poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
+			document.getElementById("seedpool").innerHTML = poolHex;
+			document.getElementById("seedpooldisplay").innerHTML = poolHex;
+		}
+		else {
+			poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
+			document.getElementById("seedpool").innerHTML = poolHex;
+			document.getElementById("seedpooldisplay").innerHTML = poolHex;
+		}
+		var percentSeeded = Math.round((ninja.seeder.seedCount / ninja.seeder.seedLimit) * 100) + "%";
+		document.getElementById("mousemovelimit").innerHTML = percentSeeded;
+		for (var wIndex in ninja.seeder.seederDependentWallets) {
+			document.getElementById(ninja.seeder.seederDependentWallets[wIndex]).innerHTML = percentSeeded;
+		}
+	},
+
+	showPoint: function (x, y) {
+		var div = document.createElement("div");
+		div.setAttribute("class", "seedpoint");
+		div.style.top = y + "px";
+		div.style.left = x + "px";
+		document.body.appendChild(div);
+		ninja.seeder.seedPoints.push(div);
+	},
+
+	removePoints: function () {
+		for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
+			document.body.removeChild(ninja.seeder.seedPoints[i]);
+		}
+		ninja.seeder.seedPoints = [];
+	},
+
+	seedingOver: function () {
+		ninja.seeder.isStillSeeding = false;
+		// run sync unit tests
+		ninja.status.unitTests();
+		// open selected tab
+		var walletType = ninja.tab.whichIsOpen();
+		if (walletType == null) {
+			ninja.tab.select("singlewallet");
+		} else {
+			ninja.tab.select(walletType)
+		}
+		document.getElementById("generate").style.display = "none";
+		// update labels for dependent wallets
+		var culture = (ninja.getQueryString()["culture"] == null ? "en" : ninja.getQueryString()["culture"]);
+		ninja.translator.translate(culture);
+		ninja.seeder.removePoints();
+	}
+};
diff --git a/src/ninja.translator.js b/src/ninja.translator.js
index 30ab2fc..2bf061e 100644
--- a/src/ninja.translator.js
+++ b/src/ninja.translator.js
@@ -124,6 +124,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Copyright del código JavaScript: en el fuente.",
 			"footerlabelnowarranty": "Sin garantía.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Generar dirección",
 			"singleprint": "Imprimir",
@@ -262,7 +284,29 @@ ninja.translator = {
 			"footerlabelcopyright1": "Copyright bitaddress.org.",
 			"footerlabelcopyright2": "Les droits d'auteurs JavaScript sont inclus dans le code source.",
 			"footerlabelnowarranty": "Aucune garantie.",
-			
+
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Générer Une Nouvelle Adresse",
 			"singleprint": "Imprimer",
@@ -276,7 +320,6 @@ ninja.translator = {
 			"singleshare": "PARTAGER",
 			"singlesecret": "SECRET",
 
-
 			// paper wallet html
 			"paperlabelhideart": "Enlever l'image ?",
 			"paperlabeladdressesperpage": "Adresses par page:",
@@ -403,6 +446,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Τα πνευματικά δικαιώματα της JavaScript περιλαμβάνονται στον κώδικα.",
 			"footerlabelnowarranty": "Καμία εγγύηση.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Δημιουργία μιας νέας Διεύθυνσης",
 			"singleprint": "Εκτύπωση",
@@ -542,6 +607,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Le note di copyright dei file JavaScript sono inclusi nei sorgenti stessi.",
 			"footerlabelnowarranty": "Nessuna garanzia.",
 
+	    	// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Genera un Nuovo Indirizzo",
 			"singleprint": "Stampa",
@@ -681,6 +768,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "JavaScript-Copyrights sind im Quelltext enthalten.",
 			"footerlabelnowarranty": "Ohne Gew&auml;hr.",
 
+	    	// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Neues Wallet erstellen",
 			"singleprint": "Drucken",
@@ -820,6 +929,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Copyright JavaScriptu je uveden ve zdrojovém kódu.",
 			"footerlabelnowarranty": "Bez záruky.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Vytvořit novou adresu",
 			"singleprint": "Tisk",
@@ -959,6 +1090,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Az egyes JavaScript kódok szerzőinek jogai a forráskódon belül találhatók meg.",
 			"footerlabelnowarranty": "Garancia nincs.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Új cím előállítása",
 			"singleprint": "Nyomtatás",
@@ -1104,6 +1257,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "JavaScriptのコピーライト情報はソースに含まれています。",
 			"footerlabelnowarranty": "保障はありません。",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "新アドレス生成",
 			"singleprint": "印刷",
@@ -1250,6 +1425,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "Copyright do código JavaScript: no código-fonte.",
 			"footerlabelnowarranty": "Sem garantia.",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "Gerar endereço",
 			"singleprint": "Imprimir",
@@ -1389,6 +1586,28 @@ ninja.translator = {
 			"footerlabelcopyright2": "JavaScript的版权信息已经包含在源代码中。",
 			"footerlabelnowarranty": "No warranty",
 
+			// status html
+			"statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+			"statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+			"statusokcryptogood": "OK", //TODO: please translate
+			"statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+			"statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+			"statusokcryptobad": "OK", //TODO: please translate
+			"statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+			"statusokunittestsgood": "OK", //TODO: please translate
+			"statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+			"statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+			"statusokunittestsbad": "OK", //TODO: please translate
+			"statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+			"statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+			"statusokprotocolgood": "OK", //TODO: please translate
+			"statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+			"statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+			"statuslabelprotocolbad2": "download", //TODO: please translate
+			"statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+			"statusokprotocolbad": "OK", //TODO: please translate
+
 			// single wallet html
 			"newaddress": "生成新地址",
 			"singleprint": "打印",
@@ -1534,6 +1753,28 @@ ninja.translator = {
             "footerlabelcopyright2": "Информация о копирайте на JavaScript в исходниках.",
             "footerlabelnowarranty": "Без гарантий.",
 
+        	// status html
+            "statuslabelcryptogood": "&#10004; Good!", //TODO: please translate
+            "statuslabelcryptogood1": "Your browser can generate cryptographically random keys using window.crypto.getRandomValues", //TODO: please translate
+            "statusokcryptogood": "OK", //TODO: please translate
+            "statuslabelcryptobad": "&times; Oh no!", //TODO: please translate
+            "statuslabelcryptobad1": "Your browser does NOT support window.crypto.getRandomValues. You should use a more modern browser with this generator to increase the security of the keys generated.",
+            "statusokcryptobad": "OK", //TODO: please translate
+            "statuslabelunittestsgood": "&#10004; Good!", //TODO: please translate
+            "statuslabelunittestsgood1": "All synchronous unit tests passed.", //TODO: please translate
+            "statusokunittestsgood": "OK", //TODO: please translate
+            "statuslabelunittestsbad": "&times; Oh no!", //TODO: please translate
+            "statuslabelunittestsbad1": "Some synchronous unit tests DID NOT pass. You should find another browser to use with this generator.", //TODO: please translate
+            "statusokunittestsbad": "OK", //TODO: please translate
+            "statuslabelprotocolgood": "&#10004; Good!", //TODO: please translate
+            "statuslabelprotocolgood1": "You are running this generator from your local computer. <br />Tip: Double check you are offline by trying ", //TODO: please translate
+            "statusokprotocolgood": "OK", //TODO: please translate
+            "statuslabelprotocolbad": "&#9888; Think twice!", //TODO: please translate
+            "statuslabelprotocolbad1": "You appear to be running this generator online from a live website. For valuable wallets it is recommended to", //TODO: please translate
+            "statuslabelprotocolbad2": "download", //TODO: please translate
+            "statuslabelprotocolbad3": "the zip file from GitHub and run this generator offline as a local html file.", //TODO: please translate
+            "statusokprotocolbad": "OK", //TODO: please translate
+
             // single wallet html
             "newaddress": "Сгенерировать новый адрес",
             "singleprint": "Распечатать",
diff --git a/src/ninja.unittests.js b/src/ninja.unittests.js
index b97f38f..9129423 100644
--- a/src/ninja.unittests.js
+++ b/src/ninja.unittests.js
@@ -1,10 +1,12 @@
 (function (ninja) {
 	var ut = ninja.unitTests = {
-		runSynchronousTests: function () {
-			document.getElementById("busyblock").className = "busy";
-			var div = document.createElement("div");
-			div.setAttribute("class", "unittests");
-			div.setAttribute("id", "unittests");
+		runSynchronousTests: function (showOutput) {
+			if (showOutput) {
+				document.getElementById("busyblock").className = "busy";
+				var div = document.createElement("div");
+				div.setAttribute("class", "unittests");
+				div.setAttribute("id", "unittests");
+			}
 			var testResults = "";
 			var passCount = 0;
 			var testCount = 0;
@@ -31,10 +33,12 @@
 			if (passCount < testCount) {
 				testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
 			}
-			div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
-			document.body.appendChild(div);
-			document.getElementById("busyblock").className = "";
-
+			if (showOutput) {
+				div.innerHTML = "<h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
+				document.body.appendChild(div);
+				document.getElementById("busyblock").className = "";
+			}
+			return { passCount: passCount, testCount: testCount };
 		},
 
 		runAsynchronousTests: function () {