veyron-browser: Initial scaffold of the veyron-browse app using
Mercury.

This initial setup includes:
-Sidebar with navigation links to Browse and Help pages
-Browse page simply has two inputs and displays the value of
those inputs as they change. (ie. No actual functionality )
-Hash-based routing between the top level navigation
pages with History support.
-Build system

Change-Id: I9f7ee3b6dc13bc7685f5b14a0891353e9eacdaf1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a230a4e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+node_modules/
+bower_components/
+public/bundle.*
+public/platform.js
+npm-debug.log
\ No newline at end of file
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..e33a040
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,27 @@
+{
+  "browser": true,
+  "camelcase": true,
+  "curly": true,
+  "eqeqeq": true,
+  "forin": true,
+  "freeze": true,
+  "immed": true,
+  "indent": 2,
+  "latedef": "nofunc",
+  "newcap": true,
+  "noarg": true,
+  "nonbsp": true,
+  "nonew": true,
+  "quotmark": "single",
+  "undef": true,
+  "unused": "vars",
+  "trailing": true,
+  "maxlen": 80,
+  "devel": true,
+  "expr": true,
+  "sub": true,
+  "node": true,
+  "globals": {
+    "Promise": true
+  }
+}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..82d5493
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,65 @@
+PATH:=$(VEYRON_ROOT)/environment/cout/node/bin:$(PATH)
+PATH:=node_modules/.bin:$(PATH)
+
+# All JS files except build.js and third party
+JS_FILES = $(shell find browser -name "*.js")
+
+# Builds everything
+all: public/bundle.js public/bundle.html public/platform.js
+
+# Creating the bundle JS file
+public/bundle.js: $(JS_FILES) node_modules
+	jshint browser # lint all browser JavaScript files
+	browserify browser/app.js -o public/bundle.js
+
+# Creating the bundle HTML file
+public/bundle.html: web-component-dependencies.html node_modules bower_components
+	vulcanize --output public/bundle.html web-component-dependencies.html --inline
+
+# Copies the web components platform file
+public/platform.js: bower_components
+	cp bower_components/platform/platform.js public/platform.js
+
+# Install what we need from NPM
+node_modules: package.json
+	npm prune
+	npm install
+	touch node_modules
+
+# Install non-JS dependencies from bower
+bower_components: bower.json node_modules
+	bower prune
+	bower install
+	touch bower_components
+
+# PHONY targets:
+
+# Uses prova to run tests in a headless chrome and then quit after all test finish
+test:
+	jshint test # lint all test JavaScript files
+	prova test/**/*.js --browser --launch chrome --headless --progress --quit
+
+# Continuously watch for changes to .js, .html or .css files.
+# Rebundles the appropriate bundles when local files change
+watch:
+	watch -n 1 make
+
+# Continuously reruns the tests as they change
+watch-test:
+	@echo "Tests being watched at: http://0.0.0.0:7559"
+	prova test/**/*.js --browser --launch chrome
+
+# Serves the needed daemons and starts a server at http://localhost:$(HTTP_PORT)
+# CTRL-C to stop
+start:
+	./services.sh
+
+# Clean all build artifacts
+clean:
+	rm -f public/bundle.js
+	rm -f public/bundle.html
+	rm -f public/platform.js
+	rm -rf node_modules
+	rm -rf bower_components
+
+.PHONY: start clean watch test watch-test
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e5039a3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# Mounttable Browser
+Mountable browser is a browser application that lets the user view and traverse mounttables.
+
+## Building
+Before you can run Mounttable Browser, you need to build. Simply run:
+
+```sh
+make
+```
+
+## Running
+
+```sh
+make start
+```
+and navigate to http://localhost:9000
+
+to stop simply CTRL-C the console running the make start
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..df95fef
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,12 @@
+{
+  "name": "veyron-browser",
+  "dependencies": {
+    "core-drawer-panel": "Polymer/core-drawer-panel#~0.3.4",
+    "core-header-panel": "Polymer/core-header-panel#~0.3.4",
+    "core-item": "Polymer/core-item#~0.3.4",
+    "core-icons": "Polymer/core-icons#~0.3.4",
+    "core-menu": "Polymer/core-menu#~0.3.4",
+    "core-toolbar": "Polymer/core-toolbar#~0.3.4",
+    "paper-button": "Polymer/paper-button#~0.3.4"
+  }
+}
diff --git a/browser/app.js b/browser/app.js
new file mode 100644
index 0000000..b136bba
--- /dev/null
+++ b/browser/app.js
@@ -0,0 +1,65 @@
+var mercury = require('mercury');
+var onDocumentReady = require('./lib/document-ready');
+var Viewport = require('./components/viewport/index');
+var router = require('./router');
+var browse = require('./components/browse/index');
+
+onDocumentReady(function startApp() {
+
+  var browseComponent = browse();
+
+  // Top level state
+  var state = mercury.struct({
+    /*
+     * Navigation related states
+     */
+    navigation: mercury.struct({
+      /*
+       * Identifier for the currently displayed page.
+       * Mutable via route handlers
+       * @type {string}
+       */
+      pageKey: mercury.value(null)
+    }),
+    /*
+     * Veyron Namespace Browsing related states
+     */
+    browse: browseComponent.state
+  });
+
+  // To level events
+  var events = mercury.input([
+    /*
+     * Navigation related events
+     */
+    'navigation',
+
+    /*
+     * Veyron Namespace Browsing related events
+     * Source: components/browse/events
+     */
+    'browse'
+  ]);
+  events.navigation = mercury.input([
+    /*
+     * Indicates a navigation request to a resource
+     * Data of form:
+     * {
+     *   path: 'path/to/resource'
+     * }
+     * is expected as data for the event
+     */
+    'navigate'
+  ]);
+  events.browse = browseComponent.events;
+
+  // Start the router which will register the application routes
+  router(state, events);
+
+  // Render the app
+  var render = function(state) {
+    return Viewport.render(state, events);
+  };
+  mercury.app(document.body, state, render);
+
+});
\ No newline at end of file
diff --git a/browser/components/browse/index.js b/browser/components/browse/index.js
new file mode 100644
index 0000000..64c5136
--- /dev/null
+++ b/browser/components/browse/index.js
@@ -0,0 +1,72 @@
+var mercury = require('mercury');
+var browseNamespace = require('./update/browseNamespace');
+var h = mercury.h;
+
+module.exports = create;
+module.exports.render = render;
+
+/*
+ * Browse component provides user interfaces for browsing the Veyron namespace
+ */
+function create() {
+
+  var state = mercury.struct({
+    /*
+     * Current Veyron namespace being displayed and queried
+     * @type {string}
+     */
+    namespace: mercury.value(null),
+
+    /*
+     * Current Glob query applied to the Veyron namespace
+     * @type {string}
+     */
+    globQuery: mercury.value(null)
+  });
+
+  var events = mercury.input([
+    /*
+     * Indicates a request to browse the Veyron namespace
+     * Data of form:
+     * {
+     *   namespace: '/veyron/name/space',
+     *   globQuery: '*',
+     * }
+     * is expected as data for the event
+     */
+    'browseNamespace'
+  ]);
+
+  wireUpEvents(state, events);
+
+  return {
+    state: state,
+    events: events
+  };
+}
+
+function render(browseState, browseEvents) {
+
+  // Trigger browseNamespace event when value of the inputs change
+  var changeEvent = mercury.valueEvent(browseEvents.browseNamespace);
+
+  return [
+    h('input', {
+      'name': 'namespace',
+      'value': browseState.namespace,
+      'ev-change': changeEvent
+    }),
+    h('input', {
+      'name': 'globQuery',
+      'value': browseState.globQuery,
+      'ev-change': changeEvent
+    }),
+    h('div', ['Current Namespace:', browseState.namespace]),
+    h('div', ['Current GlobQuery:', browseState.globQuery])
+  ];
+}
+
+// Wire up events that we know how to handle
+function wireUpEvents(state, events) {
+  events.browseNamespace(browseNamespace.bind(null, state));
+}
\ No newline at end of file
diff --git a/browser/components/browse/update/browseNamespace.js b/browser/components/browse/update/browseNamespace.js
new file mode 100644
index 0000000..e8bdfd7
--- /dev/null
+++ b/browser/components/browse/update/browseNamespace.js
@@ -0,0 +1,22 @@
+var exists = require('../../../lib/exists');
+
+module.exports = browseNamespace;
+
+/*
+ * Default event handler for the browseNamespace event.
+ * Updates the necessary states when browseNamespace is triggered
+ * Data is of the form
+ * {
+ *   namespace: '/veyron/name/space',
+ *   globQuery: '*',
+ * }
+ */
+function browseNamespace(browseState, data) {
+  if (exists(data.namespace) && data.namespace !== '') {
+    browseState.namespace.set(data.namespace);
+  }
+
+  if (exists(data.globQuery) && data.globQuery !== '') {
+    browseState.globQuery.set(data.globQuery);
+  }
+}
\ No newline at end of file
diff --git a/browser/components/help/index.js b/browser/components/help/index.js
new file mode 100644
index 0000000..d8f105a
--- /dev/null
+++ b/browser/components/help/index.js
@@ -0,0 +1,14 @@
+var mercury = require('mercury');
+var h = mercury.h;
+
+module.exports = create;
+module.exports.render = render;
+
+/*
+ * Help view
+ */
+function create() {}
+
+function render() {
+  return h('span', 'HELP! TODO(aghassemi)');
+}
\ No newline at end of file
diff --git a/browser/components/main-content/index.js b/browser/components/main-content/index.js
new file mode 100644
index 0000000..91de473
--- /dev/null
+++ b/browser/components/main-content/index.js
@@ -0,0 +1,32 @@
+var mercury = require('mercury');
+var Browse = require('../browse/index');
+var Help = require('../help/index');
+var h = mercury.h;
+
+module.exports = create;
+module.exports.render = render;
+
+/*
+ * MainContent part of the layout
+ */
+function create() {}
+
+function render(state, events) {
+  return [
+    h('h1', state.navigation.pageKey),
+    h('div', renderContent(state, events))
+  ];
+}
+
+function renderContent(state, events) {
+  var pageKey = state.navigation.pageKey;
+  switch (pageKey) {
+    case 'browse':
+      return Browse.render(state.browse, events.browse);
+    case 'help':
+      return Help.render();
+    default:
+      // We shouldn't get here with proper route handlers, so it's an error(bug)
+      throw new Error('Could not find page ' + pageKey);
+  }
+}
\ No newline at end of file
diff --git a/browser/components/sidebar/index.js b/browser/components/sidebar/index.js
new file mode 100644
index 0000000..1792ef8
--- /dev/null
+++ b/browser/components/sidebar/index.js
@@ -0,0 +1,53 @@
+var mercury = require('mercury');
+var h = mercury.h;
+
+module.exports = create;
+module.exports.render = render;
+
+/*
+ * Sidebar part of the layout
+ */
+function create() {}
+
+function render(navigationState, navigationEvents) {
+  return [
+    h('core-toolbar', [
+      h('h1', 'Veyron Browser')
+    ]),
+    h('core-menu', {
+        'selected': navigationState.pageKey,
+        'valueattr': 'itemKey'
+      },
+      renderNavigationItems(navigationEvents)
+    )
+  ];
+}
+
+var navigationItems = [{
+  key: 'browse',
+  label: 'Browse',
+  icon: 'search'
+}, {
+  key: 'help',
+  label: 'Help',
+  icon: 'help'
+}];
+
+function renderNavigationItems(navigationEvents) {
+  return navigationItems.map(function createMenuItem(navItem) {
+    return h('core-item', {
+      'itemKey': navItem.key,
+      'icon': navItem.icon,
+      'label': navItem.label
+    }, [
+      h('a', {
+        'href': '#/' + navItem.key,
+        'ev-click': mercury.event(
+          navigationEvents.navigate, {
+            path: '/' + navItem.key
+          }
+        )
+      })
+    ]);
+  });
+}
\ No newline at end of file
diff --git a/browser/components/viewport/index.js b/browser/components/viewport/index.js
new file mode 100644
index 0000000..f223eca
--- /dev/null
+++ b/browser/components/viewport/index.js
@@ -0,0 +1,28 @@
+var mercury = require('mercury');
+var AttributeHook = require('../../lib/mercury/attribute-hook');
+var Sidebar = require('../sidebar/index');
+var MainContent = require('../main-content/index');
+var h = mercury.h;
+
+module.exports = create;
+module.exports.render = render;
+
+/*
+ * Page level layout of the application
+ */
+function create() {}
+
+function render(state, events) {
+  return h('core-drawer-panel', [
+    h('core-header-panel', {
+        'drawer': new AttributeHook(true)
+      },
+      Sidebar.render(state.navigation, events.navigation)
+    ),
+    h('core-header-panel', {
+        'main': new AttributeHook(true)
+      },
+      MainContent.render(state, events)
+    )
+  ]);
+}
\ No newline at end of file
diff --git a/browser/lib/document-ready.js b/browser/lib/document-ready.js
new file mode 100644
index 0000000..4974140
--- /dev/null
+++ b/browser/lib/document-ready.js
@@ -0,0 +1,8 @@
+module.exports = onDocumentReady;
+
+function onDocumentReady(cb) {
+
+  // Since we are using third-party polymer to Polyfill for web components.
+  // We wait for polymer-ready before triggering document ready.
+  document.addEventListener('polymer-ready', cb);
+}
\ No newline at end of file
diff --git a/browser/lib/exists.js b/browser/lib/exists.js
new file mode 100644
index 0000000..44581d9
--- /dev/null
+++ b/browser/lib/exists.js
@@ -0,0 +1,22 @@
+/*
+ * Given a collection of objects, returns true if all of them exist
+ * Returns false as soon as one does not exist.
+ * @param {*} [...] objects Objects to check existence of
+ * @return {bool} Whether all of the given objects exist or not
+ */
+
+module.exports = exists;
+
+function exists(objects) {
+  if (!Array.isArray(objects)) {
+    objects = [objects];
+  }
+  for (var i = 0; i < objects.length; i++) {
+    var obj = objects[i];
+    if (typeof obj === 'undefined' || obj === null) {
+      return false;
+    }
+  }
+
+  return true;
+}
\ No newline at end of file
diff --git a/browser/lib/isMounttable.js b/browser/lib/isMounttable.js
new file mode 100644
index 0000000..dfcf7ba
--- /dev/null
+++ b/browser/lib/isMounttable.js
@@ -0,0 +1,31 @@
+var resolveRace = require('promises');
+
+/**
+ * isMounttable determines if a specific address refers to a
+ * mounttable.
+ * @param {object} client the veyron client to use.
+ * @param {string} globResult result of glob to check.
+ * @return {promise} promise to a boolean indicating if it is
+ * a mounttable.
+ */
+ // TODO(bprosnitz) Remove dependency on _proxyConnection.
+ // TODO(bprosnitz) Consider adding interface name to signature and using that.
+module.exports  = function(client, globResult) {
+  if (globResult.servers.length === 0) {
+    // This is on the same mounttable as the globResult.
+    return Promise.resolve(true);
+  }
+
+  var globbable = function(sig) {
+    return sig['glob'] !== undefined && sig['glob'].inArgs.length === 1;
+  };
+
+  var pconn = client._proxyConnection;
+  var promises = [];
+  for (var i = 0; i < globResult.servers.length; i++) {
+    var server = globResult.servers[i].server;
+    promises.push(pconn.getServiceSignature(server).then(globbable));
+  }
+
+  return resolveRace(promises);
+};
\ No newline at end of file
diff --git a/browser/lib/mercury/attribute-hook.js b/browser/lib/mercury/attribute-hook.js
new file mode 100644
index 0000000..885a425
--- /dev/null
+++ b/browser/lib/mercury/attribute-hook.js
@@ -0,0 +1,15 @@
+/*
+ * Allows attributes to be set using setAttribute:
+ * https://github.com/Raynos/mercury/blob/
+ * master/docs/faq.md#how-do-i-update-custom-properties
+ */
+
+module.exports = AttributeHook;
+
+function AttributeHook(value) {
+  this.value = value;
+}
+
+AttributeHook.prototype.hook = function(elem, prop) {
+  elem.setAttribute(prop, this.value);
+};
\ No newline at end of file
diff --git a/browser/lib/mountpoint.js b/browser/lib/mountpoint.js
new file mode 100644
index 0000000..1d4cbe1
--- /dev/null
+++ b/browser/lib/mountpoint.js
@@ -0,0 +1,91 @@
+//TODO(aghassemi) move to core Veyron API?
+
+module.exports = MountPoint;
+
+/**
+ * MountPoint handles manipulating and querying from
+ * a mounttable.
+ * @param {object} client A veyron client.
+ * @param {object} mountTable A veyron MountTable instance.
+ * @param {...string} addressParts Parts of the address to join
+ * @constructor
+ */
+function MountPoint(client, mountTable, addressParts) {
+  this.client = client;
+  this.mountTable = mountTable;
+  this.name = Array.prototype.slice.call(arguments, 2).join('/');
+  this._terminalNames = null;
+}
+
+/**
+ * A helper method that returns the terminal names for this
+ * MountPoint and memoizes them.
+ * @return {Promise} A promise that resolves to a list of terminal names.
+ */
+MountPoint.prototype._getTerminalNames = function() {
+  // We resolve to a terminal name manually because veyron rpc calls
+  // wont usually resolve a name if it's to a mounttable.  We
+  // would like to interact with all kinds of servers.
+  if (!this._terminalNames) {
+    this._terminalNames = this.mountTable.resolveMaximally(this.name);
+  }
+  return this._terminalNames;
+};
+
+/**
+ * appendToPath appends to the mountpoint path
+ * @param {...string} toAdd strings to add to the path.
+ * @return {MountPoint} a new mount point with the path args appended
+ * to the current path.
+ */
+MountPoint.prototype.appendToPath = function(toAdd) {
+  var args = Array.prototype.slice.call(arguments);
+  if (this.name.length > 0) {
+    args.unshift(this.name);
+  }
+  return new MountPoint(this.client, this.mountTable, args.join('/'));
+};
+
+/**
+ * mount mounts a target to the current mount point.
+ * @param {string} target The target to be mounted.
+ * @return {promise} a promise that completes when it is mounted
+ */
+MountPoint.prototype.mount = function(target) {
+  var client = this.client;
+  return this._getTerminalNames().then(function(terminalNames) {
+    // TODO(mattr): We should try all the names instead of just the first.
+    // Perhpas the library should allow me to pass a list of names.
+    return client.bindTo(terminalNames[0]).then(function(mtService) {
+      return mtService.mount(target, 0);
+    });
+  });
+};
+
+/**
+ * glob makes a glob request to a server relative to the current mountpoint.
+ * @param {string} expr The glob expression e.g. A/B/*.
+ * @return {promise} a promise to a list of results
+ */
+MountPoint.prototype.glob = function(expr) {
+  var results = [];
+  var client = this.client;
+  return this._getTerminalNames().then(function(terminalNames) {
+    // TODO(mattr): We should try all the names instead of just the first.
+    // Perhpas the library should allow me to pass a list of names.
+    return client.bindTo(terminalNames[0]).then(function(mtService) {
+      var promise = mtService.glob(expr);
+      var stream = promise.stream;
+
+      stream.on('data', function(val) {
+        if (val) {
+          results.push(val);
+        }
+      });
+
+      return promise.then(function() {
+        return results;
+      });
+    });
+  });
+};
\ No newline at end of file
diff --git a/browser/lib/promises.js b/browser/lib/promises.js
new file mode 100644
index 0000000..fb21ecd
--- /dev/null
+++ b/browser/lib/promises.js
@@ -0,0 +1,30 @@
+//TODO(aghassemi) move to core Veyron API. Rename to Promise.Any
+
+exports.resolveRace = resolveRace;
+
+/**
+ * resolveRace returns a promise that resolves when the first promise
+ * resolves and rejects only after every promise has rejected.
+ * @param {promise[]} promises a list of promises.
+ * @return {promse} a promise that resolves when any of the inputs resolve, or
+ * when all of the inputs reject.
+ */
+function resolveRace(promises) {
+  var resolve, reject;
+  var promise = new Promise(function(pResolve, pReject) {
+    resolve = pResolve;
+    reject = pReject;
+  });
+  var numRejects = 0;
+  var onReject = function(reason) {
+    numRejects++;
+    if (numRejects === promises.length) {
+      reject(reason);
+    }
+  };
+
+  for (var i = 0; i < promises.length; i++) {
+    promises[i].then(resolve, onReject);
+  }
+  return promise;
+}
\ No newline at end of file
diff --git a/browser/router.js b/browser/router.js
new file mode 100644
index 0000000..36fe972
--- /dev/null
+++ b/browser/router.js
@@ -0,0 +1,63 @@
+var Routes = require('routes');
+var registerRoutes = require('./routes/register-routes');
+
+module.exports = router;
+
+/*
+ * Implements a hash(#) router.
+ *
+ * Using # instead of regular routes to eliminate any configuration dependency
+ * on the server. Otherwise servers need to be configured to return index
+ * instead of 404. Although that's reasonable, for simplicity of deployment,
+ * hash-based routing is picked.
+ */
+function router(state, events) {
+
+  // Match the path to a route and trigger the route handler for it
+  var handleRouteChange = function(data) {
+    var path = normalizePath(data.path);
+    var route = routes.match(path);
+    if (!route) {
+      //TOOD(aghassemi) redirect to 404 error view?
+      return;
+    }
+    if (!data.skipHistoryPush) {
+      window.history.pushState(null, null, '#' + path);
+    }
+    route.fn.call(null, state, events, route.params);
+  };
+
+  // Triggers a navigate event using the current location as the path
+  var navigateToCurrentLocation = function() {
+    events.navigation.navigate({
+      path: window.location.hash,
+      skipHistoryPush: true
+    });
+  };
+
+  // Create and register routes
+  var routes = new Routes();
+  registerRoutes(routes);
+
+  // Route and push to history when navigation event fires
+  events.navigation.navigate(handleRouteChange);
+
+  // Fire navigation event when hash changes
+  window.addEventListener('hashchange', navigateToCurrentLocation);
+
+  // Kick off the routing by navigating to current Url
+  navigateToCurrentLocation();
+}
+
+function normalizePath(path) {
+  // Remove #
+  if (path.indexOf('#') === 0) {
+    path = path.substr(1);
+  }
+
+  // Empty means root
+  if (path === '') {
+    path = '/';
+  }
+  return path;
+}
\ No newline at end of file
diff --git a/browser/routes/browse.js b/browser/routes/browse.js
new file mode 100644
index 0000000..063afbc
--- /dev/null
+++ b/browser/routes/browse.js
@@ -0,0 +1,15 @@
+module.exports = function(routes) {
+  routes.addRoute('/browse/:namespace?/:globquery?', handleBrowseRoute);
+};
+
+function handleBrowseRoute(state, events, params) {
+
+  // Set the page to browse
+  state.navigation.pageKey.set('browse');
+
+  // Trigger browse components browseNamespace event
+  events.browse.browseNamespace({
+    'namespace': params.namespace,
+    'globQuery': params.globquery
+  });
+}
\ No newline at end of file
diff --git a/browser/routes/help.js b/browser/routes/help.js
new file mode 100644
index 0000000..714092f
--- /dev/null
+++ b/browser/routes/help.js
@@ -0,0 +1,9 @@
+module.exports = function(routes) {
+  routes.addRoute('/help', handleHelpRoute);
+};
+
+function handleHelpRoute(state) {
+
+  // Set the page to help
+  state.navigation.pageKey.set('help');
+}
\ No newline at end of file
diff --git a/browser/routes/index.js b/browser/routes/index.js
new file mode 100644
index 0000000..66f412f
--- /dev/null
+++ b/browser/routes/index.js
@@ -0,0 +1,11 @@
+module.exports = function(routes) {
+  routes.addRoute('/', handleIndexRoute);
+};
+
+function handleIndexRoute(state, events) {
+
+  // Redirect to browse
+  events.navigation.navigate({
+    path: '/browse'
+  });
+}
\ No newline at end of file
diff --git a/browser/routes/register-routes.js b/browser/routes/register-routes.js
new file mode 100644
index 0000000..d0fa475
--- /dev/null
+++ b/browser/routes/register-routes.js
@@ -0,0 +1,10 @@
+module.exports = registerRoutes;
+
+/*
+ * Registers all route handlers.
+ */
+function registerRoutes(routes) {
+  require('./index')(routes);
+  require('./help')(routes);
+  require('./browse')(routes);
+}
\ No newline at end of file
diff --git a/browser/veyron-config.js b/browser/veyron-config.js
new file mode 100644
index 0000000..3719e02
--- /dev/null
+++ b/browser/veyron-config.js
@@ -0,0 +1,8 @@
+var logLevels = require('veyron').logLevels;
+var veyronConfig = {
+  'logLevel': logLevels.INFO,
+  'identityServer': 'http://localhost:5163/random/',
+  'proxy': 'http://localhost:5165'
+};
+
+module.exports = veyronConfig;
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..465f9c5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,19 @@
+{
+  "name": "veyron-browser",
+  "description": "Veyron Browser is a browser for the Veyron namespace.",
+  "version": "0.0.1",
+  "private": true,
+  "scripts": {
+    "preinstall": "npm install --production $VEYRON_ROOT/veyron/javascript/api"
+  },
+  "devDependencies": {
+    "browserify": "^4.2.3",
+    "jshint": "^2.5.2",
+    "mercury": "^6.0.1",
+    "prova": "^1.14.0",
+    "routes": "^1.2.0",
+    "serve": "^1.4.0",
+    "veyron": "0.0.1",
+    "vulcanize": "^0.3.1"
+  }
+}
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..a7620f8
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
+  <meta name="mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-capable" content="yes">
+  <meta name="description" content="">
+  <title>Veyron Browser</title>
+  <style>
+    div[type=foo] {
+      color: red;
+    }
+  </style>
+  <script src="platform.js"></script>
+  <link rel="import" href="bundle.html">
+<head>
+<body fullbleed>
+  <script src="bundle.js"></script>
+</body>
\ No newline at end of file
diff --git a/services.sh b/services.sh
new file mode 100755
index 0000000..41500d2
--- /dev/null
+++ b/services.sh
@@ -0,0 +1,29 @@
+export PATH=$VEYRON_ROOT/veyron/go/bin:$PATH
+export PATH=node_modules/.bin:$PATH
+
+HTTP_PORT=9000
+VEYRON_MOUNTTABLE_PORT=5167
+VEYRON_MOUNTTABLE_PORT2=5168
+VEYRON_PROXY_PORT=5164
+VEYRON_PROXY_ADDR=127.0.0.1:$VEYRON_PROXY_PORT
+VEYRON_WSPR_PORT=5165
+VEYRON_IDENTITY_PORT=5163
+VEYRON_STORE_PORT=5166
+VEYRON_IDENTITY_PATH=/tmp/veyron_browser_identity
+
+trap 'kill -TERM 0' SIGINT SIGTERM EXIT
+
+identity generate veyron_browser_identity > "${VEYRON_IDENTITY_PATH}"
+
+export VEYRON_IDENTITY=$VEYRON_IDENTITY_PATH; \
+identityd --httpaddr=:$VEYRON_IDENTITY_PORT & \
+mounttabled --address=:$VEYRON_MOUNTTABLE_PORT & \
+export NAMESPACE_ROOT=/localhost:$VEYRON_MOUNTTABLE_PORT ; \
+proxyd -address=$VEYRON_PROXY_ADDR & \
+wsprd --v=3 -logtostderr=true -vproxy=$VEYRON_PROXY_ADDR --port $VEYRON_WSPR_PORT & \
+mounttabled --address=:$VEYRON_MOUNTTABLE_PORT2 --name=global & \
+sleep 1 ; \
+stored --address=:$VEYRON_STORE_PORT --name=global/$USER/store &
+serve public/. --port $HTTP_PORT --compress &
+
+wait
\ No newline at end of file
diff --git a/web-component-dependencies.html b/web-component-dependencies.html
new file mode 100644
index 0000000..494a6e5
--- /dev/null
+++ b/web-component-dependencies.html
@@ -0,0 +1,17 @@
+<!--
+TODO(aghassemi) this is not good, we are declaring a dependency on something
+outside of where we introduce that dependency.
+
+Write a browserify transform so we can know from JS code what web components
+are needed to be bundled up.
+So in js, when a component needs to use say paper-button, they just require it:
+require('wc!paper-button');
+and the browserify transforms handles the bundling of wc dependencies at runtime.
+-->
+<link rel="import" href="bower_components/core-drawer-panel/core-drawer-panel.html">
+<link rel="import" href="bower_components/core-header-panel/core-header-panel.html">
+<link rel="import" href="bower_components/core-icons/core-icons.html">
+<link rel="import" href="bower_components/core-item/core-item.html">
+<link rel="import" href="bower_components/core-menu/core-menu.html">
+<link rel="import" href="bower_components/core-toolbar/core-toolbar.html">
+<link rel="import" href="bower_components/paper-button/paper-button.html">
\ No newline at end of file