+Welcome. Your machine is currently validating the segnet4 blockchain.
+The blocks and wallet are stored on your local disk with indexed DB. You are
+connecting to the actual bitcoin P2P network via a websocket->tcp proxy.
+Enjoy. (See the bcoin repo for
+more bitcoin magic).
+
+ Last 20 Blocks/TXs:
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/proxysocket.js b/browser/proxysocket.js
new file mode 100644
index 00000000..32f14e64
--- /dev/null
+++ b/browser/proxysocket.js
@@ -0,0 +1,136 @@
+var bcoin = require('../lib/bcoin/env');
+var utils = require('../lib/bcoin/utils');
+var BufferWriter = require('../lib/bcoin/writer');
+var assert = utils.assert;
+var EventEmitter = require('events').EventEmitter;
+var IOClient = require('socket.io-client');
+
+function ProxySocket(uri) {
+ var self = this;
+
+ if (!(this instanceof ProxySocket))
+ return new ProxySocket(uri);
+
+ EventEmitter.call(this);
+
+ this.info = null;
+
+ this.socket = new IOClient(uri, { reconnection: false });
+ this.sendBuffer = [];
+ this.snonce = null;
+
+ this.closed = false;
+
+ this.socket.on('info', function(info) {
+ if (self.closed)
+ return;
+
+ self.info = info;
+
+ if (info.pow) {
+ self.snonce = new Buffer(info.snonce, 'hex');
+ self.target = new Buffer(info.target, 'hex');
+ }
+
+ self.emit('info', info);
+ });
+
+ this.socket.on('error', function(err) {
+ console.error(err);
+ });
+
+ this.socket.on('tcp connect', function() {
+ if (self.closed)
+ return;
+ self.emit('connect');
+ });
+
+ this.socket.on('tcp data', function(data) {
+ self.emit('data', new Buffer(data, 'hex'));
+ });
+
+ this.socket.on('tcp close', function(data) {
+ if (self.closed)
+ return;
+ self.closed = true;
+ self.emit('close');
+ });
+
+ this.socket.on('tcp error', function(err) {
+ self.emit('error', new Error(err));
+ });
+
+ this.socket.on('close', function() {
+ if (self.closed)
+ return;
+ self.closed = true;
+ self.emit('close');
+ });
+}
+
+utils.inherits(ProxySocket, EventEmitter);
+
+ProxySocket.prototype.connect = function connect(port, host) {
+ var nonce = 0;
+ var i, pow;
+
+ if (this.closed) {
+ this.sendBuffer.length = 0;
+ return;
+ }
+
+ if (!this.info)
+ return this.once('info', connect.bind(this, port, host));
+
+ if (this.info.pow) {
+ bcoin.debug(
+ 'Solving proof of work to create socket (%d, %s) -- please wait.',
+ port, host);
+
+ pow = new BufferWriter();
+ pow.writeU32(nonce);
+ pow.writeBytes(this.snonce);
+ pow.writeU32(port);
+ pow.writeString(host, 'ascii');
+ pow = pow.render();
+
+ do {
+ nonce++;
+ assert(nonce <= 0xffffffff, 'Could not create socket.');
+ pow.writeUInt32LE(nonce, 0, true);
+ } while (utils.cmp(utils.dsha256(pow), this.target) >= 0);
+
+ bcoin.debug('Solved proof of work: %d', nonce);
+ }
+
+ this.socket.emit('tcp connect', port, host, nonce);
+
+ for (i = 0; i < this.sendBuffer.length; i++)
+ this.write(this.sendBuffer[i]);
+
+ this.sendBuffer.length = 0;
+};
+
+ProxySocket.prototype.write = function write(data) {
+ if (!this.info) {
+ this.sendBuffer.push(data);
+ return true;
+ }
+ this.socket.emit('tcp data', data.toString('hex'));
+ return true;
+};
+
+ProxySocket.prototype.destroy = function destroy() {
+ if (this.closed)
+ return;
+ this.closed = true;
+ this.socket.disconnect();
+};
+
+ProxySocket.connect = function connect(uri, port, host) {
+ var socket = new ProxySocket(uri);
+ socket.connect(port, host);
+ return socket;
+};
+
+module.exports = ProxySocket;
diff --git a/browser/server.js b/browser/server.js
new file mode 100644
index 00000000..00905918
--- /dev/null
+++ b/browser/server.js
@@ -0,0 +1,31 @@
+var HTTPBase = require('../lib/bcoin/http/base');
+var fs = require('fs');
+
+var server = new HTTPBase();
+var proxy = require('./wsproxy')({
+ pow: process.argv.indexOf('--pow') !== -1
+});
+
+var index = fs.readFileSync(__dirname + '/index.html');
+var bcoin = fs.readFileSync(__dirname + '/bcoin.js');
+var worker = fs.readFileSync(__dirname + '/../lib/bcoin/worker.js');
+
+server.get('/favicon.ico', function(req, res, next, send) {
+ send(404, '', 'text');
+});
+
+server.get('/', function(req, res, next, send) {
+ send(200, index, 'html');
+});
+
+server.get('/bcoin.js', function(req, res, next, send) {
+ send(200, bcoin, 'js');
+});
+
+server.get('/bcoin-worker.js', function(req, res, next, send) {
+ send(200, worker, 'js');
+});
+
+proxy.attach(server.server);
+
+server.listen(8080);
diff --git a/browser/setimmediate.js b/browser/setimmediate.js
new file mode 100644
index 00000000..d5c57e6d
--- /dev/null
+++ b/browser/setimmediate.js
@@ -0,0 +1,197 @@
+/*!
+ * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+(function (global, undefined) {
+ "use strict";
+
+ if (global.setImmediate) {
+ return;
+ }
+
+ var nextHandle = 1; // Spec says greater than zero
+ var tasksByHandle = {};
+ var currentlyRunningATask = false;
+ var doc = global.document;
+ var setImmediate;
+
+ function addFromSetImmediateArguments(args) {
+ tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
+ return nextHandle++;
+ }
+
+ // This function accepts the same arguments as setImmediate, but
+ // returns a function that requires no arguments.
+ function partiallyApplied(handler) {
+ var args = [].slice.call(arguments, 1);
+ return function() {
+ if (typeof handler === "function") {
+ handler.apply(undefined, args);
+ } else {
+ (new Function("" + handler))();
+ }
+ };
+ }
+
+ function runIfPresent(handle) {
+ // From the spec: "Wait until any invocations of this algorithm started before this one have completed."
+ // So if we're currently running a task, we'll need to delay this invocation.
+ if (currentlyRunningATask) {
+ // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
+ // "too much recursion" error.
+ setTimeout(partiallyApplied(runIfPresent, handle), 0);
+ } else {
+ var task = tasksByHandle[handle];
+ if (task) {
+ currentlyRunningATask = true;
+ try {
+ task();
+ } finally {
+ clearImmediate(handle);
+ currentlyRunningATask = false;
+ }
+ }
+ }
+ }
+
+ function clearImmediate(handle) {
+ delete tasksByHandle[handle];
+ }
+
+ function installNextTickImplementation() {
+ setImmediate = function() {
+ var handle = addFromSetImmediateArguments(arguments);
+ process.nextTick(partiallyApplied(runIfPresent, handle));
+ return handle;
+ };
+ }
+
+ function canUsePostMessage() {
+ // The test against `importScripts` prevents this implementation from being installed inside a web worker,
+ // where `global.postMessage` means something completely different and can't be used for this purpose.
+ if (global.postMessage && !global.importScripts) {
+ var postMessageIsAsynchronous = true;
+ var oldOnMessage = global.onmessage;
+ global.onmessage = function() {
+ postMessageIsAsynchronous = false;
+ };
+ global.postMessage("", "*");
+ global.onmessage = oldOnMessage;
+ return postMessageIsAsynchronous;
+ }
+ }
+
+ function installPostMessageImplementation() {
+ // Installs an event handler on `global` for the `message` event: see
+ // * https://developer.mozilla.org/en/DOM/window.postMessage
+ // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
+
+ var messagePrefix = "setImmediate$" + Math.random() + "$";
+ var onGlobalMessage = function(event) {
+ if (event.source === global &&
+ typeof event.data === "string" &&
+ event.data.indexOf(messagePrefix) === 0) {
+ runIfPresent(+event.data.slice(messagePrefix.length));
+ }
+ };
+
+ if (global.addEventListener) {
+ global.addEventListener("message", onGlobalMessage, false);
+ } else {
+ global.attachEvent("onmessage", onGlobalMessage);
+ }
+
+ setImmediate = function() {
+ var handle = addFromSetImmediateArguments(arguments);
+ global.postMessage(messagePrefix + handle, "*");
+ return handle;
+ };
+ }
+
+ function installMessageChannelImplementation() {
+ var channel = new MessageChannel();
+ channel.port1.onmessage = function(event) {
+ var handle = event.data;
+ runIfPresent(handle);
+ };
+
+ setImmediate = function() {
+ var handle = addFromSetImmediateArguments(arguments);
+ channel.port2.postMessage(handle);
+ return handle;
+ };
+ }
+
+ function installReadyStateChangeImplementation() {
+ var html = doc.documentElement;
+ setImmediate = function() {
+ var handle = addFromSetImmediateArguments(arguments);
+ // Create a