diff --git a/.eslintrc b/.eslintrc
index 9959b38e84ff5682bbf9496a184dbb33206c953d..fbfdf094179eec46e2461eec93e312928904af22 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -35,6 +35,7 @@
         "react/prop-types": 0,
         "react/no-did-mount-set-state": 0,
         "react/no-did-update-set-state": 0,
+        "react/no-find-dom-node": 0,
         "flow-vars/define-flow-type": 1,
         "flow-vars/use-flow-type": 1
     },
diff --git a/bin/osx-release b/bin/osx-release
index f8eeb70cb782e3010bdccc5ccfa030aa1ff8e406..0fb2d00c3ee735b5ce6b80c81dd44c29126dc8ff 100755
--- a/bin/osx-release
+++ b/bin/osx-release
@@ -1,4 +1,4 @@
-#! /usr/bin/perl -I./bin
+#! /usr/bin/env perl -I./bin
 
 use strict;
 use warnings;
diff --git a/bin/osx-setup b/bin/osx-setup
index 66e1f8e6b4c8bcd467627d01c1a16800afefcdb3..0498fb657a33443a710129e7e45444b6c7d001a3 100755
--- a/bin/osx-setup
+++ b/bin/osx-setup
@@ -1,4 +1,4 @@
-#! /usr/bin/perl -I./bin
+#! /usr/bin/env perl -I./bin
 
 use strict;
 use warnings;
diff --git a/bin/version b/bin/version
index 0de6ea8e6cb10611d239ea9f1d61a937dc82199d..6c7568f06a9becc31663bea6d7fc16cf2d65b276 100755
--- a/bin/version
+++ b/bin/version
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-VERSION="v0.19.2"
+VERSION="v0.20.0-snapshot"
 
 # dynamically pull more interesting stuff from latest git commit
 HASH=$(git show-ref --head --hash=7 head)            # first 7 letters of hash should be enough; that's what GitHub uses
diff --git a/circle.yml b/circle.yml
index b19986d83f9fc1a06aa2bbf18369d0f395385a63..ae90f454c20a73e04630e822a26a999f56ca07cc 100644
--- a/circle.yml
+++ b/circle.yml
@@ -37,7 +37,7 @@ test:
     # 4) runs Eastwood linter, Bikeshed linter, docstring-checker & ./bin/reflection-linter
     # 5) runs JS linter + JS test
     # 6) runs lein uberjar. (We don't run bin/build because we're not really concerned about `npm install` (etc) in this test, which runs elsewhere)
-    - case $CIRCLE_NODE_INDEX in 0) ENGINES=h2,mongo,mysql,bigquery lein test ;; 1) ENGINES=h2,sqlserver MB_DB_TYPE=postgres MB_DB_DBNAME=circle_test MB_DB_PORT=5432 MB_DB_USER=ubuntu MB_DB_HOST=localhost lein test ;; 2) ENGINES=h2,postgres,sqlite,crate MB_DB_TYPE=mysql MB_DB_DBNAME=circle_test MB_DB_PORT=3306 MB_DB_USER=ubuntu MB_DB_HOST=localhost lein test ;; 3) ENGINES=h2,redshift,druid lein test ;; 4) lein eastwood && lein bikeshed && lein docstring-checker && ./bin/reflection-linter ;; 5) npm install && npm run lint && npm run build && npm run test ;; 6) lein uberjar ;; esac:
+    - case $CIRCLE_NODE_INDEX in 0) ENGINES=h2,mongo,mysql,bigquery lein test ;; 1) ENGINES=h2,sqlserver MB_DB_TYPE=postgres MB_DB_DBNAME=circle_test MB_DB_PORT=5432 MB_DB_USER=ubuntu MB_DB_HOST=localhost lein test ;; 2) ENGINES=h2,postgres,sqlite,crate MB_DB_TYPE=mysql MB_DB_DBNAME=circle_test MB_DB_PORT=3306 MB_DB_USER=ubuntu MB_DB_HOST=localhost lein test ;; 3) ENGINES=h2,redshift,druid lein test ;; 4) lein eastwood && lein bikeshed && lein docstring-checker && ./bin/reflection-linter ;; 5) npm install && npm run lint && npm run test ;; 6) lein uberjar ;; esac:
         parallel: true
 deployment:
   master:
diff --git a/docs/administration-guide/07-setting-up-slack.md b/docs/administration-guide/07-setting-up-slack.md
index 2be708483522fcd37f59d8db39c66573fb3b0e94..4a8f9ff76af27c52656532cb0c1688b0c1c2ea06 100644
--- a/docs/administration-guide/07-setting-up-slack.md
+++ b/docs/administration-guide/07-setting-up-slack.md
@@ -23,5 +23,5 @@ Now just click the `Create token` button next to the team you want to integrate
 
 Paste the value into the text box for `Slack API Token` and click the button to save your changes.  That's it!  Metabase will automatically run a quick test to check that the API token is working properly and if not you'll get an error message.
 
-## Next: Single Sign On
-Learn how to [configure Single Sign On](08-single-sign-on.md) to let users sign in or sign up with just a click.
+## Next: Single Sign-On
+Learn how to [configure Single Sign-On](08-single-sign-on.md) to let users sign in or sign up with just a click.
diff --git a/docs/administration-guide/08-single-sign-on.md b/docs/administration-guide/08-single-sign-on.md
index 23409a4c4a215e02b3ef0335d502a8e1f882ec56..84e10581e6f1a3b0fdbee9ebe56b344d470ad597 100644
--- a/docs/administration-guide/08-single-sign-on.md
+++ b/docs/administration-guide/08-single-sign-on.md
@@ -1,8 +1,8 @@
-## Single Sign On with Google
+## Single Sign-On with Google
 
-Enabling single sign on lets your team log in with a click instead of using email and password and can optionally let them sign up for Metabase accounts without an admin having to create them first.
+Enabling single sign-on lets your team log in with a click instead of using email and password and can optionally let them sign up for Metabase accounts without an admin having to create them first.
 
-Currently Metabase works with Google accounts for single sign on. As time goes on we may add other auth providers. If you have a service you’d like to see work with Metabase please let us know by [filing an issue](http://github.com/metabase/metabase/issues/new).
+Currently Metabase works with Google accounts for single sign-on. As time goes on we may add other auth providers. If you have a service you’d like to see work with Metabase please let us know by [filing an issue](http://github.com/metabase/metabase/issues/new).
 
 ### Enabling Sign in
 
@@ -12,7 +12,7 @@ To create a new application follow [the instructions from Google here](https://d
 
 Note that when creating the app you only need to specify the url of your Metabase install in the “Javascript Origins” field. You should leave the “redirect-url” blank.
 
-Once you have your client_id, copy and paste it into the box on the Single Sign on sections of your Metabase Admin settings page. ```XXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com```
+Once you have your client_id, copy and paste it into the box on the Single Sign-On sections of your Metabase Admin settings page. ```XXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com```
 
 Now existing Metabase users signed into a Google account that matches their Metabase account email can sign in with just a click.
 
@@ -20,6 +20,6 @@ Now existing Metabase users signed into a Google account that matches their Meta
 
 If you’ve added your Google client id to your Metabase settings you can also let users sign up on their own without creating accounts for them.
 
-To enable this, check the box on the Single Sign On Admin Settings page and specify the email domain you want to allow. For example if you work at WidgetCo you could enter widgetco.com in the field to let anyone with a company email sign up on their own.
+To enable this, check the box on the Single Sign-On Admin Settings page and specify the email domain you want to allow. For example if you work at WidgetCo you could enter widgetco.com in the field to let anyone with a company email sign up on their own.
 
-Note: Metabase accounts created with Single Sign On do not have passwords and must use Google to sign in to Metabase.
+Note: Metabase accounts created with Single Sign-On do not have passwords and must use Google to sign in to Metabase.
diff --git a/docs/administration-guide/start.md b/docs/administration-guide/start.md
index 89747f1a8ccf0d7a7022e1549116bfba7dd03683..d71445f4b086252a942b8321d240038eb5bbee11 100644
--- a/docs/administration-guide/start.md
+++ b/docs/administration-guide/start.md
@@ -2,15 +2,16 @@
 
 Are you in charge of managing Metabase for your organization? Then you're in the right spot. You are the chosen one.
 
-**This guide will teach you how to:**
+**This guide will teach you about:**
 
-* [Connect Metabase to databases in your organization](01-managing-databases.md)
-* [Enable features that send email (SMTP)](02-setting-up-email.md)
-* [Edit your database metadata](03-metadata-editing.md)
-* [Manage user accounts](04-managing-users.md)
+* [Connecting Metabase to databases in your organization](01-managing-databases.md)
+* [Enabling features that send email (SMTP)](02-setting-up-email.md)
+* [Editing your database metadata](03-metadata-editing.md)
+* [Managing user accounts](04-managing-users.md)
 * [Creating segments and metrics](05-segments-and-metrics.md)
-* [Configure settings](06-configuration-settings.md)
-* [Setting up Slack Integration](07-setting-up-slack.md)
+* [Configuring settings](06-configuration-settings.md)
+* [Setting up Slack integration](07-setting-up-slack.md)
+* [Enabling single sign-on with Google](08-single-sign-on.md)
 
 First things first, you'll need to install Metabase. If you haven’t done that yet, our [Installation Guide](../operations-guide/start.md#installing-and-running-metabase) will help you through the process.
 
diff --git a/docs/developers-guide-osx.md b/docs/developers-guide-osx.md
index 3e3692ac2b0895e7047eeabbcc1ed41a984f8130..a4939121af40e985ec3d460f49bdb7cb3d839435 100644
--- a/docs/developers-guide-osx.md
+++ b/docs/developers-guide-osx.md
@@ -6,17 +6,41 @@
 
 2.  Run `./bin/build` to build the latest version of the uberjar.
 
-3.  Next, you'll need to run the following commands before building the app:
+3.  Update Perl. I'm not sure these steps are actually needed, so feel free to try skipping it and come back to it if it fails:
+  
+   ```bash
+   # Upgrade Perl
+   brew install perl
+   
+   # Add new version of perl to your $PATH
+   # (replace "5.24.0_1" below with whatever version you installed)
+   echo 'export PATH="/usr/local/Cellar/perl/5.24.0_1/bin:$PATH"' >> ~/.bash_profile
+   source ~/.bash_profile
+   
+   # Double-check that we're using the newer version of CPAN
+   # (If this is your first time running CPAN, use the default config settings when prompted)
+   cpan --version # You should see a line like "running under Perl version 5.24.0."
+   ```
+
+4.  Next, you'll need to run the following commands before building the app:
 
     ```bash
    # Fetch and initialize git submodule
    git submodule update --init
    
-   # Install libcurl (needed by WWW::Curl::Simple)
+   # Install libcurl (needed by WWW::Curl::Simple (I think))
    brew install curl && brew link curl --force
    
-   # Install Perl modules used by ./setup and ./release
-   sudo cpan install File::Copy::Recursive JSON Readonly String::Util Text::Caml WWW::Curl::Simple
+   # The new version of LLVM is snippy so have CPAN pass compiler flags to fix errors
+   # (Make sure this file exists first. If you didn't upgrade Perl in the step above, 
+   # it might be in a different location; perhaps called "Config.pm". 
+   # You may need to run "cpan" (no arguments) to generate an appropriate initial config. 
+   # As above, you can go with the defaults).
+   sed -i '' -e "s/'make_arg' => q\[\]/'make_arg' => q\[CCFLAGS=\"-Wno-return-type\"\]/" ~/.cpan/CPAN/MyConfig.pm
+
+   # Install Perl modules used by ./bin/osx-setup and ./bin/osx-release
+   # You may have to run this as sudo if you didn't upgrade perl as described in step above
+   cpan install File::Copy::Recursive JSON Readonly String::Util Text::Caml WWW::Curl::Simple
    
    # Copy JRE and uberjar
    ./bin/osx-setup
@@ -25,17 +49,22 @@
 `./bin/osx-setup` will build run commands to build the uberjar for you if needed.
 Run `./bin/osx-setup` again at any time in the future to copy the latest version of the uberjar into the project.
 
+(If the script fails near the end, you can just copy the JARs in question to `OSX/Resources/metabase.jar` and `OSX/Resources/reset-password.jar`.)
 
 ## Releasing
 
 A handy Perl script called `./bin/osx-release` takes care of all of the details for you. Before you run it for the first time, you'll need to set up a few additional things:
 
 ```bash
+# Install aws command-line client (if needed)
+brew install awscli
+
 # Configure AWS Credentials
 # You'll need credentials that give you permission to write the metabase-osx-releases S3 bucket.
+# You just need the access key ID and secret key; use the defaults for locale and other options.
 aws configure --profile metabase
 
-# Copy & Edit Config file
+# Copy & Edit Config file. Alternative ask Cam for a copy of his
 cp bin/config.json.template bin/config.json
 emacs bin/config.json
 
@@ -44,7 +73,7 @@ emacs bin/config.json
 cp /path/to/private/key.pem OSX/dsa_priv.pem
 ```
 
-You'll probably also want an Apple Developer ID Application Certificate in your computer's keychain (ask Cam).
+You'll probably also want an Apple Developer ID Application Certificate in your computer's keychain. You'll need to generate a Certificate Signing Request from Keychain Access, and have Sameer go to [the Apple Developer Site](https://developer.apple.com/account/mac/certificate/) and generate one for you, then load the file on your computer. 
 
 After that, you are good to go:
 ```bash
diff --git a/docs/users-guide/12-sql-parameters.md b/docs/users-guide/12-sql-parameters.md
index fa30ba10fde05444b84c78d843ea5c1183edc57f..f74b08da9bb7e6777d9a09ad995b1a0588f20bd9 100644
--- a/docs/users-guide/12-sql-parameters.md
+++ b/docs/users-guide/12-sql-parameters.md
@@ -1,3 +1,4 @@
+
 ## SQL Parameters
 ---
 Metabase has the flexible ability to allow variables in native (SQL) queries. This lets you dynamically replace values in your queries using filter widgets or through the query's URL.
@@ -9,44 +10,48 @@ Options and settings for your variables will appear in the `Variables` side pane
 ![Variables](images/sql-parameters/01-variables.png)
 
 ### Defining Variables
-Typing `{{variable_name}}` in your native query creates a variable called `variable_name`. Variables can be given types in the side panel, which changes their behavior. All variable types other than `field filter` will cause a filter widget to be placed on this question corresponding to the chosen variable type. When a value is selected via a filter widget, that value replaces the corresponding variable in the SQL template, wherever it appears.
+Typing `{% raw %}{{variable_name}}{% endraw %}` in your native query creates a variable called `variable_name`. Variables can be given types in the side panel, which changes their behavior. All variable types other than `field filter` will cause a filter widget to be placed on this question corresponding to the chosen variable type. When a value is selected via a filter widget, that value replaces the corresponding variable in the SQL template, wherever it appears.
 
 This example defines a variable called `cat`, allowing you to dynamically change the `WHERE` clause in this query:
+
 ```
 SELECT count(*)
 FROM products
-WHERE category = {{cat}}
+WHERE category = {% raw %}{{cat}}{% endraw %}
 ```
 
 #### The `Field filter` variable type
 Giving a variable the `Field filter` type allows you to connect SQL cards to dashboard filter widgets. A field filter variable inserts SQL similar to that generated by the GUI query builder when adding filters on existing columns. This is useful because it lets you do things like insert dynamic date range filters into your native query. When adding a field filter, you should link that variable to a specific column. Field filter variables should be used inside of a `WHERE` clause.
 
 Example:
+
 ```
 SELECT count(*)
 FROM products
-WHERE {{created_at}}
+WHERE {% raw %}{{created_at}}{% endraw %}
 ```
 
 ### Optional Clauses
-To make an optional clause in your native query, type  `[[brackets around a {{variable}}]]`. If `variable` is given a value, then the entire clause is placed into the template. If not, then the entire clause is ignored.
+To make an optional clause in your native query, type  `[[brackets around a {% raw %}{{variable}}{% endraw %}]]`. If `variable` is given a value, then the entire clause is placed into the template. If not, then the entire clause is ignored.
 
 In this example, if no value is given to `cat` from its filter widget or URL, then the query will just select all the rows from the `products` table. But if `cat` does have a value, like `Widget`, then the query will only grab the products with a category type of `Widget`:
+
 ```
 SELECT count(*)
 FROM products
-[[WHERE category = {{cat}}]]
+[[WHERE category = {% raw %}{{cat}}{% endraw %}]]
 ```
 
 To use multiple optional clauses you must include at least one regular `WHERE` clause followed by optional clauses, each starting with `AND`.
 
 Example:
+
 ```
 SELECT count(*)
 FROM products
 WHERE True
-  [[AND id = {{id}}]]
-  [[AND category = {{category}}]]
+  [[AND id = {% raw %}{{id}}{% endraw %}]]
+  [[AND category = {% raw %}{{category}}{% endraw %}]]
 ```
 
 ---
diff --git a/docs/users-guide/start.md b/docs/users-guide/start.md
index c7762fc30aa36ce4126a0e6674e0c3475eb976af..efcd187fcfae17ec794c4927117e6e0dd9838f2b 100644
--- a/docs/users-guide/start.md
+++ b/docs/users-guide/start.md
@@ -24,4 +24,6 @@
 
 > [Some helpful tips on building your data model](11-data-model-reference.md)
 
+> [Creating SQL Templates](12-sql-parameters.md)
+
 Let's get started with an overview of [What Metabase does](01-what-is-metabase.md).
diff --git a/frontend/src/metabase/App.jsx b/frontend/src/metabase/App.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..a35f4d951010de50ab4f0468dea7b685b58e6d78
--- /dev/null
+++ b/frontend/src/metabase/App.jsx
@@ -0,0 +1,15 @@
+import React, { Component, PropTypes } from "react";
+
+import Navbar from "metabase/nav/containers/Navbar.jsx";
+
+export default class App extends Component {
+    render() {
+        const { children, location } = this.props;
+        return (
+            <div className="spread flex flex-column">
+                <Navbar location={location} className="flex-no-shrink" />
+                {children}
+            </div>
+        )
+    }
+}
diff --git a/frontend/src/metabase/Routes.jsx b/frontend/src/metabase/Routes.jsx
deleted file mode 100644
index 25f5c3a7b993198eb520ea75bad38e48fa3fb98d..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/Routes.jsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import React, { Component, PropTypes } from "react";
-
-import { Route } from 'react-router';
-import { ReduxRouter } from 'redux-router';
-
-// auth containers
-import ForgotPasswordApp from "metabase/auth/containers/ForgotPasswordApp.jsx";
-import LoginApp from "metabase/auth/containers/LoginApp.jsx";
-import LogoutApp from "metabase/auth/containers/LogoutApp.jsx";
-import PasswordResetApp from "metabase/auth/containers/PasswordResetApp.jsx";
-import GoogleNoAccount from "metabase/auth/components/GoogleNoAccount.jsx";
-
-// main app containers
-import DashboardApp from "metabase/dashboard/containers/DashboardApp.jsx";
-import HomepageApp from "metabase/home/containers/HomepageApp.jsx";
-import EntityBrowser from "metabase/questions/containers/EntityBrowser.jsx";
-import EntityList from "metabase/questions/containers/EntityList.jsx";
-import EditLabels from "metabase/questions/containers/EditLabels.jsx";
-import PulseEditApp from "metabase/pulse/containers/PulseEditApp.jsx";
-import PulseListApp from "metabase/pulse/containers/PulseListApp.jsx";
-import QueryBuilder from "metabase/query_builder/containers/QueryBuilder.jsx";
-import SetupApp from "metabase/setup/containers/SetupApp.jsx";
-import UserSettingsApp from "metabase/user/containers/UserSettingsApp.jsx";
-
-// admin containers
-import DatabaseListApp from "metabase/admin/databases/containers/DatabaseListApp.jsx";
-import DatabaseEditApp from "metabase/admin/databases/containers/DatabaseEditApp.jsx";
-import MetadataEditorApp from "metabase/admin/datamodel/containers/MetadataEditorApp.jsx";
-import MetricApp from "metabase/admin/datamodel/containers/MetricApp.jsx";
-import SegmentApp from "metabase/admin/datamodel/containers/SegmentApp.jsx";
-import RevisionHistoryApp from "metabase/admin/datamodel/containers/RevisionHistoryApp.jsx";
-import AdminPeopleApp from "metabase/admin/people/containers/AdminPeopleApp.jsx";
-import SettingsEditorApp from "metabase/admin/settings/containers/SettingsEditorApp.jsx";
-
-import NotFound from "metabase/components/NotFound.jsx";
-import Unauthorized from "metabase/components/Unauthorized.jsx";
-
-
-import ReferenceApp from "metabase/reference/containers/ReferenceApp.jsx";
-import ReferenceEntity from "metabase/reference/containers/ReferenceEntity.jsx";
-import ReferenceEntityList from "metabase/reference/containers/ReferenceEntityList.jsx";
-import ReferenceFieldsList from "metabase/reference/containers/ReferenceFieldsList.jsx";
-import ReferenceRevisionsList from "metabase/reference/containers/ReferenceRevisionsList.jsx";
-import ReferenceGettingStartedGuide from "metabase/reference/containers/ReferenceGettingStartedGuide.jsx";
-
-export default class Routes extends Component {
-    // this lets us forward props we've injected from the Angular controller
-    _forwardProps(ComposedComponent, propNames) {
-        let forwarededProps = {};
-        for (const propName of propNames) {
-            forwarededProps[propName] = this.props[propName];
-        }
-        return (props) => <ComposedComponent {...props} {...forwarededProps} />;
-    }
-
-    render() {
-        return (
-            <ReduxRouter>
-                <Route path="/" component={this._forwardProps(HomepageApp, ["onChangeLocation"])} />
-
-                <Route path="/admin">
-                    <Route path="databases" component={DatabaseListApp} />
-                    <Route path="databases/create" component={this._forwardProps(DatabaseEditApp, ["onChangeLocation"])} />
-                    <Route path="databases/:databaseId" component={this._forwardProps(DatabaseEditApp, ["onChangeLocation"])} />
-
-                    <Route path="datamodel">
-                        <Route path="database" component={this._forwardProps(MetadataEditorApp, ["onChangeLocation"])} />
-                        <Route path="database/:databaseId" component={this._forwardProps(MetadataEditorApp, ["onChangeLocation"])} />
-                        <Route path="database/:databaseId/:mode" component={this._forwardProps(MetadataEditorApp, ["onChangeLocation"])} />
-                        <Route path="database/:databaseId/:mode/:tableId" component={this._forwardProps(MetadataEditorApp, ["onChangeLocation"])} />
-                        <Route path="metric/create" component={this._forwardProps(MetricApp, ["onChangeLocation"])} />
-                        <Route path="metric/:id" component={this._forwardProps(MetricApp, ["onChangeLocation"])} />
-                        <Route path="segment/create" component={this._forwardProps(SegmentApp, ["onChangeLocation"])} />
-                        <Route path="segment/:id" component={this._forwardProps(SegmentApp, ["onChangeLocation"])} />
-                        <Route path=":entity/:id/revisions" component={RevisionHistoryApp} />
-                    </Route>
-
-                    <Route path="people" component={this._forwardProps(AdminPeopleApp, ["onChangeLocation"])} />
-                    <Route path="settings" component={this._forwardProps(SettingsEditorApp, ["refreshSiteSettings"])} />
-                </Route>
-
-                <Route path="/reference" component={ReferenceApp}>
-                    <Route path="guide" component={ReferenceGettingStartedGuide} />
-                    <Route path="metrics" component={ReferenceEntityList} />
-                    <Route path="metrics/:metricId" component={ReferenceEntity} />
-                    <Route path="metrics/:metricId/questions" component={ReferenceEntityList} />
-                    <Route path="metrics/:metricId/revisions" component={ReferenceRevisionsList} />
-                    <Route path="segments" component={ReferenceEntityList} />
-                    <Route path="segments/:segmentId" component={ReferenceEntity} />
-                    <Route path="segments/:segmentId/fields" component={ReferenceFieldsList} />
-                    <Route path="segments/:segmentId/fields/:fieldId" component={ReferenceEntity} />
-                    <Route path="segments/:segmentId/questions" component={ReferenceEntityList} />
-                    <Route path="segments/:segmentId/revisions" component={ReferenceRevisionsList} />
-                    <Route path="databases" component={ReferenceEntityList} />
-                    <Route path="databases/:databaseId" component={ReferenceEntity} />
-                    <Route path="databases/:databaseId/tables" component={ReferenceEntityList} />
-                    <Route path="databases/:databaseId/tables/:tableId" component={ReferenceEntity} />
-                    <Route path="databases/:databaseId/tables/:tableId/fields" component={ReferenceFieldsList} />
-                    <Route path="databases/:databaseId/tables/:tableId/fields/:fieldId" component={ReferenceEntity} />
-                    <Route path="databases/:databaseId/tables/:tableId/questions" component={ReferenceEntityList} />
-                </Route>
-
-                <Route path="/auth/forgot_password" component={ForgotPasswordApp} />
-                <Route path="/auth/login" component={this._forwardProps(LoginApp, ["onChangeLocation", "setSessionFn"])} />
-                <Route path="/auth/logout" component={this._forwardProps(LogoutApp, ["onChangeLocation"])} />
-                <Route path="/auth/reset_password/:token" component={this._forwardProps(PasswordResetApp, ["onChangeLocation"])} />
-                <Route path="/auth/google_no_mb_account" component={GoogleNoAccount} />
-
-                <Route path="/card/:cardId" component={this._forwardProps(QueryBuilder, ["onChangeLocation", "broadcastEventFn", "updateUrl"])} />
-
-                <Route path="/dash/:dashboardId" component={this._forwardProps(DashboardApp, ["onChangeLocation", "onChangeLocationSearch", "onBroadcast"])} />
-
-                <Route path="/pulse" component={this._forwardProps(PulseListApp, ["onChangeLocation"])} />
-                <Route path="/pulse/create" component={this._forwardProps(PulseEditApp, ["onChangeLocation"])} />
-                <Route path="/pulse/:pulseId" component={this._forwardProps(PulseEditApp, ["onChangeLocation"])} />
-
-                <Route path="/q" component={this._forwardProps(QueryBuilder, ["onChangeLocation", "broadcastEventFn", "updateUrl"])} />
-
-                <Route path="/questions" component={EntityBrowser}>
-                    <Route path="edit/labels" component={EditLabels} />
-                    <Route path=":section" component={EntityList} />
-                    <Route path=":section/:slug" component={EntityList} />
-                </Route>
-
-                <Route path="/setup" component={this._forwardProps(SetupApp, ["setSessionFn"])} />
-
-                <Route path="/user/edit_current" component={UserSettingsApp} />
-
-                <Route path="/unauthorized" component={Unauthorized} />
-                <Route path="/*" component={NotFound} />
-            </ReduxRouter>
-        );
-    }
-}
diff --git a/frontend/src/metabase/admin/databases/components/CreatedDatabaseModal.jsx b/frontend/src/metabase/admin/databases/components/CreatedDatabaseModal.jsx
index 7cc60920674b3faa2e9a37c8b223bd74ced9b39f..78a3ff6f4f10747469cade90bd673fcba62b2b3c 100644
--- a/frontend/src/metabase/admin/databases/components/CreatedDatabaseModal.jsx
+++ b/frontend/src/metabase/admin/databases/components/CreatedDatabaseModal.jsx
@@ -1,25 +1,34 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import ModalContent from "metabase/components/ModalContent.jsx";
 
 export default class CreatedDatabaseModal extends Component {
     static propTypes = {
+        databaseId: PropTypes.number.isRequired,
         onClose: PropTypes.func.isRequired,
         onDone: PropTypes.func.isRequired
     };
 
     render() {
+        const { onClose, onDone, databaseId } = this.props;
         return (
             <ModalContent
                 title="Your database has been added!"
-                closeFn={this.props.onClose}
+                closeFn={onClose}
             >
                 <div className="Form-inputs mb4">
-                    <p>We're analyzing its schema now to make some educated guesses about its metadata. Click on the Metadata section to see what we've found and to make edits.</p>
+                    <p>
+                        We're analyzing its schema now to make some educated guesses about its
+                        metadata. <Link to={"/admin/datamodel/database/"+databaseId}>View this
+                        database</Link> in the Data Model section to see what we've found and to
+                        make edits, or <Link to={"/q?db="+databaseId}>ask a question</Link> about
+                        this database.
+                    </p>
                 </div>
 
                 <div className="Form-actions flex layout-centered">
-                    <button className="Button Button--primary px3" onClick={() => this.props.onDone()}>Done</button>
+                    <button className="Button Button--primary px3" onClick={onDone}>Done</button>
                 </div>
             </ModalContent>
         );
diff --git a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx
index 946268410de4318aeb7f9c0cd05b395cbcef200b..3c54bc8b0caed2a976675ee85fb9eb6e04e4d9fc 100644
--- a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx
+++ b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx
@@ -1,5 +1,6 @@
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+
 import MetabaseSettings from "metabase/lib/settings";
 import DeleteDatabaseModal from "../components/DeleteDatabaseModal.jsx";
 import DatabaseEditForms from "../components/DatabaseEditForms.jsx";
@@ -17,15 +18,14 @@ import * as databaseActions from "../database";
 
 const mapStateToProps = (state, props) => {
     return {
-        databaseId:       state.router && state.router.params && state.router.params.databaseId,
+        databaseId:       props.params.databaseId,
         database:         getEditingDatabase(state),
-        formState:        getFormState(state),
-        onChangeLocation: props.onChangeLocation
+        formState:        getFormState(state)
     }
 }
 
 const mapDispatchToProps = {
-    ...databaseActions
+    ...databaseActions,
 }
 
 @connect(mapStateToProps, mapDispatchToProps)
@@ -38,7 +38,7 @@ export default class DatabaseEditApp extends Component {
     };
 
     componentWillMount() {
-        this.props.initializeDatabase(this.props.databaseId, this.props.onChangeLocation);
+        this.props.initializeDatabase(this.props.databaseId);
     }
 
     render() {
@@ -47,7 +47,7 @@ export default class DatabaseEditApp extends Component {
         return (
             <div className="wrapper">
                 <Breadcrumbs crumbs={[
-                    ["Databases", "/admin/databases/"],
+                    ["Databases", "/admin/databases"],
                     [database && database.id != null ? database.name : "Add Database"]
                 ]} />
                 <section className="Grid Grid--gutters Grid--2-of-3">
diff --git a/frontend/src/metabase/admin/databases/containers/DatabaseListApp.jsx b/frontend/src/metabase/admin/databases/containers/DatabaseListApp.jsx
index d171b25d173e5d894c2592f203221864ac0be949..be1a47611184eb2f80c1823dfc80e9204b4e8b76 100644
--- a/frontend/src/metabase/admin/databases/containers/DatabaseListApp.jsx
+++ b/frontend/src/metabase/admin/databases/containers/DatabaseListApp.jsx
@@ -1,5 +1,7 @@
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+import { Link } from "react-router";
+
 import cx from "classnames";
 import MetabaseSettings from "metabase/lib/settings";
 import ModalWithTrigger from "metabase/components/ModalWithTrigger.jsx";
@@ -17,7 +19,7 @@ import * as databaseActions from "../database";
 
 const mapStateToProps = (state, props) => {
     return {
-        created:              state.router && state.router.params && state.router.params.created,
+        created:              props.location.query.created,
         databases:            getDatabasesSorted(state),
         hasSampleDataset:     hasSampleDataset(state),
         engines:              MetabaseSettings.get('engines')
@@ -46,7 +48,7 @@ export default class DatabaseList extends Component {
         return (
             <div className="wrapper">
                 <section className="PageHeader px2 clearfix">
-                    <a className="Button Button--primary float-right" href="/admin/databases/create">Add database</a>
+                    <Link to="/admin/databases/create" className="Button Button--primary float-right">Add database</Link>
                     <h2 className="PageTitle">Databases</h2>
                 </section>
                 <section>
@@ -63,7 +65,7 @@ export default class DatabaseList extends Component {
                                 databases.map(database =>
                                     <tr key={database.id}>
                                         <td>
-                                            <a className="text-bold link" href={"/admin/databases/"+database.id}>{database.name}</a>
+                                            <Link to={"/admin/databases/"+database.id} className="text-bold link">{database.name}</Link>
                                         </td>
                                         <td>
                                             {engines && engines[database.engine] ? engines[database.engine]['driver-name'] : database.engine}
@@ -106,6 +108,7 @@ export default class DatabaseList extends Component {
                     isInitiallyOpen={created}
                 >
                     <CreatedDatabaseModal
+                        databaseId={parseInt(created)}
                         onDone={() => this.refs.createdDatabaseModal.toggle() }
                         onClose={() => this.refs.createdDatabaseModal.toggle() }
                     />
diff --git a/frontend/src/metabase/admin/databases/database.js b/frontend/src/metabase/admin/databases/database.js
index ec4f6aa11990da081f2559205968c0cdefe35c22..1be971f1f394479e5204937540e92d4f9a54f70c 100644
--- a/frontend/src/metabase/admin/databases/database.js
+++ b/frontend/src/metabase/admin/databases/database.js
@@ -2,6 +2,7 @@ import _ from "underscore";
 
 import { createAction } from "redux-actions";
 import { handleActions, combineReducers, AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
+import { push } from "react-router-redux";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
 import MetabaseSettings from "metabase/lib/settings";
@@ -26,15 +27,11 @@ export const fetchDatabases = createThunkAction("FETCH_DATABASES", function() {
 });
 
 // initializeDatabase
-export const initializeDatabase = createThunkAction("INITIALIZE_DATABASE", function(databaseId, onChangeLocation) {
+export const initializeDatabase = createThunkAction("INITIALIZE_DATABASE", function(databaseId) {
     return async function(dispatch, getState) {
         if (databaseId) {
             try {
-                let database = await MetabaseApi.db_get({"dbId": databaseId});
-                return {
-                    database,
-                    onChangeLocation
-                }
+                return await MetabaseApi.db_get({"dbId": databaseId});
             } catch (error) {
                 if (error.status == 404) {
                     //$location.path('/admin/databases/');
@@ -42,16 +39,12 @@ export const initializeDatabase = createThunkAction("INITIALIZE_DATABASE", funct
                     console.log("error fetching database", databaseId, error);
                 }
             }
-
         } else {
             return {
-                database: {
-                    name: '',
-                    engine: Object.keys(MetabaseSettings.get('engines'))[0],
-                    details: {},
-                    created: false
-                },
-                onChangeLocation
+                name: '',
+                engine: Object.keys(MetabaseSettings.get('engines'))[0],
+                details: {},
+                created: false
             }
         }
     }
@@ -75,8 +68,6 @@ export const addSampleDataset = createThunkAction("ADD_SAMPLE_DATASET", function
 // saveDatabase
 export const saveDatabase = createThunkAction("SAVE_DATABASE", function(database, details) {
     return async function(dispatch, getState) {
-        const { databases: { onChangeLocation } } = getState();
-
         let savedDatabase, formState;
 
         try {
@@ -91,7 +82,7 @@ export const saveDatabase = createThunkAction("SAVE_DATABASE", function(database
                 //$scope.$emit("database:created", new_database);
                 savedDatabase = await MetabaseApi.db_create(database);
                 MetabaseAnalytics.trackEvent("Databases", "Create", database.engine);
-                onChangeLocation('/admin/databases?created');
+                dispatch(push('/admin/databases?created='+savedDatabase.id));
             }
 
             // this object format is what FormMessage expects:
@@ -114,15 +105,11 @@ export const saveDatabase = createThunkAction("SAVE_DATABASE", function(database
 // deleteDatabase
 export const deleteDatabase = createThunkAction("DELETE_DATABASE", function(databaseId, redirect=false) {
     return async function(dispatch, getState) {
-        const { databases: { onChangeLocation } } = getState();
-
         try {
-            console.log("deleting database", databaseId);
             await MetabaseApi.db_delete({"dbId": databaseId});
             MetabaseAnalytics.trackEvent("Databases", "Delete", redirect ? "Using Detail" : "Using List");
             if (redirect) {
-                console.log("redirecting");
-                onChangeLocation('/admin/databases/');
+                dispatch(push('/admin/databases/'));
             }
             return databaseId;
         } catch(error) {
@@ -133,7 +120,7 @@ export const deleteDatabase = createThunkAction("DELETE_DATABASE", function(data
 
 // syncDatabase
 export const syncDatabase = createThunkAction("SYNC_DATABASE", function(databaseId) {
-    return async function(dispatch, getState) {
+    return function(dispatch, getState) {
         try {
             let call = MetabaseApi.db_sync_metadata({"dbId": databaseId});
             MetabaseAnalytics.trackEvent("Databases", "Manual Sync");
@@ -147,11 +134,6 @@ export const syncDatabase = createThunkAction("SYNC_DATABASE", function(database
 
 // reducers
 
-// this is a backwards compatibility thing with angular to allow programmatic route changes.  remove/change this when going to ReduxRouter
-const onChangeLocation = handleActions({
-    ["INITIALIZE_DATABASE"]: { next: (state, { payload }) => payload ? payload.onChangeLocation : state },
-}, () => null);
-
 const databases = handleActions({
     ["FETCH_DATABASES"]: { next: (state, { payload }) => payload },
     ["ADD_SAMPLE_DATASET"]: { next: (state, { payload }) => payload ? [...state, payload] : state },
@@ -159,7 +141,7 @@ const databases = handleActions({
 }, null);
 
 const editingDatabase = handleActions({
-    ["INITIALIZE_DATABASE"]: { next: (state, { payload }) => payload ? payload.database : state },
+    ["INITIALIZE_DATABASE"]: { next: (state, { payload }) => payload },
     ["SAVE_DATABASE"]: { next: (state, { payload }) => payload.database || state },
     ["DELETE_DATABASE"]: { next: (state, { payload }) => null },
     ["SELECT_ENGINE"]: { next: (state, { payload }) => ({...state, engine: payload }) }
@@ -172,6 +154,5 @@ const formState = handleActions({
 export default combineReducers({
     databases,
     editingDatabase,
-    formState,
-    onChangeLocation
+    formState
 });
diff --git a/frontend/src/metabase/admin/datamodel/components/ObjectActionSelect.jsx b/frontend/src/metabase/admin/datamodel/components/ObjectActionSelect.jsx
index 945e45c5f5a9d56b082fba00611cb96350b334ad..9910e1a11a7a4915d4884a6c09ba60046ec5da5c 100644
--- a/frontend/src/metabase/admin/datamodel/components/ObjectActionSelect.jsx
+++ b/frontend/src/metabase/admin/datamodel/components/ObjectActionSelect.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import Icon from "metabase/components/Icon.jsx";
 import PopoverWithTrigger from "metabase/components/PopoverWithTrigger.jsx";
@@ -30,14 +31,14 @@ export default class ObjectActionsSelect extends Component {
                 >
                     <ul className="UserActionsSelect">
                         <li>
-                            <a data-metabase-event={"Data Model;"+objectType+" Edit Page"}href={"/admin/datamodel/" + objectType + "/" + object.id} className="py1 px2 block bg-brand-hover text-white-hover no-decoration cursor-pointer">
+                            <Link to={"/admin/datamodel/" + objectType + "/" + object.id} data-metabase-event={"Data Model;"+objectType+" Edit Page"} className="py1 px2 block bg-brand-hover text-white-hover no-decoration cursor-pointer">
                                 Edit {capitalize(objectType)}
-                            </a>
+                            </Link>
                         </li>
                         <li>
-                            <a data-metabase-event={"Data Model;"+objectType+" History"} href={"/admin/datamodel/" + objectType + "/" + object.id + "/revisions"} className="py1 px2 block bg-brand-hover text-white-hover no-decoration cursor-pointer">
+                            <Link to={"/admin/datamodel/" + objectType + "/" + object.id + "/revisions"} data-metabase-event={"Data Model;"+objectType+" History"} className="py1 px2 block bg-brand-hover text-white-hover no-decoration cursor-pointer">
                                 Revision History
-                            </a>
+                            </Link>
                         </li>
                         <li className="mt1 border-top">
                             <ModalWithTrigger
diff --git a/frontend/src/metabase/admin/datamodel/components/database/MetadataTableList.jsx b/frontend/src/metabase/admin/datamodel/components/database/MetadataTableList.jsx
index f7932ad14f935e74b72301bae4a456e9f9c9acde..c33d7bfe0ebc974e1bc6f6245fd8eff6c132ca80 100644
--- a/frontend/src/metabase/admin/datamodel/components/database/MetadataTableList.jsx
+++ b/frontend/src/metabase/admin/datamodel/components/database/MetadataTableList.jsx
@@ -43,7 +43,7 @@ export default class MetadataTableList extends Component {
             _.each(tables, (table) => {
                 var row = (
                     <li key={table.id}>
-                        <a href="#" className={cx("AdminList-item flex align-center no-decoration", { selected: this.props.tableId === table.id })} onClick={this.props.selectTable.bind(null, table)}>
+                        <a className={cx("AdminList-item flex align-center no-decoration", { selected: this.props.tableId === table.id })} onClick={this.props.selectTable.bind(null, table)}>
                             {table.display_name}
                             <ProgressBar className="ProgressBar ProgressBar--mini flex-align-right" percentage={table.metadataStrength} />
                         </a>
diff --git a/frontend/src/metabase/admin/datamodel/components/database/MetricsList.jsx b/frontend/src/metabase/admin/datamodel/components/database/MetricsList.jsx
index 06612a95f6cfa09c08a87ef1ba89eb2d85726c5e..a8e5b6d209759a6b3cad2e4178e97c76985acbe3 100644
--- a/frontend/src/metabase/admin/datamodel/components/database/MetricsList.jsx
+++ b/frontend/src/metabase/admin/datamodel/components/database/MetricsList.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import MetricItem from "./MetricItem.jsx";
 
@@ -18,7 +19,7 @@ export default class MetricsList extends Component {
             <div className="my3">
                 <div className="flex mb1">
                     <h2 className="px1 text-green">Metrics</h2>
-                    <a data-metabase-event="Data Model;Add Metric Page" className="flex-align-right float-right text-bold text-brand no-decoration" href={"/admin/datamodel/metric/create?table="+tableMetadata.id}>+ Add a Metric</a>
+                    <Link to={"/admin/datamodel/metric/create?table="+tableMetadata.id} data-metabase-event="Data Model;Add Metric Page" className="flex-align-right float-right text-bold text-brand no-decoration">+ Add a Metric</Link>
                 </div>
                 <table className="AdminTable">
                     <thead>
diff --git a/frontend/src/metabase/admin/datamodel/components/database/SegmentsList.jsx b/frontend/src/metabase/admin/datamodel/components/database/SegmentsList.jsx
index 9d977347755fdb56a2183c86c382a5be916d37b4..c53d38e100c8f0d42a6c90f8f26a513a47c6333c 100644
--- a/frontend/src/metabase/admin/datamodel/components/database/SegmentsList.jsx
+++ b/frontend/src/metabase/admin/datamodel/components/database/SegmentsList.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import SegmentItem from "./SegmentItem.jsx";
 
@@ -18,7 +19,7 @@ export default class SegmentsList extends Component {
             <div className="my3">
                 <div className="flex mb1">
                     <h2 className="px1 text-purple">Segments</h2>
-                    <a data-metabase-event="Data Model;Add Segment Page" className="flex-align-right float-right text-bold text-brand no-decoration" href={"/admin/datamodel/segment/create?table="+tableMetadata.id}>+ Add a Segment</a>
+                    <Link to={"/admin/datamodel/segment/create?table="+tableMetadata.id} data-metabase-event="Data Model;Add Segment Page" className="flex-align-right float-right text-bold text-brand no-decoration">+ Add a Segment</Link>
                 </div>
                 <table className="AdminTable">
                     <thead>
diff --git a/frontend/src/metabase/admin/datamodel/containers/MetadataEditorApp.jsx b/frontend/src/metabase/admin/datamodel/containers/MetadataEditorApp.jsx
index 2961405399f51fb5a02fe544620872806b9b5cd5..389d0b34cd68218b127ad66998c06441bad657f6 100644
--- a/frontend/src/metabase/admin/datamodel/containers/MetadataEditorApp.jsx
+++ b/frontend/src/metabase/admin/datamodel/containers/MetadataEditorApp.jsx
@@ -1,5 +1,6 @@
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+
 import _ from "underscore";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
@@ -9,7 +10,6 @@ import MetadataTablePicker from '../components/database/MetadataTablePicker.jsx'
 import MetadataTable from '../components/database/MetadataTable.jsx';
 import MetadataSchema from '../components/database/MetadataSchema.jsx';
 
-
 import {
     getDatabases,
     getDatabaseIdfields,
@@ -18,21 +18,19 @@ import {
 } from "../selectors";
 import * as metadataActions from "../metadata";
 
-
 const mapStateToProps = (state, props) => {
     return {
-        databaseId:           state.router && state.router.params && parseInt(state.router.params.databaseId),
-        tableId:              state.router && state.router.params && parseInt(state.router.params.tableId),
-        onChangeLocation:     props.onChangeLocation,
-        databases:            getDatabases(state),
-        idfields:             getDatabaseIdfields(state),
-        databaseMetadata:     getEditingDatabaseWithTableMetadataStrengths(state),
-        editingTable:         getEditingTable(state)
+        databaseId:           parseInt(props.params.databaseId),
+        tableId:              parseInt(props.params.tableId),
+        databases:            getDatabases(state, props),
+        idfields:             getDatabaseIdfields(state, props),
+        databaseMetadata:     getEditingDatabaseWithTableMetadataStrengths(state, props),
+        editingTable:         getEditingTable(state, props)
     }
 }
 
 const mapDispatchToProps = {
-    ...metadataActions
+    ...metadataActions,
 }
 
 @connect(mapStateToProps, mapDispatchToProps)
@@ -64,7 +62,7 @@ export default class MetadataEditor extends Component {
 
     componentWillMount() {
         // if we know what database we are initialized with, include that
-        this.props.initializeMetadata(this.props.databaseId, this.props.tableId, this.props.onChangeLocation);
+        this.props.initializeMetadata(this.props.databaseId, this.props.tableId);
     }
 
     toggleShowSchema() {
diff --git a/frontend/src/metabase/admin/datamodel/containers/MetricApp.jsx b/frontend/src/metabase/admin/datamodel/containers/MetricApp.jsx
index baf31dc994fa0537dae2d927a81822176761553a..a1ac509f7a9e53448137928c268958065f390fe2 100644
--- a/frontend/src/metabase/admin/datamodel/containers/MetricApp.jsx
+++ b/frontend/src/metabase/admin/datamodel/containers/MetricApp.jsx
@@ -1,4 +1,6 @@
 import React, { Component, PropTypes } from "react";
+import { connect } from "react-redux";
+import { push } from "react-router-redux";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
 
@@ -7,9 +9,12 @@ import MetricForm from "./MetricForm.jsx";
 import { metricEditSelectors } from "../selectors";
 import * as actions from "../metadata";
 
-import { connect } from "react-redux";
+const mapDispatchToProps = {
+    ...actions,
+    onChangeLocation: push
+};
 
-@connect(metricEditSelectors, actions)
+@connect(metricEditSelectors, mapDispatchToProps)
 export default class MetricApp extends Component {
     async componentWillMount() {
         const { params, location } = this.props;
diff --git a/frontend/src/metabase/admin/datamodel/containers/MetricForm.jsx b/frontend/src/metabase/admin/datamodel/containers/MetricForm.jsx
index 185af29564dff40a03435a9dfa43049b60618b44..2913ed122cd7f4507ad3266258be4a5999b01b04 100644
--- a/frontend/src/metabase/admin/datamodel/containers/MetricForm.jsx
+++ b/frontend/src/metabase/admin/datamodel/containers/MetricForm.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import FormLabel from "../components/FormLabel.jsx";
 import FormInput from "../components/FormInput.jsx";
@@ -53,7 +54,7 @@ export default class MetricForm extends Component {
         return (
             <div>
                 <button className={cx("Button", { "Button--primary": !invalid, "disabled": invalid })} onClick={handleSubmit}>Save changes</button>
-                <a className="Button Button--borderless mx1" href={"/admin/datamodel/database/" + tableMetadata.db_id + "/table/" + tableMetadata.id}>Cancel</a>
+                <Link to={"/admin/datamodel/database/" + tableMetadata.db_id + "/table/" + tableMetadata.id} className="Button Button--borderless mx1">Cancel</Link>
             </div>
         )
     }
diff --git a/frontend/src/metabase/admin/datamodel/containers/RevisionHistoryApp.jsx b/frontend/src/metabase/admin/datamodel/containers/RevisionHistoryApp.jsx
index 76e9f944f951bbeba4150fd28a4a4850f6dffda6..dcf06543ce3b0e008f2aff4376ca8155631f46ce 100644
--- a/frontend/src/metabase/admin/datamodel/containers/RevisionHistoryApp.jsx
+++ b/frontend/src/metabase/admin/datamodel/containers/RevisionHistoryApp.jsx
@@ -1,21 +1,24 @@
 import React, { Component, PropTypes } from "react";
+import { connect } from "react-redux";
 
 import RevisionHistory from "../components/revisions/RevisionHistory.jsx";
 
 import { revisionHistorySelectors } from "../selectors";
 import * as actions from "../metadata";
 
-import { connect } from "react-redux";
-
 const mapStateToProps = (state, props) => {
     return {
-        ...revisionHistorySelectors(state),
-        entity: state.router && state.router.params && state.router.params.entity,
-        id:     state.router && state.router.params && state.router.params.id
+        ...revisionHistorySelectors(state, props),
+        entity: props.params.entity,
+        id:     props.params.id
     }
 }
 
-@connect(mapStateToProps, actions)
+const mapDispatchToProps = {
+    ...actions,
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
 export default class RevisionHistoryApp extends Component {
     componentWillMount() {
         let { entity, id } = this.props;
diff --git a/frontend/src/metabase/admin/datamodel/containers/SegmentApp.jsx b/frontend/src/metabase/admin/datamodel/containers/SegmentApp.jsx
index c88ec2b1b4895aa7be7d0e7585bf5d09158e26e2..7903451caf57d270b8331647494ffd0fdd857fb0 100644
--- a/frontend/src/metabase/admin/datamodel/containers/SegmentApp.jsx
+++ b/frontend/src/metabase/admin/datamodel/containers/SegmentApp.jsx
@@ -1,4 +1,6 @@
 import React, { Component, PropTypes } from "react";
+import { connect } from "react-redux";
+import { push } from "react-router-redux";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
 
@@ -7,9 +9,12 @@ import SegmentForm from "./SegmentForm.jsx";
 import { segmentEditSelectors } from "../selectors";
 import * as actions from "../metadata";
 
-import { connect } from "react-redux";
+const mapDispatchToProps = {
+    ...actions,
+    onChangeLocation: push
+};
 
-@connect(segmentEditSelectors, actions)
+@connect(segmentEditSelectors, mapDispatchToProps)
 export default class SegmentApp extends Component {
     async componentWillMount() {
         const { params, location } = this.props;
diff --git a/frontend/src/metabase/admin/datamodel/containers/SegmentForm.jsx b/frontend/src/metabase/admin/datamodel/containers/SegmentForm.jsx
index a0e41a11ffa851fd4a636652a1339c9c1d650f09..09f324407fa8632c99e1fe551243877327958827 100644
--- a/frontend/src/metabase/admin/datamodel/containers/SegmentForm.jsx
+++ b/frontend/src/metabase/admin/datamodel/containers/SegmentForm.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import FormLabel from "../components/FormLabel.jsx";
 import FormInput from "../components/FormInput.jsx";
@@ -54,7 +55,7 @@ export default class SegmentForm extends Component {
         return (
             <div>
                 <button className={cx("Button", { "Button--primary": !invalid, "disabled": invalid })} onClick={handleSubmit}>Save changes</button>
-                <a className="Button Button--borderless mx1" href={"/admin/datamodel/database/" + tableMetadata.db_id + "/table/" + tableMetadata.id}>Cancel</a>
+                <Link to={"/admin/datamodel/database/" + tableMetadata.db_id + "/table/" + tableMetadata.id} className="Button Button--borderless mx1">Cancel</Link>
             </div>
         )
     }
diff --git a/frontend/src/metabase/admin/datamodel/metadata.js b/frontend/src/metabase/admin/datamodel/metadata.js
index 006867fd26eef60ccc0b1bf35906769f5f652979..ff6be7afe0b9139f544b1a6f4a6c96d20f005163 100644
--- a/frontend/src/metabase/admin/datamodel/metadata.js
+++ b/frontend/src/metabase/admin/datamodel/metadata.js
@@ -1,6 +1,7 @@
 import _ from "underscore";
 
 import { handleActions, combineReducers, AngularResourceProxy, createAction, createThunkAction, momentifyTimestamps } from "metabase/lib/redux";
+import { push } from "react-router-redux";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
 import { augmentTable } from "metabase/lib/table";
@@ -29,7 +30,7 @@ async function loadDatabaseMetadata(databaseId) {
 }
 
 // initializeMetadata
-export const initializeMetadata = createThunkAction("INITIALIZE_METADATA", function(databaseId, tableId, onChangeLocation) {
+export const initializeMetadata = createThunkAction("INITIALIZE_METADATA", function(databaseId, tableId) {
     return async function(dispatch, getState) {
         let databases, database;
         try {
@@ -50,7 +51,6 @@ export const initializeMetadata = createThunkAction("INITIALIZE_METADATA", funct
         }
 
         return {
-            onChangeLocation,
             databases,
             database,
             tableId
@@ -76,15 +76,13 @@ export const fetchDatabaseIdfields = createThunkAction("FETCH_IDFIELDS", functio
 // selectDatabase
 export const selectDatabase = createThunkAction("SELECT_DATABASE", function(db) {
     return async function(dispatch, getState) {
-        const { datamodel: { onChangeLocation } } = getState();
-
         try {
             let database = await loadDatabaseMetadata(db.id);
 
             dispatch(fetchDatabaseIdfields(db.id));
 
             // we also want to update our url to match our new state
-            onChangeLocation('/admin/datamodel/database/'+db.id);
+            dispatch(push('/admin/datamodel/database/'+db.id));
 
             return database;
         } catch (error) {
@@ -95,11 +93,9 @@ export const selectDatabase = createThunkAction("SELECT_DATABASE", function(db)
 
 // selectTable
 export const selectTable = createThunkAction("SELECT_TABLE", function(table) {
-    return async function(dispatch, getState) {
-        const { datamodel: { onChangeLocation } } = getState();
-
+    return function(dispatch, getState) {
         // we also want to update our url to match our new state
-        onChangeLocation('/admin/datamodel/database/'+table.db_id+'/table/'+table.id);
+        dispatch(push('/admin/datamodel/database/'+table.db_id+'/table/'+table.id));
 
         return table.id;
     };
@@ -160,7 +156,7 @@ export const updateField = createThunkAction("UPDATE_FIELD", function(field) {
 
 // updateFieldSpecialType
 export const updateFieldSpecialType = createThunkAction("UPDATE_FIELD_SPECIAL_TYPE", function(field) {
-    return async function(dispatch, getState) {
+    return function(dispatch, getState) {
 
         // If we are changing the field from a FK to something else, we should delete any FKs present
         if (field.target && field.target.id != null && field.special_type !== "fk") {
@@ -179,7 +175,7 @@ export const updateFieldSpecialType = createThunkAction("UPDATE_FIELD_SPECIAL_TY
 
 // updateFieldTarget
 export const updateFieldTarget = createThunkAction("UPDATE_FIELD_TARGET", function(field) {
-    return async function(dispatch, getState) {
+    return function(dispatch, getState) {
         // This function notes a change in the target of the target of a foreign key
         dispatch(updateField(field));
 
@@ -270,11 +266,6 @@ export const fetchRevisions = createThunkAction(FETCH_REVISIONS, ({ entity, id }
 
 // reducers
 
-// this is a backwards compatibility thing with angular to allow programmatic route changes.  remove/change this when going to ReduxRouter
-const onChangeLocation = handleActions({
-    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.onChangeLocation }
-}, () => null);
-
 const databases = handleActions({
     ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.databases }
 }, []);
@@ -329,7 +320,6 @@ export default combineReducers({
     idfields,
     editingDatabase,
     editingTable,
-    onChangeLocation,
     segments,
     metrics,
     tableMetadata,
diff --git a/frontend/src/metabase/admin/datamodel/selectors.js b/frontend/src/metabase/admin/datamodel/selectors.js
index 189c0caab3bf8d2ec39d22a1679d1b5207c4b0c5..8feb9612b0469de7a734e279e28a9a25cab63911 100644
--- a/frontend/src/metabase/admin/datamodel/selectors.js
+++ b/frontend/src/metabase/admin/datamodel/selectors.js
@@ -3,17 +3,17 @@ import { createSelector } from 'reselect';
 import { computeMetadataStrength } from "metabase/lib/schema_metadata";
 
 
-const segmentsSelector         = state => state.datamodel.segments;
-const metricsSelector          = state => state.datamodel.metrics;
+const segmentsSelector         = (state, props) => state.datamodel.segments;
+const metricsSelector          = (state, props) => state.datamodel.metrics;
 
-const tableMetadataSelector    = state => state.datamodel.tableMetadata;
-const previewSummarySelector   = state => state.datamodel.previewSummary;
-const revisionObjectSelector   = state => state.datamodel.revisionObject;
+const tableMetadataSelector    = (state, props) => state.datamodel.tableMetadata;
+const previewSummarySelector   = (state, props) => state.datamodel.previewSummary;
+const revisionObjectSelector   = (state, props) => state.datamodel.revisionObject;
 
-const idSelector               = state => state.router.params.id == null ? null : parseInt(state.router.params.id);
-const tableIdSelector          = state => state.router.location.query.table == null ? null : parseInt(state.router.location.query.table);
+const idSelector               = (state, props) => props.params.id == null ? null : parseInt(props.params.id);
+const tableIdSelector          = (state, props) => props.location.query.table == null ? null : parseInt(props.location.query.table);
 
-const userSelector             = state => state.currentUser;
+const userSelector             = (state, props) => state.currentUser;
 
 export const segmentEditSelectors = createSelector(
     segmentsSelector,
@@ -73,9 +73,9 @@ export const revisionHistorySelectors = createSelector(
 );
 
 
-export const getDatabases             = state => state.datamodel.databases;
-export const getDatabaseIdfields      = state => state.datamodel.idfields;
-export const getEditingTable          = state => state.datamodel.editingTable;
+export const getDatabases             = (state, props) => state.datamodel.databases;
+export const getDatabaseIdfields      = (state, props) => state.datamodel.idfields;
+export const getEditingTable          = (state, props) => state.datamodel.editingTable;
 
 
 export const getEditingDatabaseWithTableMetadataStrengths = createSelector(
@@ -93,4 +93,3 @@ export const getEditingDatabaseWithTableMetadataStrengths = createSelector(
         return database;
     }
 );
-
diff --git a/frontend/src/metabase/admin/people/components/AdminPeople.jsx b/frontend/src/metabase/admin/people/components/AdminPeople.jsx
index 237533ea7f02f17fcac1eb2da3aa659832148e17..0b05a01cb1ce97e859e24215d03ffd930c9a0ed9 100644
--- a/frontend/src/metabase/admin/people/components/AdminPeople.jsx
+++ b/frontend/src/metabase/admin/people/components/AdminPeople.jsx
@@ -1,4 +1,6 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 import _ from "underscore";
 
 import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
@@ -14,16 +16,6 @@ import Tooltip from "metabase/components/Tooltip.jsx";
 import EditUserForm from "./EditUserForm.jsx";
 import UserActionsSelect from "./UserActionsSelect.jsx";
 import UserRoleSelect from "./UserRoleSelect.jsx";
-import { createUser,
-         deleteUser,
-         fetchUsers,
-         grantAdmin,
-         resetPasswordManually,
-         resetPasswordViaEmail,
-         revokeAdmin,
-         showModal,
-         updateUser } from "../actions";
-
 
 export const MODAL_ADD_PERSON = 'MODAL_ADD_PERSON';
 export const MODAL_EDIT_DETAILS = 'MODAL_EDIT_DETAILS';
@@ -45,13 +37,24 @@ export default class AdminPeople extends Component {
     }
 
     static propTypes = {
-        dispatch: PropTypes.func.isRequired,
-        users: PropTypes.object
+        user: PropTypes.object.isRequired,
+        users: PropTypes.object,
+        modal: PropTypes.object,
+        createUser: PropTypes.func.isRequired,
+        deleteUser: PropTypes.func.isRequired,
+        fetchUsers: PropTypes.func.isRequired,
+        grantAdmin: PropTypes.func.isRequired,
+        resetPasswordManually: PropTypes.func.isRequired,
+        resetPasswordViaEmail: PropTypes.func.isRequired,
+        revokeAdmin: PropTypes.func.isRequired,
+        showModal: PropTypes.func.isRequired,
+        updateUser: PropTypes.func.isRequired,
+        resendInvite: PropTypes.func.isRequired,
     };
 
     async componentDidMount() {
         try {
-            await this.props.dispatch(fetchUsers());
+            await this.props.fetchUsers();
         } catch (error) {
             this.setState({ error });
         }
@@ -65,17 +68,17 @@ export default class AdminPeople extends Component {
             });
 
             if (admins && _.keys(admins).length > 1) {
-                this.props.dispatch(revokeAdmin(user));
+                this.props.revokeAdmin(user);
             }
 
         } else if (roleDef.id === "admin" && !user.is_superuser) {
-            this.props.dispatch(grantAdmin(user));
+            this.props.grantAdmin(user);
         }
     }
 
     async onAddPerson(user) {
         // close the modal no matter what
-        this.props.dispatch(showModal(null));
+        this.props.showModal(null);
 
         if (user) {
             let modal = MODAL_USER_ADDED_WITH_INVITE;
@@ -87,63 +90,67 @@ export default class AdminPeople extends Component {
             }
 
             // create the user
-            this.props.dispatch(createUser(user));
+            this.props.createUser(user);
 
             // carry on
-            this.props.dispatch(showModal({
+            this.props.showModal({
                 type: modal,
                 details: {
                     user: user
                 }
-            }));
+            });
         }
     }
 
     onEditDetails(user) {
         // close the modal no matter what
-        this.props.dispatch(showModal(null));
+        this.props.showModal(null);
 
         if (user) {
-            this.props.dispatch(updateUser(user));
+            this.props.updateUser(user);
         }
     }
 
     onPasswordResetConfirm(user) {
         if (MetabaseSettings.isEmailConfigured()) {
             // trigger password reset email
-            this.props.dispatch(resetPasswordViaEmail(user));
+            this.props.resetPasswordViaEmail(user);
 
             // show confirmation modal
-            this.props.dispatch(showModal({
+            this.props.showModal({
                 type: MODAL_RESET_PASSWORD_EMAIL,
                 details: {user: user}
-            }));
+            });
 
         } else {
             // generate a password
             const password = MetabaseUtils.generatePassword(14, MetabaseSettings.get('password_complexity'));
 
             // trigger the reset
-            this.props.dispatch(resetPasswordManually(user, password));
+            this.props.resetPasswordManually(user, password);
 
             // show confirmation modal
-            this.props.dispatch(showModal({
+            this.props.showModal({
                 type: MODAL_RESET_PASSWORD_MANUAL,
                 details: {password: password, user: user}
-            }));
+            });
         }
     }
 
     onRemoveUserConfirm(user) {
-        this.props.dispatch(showModal(null));
-        this.props.dispatch(deleteUser(user));
+        this.props.showModal(null);
+        this.props.deleteUser(user);
+    }
+
+    onCloseModal = () => {
+        this.props.showModal(null);
     }
 
     renderAddPersonModal(modalDetails) {
         return (
-            <Modal>
+            <Modal onClose={this.onCloseModal}>
                 <ModalContent title="Add Person"
-                              closeFn={() => this.props.dispatch(showModal(null))}>
+                              closeFn={this.onCloseModal}>
                     <EditUserForm
                         buttonText="Add Person"
                         submitFn={this.onAddPerson.bind(this)} />
@@ -156,9 +163,9 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal>
+            <Modal onClose={this.onCloseModal}>
                 <ModalContent title="Edit Details"
-                              closeFn={() => this.props.dispatch(showModal(null))}>
+                              closeFn={this.onCloseModal}>
                     <EditUserForm
                         user={user}
                         submitFn={this.onEditDetails.bind(this)} />
@@ -171,9 +178,9 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={user.first_name+" has been added"}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div className="px4 pb4">
@@ -183,12 +190,12 @@ export default class AdminPeople extends Component {
 
                             <PasswordReveal password={user.password} />
 
-                            <div style={{paddingLeft: "5em", paddingRight: "5em"}} className="pt4 text-centered">If you want to be able to send email invites, just go to the <a className="link text-bold" href="/admin/settings/?section=Email">Email Settings</a> page.</div>
+                            <div style={{paddingLeft: "5em", paddingRight: "5em"}} className="pt4 text-centered">If you want to be able to send email invites, just go to the <Link to="/admin/settings/email" className="link text-bold">Email Settings</Link> page.</div>
                         </div>
 
                         <div className="Form-actions">
-                            <button className="Button Button--primary" onClick={() => this.props.dispatch(showModal(null))}>Done</button>
-                            <span className="pl1">or<a className="link ml1 text-bold" href="" onClick={() => this.props.dispatch(showModal({type: MODAL_ADD_PERSON}))}>Add another person</a></span>
+                            <button className="Button Button--primary" onClick={this.onCloseModal}>Done</button>
+                            <span className="pl1">or<a className="link ml1 text-bold" href="" onClick={() => this.props.showModal({type: MODAL_ADD_PERSON})}>Add another person</a></span>
                         </div>
                     </div>
                 </ModalContent>
@@ -200,16 +207,16 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={user.first_name+" has been added"}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div style={{paddingLeft: "5em", paddingRight: "5em"}} className="pb4">We’ve sent an invite to <span className="text-bold">{user.email}</span> with instructions to set their password.</div>
 
                         <div className="Form-actions">
-                            <button className="Button Button--primary" onClick={() => this.props.dispatch(showModal(null))}>Done</button>
-                            <span className="pl1">or<a className="link ml1 text-bold" href="" onClick={() => this.props.dispatch(showModal({type: MODAL_ADD_PERSON}))}>Add another person</a></span>
+                            <button className="Button Button--primary" onClick={this.onCloseModal}>Done</button>
+                            <span className="pl1">or<a className="link ml1 text-bold" href="" onClick={() => this.props.showModal({type: MODAL_ADD_PERSON})}>Add another person</a></span>
                         </div>
                     </div>
                 </ModalContent>
@@ -221,15 +228,15 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={"We've Re-sent "+user.first_name+"'s Invite"}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div className="px4 pb4">Any previous email invites they have will no longer work.</div>
 
                         <div className="Form-actions">
-                            <button className="Button Button--primary mr2" onClick={() => this.props.dispatch(showModal(null))}>Okay</button>
+                            <button className="Button Button--primary mr2" onClick={this.onCloseModal}>Okay</button>
                         </div>
                     </div>
                 </ModalContent>
@@ -241,9 +248,9 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={"Remove "+user.common_name}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div className="px4 pb4">
@@ -252,7 +259,7 @@ export default class AdminPeople extends Component {
 
                         <div className="Form-actions">
                             <button className="Button Button--warning" onClick={() => this.onRemoveUserConfirm(user)}>Yes</button>
-                            <button className="Button Button--primary ml2" onClick={() => this.props.dispatch(showModal(null))}>No</button>
+                            <button className="Button Button--primary ml2" onClick={this.onCloseModal}>No</button>
                         </div>
                     </div>
                 </ModalContent>
@@ -264,9 +271,9 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={"Reset "+user.first_name+"'s Password"}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div className="px4 pb4">
@@ -275,7 +282,7 @@ export default class AdminPeople extends Component {
 
                         <div className="Form-actions">
                             <button className="Button Button--warning" onClick={() => this.onPasswordResetConfirm(user)}>Yes</button>
-                            <button className="Button Button--primary ml2" onClick={() => this.props.dispatch(showModal(null))}>No</button>
+                            <button className="Button Button--primary ml2" onClick={this.onCloseModal}>No</button>
                         </div>
                     </div>
                 </ModalContent>
@@ -287,9 +294,9 @@ export default class AdminPeople extends Component {
         let { user, password } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={user.first_name+"'s Password Has Been Reset"}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div className="px4 pb4">
@@ -299,7 +306,7 @@ export default class AdminPeople extends Component {
                         </div>
 
                         <div className="Form-actions">
-                            <button className="Button Button--primary mr2" onClick={() => this.props.dispatch(showModal(null))}>Done</button>
+                            <button className="Button Button--primary mr2" onClick={this.onCloseModal}>Done</button>
                         </div>
                     </div>
                 </ModalContent>
@@ -311,15 +318,15 @@ export default class AdminPeople extends Component {
         let { user } = modalDetails;
 
         return (
-            <Modal className="Modal Modal--small">
+            <Modal className="Modal Modal--small" onClose={this.onCloseModal}>
                 <ModalContent title={user.first_name+"'s Password Has Been Reset"}
-                              closeFn={() => this.props.dispatch(showModal(null))}
+                              closeFn={this.onCloseModal}
                               className="Modal-content Modal-content--small NewForm">
                     <div>
                         <div className="px4 pb4">We've sent them an email with instructions for creating a new password.</div>
 
                         <div className="Form-actions">
-                            <button className="Button Button--primary mr2" onClick={() => this.props.dispatch(showModal(null))}>Done</button>
+                            <button className="Button Button--primary mr2" onClick={this.onCloseModal}>Done</button>
                         </div>
                     </div>
                 </ModalContent>
@@ -357,7 +364,7 @@ export default class AdminPeople extends Component {
                     { modal ? this.renderModal(modal.type, modal.details) : null }
 
                     <section className="PageHeader clearfix px2">
-                        <a data-metabase-event="People Admin;Add Person Modal" className="Button Button--primary float-right" href="#" onClick={() => this.props.dispatch(showModal({type: MODAL_ADD_PERSON}))}>Add person</a>
+                        <a data-metabase-event="People Admin;Add Person Modal" className="Button Button--primary float-right" href="#" onClick={() => this.props.showModal({type: MODAL_ADD_PERSON})}>Add person</a>
                         <h2 className="PageTitle">People</h2>
                     </section>
 
@@ -391,7 +398,7 @@ export default class AdminPeople extends Component {
                                     </td>
                                     <td>{ user.last_login ? user.last_login.fromNow() : "Never" }</td>
                                     <td className="text-right">
-                                        <UserActionsSelect user={user} dispatch={this.props.dispatch} isActiveUser={this.props.user.id === user.id} />
+                                        <UserActionsSelect user={user} showModal={this.props.showModal} resendInvite={this.props.resendInvite} isActiveUser={this.props.user.id === user.id} />
                                     </td>
                                 </tr>
                                 )}
diff --git a/frontend/src/metabase/admin/people/components/EditUserForm.jsx b/frontend/src/metabase/admin/people/components/EditUserForm.jsx
index 1513b4cf2a1f746f7c55bb15f6fc7f94007429f6..d553023686e69eb563b2516fe33a53cda92e6a76 100644
--- a/frontend/src/metabase/admin/people/components/EditUserForm.jsx
+++ b/frontend/src/metabase/admin/people/components/EditUserForm.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
diff --git a/frontend/src/metabase/admin/people/components/UserActionsSelect.jsx b/frontend/src/metabase/admin/people/components/UserActionsSelect.jsx
index e07113fdc15adbf8e587c968206fc65d576a68d5..ef56fafef8e30ca908b1b743771433e08a093561 100644
--- a/frontend/src/metabase/admin/people/components/UserActionsSelect.jsx
+++ b/frontend/src/metabase/admin/people/components/UserActionsSelect.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import Icon from "metabase/components/Icon.jsx";
@@ -8,24 +9,24 @@ import { MODAL_EDIT_DETAILS,
          MODAL_INVITE_RESENT,
          MODAL_REMOVE_USER,
          MODAL_RESET_PASSWORD } from "./AdminPeople.jsx";
-import { resendInvite, showModal } from "../actions";
-
 
 export default class UserActionsSelect extends Component {
 
     static propTypes = {
         user: PropTypes.object.isRequired,
-        isActiveUser: PropTypes.bool.isRequired
+        isActiveUser: PropTypes.bool.isRequired,
+        showModal: PropTypes.func.isRequired,
+        resendInvite: PropTypes.func.isRequired,
     };
 
     onEditDetails() {
-        this.props.dispatch(showModal({type: MODAL_EDIT_DETAILS, details: {user: this.props.user}}));
+        this.props.showModal({type: MODAL_EDIT_DETAILS, details: {user: this.props.user}});
         this.refs.popover.toggle();
     }
 
     onResendInvite() {
-        this.props.dispatch(resendInvite(this.props.user));
-        this.props.dispatch(showModal({type: MODAL_INVITE_RESENT, details: {user: this.props.user}}));
+        this.props.resendInvite(this.props.user);
+        this.props.showModal({type: MODAL_INVITE_RESENT, details: {user: this.props.user}});
         this.refs.popover.toggle();
     }
 
@@ -35,12 +36,12 @@ export default class UserActionsSelect extends Component {
             return;
         }
 
-        this.props.dispatch(showModal({type: MODAL_RESET_PASSWORD, details: {user: this.props.user}}));
+        this.props.showModal({type: MODAL_RESET_PASSWORD, details: {user: this.props.user}});
         this.refs.popover.toggle();
     }
 
     onRemoveUser() {
-        this.props.dispatch(showModal({type: MODAL_REMOVE_USER, details: {user: this.props.user}}));
+        this.props.showModal({type: MODAL_REMOVE_USER, details: {user: this.props.user}});
         this.refs.popover.toggle();
     }
 
diff --git a/frontend/src/metabase/admin/people/components/UserRoleSelect.jsx b/frontend/src/metabase/admin/people/components/UserRoleSelect.jsx
index cad798d036cd136429fac7f9f02f3f379bcc88d6..dfd644b3f983e9f635d085e698d7a0907d888454 100644
--- a/frontend/src/metabase/admin/people/components/UserRoleSelect.jsx
+++ b/frontend/src/metabase/admin/people/components/UserRoleSelect.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import cx from "classnames";
 
diff --git a/frontend/src/metabase/admin/people/containers/AdminPeopleApp.jsx b/frontend/src/metabase/admin/people/containers/AdminPeopleApp.jsx
index 0939397945145ff01ae102f678662367195cc721..32417758a127693b8a6fd20c07f6461f97cd273b 100644
--- a/frontend/src/metabase/admin/people/containers/AdminPeopleApp.jsx
+++ b/frontend/src/metabase/admin/people/containers/AdminPeopleApp.jsx
@@ -1,9 +1,21 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
 
 import AdminPeople from "../components/AdminPeople.jsx";
 import { adminPeopleSelectors } from "../selectors";
-
+import {
+    createUser,
+    deleteUser,
+    fetchUsers,
+    grantAdmin,
+    resetPasswordManually,
+    resetPasswordViaEmail,
+    revokeAdmin,
+    showModal,
+    updateUser,
+    resendInvite
+} from "../actions";
 
 const mapStateToProps = (state, props) => {
     return {
@@ -12,7 +24,20 @@ const mapStateToProps = (state, props) => {
     }
 }
 
-@connect(mapStateToProps)
+const mapDispatchToProps = {
+    createUser,
+    deleteUser,
+    fetchUsers,
+    grantAdmin,
+    resetPasswordManually,
+    resetPasswordViaEmail,
+    revokeAdmin,
+    showModal,
+    updateUser,
+    resendInvite
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
 export default class AdminPeopleApp extends Component {
     render() {
         return <AdminPeople {...this.props} />;
diff --git a/frontend/src/metabase/admin/settings/components/SettingsSetupList.jsx b/frontend/src/metabase/admin/settings/components/SettingsSetupList.jsx
index 0f77c12d8e74ecfbfea4b9b6e7853c585a47cb3c..111727d889a93f047e8b7861256fe1d3967b3c8a 100644
--- a/frontend/src/metabase/admin/settings/components/SettingsSetupList.jsx
+++ b/frontend/src/metabase/admin/settings/components/SettingsSetupList.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 import Icon from "metabase/components/Icon.jsx";
 import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
 
@@ -36,7 +37,7 @@ const CompletionBadge = ({completed}) =>
 
 
 export const Task = ({title, description, completed, link}) =>
-  <a className="bordered border-brand-hover rounded transition-border flex align-center p2 no-decoration" href={link}>
+  <Link to={link} className="bordered border-brand-hover rounded transition-border flex align-center p2 no-decoration">
     <CompletionBadge completed={completed} />
     <div>
       <TaskTitle title={title} titleClassName={
@@ -44,7 +45,7 @@ export const Task = ({title, description, completed, link}) =>
         } />
       { !completed ? <TaskDescription description={description} /> : null }
     </div>
-  </a>
+  </Link>
 
 export default class SettingsSetupList extends Component {
     constructor(props, context) {
diff --git a/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx b/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx
index 393b26ff60c64a52c2f8c964ac2f2908bfa466a0..bbc42dda00293110ae71b4e4618c8e99b1b22386 100644
--- a/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx
+++ b/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 import { connect } from "react-redux";
 import MetabaseAnalytics from "metabase/lib/analytics";
 
@@ -24,11 +25,10 @@ import * as settingsActions from "../settings";
 
 const mapStateToProps = (state, props) => {
     return {
-        refreshSiteSettings: props.refreshSiteSettings,
-        settings:            getSettings(state),
-        sections:            getSections(state),
-        activeSection:       getActiveSection(state),
-        newVersionAvailable: getNewVersionAvailable(state)
+        settings:            getSettings(state, props),
+        sections:            getSections(state, props),
+        activeSection:       getActiveSection(state, props),
+        newVersionAvailable: getNewVersionAvailable(state, props)
     }
 }
 
@@ -54,7 +54,7 @@ export default class SettingsEditorApp extends Component {
     };
 
     componentWillMount() {
-        this.props.initializeSettings(this.props.refreshSiteSettings);
+        this.props.initializeSettings();
     }
 
     updateSetting(setting, value) {
@@ -120,7 +120,7 @@ export default class SettingsEditorApp extends Component {
                     />
                 </div>
             );
-        } else if (section.name === "Single Sign On") {
+        } else if (section.name === "Single Sign-On") {
             return (
                 <div className="px2">
                     <SettingsSingleSignOnForm
@@ -160,10 +160,10 @@ export default class SettingsEditorApp extends Component {
 
             return (
                 <li key={section.name}>
-                    <a href={"/admin/settings/?section=" + section.name} className={classes}>
+                    <Link to={"/admin/settings/" + section.slug}  className={classes}>
                         <span>{section.name}</span>
                         {newVersionIndicator}
-                    </a>
+                    </Link>
                 </li>
             );
         });
diff --git a/frontend/src/metabase/admin/settings/selectors.js b/frontend/src/metabase/admin/settings/selectors.js
index b064ccb015a59d40893c2aeadc24ddc624acae79..423b32f457f257d5d05a9fe0ac3a210e87d9b98f 100644
--- a/frontend/src/metabase/admin/settings/selectors.js
+++ b/frontend/src/metabase/admin/settings/selectors.js
@@ -2,6 +2,7 @@ import _ from "underscore";
 import { createSelector } from "reselect";
 import MetabaseSettings from "metabase/lib/settings";
 
+import { slugify } from "metabase/lib/formatting";
 
 const SECTIONS = [
     {
@@ -138,7 +139,7 @@ const SECTIONS = [
         ]
     },
     {
-        name: "Single Sign On",
+        name: "Single Sign-On",
         settings: [
             {
                 key: "google-auth-client-id"
@@ -149,6 +150,9 @@ const SECTIONS = [
         ]
     }
 ];
+for (const section of SECTIONS) {
+    section.slug = slugify(section.name);
+}
 
 export const getSettings = state => state.settings.settings;
 
@@ -183,14 +187,14 @@ export const getSections = createSelector(
     }
 );
 
-export const getActiveSectionName = (state) => state.router && state.router.location && state.router.location.query.section
+export const getActiveSectionName = (state, props) => props.params.section
 
 export const getActiveSection = createSelector(
     getActiveSectionName,
     getSections,
-    (section = "Setup", sections) => {
+    (section = "setup", sections) => {
         if (sections) {
-            return _.findWhere(sections, {name: section});
+            return _.findWhere(sections, { slug: section });
         } else {
             return null;
         }
diff --git a/frontend/src/metabase/admin/settings/settings.js b/frontend/src/metabase/admin/settings/settings.js
index 48987fce6e7d7b6e72cb153cfba31f31a27ab573..49ad04b471408648b8b83cba53733f49b2bb000e 100644
--- a/frontend/src/metabase/admin/settings/settings.js
+++ b/frontend/src/metabase/admin/settings/settings.js
@@ -1,12 +1,20 @@
 
 import { handleActions, combineReducers, AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
 
+import MetabaseSettings from 'metabase/lib/settings';
+
+import _ from "underscore";
 
 // resource wrappers
 const SettingsApi = new AngularResourceProxy("Settings", ["list", "put"]);
 const EmailApi = new AngularResourceProxy("Email", ["updateSettings", "sendTest"]);
 const SlackApi = new AngularResourceProxy("Slack", ["updateSettings"]);
+const SessionApi = new AngularResourceProxy("Session", ["properties"]);
 
+async function refreshSiteSettings() {
+    const settings = await SessionApi.properties();
+    MetabaseSettings.setAll(_.omit(settings, (value, key) => key.indexOf('$') === 0));
+}
 
 async function loadSettings() {
     try {
@@ -22,14 +30,10 @@ async function loadSettings() {
 }
 
 // initializeSettings
-export const initializeSettings = createThunkAction("INITIALIZE_SETTINGS", function(refreshSiteSettings) {
+export const initializeSettings = createThunkAction("INITIALIZE_SETTINGS", function() {
     return async function(dispatch, getState) {
         try {
-            let settings = await loadSettings();
-            return {
-                settings,
-                refreshSiteSettings
-            }
+            return await loadSettings();
         } catch(error) {
             console.log("error fetching settings", error);
             throw error;
@@ -40,8 +44,6 @@ export const initializeSettings = createThunkAction("INITIALIZE_SETTINGS", funct
 // updateSetting
 export const updateSetting = createThunkAction("UPDATE_SETTING", function(setting) {
     return async function(dispatch, getState) {
-        const { settings: { refreshSiteSettings } } = getState();
-
         try {
             await SettingsApi.put({ key: setting.key }, setting);
             refreshSiteSettings();
@@ -56,8 +58,6 @@ export const updateSetting = createThunkAction("UPDATE_SETTING", function(settin
 // updateEmailSettings
 export const updateEmailSettings = createThunkAction("UPDATE_EMAIL_SETTINGS", function(settings) {
     return async function(dispatch, getState) {
-        const { settings: { refreshSiteSettings } } = getState();
-
         try {
             await EmailApi.updateSettings(settings);
             refreshSiteSettings();
@@ -84,8 +84,6 @@ export const sendTestEmail = createThunkAction("SEND_TEST_EMAIL", function() {
 // updateSlackSettings
 export const updateSlackSettings = createThunkAction("UPDATE_SLACK_SETTINGS", function(settings) {
     return async function(dispatch, getState) {
-        const { settings: { refreshSiteSettings } } = getState();
-
         try {
             await SlackApi.updateSettings(settings);
             refreshSiteSettings();
@@ -97,22 +95,15 @@ export const updateSlackSettings = createThunkAction("UPDATE_SLACK_SETTINGS", fu
     };
 });
 
-
 // reducers
 
-// this is a backwards compatibility thing with angular to allow programmatic route changes.  remove/change this when going to ReduxRouter
-const refreshSiteSettings = handleActions({
-    ["INITIALIZE_SETTINGS"]: { next: (state, { payload }) => payload ? payload.refreshSiteSettings : state }
-}, () => null);
-
 const settings = handleActions({
-    ["INITIALIZE_SETTINGS"]: { next: (state, { payload }) => payload ? payload.settings : state },
+    ["INITIALIZE_SETTINGS"]: { next: (state, { payload }) => payload },
     ["UPDATE_SETTING"]: { next: (state, { payload }) => payload },
     ["UPDATE_EMAIL_SETTINGS"]: { next: (state, { payload }) => payload },
     ["UPDATE_SLACK_SETTINGS"]: { next: (state, { payload }) => payload }
 }, []);
 
 export default combineReducers({
-    settings,
-    refreshSiteSettings
+    settings
 });
diff --git a/frontend/src/metabase/app.js b/frontend/src/metabase/app.js
index 9b3e14702cbb1f63f35f6fd49d4fc7de50ba07e6..f9d1a73138aedab69c929e0d81bb2eb74882e69e 100644
--- a/frontend/src/metabase/app.js
+++ b/frontend/src/metabase/app.js
@@ -1,435 +1,68 @@
 /* @flow weak */
 
-import 'babel-polyfill';
-
 // angular:
-import 'angular';
-import 'angular-cookies';
-import 'angular-resource';
-import 'angular-route';
-
-// angular 3rd-party:
-import 'angular-cookie';
-import 'angular-http-auth';
-
-import "./controllers";
-import "./directives";
 import "./services";
 
+angular
+.module('metabase', ['ipCookie', 'metabase.controllers'])
+.run([function() {}])
 
-import React from "react";
-//import { render } from "react-dom";
-//import { Provider } from "react-redux";
-import { combineReducers } from "redux";
-import { reducer as form } from "redux-form";
-import { reduxReactRouter, routerStateReducer } from "redux-router";
-
-import Navbar from "./components/Navbar.jsx";
-import Routes from "./Routes.jsx";
-
-import auth from "metabase/auth/auth";
-
-/* ducks */
-import metadata from "metabase/redux/metadata";
-import requests from "metabase/redux/requests";
-
-/* admin */
-import settings from "metabase/admin/settings/settings";
-import * as people from "metabase/admin/people/reducers";
-import databases from "metabase/admin/databases/database";
-import datamodel from "metabase/admin/datamodel/metadata";
-
-/* dashboards */
-import dashboard from "metabase/dashboard/dashboard";
-import * as home from "metabase/home/reducers";
-
-/* questions / query builder */
-import questions from "metabase/questions/questions";
-import labels from "metabase/questions/labels";
-import undo from "metabase/questions/undo";
-import * as qb from "metabase/query_builder/reducers";
+angular
+.module('metabase.controllers', ['metabase.services'])
+.controller('Metabase', [function() {}]);
 
-/* data reference */
-import reference from "metabase/reference/reference";
+import React from 'react'
+import ReactDOM from 'react-dom'
+import { Provider } from 'react-redux'
+import { push } from "react-router-redux";
 
-/* pulses */
-import * as pulse from "metabase/pulse/reducers";
+import MetabaseAnalytics, { registerAnalyticsClickListener } from "metabase/lib/analytics";
+import MetabaseSettings from "metabase/lib/settings";
 
-/* setup */
-import * as setup from "metabase/setup/reducers";
+import { getRoutes } from "./routes.jsx";
+import { getStore } from './store'
 
-/* user */
-import * as user from "metabase/user/reducers";
-import { currentUser, setUser } from "metabase/user";
+import { Router, browserHistory } from "react-router";
+import { syncHistoryWithStore } from 'react-router-redux'
 
-import { registerAnalyticsClickListener } from "metabase/lib/analytics";
-import { serializeCardForUrl, cleanCopyCard, urlForCardState } from "metabase/lib/card";
-import { createStoreWithAngularScope } from "metabase/lib/redux";
+function init() {
+    const store = getStore(browserHistory);
+    const routes = getRoutes(store);
+    const history = syncHistoryWithStore(browserHistory, store);
 
-const reducers = combineReducers({
-    form,
-    router: routerStateReducer,
+    ReactDOM.render(
+        <Provider store={store}>
+          <Router history={history}>
+            {routes}
+          </Router>
+        </Provider>
+    , document.getElementById('root'));
 
-    // global reducers
-    auth,
-    currentUser,
-    metadata,
-    requests,
-
-    // main app reducers
-    dashboard,
-    home: combineReducers(home),
-    labels,
-    pulse: combineReducers(pulse),
-    qb: combineReducers(qb),
-    questions,
-    reference,
-    setup: combineReducers(setup),
-    undo,
-    user: combineReducers(user),
-
-    // admin reducers
-    databases,
-    datamodel: datamodel,
-    people: combineReducers(people),
-    settings
-});
-
-// Declare app level module which depends on filters, and services
-angular.module('metabase', [
-    'ngRoute',
-    'ngCookies',
-    'metabase.directives',
-    'metabase.controllers',
-])
-.run(["AppState", function(AppState) {
-    // initialize app state
-    AppState.init();
-
-    // start our analytics click listener
-    registerAnalyticsClickListener();
-}])
-.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
-    $locationProvider.html5Mode({
-        enabled: true,
-        requireBase: false
+    // listen for location changes and use that as a trigger for page view tracking
+    history.listen(location => {
+        MetabaseAnalytics.trackPageView(location.pathname);
     });
 
-    const route = {
-        template: '<div mb-redux-component class="flex flex-column spread" id="main" />',
-        controller: 'AppController',
-        resolve: {
-            appState: ["AppState", function(AppState) {
-                return AppState.init();
-            }]
-        },
-        className: "flex flex-column spread"
-    };
-
-    $routeProvider.when('/', { ...route, className: "full-height"});
-
-    $routeProvider.when('/admin/', { redirectTo: () => ('/admin/settings') });
-    $routeProvider.when('/admin/databases', route);
-    $routeProvider.when('/admin/databases/create', route);
-    $routeProvider.when('/admin/databases/:databaseId', route);
-    $routeProvider.when('/admin/datamodel/database', { ...route, className: "full-height spread" });
-    $routeProvider.when('/admin/datamodel/database/:databaseId', { ...route, className: "full-height spread" });
-    $routeProvider.when('/admin/datamodel/database/:databaseId/:mode', { ...route, className: "full-height spread" });
-    $routeProvider.when('/admin/datamodel/database/:databaseId/:mode/:tableId', { ...route, className: "full-height spread" });
-    $routeProvider.when('/admin/datamodel/metric', route);
-    $routeProvider.when('/admin/datamodel/metric/:segmentId', route);
-    $routeProvider.when('/admin/datamodel/segment', route);
-    $routeProvider.when('/admin/datamodel/segment/:segmentId', route);
-    $routeProvider.when('/admin/datamodel/:objectType/:objectId/revisions', route);
-    $routeProvider.when('/admin/people/', route);
-    $routeProvider.when('/admin/settings/', { ...route, className: "full-height" });
-
-    $routeProvider.when('/reference', route);
-    $routeProvider.when('/reference/guide', route);
-    $routeProvider.when('/reference/metrics', route);
-    $routeProvider.when('/reference/metrics/:metricId', route);
-    $routeProvider.when('/reference/metrics/:metricId/questions', route);
-    $routeProvider.when('/reference/metrics/:metricId/questions/:cardId', route);
-    $routeProvider.when('/reference/metrics/:metricId/revisions', route);
-    $routeProvider.when('/reference/segments', route);
-    $routeProvider.when('/reference/segments/:segmentId', route);
-    $routeProvider.when('/reference/segments/:segmentId/fields', route);
-    $routeProvider.when('/reference/segments/:segmentId/fields/:fieldId', route);
-    $routeProvider.when('/reference/segments/:segmentId/questions', route);
-    $routeProvider.when('/reference/segments/:segmentId/questions/:cardId', route);
-    $routeProvider.when('/reference/segments/:segmentId/revisions', route);
-    $routeProvider.when('/reference/databases', route);
-    $routeProvider.when('/reference/databases/:databaseId', route);
-    $routeProvider.when('/reference/databases/:databaseId/tables', route);
-    $routeProvider.when('/reference/databases/:databaseId/tables/:tableId', route);
-    $routeProvider.when('/reference/databases/:databaseId/tables/:tableId/fields', route);
-    $routeProvider.when('/reference/databases/:databaseId/tables/:tableId/fields/:fieldId', route);
-    $routeProvider.when('/reference/databases/:databaseId/tables/:tableId/questions', route);
-    $routeProvider.when('/reference/databases/:databaseId/tables/:tableId/questions/:cardId', route);
-
-    $routeProvider.when('/auth/', { redirectTo: () => ('/auth/login') });
-    $routeProvider.when('/auth/forgot_password', { ...route, className: "full-height" });
-    $routeProvider.when('/auth/login', { ...route, className: "full-height" });
-    $routeProvider.when('/auth/logout', { ...route, className: "full-height" });
-    $routeProvider.when('/auth/reset_password/:token', { ...route, className: "full-height" });
-
-    $routeProvider.when('/card/', { redirectTo: () => ("/questions/all") });
-    $routeProvider.when('/card/:cardId', { ...route, className: "" });
-    $routeProvider.when('/card/:cardId/:serializedCard', { redirectTo: (routeParams) => ("/card/"+routeParams.cardId+"#"+routeParams.serializedCard) });
-
-    $routeProvider.when('/dash/:dashboardId', route);
-
-    $routeProvider.when('/pulse/', { ...route, className: "" });
-    $routeProvider.when('/pulse/create', { ...route, className: "flex flex-column flex-full" });
-    $routeProvider.when('/pulse/:pulseId', { ...route, className: "flex flex-column flex-full" });
-
-    $routeProvider.when('/q', { ...route, className: "" });
-    $routeProvider.when('/q/:serializedCard', { redirectTo: (routeParams) => ("/q#"+routeParams.serializedCard) });
-
-    $routeProvider.when('/questions', route);
-    $routeProvider.when('/questions/edit/:section', route);
-    $routeProvider.when('/questions/:section', route);
-    $routeProvider.when('/questions/:section/:slug', route);
-
-    $routeProvider.when('/setup/', { ...route, className: "full-height" });
-
-    $routeProvider.when('/unauthorized/', route);
-    $routeProvider.when('/user/edit_current', route);
-
-    $routeProvider.otherwise(route);
-}])
-.controller('AppController', ['$scope', '$location', '$route', '$routeParams', '$rootScope', '$timeout', 'ipCookie', 'AppState',
-    function($scope, $location, $route, $routeParams, $rootScope, $timeout, ipCookie, AppState) {
-        $scope.Component = Routes;
-        $scope.props = {
-            onChangeLocation(url) {
-                $scope.$apply(() => $location.url(url));
-            },
-            onChangeLocationSearch(name, value) {
-                // FIXME: this doesn't seem to work
-                $scope.$apply(() => $location.search(name, value));
-            },
-            onBroadcast(...args) {
-                $scope.$apply(() => $rootScope.$broadcast(...args));
-            },
-            refreshSiteSettings() {
-                $scope.$apply(() => AppState.refreshSiteSettings());
-            },
-            setSessionFn(sessionId) {
-                // TODO - this session cookie code needs to be somewhere easily reusable
-                var isSecure = ($location.protocol() === "https") ? true : false;
-                ipCookie('metabase.SESSION_ID', sessionId, {
-                    path: '/',
-                    expires: 14,
-                    secure: isSecure
-                });
-
-                // send a login notification event
-                $scope.$emit('appstate:login', sessionId);
-
-                // this is ridiculously stupid.  we have to wait (300ms) for the cookie to actually be set in the browser :(
-                return $timeout(function(){}, 1000);
-            },
-            broadcastEventFn: function(eventName, value) {
-                $rootScope.$broadcast(eventName, value);
-            },
-            updateUrl: (card, isDirty=false, replaceState=false) => {
-                if (!card) {
-                    return;
-                }
-                var copy = cleanCopyCard(card);
-                var newState = {
-                    card: copy,
-                    cardId: copy.id,
-                    serializedCard: serializeCardForUrl(copy)
-                };
-
-                if (angular.equals(window.history.state, newState)) {
-                    return;
-                }
-
-                var url = urlForCardState(newState, isDirty);
-
-                // if the serialized card is identical replace the previous state instead of adding a new one
-                // e.x. when saving a new card we want to replace the state and URL with one with the new card ID
-                replaceState = replaceState || (window.history.state && window.history.state.serializedCard === newState.serializedCard);
-
-                // ensure the digest cycle is run, otherwise pending location changes will prevent navigation away from query builder on the first click
-                $scope.$apply(() => {
-                    // prevents infinite digest loop
-                    // https://stackoverflow.com/questions/22914228/successfully-call-history-pushstate-from-angular-without-inifinite-digest
-                    $location.url(url);
-                    $location.replace();
-                    if (replaceState) {
-                        window.history.replaceState(newState, null, $location.absUrl());
-                    } else {
-                        window.history.pushState(newState, null, $location.absUrl());
-                    }
-                });
-            }
-        };
-        $scope.store = createStoreWithAngularScope($scope, $location, reducers, {currentUser: AppState.model.currentUser});
-
-        // ANGULAR_HACKâ„¢: this seems like the easiest way to keep the redux store up to date with the currentUser :-/
-        let userSyncTimer = setInterval(() => {
-            if ($scope.store.getState().currentUser !== AppState.model.currentUser) {
-                $scope.store.dispatch(setUser(AppState.model.currentUser));
-            }
-        }, 250);
-        $scope.$on("$destroy", () => clearInterval(userSyncTimer));
-
-        // HACK: prevent reloading controllers as the URL changes
-        let route = $route.current;
-        $scope.$on('$locationChangeSuccess', function (event) {
-            let newParams = $route.current.params;
-            let oldParams = route.params;
-
-            if ($route.current.$$route.controller === 'AppController') {
-                updateClassName();
-                $route.current = route;
-
-                angular.forEach(oldParams, function(value, key) {
-                    delete $route.current.params[key];
-                    delete $routeParams[key];
-                });
-                angular.forEach(newParams, function(value, key) {
-                    $route.current.params[key] = value;
-                    $routeParams[key] = value;
-                });
-            }
-        });
-
-        // HACK: keep className up to date when changing location, since we don't actually change routes
-        function updateClassName() {
-            const el = document.getElementById("main");
-            if (el) {
-                el.className = $route.current.$$route.className;
-            }
-        }
-
-        updateClassName();
-    }
-])
-.controller('Nav', ['$scope', '$routeParams', '$location', '$rootScope', 'AppState', 'Dashboard',
-    function($scope, $routeParams, $location, $rootScope, AppState, Dashboard) {
-
-        function refreshDashboards() {
-            if (AppState.model.currentUser) {
-                Dashboard.list({ f: "all" }, function (dashes) {
-                    $scope.dashboards = dashes;
-                }, function (error) {
-                    console.log('error getting dahsboards list', error);
-                });
-            }
-        }
-
-        function setNavContext(context) {
-            $scope.context = context;
-        }
-
-        $scope.Navbar = Navbar;
-        $scope.location = $location;
-
-        $scope.dashboards = [];
-        $scope.createDashboardFn = async function(newDashboard) {
-            var dashboard = await Dashboard.create(newDashboard).$promise;
-            $rootScope.$broadcast("dashboard:create", dashboard.id);
-            $location.path("/dash/" + dashboard.id);
-
-            // this is important because it allows our caller to perform any of their own actions after the promis resolves
-            return dashboard;
-        };
-
-        $scope.$on('appstate:context-changed', function(event, newAppContext) {
-            setNavContext(newAppContext);
-        });
-
-        $scope.$on("dashboard:create", function(event, dashboardId) {
-            refreshDashboards();
-        });
-
-        $scope.$on("dashboard:delete", function(event, dashboardId) {
-            refreshDashboards();
-        });
-
-        $scope.$on("dashboard:update", function(event, dashboardId) {
-            refreshDashboards();
-        });
-
-        $scope.$on("appstate:user", function(event, dashboardId) {
-            refreshDashboards();
-        });
-
-        $scope.$on("appstate:login", function(event, dashboardId) {
-            refreshDashboards();
-        });
-
-        $scope.$on("appstate:logout", function(event, dashboardId) {
-            $scope.dashboards = [];
-        });
-
-        // always initialize with a fresh listing
-        refreshDashboards();
-
-        // initialize our state from the current AppState model, which we expect to have resolved already
-        setNavContext(AppState.model.appContext);
-    }
-]);
-
-
-
-
-// async function refreshCurrentUser() {
-//     let response = await fetch("/api/user/current", { credentials: 'same-origin' });
-//     if (response.status === 200) {
-//         return await response.json();
-//     }
-// }
-
-
-// This is the entry point for our Redux application which is fired once on page load.
-// We attempt to:
-//   1. Identify the currently authenticated user, if possible
-//   2. Create the application Redux store
-//   3. Render our React/Redux application using a single Redux `Provider`
-// window.onload = async function() {
-//     // refresh site settings
-
-//     // fetch current user
-//     let user = await refreshCurrentUser();
-
-//     // initialize redux store
-//     // NOTE: we want to initialize the store with the active user because it makes lots of other initialization steps simpler
-//     let store = createMetabaseStore(reducers, {currentUser: user});
-
-//     // route change listener
-//     // set app context (for navbar)
-//     // guard admin urls and redirect to auth pages
+    registerAnalyticsClickListener();
 
-//     // events fired
-//     // appstate:user - currentUser changed
-//     // appstate:site-settings - changes made to current app settings
-//     // appstate:context-changed - app section changed (only used by navbar?)
+    // enable / disable GA based on opt-out of anonymous tracking
+    MetabaseSettings.on("anon_tracking_enabled", () => {
+        window['ga-disable-' + MetabaseSettings.get('ga_code')] = MetabaseSettings.isTrackingEnabled() ? null : true;
+    });
 
-//     // listeners
-//     // $locationChangeSuccess - analytics route tracking
-//     // $routeChangeSuccess - route protection logic (updates context and redirects urls based on user perms)
-//     // appstate:login - refresh the currentUser
-//     // appstate:logout - null the currentUser and make sure cookie is cleared and session deleted
-//     // appstate:site-settings - if GA setting changed then update analytics appropriately
-//     // event:auth-loginRequired - (fired by angular service middleware) lets us know an api call returned a 401
-//     // event:auth-forbidden - (fired by angular service middleware) lets us know an api call returned a 403
+    // $http interceptor received a 401 response
+    angular.element(document.body).injector().get("$rootScope").$on("event:auth-loginRequired", function() {
+        store.dispatch(push("/auth/login"));
+    });
 
-//     // start analytics
+    // $http interceptor received a 403 response
+    angular.element(document.body).injector().get("$rootScope").$on("event:auth-forbidden", function() {
+        store.dispatch(push("/unauthorized"));
+    });
+}
 
-//     let reduxApp = document.getElementById("redux-app");
-//     render(
-//         <Provider store={store}>
-//             <div className="full full-height">
-//                 <div className="Nav"><Navbar /></div>
-//                 <main className="relative full-height z1"><Routes /></main>
-//             </div>
-//         </Provider>,
-//         reduxApp
-//     );
-// }
+if (document.readyState != 'loading') {
+    init();
+} else {
+    document.addEventListener('DOMContentLoaded', init);
+}
diff --git a/frontend/src/metabase/auth/auth.js b/frontend/src/metabase/auth/auth.js
index 3af4c586edaa3e53012ed11934d3bfa8a7a08267..58a9fb31fedcfe5c3a3a5de6ee737bf781daf164 100644
--- a/frontend/src/metabase/auth/auth.js
+++ b/frontend/src/metabase/auth/auth.js
@@ -1,19 +1,22 @@
 
 import { handleActions, combineReducers, AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
 
+import { push } from "react-router-redux";
+
 import MetabaseCookies from "metabase/lib/cookies";
 import MetabaseUtils from "metabase/lib/utils";
 import MetabaseAnalytics from "metabase/lib/analytics";
 
 import { clearGoogleAuthCredentials } from "metabase/lib/auth";
 
+import { refreshCurrentUser } from "metabase/user";
 
 // resource wrappers
 const SessionApi = new AngularResourceProxy("Session", ["create", "createWithGoogleAuth", "delete", "reset_password"]);
 
 
 // login
-export const login = createThunkAction("AUTH_LOGIN", function(credentials, onChangeLocation) {
+export const login = createThunkAction("AUTH_LOGIN", function(credentials) {
     return async function(dispatch, getState) {
 
         if (!MetabaseUtils.validEmail(credentials.email)) {
@@ -28,8 +31,8 @@ export const login = createThunkAction("AUTH_LOGIN", function(credentials, onCha
 
             MetabaseAnalytics.trackEvent('Auth', 'Login');
             // TODO: redirect after login (carry user to intended destination)
-            // this is ridiculously stupid.  we have to wait (300ms) for the cookie to actually be set in the browser :(
-            setTimeout(() => onChangeLocation("/"), 300);
+            await dispatch(refreshCurrentUser());
+            dispatch(push("/"));
 
         } catch (error) {
             return error;
@@ -39,7 +42,7 @@ export const login = createThunkAction("AUTH_LOGIN", function(credentials, onCha
 
 
 // login Google
-export const loginGoogle = createThunkAction("AUTH_LOGIN_GOOGLE", function(googleUser, onChangeLocation) {
+export const loginGoogle = createThunkAction("AUTH_LOGIN_GOOGLE", function(googleUser) {
     return async function(dispatch, getState) {
         try {
             let newSession = await SessionApi.createWithGoogleAuth({
@@ -52,14 +55,14 @@ export const loginGoogle = createThunkAction("AUTH_LOGIN_GOOGLE", function(googl
             MetabaseAnalytics.trackEvent('Auth', 'Google Auth Login');
 
             // TODO: redirect after login (carry user to intended destination)
-            // this is ridiculously stupid.  we have to wait (300ms) for the cookie to actually be set in the browser :(
-            setTimeout(() => onChangeLocation("/"), 300);
+            await dispatch(refreshCurrentUser());
+            dispatch(push("/"));
 
         } catch (error) {
             clearGoogleAuthCredentials();
             // If we see a 428 ("Precondition Required") that means we need to show the "No Metabase account exists for this Google Account" page
             if (error.status === 428) {
-                onChangeLocation('/auth/google_no_mb_account');
+                dispatch(push("/auth/google_no_mb_account"));
             } else {
                 return error;
             }
@@ -68,8 +71,8 @@ export const loginGoogle = createThunkAction("AUTH_LOGIN_GOOGLE", function(googl
 });
 
 // logout
-export const logout = createThunkAction("AUTH_LOGOUT", function(onChangeLocation) {
-    return async function(dispatch, getState) {
+export const logout = createThunkAction("AUTH_LOGOUT", function() {
+    return function(dispatch, getState) {
         // TODO: as part of a logout we want to clear out any saved state that we have about anything
 
         let sessionId = MetabaseCookies.setSessionCookie();
@@ -79,12 +82,12 @@ export const logout = createThunkAction("AUTH_LOGOUT", function(onChangeLocation
         }
         MetabaseAnalytics.trackEvent('Auth', 'Logout');
 
-        setTimeout(() => onChangeLocation("/auth/login"), 300);
+        dispatch(push("/auth/login"));
     };
 });
 
 // passwordReset
-export const passwordReset = createThunkAction("AUTH_PASSWORD_RESET", function(token, credentials, onChangeLocation) {
+export const passwordReset = createThunkAction("AUTH_PASSWORD_RESET", function(token, credentials) {
     return async function(dispatch, getState) {
 
         if (credentials.password !== credentials.password2) {
diff --git a/frontend/src/metabase/auth/components/BackToLogin.jsx b/frontend/src/metabase/auth/components/BackToLogin.jsx
index 4d602083b2b91dcc6750b175e0ed7d08183fb9a7..4ded6c192a19e71fae793f0012454001958d3df9 100644
--- a/frontend/src/metabase/auth/components/BackToLogin.jsx
+++ b/frontend/src/metabase/auth/components/BackToLogin.jsx
@@ -1,6 +1,7 @@
-import React from 'react'
+import React from 'react';
+import { Link } from "react-router";
 
 const BackToLogin = () =>
-    <a className="link block" href="/auth/login">Back to login</a>
+    <Link to="/auth/login" className="link block">Back to login</Link>
 
 export default BackToLogin;
diff --git a/frontend/src/metabase/auth/containers/LoginApp.jsx b/frontend/src/metabase/auth/containers/LoginApp.jsx
index abc33827c51ecca1750b17415134996dae8ff5e1..e2970bebcf9a646edcd607cfcecca70aa924b595 100644
--- a/frontend/src/metabase/auth/containers/LoginApp.jsx
+++ b/frontend/src/metabase/auth/containers/LoginApp.jsx
@@ -1,5 +1,6 @@
 import React, { Component, PropTypes } from "react";
 import { findDOMNode } from "react-dom";
+import { Link } from "react-router";
 import { connect } from "react-redux";
 
 import cx from "classnames";
@@ -19,8 +20,7 @@ import * as authActions from "../auth";
 const mapStateToProps = (state, props) => {
     return {
         loginError:       state.auth && state.auth.loginError,
-        user:             state.currentUser,
-        onChangeLocation: props.onChangeLocation
+        user:             state.currentUser
     }
 }
 
@@ -57,7 +57,7 @@ export default class LoginApp extends Component {
 
         this.validateForm();
 
-        const { loginGoogle, onChangeLocation } = this.props;
+        const { loginGoogle } = this.props;
 
         let ssoLoginButton = findDOMNode(this.refs.ssoLoginButton);
 
@@ -74,7 +74,7 @@ export default class LoginApp extends Component {
                       cookiepolicy: 'single_host_origin',
                   });
                   auth2.attachClickHandler(ssoLoginButton, {},
-                      (googleUser) => loginGoogle(googleUser, onChangeLocation),
+                      (googleUser) => loginGoogle(googleUser),
                       (error) => console.error('There was an error logging in', error)
                   );
                 })
@@ -89,14 +89,6 @@ export default class LoginApp extends Component {
         this.validateForm();
     }
 
-    componentWillReceiveProps(newProps) {
-        const { user, onChangeLocation } = newProps;
-            // if we already have a user then we shouldn't be logging in
-        if (user) {
-            onChangeLocation("/");
-        }
-    }
-
     onChange(fieldName, fieldValue) {
         this.setState({ credentials: { ...this.state.credentials, [fieldName]: fieldValue }});
     }
@@ -104,10 +96,10 @@ export default class LoginApp extends Component {
     formSubmitted(e) {
         e.preventDefault();
 
-        let { login, onChangeLocation } = this.props;
+        let { login } = this.props;
         let { credentials } = this.state;
 
-        login(credentials, onChangeLocation);
+        login(credentials);
     }
 
     render() {
@@ -158,7 +150,7 @@ export default class LoginApp extends Component {
                                 <button className={cx("Button Grid-cell", {'Button--primary': this.state.valid})} disabled={!this.state.valid}>
                                     Sign in
                                 </button>
-                                <a className="Grid-cell py2 sm-py0 text-grey-3 md-text-right text-centered flex-full link" href="/auth/forgot_password" onClick={(e) => { window.OSX ? window.OSX.resetPassword() : null }}>I seem to have forgotten my password</a>
+                                <Link to="/auth/forgot_password" className="Grid-cell py2 sm-py0 text-grey-3 md-text-right text-centered flex-full link" onClick={(e) => { window.OSX ? window.OSX.resetPassword() : null }}>I seem to have forgotten my password</Link>
                             </div>
                         </form>
                     </div>
diff --git a/frontend/src/metabase/auth/containers/LogoutApp.jsx b/frontend/src/metabase/auth/containers/LogoutApp.jsx
index d6bda34e5c64aa907cb49b6cb1fd9754bf31167c..c7ac8276c83d8f19243087ed6910444156fc8b10 100644
--- a/frontend/src/metabase/auth/containers/LogoutApp.jsx
+++ b/frontend/src/metabase/auth/containers/LogoutApp.jsx
@@ -1,25 +1,19 @@
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
 
-import * as authActions from "../auth";
+import { logout } from "../auth";
 
-
-const mapStateToProps = (state, props) => {
-    return {
-        user:             state.currentUser,
-        onChangeLocation: props.onChangeLocation
-    }
-}
+const mapStateToProps = null;
 
 const mapDispatchToProps = {
-    ...authActions
-}
+    logout
+};
 
 @connect(mapStateToProps, mapDispatchToProps)
 export default class LogoutApp extends Component {
 
     componentWillMount() {
-        this.props.logout(this.props.onChangeLocation);
+        this.props.logout();
     }
 
     render() {
diff --git a/frontend/src/metabase/auth/containers/PasswordResetApp.jsx b/frontend/src/metabase/auth/containers/PasswordResetApp.jsx
index bc573a7668f3e3a9db8ac5f2217fcd35919ad97f..4a11c424e0d99c7f0b0e76bec865432118980247 100644
--- a/frontend/src/metabase/auth/containers/PasswordResetApp.jsx
+++ b/frontend/src/metabase/auth/containers/PasswordResetApp.jsx
@@ -1,5 +1,6 @@
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+import { Link } from "react-router";
 import { AngularResourceProxy } from "metabase/lib/redux";
 
 import cx from "classnames";
@@ -19,11 +20,10 @@ const SessionApi = new AngularResourceProxy("Session", ["password_reset_token_va
 
 const mapStateToProps = (state, props) => {
     return {
-        token:            state.router && state.router.params && state.router.params.token,
+        token:            props.params.token,
         resetError:       state.auth && state.auth.resetError,
         resetSuccess:     state.auth && state.auth.resetSuccess,
-        newUserJoining:   state.router && state.router.location && state.router.location.hash === "#new",
-        onChangeLocation: props.onChangeLocation
+        newUserJoining:   props.location.hash === "#new"
     }
 }
 
@@ -83,10 +83,10 @@ export default class PasswordResetApp extends Component {
     formSubmitted(e) {
         e.preventDefault();
 
-        let { token, passwordReset, onChangeLocation } = this.props;
+        let { token, passwordReset } = this.props;
         let { credentials } = this.state;
 
-        passwordReset(token, credentials, onChangeLocation);
+        passwordReset(token, credentials);
     }
 
     render() {
@@ -106,7 +106,7 @@ export default class PasswordResetApp extends Component {
                                     <h3 className="Login-header Form-offset mt4">Whoops, that's an expired link</h3>
                                     <p className="Form-offset mb4 mr4">
                                         For security reasons, password reset links expire after a little while. If you still need
-                                        to reset your password, you can <a href="/auth/forgot_password" className="link">request a new reset email</a>.
+                                        to reset your password, you can <Link to="/auth/forgot_password" className="link">request a new reset email</Link>.
                                     </p>
                                 </div>
                             </div>
@@ -160,9 +160,9 @@ export default class PasswordResetApp extends Component {
                                   <p>Your password has been reset.</p>
                                   <p>
                                       { newUserJoining ?
-                                      <a href="/?new" className="Button Button--primary">Sign in with your new password</a>
+                                      <Link to="/?new" className="Button Button--primary">Sign in with your new password</Link>
                                       :
-                                      <a href="/" className="Button Button--primary">Sign in with your new password</a>
+                                      <Link to="/" className="Button Button--primary">Sign in with your new password</Link>
                                       }
                                   </p>
                               </div>
diff --git a/frontend/src/metabase/components/BodyComponent.jsx b/frontend/src/metabase/components/BodyComponent.jsx
index 6cb8f476af29a66b757d2cf13489303054dbe3ec..631c01d7ffa5cddcb4523fb18ee81db7d6a02aee 100644
--- a/frontend/src/metabase/components/BodyComponent.jsx
+++ b/frontend/src/metabase/components/BodyComponent.jsx
@@ -26,7 +26,9 @@ export default ComposedComponent => class extends Component {
 
     _render() {
         this._element.className = this.props.className || "";
-        ReactDOM.render(<ComposedComponent {...this.props} className={undefined} />, this._element);
+        ReactDOM.unstable_renderSubtreeIntoContainer(this,
+            <ComposedComponent {...this.props} className={undefined} />
+        , this._element);
     }
 
     render() {
diff --git a/frontend/src/metabase/components/Breadcrumbs.jsx b/frontend/src/metabase/components/Breadcrumbs.jsx
index af080db1ba4db5e1b34674b833e604ad0a2e80fa..c32baf6d26a18125317e1e4f2e9619c86d21e592 100644
--- a/frontend/src/metabase/components/Breadcrumbs.jsx
+++ b/frontend/src/metabase/components/Breadcrumbs.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import S from "./Breadcrumbs.css";
 
@@ -51,7 +52,7 @@ export default class Breadcrumbs extends Component {
                                 )}
                             >
                                 { breadcrumb.length > 1 ?
-                                    <a href={breadcrumb[1]}>{breadcrumb[0]}</a> :
+                                    <Link to={breadcrumb[1]}>{breadcrumb[0]}</Link> :
                                     <span>{breadcrumb[0]}</span>
                                 }
                             </Ellipsified>
diff --git a/frontend/src/metabase/components/DeleteModalWithConfirm.jsx b/frontend/src/metabase/components/DeleteModalWithConfirm.jsx
index e45d47fd545f6e416c6ef4b36a4235c0b39d932f..f3e48b35f54b8519f8bf49440eba71c3357c1cbd 100644
--- a/frontend/src/metabase/components/DeleteModalWithConfirm.jsx
+++ b/frontend/src/metabase/components/DeleteModalWithConfirm.jsx
@@ -41,7 +41,7 @@ export default class DeleteModalWithConfirm extends Component {
             <div className="px4 pb4">
                 <ul>
                     {confirmItems.map((item, index) =>
-                        <li className="pb2 mb2 border-row-divider flex align-center">
+                        <li key={index} className="pb2 mb2 border-row-divider flex align-center">
                             <span className="text-error">
                                 <CheckBox
                                     checkColor="currentColor" borderColor={checked[index] ? "currentColor" : undefined} size={20}
diff --git a/frontend/src/metabase/components/Detail.css b/frontend/src/metabase/components/Detail.css
index 81dfce80cb64afc836e29d5ba5cffcdedd2fd466..5d5f63859910f477fdb3137f84a69c560864de22 100644
--- a/frontend/src/metabase/components/Detail.css
+++ b/frontend/src/metabase/components/Detail.css
@@ -3,12 +3,13 @@
     --subtitle-color: #AAB7C3;
     --muted-color: #DEEAF1;
     --blue-color: #2D86D4;
+    --icon-width: calc(48px + 1rem);
 }
 
 :local(.detail) {
-    composes: flex align-center pl2 from "style";
+    composes: flex align-center from "style";
     composes: relative from "style";
-    margin-left: 48px;
+    margin-left: var(--icon-width);
 }
 
 :local(.detailBody) {
@@ -19,8 +20,7 @@
 }
 
 :local(.detailTitle) {
-    composes: text-bold from "style";
-    composes: inline-block from "style";
+    composes: text-bold inline-block from "style";
     color: var(--title-color);
     font-size: 18px;
 }
diff --git a/frontend/src/metabase/components/Detail.jsx b/frontend/src/metabase/components/Detail.jsx
index 37d7e8e24c3c17c6e516b813e37236e0e637aa05..9e9a6766fffac6473af49fb48bfa540774f67675 100644
--- a/frontend/src/metabase/components/Detail.jsx
+++ b/frontend/src/metabase/components/Detail.jsx
@@ -6,7 +6,7 @@ import S from "./Detail.css";
 import cx from "classnames";
 import pure from "recompose/pure";
 
-const Detail = ({ name, description, placeholder, url, icon, isEditing, field }) =>
+const Detail = ({ name, description, placeholder, subtitleClass, url, icon, isEditing, field }) =>
     <div className={cx(S.detail)}>
         <div className={S.detailBody}>
             <div className={S.detailTitle}>
@@ -23,7 +23,7 @@ const Detail = ({ name, description, placeholder, url, icon, isEditing, field })
                         {...field}
                         defaultValue={description}
                     /> :
-                    description || placeholder || 'No description yet'
+                    <span className={subtitleClass}>{description || placeholder || 'No description yet'}</span>
                 }
                 { isEditing && field.error && field.touched &&
                     <span className="text-error">{field.error}</span>
@@ -37,6 +37,7 @@ Detail.propTypes = {
     url:                PropTypes.string,
     description:        PropTypes.string,
     placeholder:        PropTypes.string,
+    subtitleClass:      PropTypes.string,
     icon:               PropTypes.string,
     isEditing:          PropTypes.bool,
     field:              PropTypes.object
diff --git a/frontend/src/metabase/components/EmptyState.jsx b/frontend/src/metabase/components/EmptyState.jsx
index 0e66f2d34a1d67b0407d8e91278505b88ecbacf8..a18124e60e03223f1ad35146a7bafea85be14548 100644
--- a/frontend/src/metabase/components/EmptyState.jsx
+++ b/frontend/src/metabase/components/EmptyState.jsx
@@ -1,4 +1,5 @@
 import React, { PropTypes } from "react";
+import { Link } from "react-router";
 
 import Icon from "metabase/components/Icon.jsx";
 
@@ -14,10 +15,10 @@ const EmptyState = ({ title, message, icon, image, action, link }) =>
             <img src={`${image}.png`} height="250px" alt={message} srcSet={`${image}@2x.png 2x`} />
         }
         <div className="flex justify-center">
-            <h3 className="text-grey-2 mt4" style={{maxWidth: "350px"}}>{message}</h3>
+            <h3 className="text-grey-2 mt4" style={{maxWidth: "375px"}}>{message}</h3>
         </div>
         { action &&
-            <a className="Button Button--primary mt3" href={link} target={link.startsWith('http') ? "_blank" : ""}>{action}</a>
+            <Link to={link} className="Button Button--primary mt3" target={link.startsWith('http') ? "_blank" : ""}>{action}</Link>
         }
     </div>
 
diff --git a/frontend/src/metabase/components/HeaderModal.jsx b/frontend/src/metabase/components/HeaderModal.jsx
index 39b791da26f9d979cd0b87920444da8ba53c63a1..6e37e5b5e33d9efb982a91c3c105e34d2bb60580 100644
--- a/frontend/src/metabase/components/HeaderModal.jsx
+++ b/frontend/src/metabase/components/HeaderModal.jsx
@@ -22,7 +22,7 @@ export default class HeaderModal extends Component {
         return (
             <div
                 className={cx(className, "absolute top left right bg-brand flex flex-column layout-centered")}
-                style={{ zIndex: 2, height: height, minHeight: 50, transform: `translateY(${isOpen ? initialTop : "-100%"})`, transition: "transform 400ms ease-in-out", overflow: 'hidden' }}
+                style={{ zIndex: 3, height: height, minHeight: 50, transform: `translateY(${isOpen ? initialTop : "-100%"})`, transition: "transform 400ms ease-in-out", overflow: 'hidden' }}
             >
                     <h2 className="text-white pb2">{title}</h2>
                     <div className="flex layout-centered">
diff --git a/frontend/src/metabase/components/Modal.jsx b/frontend/src/metabase/components/Modal.jsx
index c79e105cd3303ade139c944f25188100c87e660e..9af365a96710492b8c3202fcd2421b5e735a46d6 100644
--- a/frontend/src/metabase/components/Modal.jsx
+++ b/frontend/src/metabase/components/Modal.jsx
@@ -58,7 +58,7 @@ export default class Modal extends Component {
     _renderPopover() {
         const { backdropClassName, isOpen, style } = this.props;
         const backdropClassnames = 'flex justify-center align-center fixed top left bottom right';
-        ReactDOM.render(
+        ReactDOM.unstable_renderSubtreeIntoContainer(this,
             <ReactCSSTransitionGroup transitionName="Modal" transitionAppear={true} transitionAppearTimeout={250} transitionEnterTimeout={250} transitionLeaveTimeout={250}>
                 { isOpen &&
                     <div key="modal" className={cx(backdropClassName, backdropClassnames)} style={style}>
diff --git a/frontend/src/metabase/components/ModalContent.jsx b/frontend/src/metabase/components/ModalContent.jsx
index 0ef3e406f0ea0755855e4c251a2d50641ae0b145..350ac57e12a3f1c43c5eae3db71c2b340c37d4ae 100644
--- a/frontend/src/metabase/components/ModalContent.jsx
+++ b/frontend/src/metabase/components/ModalContent.jsx
@@ -4,7 +4,7 @@ import Icon from "metabase/components/Icon.jsx";
 
 export default class ModalContent extends Component {
     static propTypes = {
-        title: PropTypes.string.isRequired,
+        title: PropTypes.string,
         closeFn: PropTypes.func.isRequired
     };
 
diff --git a/frontend/src/metabase/components/NewsletterForm.jsx b/frontend/src/metabase/components/NewsletterForm.jsx
index 15940f721007c344f6cb81ff2ac9a3c6cf5b0d50..18955f11386584ca14d33e4a359165071b29fee0 100644
--- a/frontend/src/metabase/components/NewsletterForm.jsx
+++ b/frontend/src/metabase/components/NewsletterForm.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -28,7 +29,7 @@ export default class NewsletterForm extends Component {
     }
 
     static propTypes = {
-        password: PropTypes.string.isRequired
+        initialEmail: PropTypes.string.isRequired
     };
 
     subscribeUser(e) {
diff --git a/frontend/src/metabase/components/NotFound.jsx b/frontend/src/metabase/components/NotFound.jsx
index 08338513869a3f4fb12a48b912b4d7e77cf235a4..0eb16a19945a2dbe89ac36d3a778b913b0820d96 100644
--- a/frontend/src/metabase/components/NotFound.jsx
+++ b/frontend/src/metabase/components/NotFound.jsx
@@ -1,5 +1,5 @@
 import React, { Component, PropTypes } from "react";
-
+import { Link } from "react-router";
 
 export default class NotFound extends Component {
     render() {
@@ -11,9 +11,9 @@ export default class NotFound extends Component {
                     <p className="h4">You might've been tricked by a ninja, but in all likelihood, you were just given a bad link.</p>
                     <p className="h4 my4">You can always:</p>
                     <div className="flex align-center">
-                        <a className="Button Button--primary" href="/q">
+                        <Link to="/q" className="Button Button--primary">
                             <div className="p1">Ask a new question.</div>
-                        </a>
+                        </Link>
                         <span className="mx2">or</span>
                         <a className="Button Button--withIcon" target="_blank" href="http://tv.giphy.com/kitten">
                             <div className="p1 flex align-center relative">
@@ -26,4 +26,4 @@ export default class NotFound extends Component {
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/frontend/src/metabase/components/OnClickOutsideWrapper.jsx b/frontend/src/metabase/components/OnClickOutsideWrapper.jsx
index 378bd3fb6fa290aa349e6ae16c92f23e33f0c5db..7a972d73ec8c0bee92630b34eb954b946b2291bf 100644
--- a/frontend/src/metabase/components/OnClickOutsideWrapper.jsx
+++ b/frontend/src/metabase/components/OnClickOutsideWrapper.jsx
@@ -1,57 +1,68 @@
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
-import ClickOutComponent from 'react-onclickout';
-
-// this feels a little silly, but we have this component ONLY so that we can add the OnClickOutside functionality on an
-// arbitrary set of html content.  I wish we could do that more easily
-
 // keep track of the order popovers were opened so we only close the last one when clicked outside
-var popoverStack = [];
+const popoverStack = [];
 
 const ESC_KEY = 27;
 
-export default class OnClickOutsideWrapper extends ClickOutComponent {
+export default class OnClickOutsideWrapper extends Component {
     static propTypes = {
         handleDismissal: PropTypes.func.isRequired
-    }
+    };
+
+    static defaultProps = {
+        dismissOnClickOutside: true,
+        dismissOnEscape: true
+    };
 
-    constructor() {
-        super();
-        this.handleKeyPress = this.handleKeyPress.bind(this);
-    }
     componentDidMount() {
-        super.componentDidMount();
         // necessary to ignore click events that fire immediately, causing modals/popovers to close prematurely
-        this.timeout = setTimeout(() => {
+        this._timeout = setTimeout(() => {
             popoverStack.push(this);
-            // HACK: set the z-index of the parent element to ensure it's always on top
-            // NOTE: this actually doesn't seem to be working correctly for popovers since PopoverBody creates a stacking context
-            ReactDOM.findDOMNode(this).parentNode.style.zIndex = popoverStack.length + 2; // HACK: add 2 to ensure it's in front of main and nav elements
-        }, 10);
 
-        document.addEventListener('keydown', this.handleKeyPress, false)
+            // HACK: set the z-index of the parent element to ensure it"s always on top
+            // NOTE: this actually doesn"t seem to be working correctly for popovers since PopoverBody creates a stacking context
+            ReactDOM.findDOMNode(this).parentNode.style.zIndex = popoverStack.length + 2; // HACK: add 2 to ensure it"s in front of main and nav elements
+
+            if (this.props.dismissOnEscape) {
+                document.addEventListener("keydown", this._handleKeyPress, false);
+            }
+            if (this.props.dismissOnClickOutside) {
+                window.addEventListener("click", this._handleClick, true);
+            }
+        }, 0);
     }
 
-    handleKeyPress (event) {
-        if (event.keyCode === ESC_KEY) {
-            event.preventDefault();
-            this.onClickOut();
+    componentWillUnmount() {
+        document.removeEventListener("keydown", this._handleKeyPress, false);
+        window.removeEventListener("click", this._handleClick, true);
+        clearTimeout(this._timeout);
+
+        // remove from the stack after a delay, if it is removed through some other
+        // means this will happen too early causing parent modal to close
+        setTimeout(() => {
+            var index = popoverStack.indexOf(this);
+            if (index >= 0) {
+                popoverStack.splice(index, 1);
+            }
+        }, 0);
+    }
+
+    _handleClick = (e) => {
+        if (!ReactDOM.findDOMNode(this).contains(e.target)) {
+            setTimeout(this._handleDismissal, 0);
         }
     }
 
-    componentWillUnmount() {
-        super.componentWillUnmount();
-        document.removeEventListener('keydown', this.handleKeyPress, false);
-        // remove popover from the stack
-        var index = popoverStack.indexOf(this);
-        if (index >= 0) {
-            popoverStack.splice(index, 1);
+    _handleKeyPress = (e) => {
+        if (e.keyCode === ESC_KEY) {
+            e.preventDefault();
+            this._handleDismissal();
         }
-        clearTimeout(this.timeout);
     }
 
-    onClickOut(e) {
+    _handleDismissal = (e) => {
         // only propagate event for the popover on top of the stack
         if (this === popoverStack[popoverStack.length - 1]) {
             this.props.handleDismissal(e);
@@ -59,6 +70,6 @@ export default class OnClickOutsideWrapper extends ClickOutComponent {
     }
 
     render() {
-        return this.props.children;
+        return React.Children.only(this.props.children);
     }
 }
diff --git a/frontend/src/metabase/components/PasswordReveal.jsx b/frontend/src/metabase/components/PasswordReveal.jsx
index 3ea272222ea85c75e4c3fe6c4751353f4d797adf..eba44e2cc2d075b759376c8d308fe5e1c8d86a25 100644
--- a/frontend/src/metabase/components/PasswordReveal.jsx
+++ b/frontend/src/metabase/components/PasswordReveal.jsx
@@ -1,6 +1,6 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
-
 export default class PasswordReveal extends Component {
 
     constructor(props, context) {
@@ -16,7 +16,9 @@ export default class PasswordReveal extends Component {
             input: {
                 fontSize: '1.2rem',
                 letterSpacing: '2',
-                color: '#676C72'
+                color: '#676C72',
+                border: "none",
+                outline: "none"
             },
 
             label: {
@@ -46,7 +48,7 @@ export default class PasswordReveal extends Component {
                 </div>
 
                 { visible ?
-                    <span style={this.styles.input} className="text-grey-2 text-normal mr3">{password}</span>
+                    <input ref="input" style={this.styles.input} className="text-grey-2 text-normal mr3" value={password} onClick={({ target }) => target.setSelectionRange(0, target.value.length) }/>
                 :
                     <span style={this.styles.input} className="mr3">&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;&#9679;</span>
                 }
diff --git a/frontend/src/metabase/components/Popover.jsx b/frontend/src/metabase/components/Popover.jsx
index 61b2024a13604ce5776f6f72f8f5cd213fc5a198..950d6fb7734a1a3a11b3da7d8151894f811b2bbb 100644
--- a/frontend/src/metabase/components/Popover.jsx
+++ b/frontend/src/metabase/components/Popover.jsx
@@ -152,18 +152,17 @@ export default class Popover extends Component {
         if (this.props.isOpen) {
             // popover is open, lets do this!
             const popoverElement = this._getPopoverElement();
-            ReactDOM.render(
-              <ReactCSSTransitionGroup
-                transitionName="Popover"
-                transitionAppear={true}
-                transitionAppearTimeout={250}
-                transitionEnterTimeout={250}
-                transitionLeaveTimeout={250}
-              >
-                {this._popoverComponent()}
-              </ReactCSSTransitionGroup>
-              , popoverElement
-            );
+            ReactDOM.unstable_renderSubtreeIntoContainer(this,
+                <ReactCSSTransitionGroup
+                    transitionName="Popover"
+                    transitionAppear={true}
+                    transitionAppearTimeout={250}
+                    transitionEnterTimeout={250}
+                    transitionLeaveTimeout={250}
+                >
+                    {this._popoverComponent()}
+                </ReactCSSTransitionGroup>
+            , popoverElement);
 
             var tetherOptions = {};
 
diff --git a/frontend/src/metabase/components/QueryButton.css b/frontend/src/metabase/components/QueryButton.css
new file mode 100644
index 0000000000000000000000000000000000000000..460d7909bdc7ccd98a143af109975adb757cf103
--- /dev/null
+++ b/frontend/src/metabase/components/QueryButton.css
@@ -0,0 +1,16 @@
+:local(.queryButton) {
+    composes: flex align-center no-decoration py1 from "style";
+}
+
+:local(.queryButtonText) {
+    composes: flex-full mx2 text-default from "style";
+    max-width: 100%;
+}
+
+:local(.queryButtonCircle) {
+    composes: flex align-center justify-center text-brand from "style";
+    border: 1px solid currentColor;
+    border-radius: 99px;
+    width: 1.25rem;
+    height: 1.25rem;
+}
\ No newline at end of file
diff --git a/frontend/src/metabase/components/QueryButton.jsx b/frontend/src/metabase/components/QueryButton.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..83fdb22244dfeda38d2097d0a7860a3b54309119
--- /dev/null
+++ b/frontend/src/metabase/components/QueryButton.jsx
@@ -0,0 +1,42 @@
+import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
+import pure from "recompose/pure";
+import cx from "classnames";
+
+import S from "./QueryButton.css";
+
+import Icon from "metabase/components/Icon.jsx";
+
+const QueryButton = ({
+    className,
+    text,
+    icon,
+    iconClass,
+    onClick,
+    link,
+}) => 
+    <div className={className}>
+        <Link className={S.queryButton} onClick={onClick} to={link}>
+            <Icon 
+                className={iconClass} 
+                size={20} 
+                {...(typeof icon === 'string' ? { name: icon } : icon)} 
+            />
+            <span className={cx(S.queryButtonText, 'text-brand-hover')}>
+                {text}
+            </span>
+            <span className={S.queryButtonCircle}>
+                <Icon size={8} name="chevronright" />
+            </span>
+        </Link>
+    </div>;
+QueryButton.propTypes = {
+    className: PropTypes.string,
+    icon: PropTypes.any.isRequired,
+    text: PropTypes.string.isRequired,
+    iconClass: PropTypes.string,
+    onClick: PropTypes.func,
+    link: PropTypes.string
+};
+
+export default pure(QueryButton);
\ No newline at end of file
diff --git a/frontend/src/metabase/components/SidebarLayout.jsx b/frontend/src/metabase/components/SidebarLayout.jsx
index 5ca09f2bad040eac73c8dca0c713a23fba3dd07d..3ad943653ccfb66c89dcd344d68e6a2f2a8872ee 100644
--- a/frontend/src/metabase/components/SidebarLayout.jsx
+++ b/frontend/src/metabase/components/SidebarLayout.jsx
@@ -1,9 +1,8 @@
 /* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
-import cx from "classnames"
 
 const SidebarLayout = ({ className, style, sidebar, children }) =>
-    <div className={cx('spread', className)} style={{ ...style, display: "flex", flexDirection: "row"}}>
+    <div className={className} style={{ ...style, display: "flex", flexDirection: "row"}}>
         { React.cloneElement(
             sidebar,
             { style: { flexShrink: 0 },
diff --git a/frontend/src/metabase/components/Triggerable.jsx b/frontend/src/metabase/components/Triggerable.jsx
index 0a784bfea3aa75aa4590a2fd106b1d2169b32850..87d21025299e539495e7ab1cc95e2c53e5f817cf 100644
--- a/frontend/src/metabase/components/Triggerable.jsx
+++ b/frontend/src/metabase/components/Triggerable.jsx
@@ -99,9 +99,9 @@ export default ComposedComponent => class extends Component {
             triggerElement = React.cloneElement(triggerElement, { isEnabled: triggerElement.props.isEnabled && !isOpen });
         }
 
-        // if we have a single child which doesn't have an onClose prop go ahead and inject it directly
+        // if we have a single child which isn't an HTML element and doesn't have an onClose prop go ahead and inject it directly
         let { children } = this.props;
-        if (React.Children.count(children) === 1 && React.Children.only(children).props.onClose === undefined) {
+        if (React.Children.count(children) === 1 && React.Children.only(children).props.onClose === undefined && typeof React.Children.only(children).type !== "string") {
             children = React.cloneElement(children, { onClose: this.onClose });
         }
 
diff --git a/frontend/src/metabase/controllers.js b/frontend/src/metabase/controllers.js
deleted file mode 100644
index ed46d60668be5e211a3e5440f195e404f4e25345..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/controllers.js
+++ /dev/null
@@ -1,37 +0,0 @@
-
-angular
-.module('metabase.controllers', ['metabase.services'])
-.controller('Metabase', ['$scope', '$location', 'MetabaseCore', 'AppState', function($scope, $location, MetabaseCore, AppState) {
-
-    var clearState = function() {
-        $scope.siteName = undefined;
-        $scope.user = undefined;
-        $scope.userIsSuperuser = false;
-    };
-
-    // make our utilities object available throughout the application
-    $scope.utils = MetabaseCore;
-
-    // current User
-    $scope.user = undefined;
-    $scope.userIsSuperuser = false;
-
-    $scope.$on("appstate:site-settings", function(event, settings) {
-        // change in global settings
-        $scope.siteName = settings.site_name;
-    });
-
-    $scope.$on("appstate:user", function(event, user) {
-        // change in current user
-        $scope.user = user;
-        $scope.userIsSuperuser = user.is_superuser;
-    });
-
-    $scope.$on("appstate:logout", function(event, user) {
-        clearState();
-    });
-
-    $scope.refreshCurrentUser = function() {
-        AppState.refreshCurrentUser();
-    };
-}]);
diff --git a/frontend/src/metabase/css/components/modal.css b/frontend/src/metabase/css/components/modal.css
index 4943174579f853b123efb77791f1b02b9a8f8f63..c9c22c20f8fde6bc1575e70a190fc163ec3fae12 100644
--- a/frontend/src/metabase/css/components/modal.css
+++ b/frontend/src/metabase/css/components/modal.css
@@ -1,3 +1,7 @@
+.ModalContainer {
+    z-index: 3;
+}
+
 .Modal {
   margin: auto;
   width: 640px;
diff --git a/frontend/src/metabase/css/core/colors.css b/frontend/src/metabase/css/core/colors.css
index 729c7b06ba527dc7f245c171c7b73803f19fc2cb..709307322c22f430f5a2925d62758cff392d9efd 100644
--- a/frontend/src/metabase/css/core/colors.css
+++ b/frontend/src/metabase/css/core/colors.css
@@ -27,7 +27,7 @@
   --slate-light-color: #DFE8EA;
 }
 
-.text-default {
+.text-default, :local(.text-default) {
     color: var(--default-font-color);
 }
 
diff --git a/frontend/src/metabase/css/core/link.css b/frontend/src/metabase/css/core/link.css
index f13061fd5e17305a0f4e0a3e91916adef4470461..e8c7b19254c691cef269bc5b9eba9158149fd2a3 100644
--- a/frontend/src/metabase/css/core/link.css
+++ b/frontend/src/metabase/css/core/link.css
@@ -2,7 +2,7 @@
   --default-link-color: #4A90E2;
 }
 
-.no-decoration {
+.no-decoration, :local(.no-decoration) {
     text-decoration: none;
 }
 
diff --git a/frontend/src/metabase/css/home.css b/frontend/src/metabase/css/home.css
index 1b4fa7deead837f262b1bd79b632f2a6f88e7f95..75ed5e8ae0a9b06c27d1bead0291638aec773932 100644
--- a/frontend/src/metabase/css/home.css
+++ b/frontend/src/metabase/css/home.css
@@ -1,5 +1,5 @@
 .Nav {
-    z-index: 2;
+    z-index: 3;
 }
 
 .CheckBg {
@@ -97,8 +97,12 @@
 }
 .NavDropdown .NavDropdown-button:before {
     z-index: -1;
+    opacity: 0;
     border-radius: 8px;
 }
+.NavDropdown.open .NavDropdown-button:before {
+    opacity: 1;
+}
 .NavDropdown .NavDropdown-content-layer {
     position: relative;
     z-index: 1;
diff --git a/frontend/src/metabase/css/query_builder.css b/frontend/src/metabase/css/query_builder.css
index 0e1e379288f484ad300be80f873f2dfaa6218605..00d5025a1402bb179976f3d85dab4f5733acdd0f 100644
--- a/frontend/src/metabase/css/query_builder.css
+++ b/frontend/src/metabase/css/query_builder.css
@@ -558,20 +558,6 @@
     font-size: 20pt;
 }
 
-.DataRefererenceQueryButton-circle {
-    border: 1px solid currentColor;
-    border-radius: 99px;
-    width: 1.25rem;
-    height: 1.25rem;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-}
-
-.DataRefererenceQueryButton-text {
-    max-width: 160px;
-}
-
 .DataReference-paneCount {
     padding-right: 0.6em;
 }
diff --git a/frontend/src/metabase/dashboard/components/Dashboard.jsx b/frontend/src/metabase/dashboard/components/Dashboard.jsx
index c2550c9fdd59c4b59bff1f0fb77f9003bd8b5a10..47032890384e67d9e86ec5ec01f0038856f045b0 100644
--- a/frontend/src/metabase/dashboard/components/Dashboard.jsx
+++ b/frontend/src/metabase/dashboard/components/Dashboard.jsx
@@ -60,11 +60,10 @@ export default class Dashboard extends Component {
         setDashCardVisualizationSetting: PropTypes.func.isRequired,
 
         onChangeLocation: PropTypes.func.isRequired,
-        onDashboardDeleted: PropTypes.func.isRequired,
     };
 
     async componentDidMount() {
-        this.loadDashboard(this.props.selectedDashboard);
+        this.loadDashboard(this.props.params.dashboardId);
     }
 
     componentDidUpdate() {
@@ -78,8 +77,8 @@ export default class Dashboard extends Component {
     }
 
     componentWillReceiveProps(nextProps) {
-        if (this.props.selectedDashboard !== nextProps.selectedDashboard) {
-            this.loadDashboard(nextProps.selectedDashboard);
+        if (this.props.params.dashboardId !== nextProps.params.dashboardId) {
+            this.loadDashboard(nextProps.params.dashboardId);
         } else if (!_.isEqual(this.props.parameterValues, nextProps.parameterValues) || !this.props.dashboard) {
             this.fetchDashboardCardData(nextProps, true);
         }
@@ -101,10 +100,10 @@ export default class Dashboard extends Component {
 
     async loadDashboard(dashboardId) {
         this.loadParams();
-        const { addCardOnLoad, fetchDashboard, fetchCards, addCardToDashboard, onChangeLocation } = this.props;
+        const { addCardOnLoad, fetchDashboard, fetchCards, addCardToDashboard, onChangeLocation, location } = this.props;
 
         try {
-            await fetchDashboard(dashboardId);
+            await fetchDashboard(dashboardId, location.query);
             if (addCardOnLoad != null) {
                 // we have to load our cards before we can add one
                 await fetchCards();
@@ -285,7 +284,7 @@ export default class Dashboard extends Component {
         if (refreshElapsed >= this.state.refreshPeriod) {
             refreshElapsed = 0;
 
-            await this.props.fetchDashboard(this.props.selectedDashboard);
+            await this.props.fetchDashboard(this.props.params.dashboardId, this.props.location.query);
             this.fetchDashboardCardData(this.props);
         }
         this.setState({ refreshElapsed });
@@ -318,7 +317,7 @@ export default class Dashboard extends Component {
         );
 
         return (
-            <LoadingAndErrorWrapper style={{ minHeight: "100%" }} className={cx("Dashboard absolute top left right", { "Dashboard--fullscreen": isFullscreen, "Dashboard--night": isNightMode})} loading={!dashboard} error={error}>
+            <LoadingAndErrorWrapper style={{ minHeight: "100%" }} className={cx("Dashboard flex-full", { "Dashboard--fullscreen": isFullscreen, "Dashboard--night": isNightMode})} loading={!dashboard} error={error}>
             {() =>
                 <div className="full" style={{ overflowX: "hidden" }}>
                     <header className="DashboardHeader relative z2">
diff --git a/frontend/src/metabase/dashboard/components/DashboardHeader.jsx b/frontend/src/metabase/dashboard/components/DashboardHeader.jsx
index 973adb6af3e492a6969c5de0e182db6434a14d18..d6d32275a34e5075dbeedbf364411e56516aaa0a 100644
--- a/frontend/src/metabase/dashboard/components/DashboardHeader.jsx
+++ b/frontend/src/metabase/dashboard/components/DashboardHeader.jsx
@@ -61,7 +61,7 @@ export default class DashboardHeader extends Component {
     }
 
     onRevert() {
-        this.props.fetchDashboard(this.props.dashboard.id);
+        this.props.fetchDashboard(this.props.dashboard.id, this.props.location.query);
     }
 
     async onSave() {
@@ -76,8 +76,7 @@ export default class DashboardHeader extends Component {
 
     async onDelete() {
         await this.props.deleteDashboard(this.props.dashboard.id);
-        this.props.onDashboardDeleted(this.props.dashboard.id)
-        this.props.onChangeLocation("/")
+        this.props.onChangeLocation("/");
     }
 
     // 1. fetch revisions
@@ -93,7 +92,7 @@ export default class DashboardHeader extends Component {
     // 3. finished reverting to a revision
     onRevertedRevision() {
         this.refs.dashboardHistory.toggle();
-        this.props.fetchDashboard(this.props.dashboard.id);
+        this.props.fetchDashboard(this.props.dashboard.id, this.props.location.query);
     }
 
     getEditingButtons() {
diff --git a/frontend/src/metabase/dashboard/containers/DashCardCardParameterMapper.jsx b/frontend/src/metabase/dashboard/containers/DashCardCardParameterMapper.jsx
index ba513b33524c220ce3c3037d17cf701f66940b1f..c7524d1ad3be2b1911410587973422e8016355c5 100644
--- a/frontend/src/metabase/dashboard/containers/DashCardCardParameterMapper.jsx
+++ b/frontend/src/metabase/dashboard/containers/DashCardCardParameterMapper.jsx
@@ -24,11 +24,11 @@ import type { DatabaseId } from "metabase/meta/types/base";
 const makeMapStateToProps = () => {
     const getParameterMappingOptions = makeGetParameterMappingOptions()
     const mapStateToProps = (state, props) => ({
-        parameter:           getEditingParameter(state),
+        parameter:           getEditingParameter(state, props),
         mappingOptions:      getParameterMappingOptions(state, props),
         mappingOptionSections: _.groupBy(getParameterMappingOptions(state, props), "sectionName"),
         target:              getParameterTarget(state, props),
-        mappingsByParameter: getMappingsByParameter(state)
+        mappingsByParameter: getMappingsByParameter(state, props)
     });
     return mapStateToProps;
 }
diff --git a/frontend/src/metabase/dashboard/containers/DashboardApp.jsx b/frontend/src/metabase/dashboard/containers/DashboardApp.jsx
index 77d8c92cbfb56251005395af550993ca7559edde..7297f3faf9f2a00babb3c1504696247dbcd2f70f 100644
--- a/frontend/src/metabase/dashboard/containers/DashboardApp.jsx
+++ b/frontend/src/metabase/dashboard/containers/DashboardApp.jsx
@@ -2,45 +2,41 @@
 
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+import { push } from "react-router-redux";
 
 import Dashboard from "../components/Dashboard.jsx";
 
 import { fetchDatabaseMetadata } from "metabase/redux/metadata";
 
-import { getIsEditing, getIsEditingParameter, getIsDirty, getSelectedDashboard, getDashboardComplete, getCardList, getRevisions, getCardData, getCardDurations, getDatabases, getEditingParameter, getParameterValues } from "../selectors";
+import { getIsEditing, getIsEditingParameter, getIsDirty, getDashboardComplete, getCardList, getRevisions, getCardData, getCardDurations, getDatabases, getEditingParameter, getParameterValues } from "../selectors";
 import * as dashboardActions from "../dashboard";
 
 const mapStateToProps = (state, props) => {
   return {
-      isEditing:            getIsEditing(state),
-      isEditingParameter:   getIsEditingParameter(state),
-      isDirty:              getIsDirty(state),
-      selectedDashboard:    getSelectedDashboard(state),
-      dashboard:            getDashboardComplete(state),
-      cards:                getCardList(state),
-      revisions:            getRevisions(state),
-      dashcardData:             getCardData(state),
-      cardDurations:        getCardDurations(state),
-      databases:            getDatabases(state),
-      editingParameter:     getEditingParameter(state),
-      parameterValues:      getParameterValues(state),
-      addCardOnLoad:        parseInt(state.router.location.query.add) || null
+      isEditing:            getIsEditing(state, props),
+      isEditingParameter:   getIsEditingParameter(state, props),
+      isDirty:              getIsDirty(state, props),
+      dashboard:            getDashboardComplete(state, props),
+      cards:                getCardList(state, props),
+      revisions:            getRevisions(state, props),
+      dashcardData:         getCardData(state, props),
+      cardDurations:        getCardDurations(state, props),
+      databases:            getDatabases(state, props),
+      editingParameter:     getEditingParameter(state, props),
+      parameterValues:      getParameterValues(state, props),
+      addCardOnLoad:        props.location.query.add ? parseInt(props.location.query.add) : null
   }
 }
 
 const mapDispatchToProps = {
     ...dashboardActions,
-    fetchDatabaseMetadata
+    fetchDatabaseMetadata,
+    onChangeLocation: push
 }
 
 @connect(mapStateToProps, mapDispatchToProps)
 export default class DashboardApp extends Component {
-    componentDidMount() {
-        if (this.props.addCardOnLoad != null) {
-            this.props.onChangeLocationSearch("add", null);
-        }
-    }
     render() {
-        return <Dashboard {...this.props} onDashboardDeleted={(id) => this.props.onBroadcast("dashboard:delete", id)}/>;
+        return <Dashboard {...this.props} />;
     }
 }
diff --git a/frontend/src/metabase/dashboard/containers/ParameterWidget.jsx b/frontend/src/metabase/dashboard/containers/ParameterWidget.jsx
index 4a7c5cb02bc0e7b81995bc6f7e5ce0b6b7974d31..cfbc1e66d2b43c22989da1e9f307929996134a1c 100644
--- a/frontend/src/metabase/dashboard/containers/ParameterWidget.jsx
+++ b/frontend/src/metabase/dashboard/containers/ParameterWidget.jsx
@@ -12,7 +12,7 @@ import { getMappingsByParameter } from "../selectors";
 
 const makeMapStateToProps = () => {
     const mapStateToProps = (state, props) => ({
-        mappingsByParameter: getMappingsByParameter(state)
+        mappingsByParameter: getMappingsByParameter(state, props)
     });
     return mapStateToProps;
 }
diff --git a/frontend/src/metabase/dashboard/dashboard.js b/frontend/src/metabase/dashboard/dashboard.js
index 58045582f1fe0a9b713f7c7c18deed713804e193..254865b134f8c5cc5ede58f96619cb395c1ee98a 100644
--- a/frontend/src/metabase/dashboard/dashboard.js
+++ b/frontend/src/metabase/dashboard/dashboard.js
@@ -22,41 +22,50 @@ dashboard.define({
     ordered_cards: arrayOf(dashcard)
 });
 
+
+
 // action constants
-export const SET_EDITING_DASHBOARD = 'SET_EDITING';
+export const SET_EDITING_DASHBOARD = "metabase/dashboard/SET_EDITING_DASHBOARD";
 
-export const FETCH_CARDS = 'FETCH_CARDS';
-export const DELETE_CARD = 'DELETE_CARD';
+export const FETCH_CARDS = "metabase/dashboard/FETCH_CARDS";
+export const DELETE_CARD = "metabase/dashboard/DELETE_CARD";
 
-export const FETCH_DASHBOARD = 'FETCH_DASHBOARD';
-export const SET_DASHBOARD_ATTRIBUTES = 'SET_DASHBOARD_ATTRIBUTES';
-export const SET_DASHCARD_VISUALIZATION_SETTING = 'SET_DASHCARD_VISUALIZATION_SETTING';
-export const SAVE_DASHBOARD = 'SAVE_DASHBOARD';
-export const DELETE_DASHBOARD = 'DELETE_DASHBOARD';
+export const FETCH_DASHBOARD = "metabase/dashboard/FETCH_DASHBOARD";
+export const FETCH_DASHBOARDS = "metabase/dashboard/FETCH_DASHBOARDS";
+export const CREATE_DASHBOARD = "metabase/dashboard/CREATE_DASHBOARD";
+export const SAVE_DASHBOARD = "metabase/dashboard/SAVE_DASHBOARD";
+export const DELETE_DASHBOARD = "metabase/dashboard/DELETE_DASHBOARD";
+export const SET_DASHBOARD_ATTRIBUTES = "metabase/dashboard/SET_DASHBOARD_ATTRIBUTES";
 
-export const ADD_CARD_TO_DASH = 'ADD_CARD_TO_DASH';
-export const REMOVE_CARD_FROM_DASH = 'REMOVE_CARD_FROM_DASH';
-export const SET_DASHCARD_ATTRIBUTES = 'SET_DASHCARD_ATTRIBUTES';
-export const SAVE_DASHCARD = 'SAVE_DASHCARD';
+export const ADD_CARD_TO_DASH = "metabase/dashboard/ADD_CARD_TO_DASH";
+export const REMOVE_CARD_FROM_DASH = "metabase/dashboard/REMOVE_CARD_FROM_DASH";
+export const SET_DASHCARD_ATTRIBUTES = "metabase/dashboard/SET_DASHCARD_ATTRIBUTES";
+export const SET_DASHCARD_VISUALIZATION_SETTING = "metabase/dashboard/SET_DASHCARD_VISUALIZATION_SETTING";
+export const UPDATE_DASHCARD_ID = "metabase/dashboard/UPDATE_DASHCARD_ID"
+export const SAVE_DASHCARD = "metabase/dashboard/SAVE_DASHCARD";
 
-export const FETCH_CARD_DATA = 'FETCH_CARD_DATA';
-export const FETCH_CARD_DURATION = 'FETCH_CARD_DURATION';
-export const FETCH_REVISIONS = 'FETCH_REVISIONS';
-export const REVERT_TO_REVISION = 'REVERT_TO_REVISION';
+export const FETCH_CARD_DATA = "metabase/dashboard/FETCH_CARD_DATA";
+export const FETCH_CARD_DURATION = "metabase/dashboard/FETCH_CARD_DURATION";
+export const CLEAR_CARD_DATA = "metabase/dashboard/CLEAR_CARD_DATA";
 
-export const MARK_NEW_CARD_SEEN = 'MARK_NEW_CARD_SEEN';
+export const FETCH_REVISIONS = "metabase/dashboard/FETCH_REVISIONS";
+export const REVERT_TO_REVISION = "metabase/dashboard/REVERT_TO_REVISION";
 
-export const FETCH_DATABASE_METADATA = 'FETCH_DATABASE_METADATA';
+export const MARK_NEW_CARD_SEEN = "metabase/dashboard/MARK_NEW_CARD_SEEN";
 
-export const SET_EDITING_PARAMETER_ID = 'SET_EDITING_PARAMETER_ID';
-export const ADD_PARAMETER = 'ADD_PARAMETER';
-export const SET_PARAMETER_MAPPING = 'SET_PARAMETER_MAPPING';
-export const SET_PARAMETER_NAME = 'SET_PARAMETER_NAME';
-export const SET_PARAMETER_VALUE = 'SET_PARAMETER_VALUE';
-export const SET_PARAMETER_DEFAULT_VALUE = 'SET_PARAMETER_DEFAULT_VALUE';
+export const FETCH_DATABASE_METADATA = "metabase/dashboard/FETCH_DATABASE_METADATA";
+
+export const SET_EDITING_PARAMETER_ID = "metabase/dashboard/SET_EDITING_PARAMETER_ID";
+export const ADD_PARAMETER = "metabase/dashboard/ADD_PARAMETER";
+export const SET_PARAMETER_MAPPING = "metabase/dashboard/SET_PARAMETER_MAPPING";
+export const SET_PARAMETER_NAME = "metabase/dashboard/SET_PARAMETER_NAME";
+export const SET_PARAMETER_VALUE = "metabase/dashboard/SET_PARAMETER_VALUE";
+export const SET_PARAMETER_DEFAULT_VALUE = "metabase/dashboard/SET_PARAMETER_DEFAULT_VALUE";
 
 // resource wrappers
-const DashboardApi = new AngularResourceProxy("Dashboard", ["get", "update", "delete", "reposition_cards", "addcard", "removecard"]);
+const DashboardApi = new AngularResourceProxy("Dashboard", [
+    "list", "get", "create", "update", "delete", "reposition_cards", "addcard", "removecard"
+]);
 const MetabaseApi = new AngularResourceProxy("Metabase", ["dataset", "dataset_duration", "db_metadata"]);
 const CardApi = new AngularResourceProxy("Card", ["list", "update", "delete"]);
 const RevisionApi = new AngularResourceProxy("Revision", ["list", "revert"]);
@@ -107,10 +116,8 @@ export const addCardToDashboard = function({ dashId, cardId }) {
 
 export const removeCardFromDashboard = createAction(REMOVE_CARD_FROM_DASH);
 
-const UPDATE_DASHCARD_ID = "UPDATE_DASHCARD_ID"
 const updateDashcardId = createAction(UPDATE_DASHCARD_ID, (oldDashcardId, newDashcardId) => ({ oldDashcardId, newDashcardId }));
 
-const CLEAR_CARD_DATA = "CLEAR_CARD_DATA";
 export const clearCardData = createAction(CLEAR_CARD_DATA, (cardId, dashcardId) => ({ cardId, dashcardId }));
 
 export async function fetchDataOrError(dataPromise) {
@@ -131,7 +138,7 @@ export const fetchCardData = createThunkAction(FETCH_CARD_DATA, function(card, d
         let result = null;
 
         // if we have a parameter, apply it to the card query before we execute
-        let { dashboardId } = getState().router.params;
+        let { dashboardId } = getState().dashboard;
         let { dashboards, parameterValues } = getState().dashboard;
 
         let dashboard = dashboards[dashboardId];
@@ -164,19 +171,26 @@ export const fetchCardDuration = createThunkAction(FETCH_CARD_DURATION, function
     };
 });
 
-export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(id, enableQueryParameters = true, enableDefaultParameters = true) {
+const SET_DASHBOARD_ID = "metabase/dashboard/SET_DASHBOARD_ID";
+export const setDashboardId = createAction(SET_DASHBOARD_ID);
+
+export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(dashId, queryParams, enableDefaultParameters = true) {
     return async function(dispatch, getState) {
-        let result = await DashboardApi.get({ dashId: id });
+        let result = await DashboardApi.get({ dashId: dashId });
+
+        dispatch(setDashboardId(dashId));
+
         if (result.parameters) {
-            const { query } = getState().router.location;
             for (const parameter of result.parameters) {
-                if (enableQueryParameters && query[parameter.slug] != null) {
-                    dispatch(setParameterValue(parameter.id, query[parameter.slug]));
+                if (queryParams && queryParams[parameter.slug] != null) {
+                    dispatch(setParameterValue(parameter.id, queryParams[parameter.slug]));
                 } else if (enableDefaultParameters && parameter.default != null) {
                     dispatch(setParameterValue(parameter.id, parameter.default));
                 }
             }
         }
+
+        // fetch database metadata for every card
         _.chain(result.ordered_cards)
             .map((dc) => [dc.card].concat(dc.series))
             .flatten()
@@ -190,10 +204,10 @@ export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(id, en
 
 export const saveDashboard = createThunkAction(SAVE_DASHBOARD, function(dashId) {
     return async function(dispatch, getState) {
-        let { dashboards, dashcards } = getState().dashboard;
+        let { dashboards, dashcards, dashboardId } = getState().dashboard;
         let dashboard = {
-            ...dashboards[dashId],
-            ordered_cards: dashboards[dashId].ordered_cards.map(dashcardId => dashcards[dashcardId])
+            ...dashboards[dashboardId],
+            ordered_cards: dashboards[dashboardId].ordered_cards.map(dashcardId => dashcards[dashcardId])
         };
 
         // remove isRemoved dashboards
@@ -246,7 +260,7 @@ export const saveDashboard = createThunkAction(SAVE_DASHBOARD, function(dashId)
         }
 
         // make sure that we've fully cleared out any dirty state from editing (this is overkill, but simple)
-        dispatch(fetchDashboard(dashId, false, true)); // disable using query parameters when saving
+        dispatch(fetchDashboard(dashId, null, true)); // disable using query parameters when saving
 
         MetabaseAnalytics.trackEvent("Dashboard", "Update");
 
@@ -254,12 +268,19 @@ export const saveDashboard = createThunkAction(SAVE_DASHBOARD, function(dashId)
     };
 });
 
-export const deleteDashboard = createThunkAction(DELETE_DASHBOARD, function(dashId) {
-    return async function(dispatch, getState) {
-        await DashboardApi.delete({ dashId });
-        MetabaseAnalytics.trackEvent("Dashboard", "Delete");
-        return dashId;
-    };
+export const fetchDashboards = createAction(FETCH_DASHBOARDS, () =>
+    DashboardApi.list({ f: "all" })
+);
+
+export const createDashboard = createAction(CREATE_DASHBOARD, (newDashboard) => {
+    MetabaseAnalytics.trackEvent("Dashboard", "Create");
+    return DashboardApi.create(newDashboard);
+});
+
+export const deleteDashboard = createAction(DELETE_DASHBOARD, async (dashId) => {
+    MetabaseAnalytics.trackEvent("Dashboard", "Delete");
+    await DashboardApi.delete({ dashId });
+    return dashId;
 });
 
 export const fetchRevisions = createThunkAction(FETCH_REVISIONS, function({ entity, id }) {
@@ -297,6 +318,10 @@ export const setParameterValue = createThunkAction(SET_PARAMETER_VALUE, (paramet
 
 // reducers
 
+const dashboardId = handleActions({
+    [SET_DASHBOARD_ID]: { next: (state, { payload }) => payload }
+}, null);
+
 const isEditing = handleActions({
     [SET_EDITING_DASHBOARD]: { next: (state, { payload }) => payload }
 }, false);
@@ -383,7 +408,15 @@ const parameterValues = handleActions({
     [SET_PARAMETER_VALUE]: { next: (state, { payload: { id, value }}) => i.assoc(state, id, value) }
 }, {});
 
+const dashboardListing = handleActions({
+    [FETCH_DASHBOARDS]: (state, { payload }) => payload,
+    [CREATE_DASHBOARD]: (state, { payload }) => state.concat(payload),
+    [DELETE_DASHBOARD]: (state, { payload }) => state.filter(d => d.id !== payload),
+    [SAVE_DASHBOARD]:   (state, { payload }) => state.map(d => d.id === payload.id ? payload : d),
+}, []);
+
 export default combineReducers({
+    dashboardId,
     isEditing,
     cards,
     cardList,
@@ -393,5 +426,6 @@ export default combineReducers({
     revisions,
     dashcardData,
     cardDurations,
-    parameterValues
+    parameterValues,
+    dashboardListing
 });
diff --git a/frontend/src/metabase/dashboard/selectors.js b/frontend/src/metabase/dashboard/selectors.js
index 832e8bde8f47efb341ec89906c3d36009d24f3dd..fcb4c46616141c6289f8b2553d55733f7b1033b7 100644
--- a/frontend/src/metabase/dashboard/selectors.js
+++ b/frontend/src/metabase/dashboard/selectors.js
@@ -13,7 +13,7 @@ import Query from "metabase/lib/query";
 import type { CardObject } from "metabase/meta/types/Card";
 import type { ParameterMappingOption, ParameterObject } from "metabase/meta/types/Dashboard";
 
-export const getSelectedDashboard = state => state.router.params.dashboardId;
+export const getDashboardId       = state => state.dashboard.dashboardId;
 export const getIsEditing         = state => state.dashboard.isEditing;
 export const getCards             = state => state.dashboard.cards;
 export const getDashboards        = state => state.dashboard.dashboards;
@@ -32,8 +32,8 @@ export const getMetadata = createSelector(
 )
 
 export const getDashboard = createSelector(
-    [getSelectedDashboard, getDashboards],
-    (selectedDashboard, dashboards) => dashboards[selectedDashboard]
+    [getDashboardId, getDashboards],
+    (dashboardId, dashboards) => dashboards[dashboardId]
 );
 
 export const getDashboardComplete = createSelector(
diff --git a/frontend/src/metabase/directives.js b/frontend/src/metabase/directives.js
deleted file mode 100644
index 31033dfb6f2906842e68e03a0be9d2d74b3557dc..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/directives.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import React from "react";
-import ReactDOM from "react-dom";
-
-import { Provider } from 'react-redux';
-
-/* Directives */
-var MetabaseDirectives = angular.module('metabase.directives', []);
-
-MetabaseDirectives.directive('mbDelayedCall', ['$timeout', function($timeout) {
-
-    function link(scope, element, attr) {
-        var delay = attr.delay;
-        if (!delay) {
-            delay = 8000;
-        }
-
-        var func = attr.mbDelayedCall;
-
-        $timeout(() => scope.$eval(func), delay);
-    }
-
-    return {
-        restrict: 'A',
-        link: link
-    };
-}]);
-
-MetabaseDirectives.directive('mbReduxComponent', ['$timeout', function ($timeout) {
-    return {
-        restrict: 'A',
-        link: function (scope, element, attr) {
-            ReactDOM.render(
-                <Provider store={scope.store}>
-                    <scope.Component {...scope.props} />
-                </Provider>,
-                element[0]
-            );
-
-            scope.$on("$destroy", function() {
-                ReactDOM.unmountComponentAtNode(element[0]);
-            });
-        }
-    };
-}]);
-
-MetabaseDirectives.directive('mbReactComponent', ['$timeout', function ($timeout) {
-    return {
-        restrict: 'A',
-        link: function (scope, element, attr) {
-            var Component = scope[attr.mbReactComponent];
-            delete scope[attr.mbReactComponent];
-
-            function render() {
-                var props = {};
-                function copyProps(dest, src) {
-                    for (var key in src) {
-                        copyProp(dest, key, src[key]);
-                    }
-                }
-                function copyProp(dest, key, value) {
-                    if (typeof value === "function") {
-                        dest[key] = function() {
-                            try {
-                                return value.apply(this, arguments);
-                            } finally {
-                                $timeout(() => scope.$digest());
-                            }
-                        }
-                        copyProps(dest[key], value);
-                    } else {
-                        dest[key] = value;
-                    }
-                }
-                copyProps(props, scope)
-                ReactDOM.render(<Component {...props}/>, element[0]);
-            }
-
-            // limit renders to once per animation frame
-            var timeout;
-            scope.$watch(function() {
-                if (!timeout) {
-                    timeout = requestAnimationFrame(function() {
-                        timeout = null;
-                        render();
-                    });
-                }
-            });
-
-            scope.$on("$destroy", function() {
-                ReactDOM.unmountComponentAtNode(element[0]);
-                // make sure to clear the timeout if set otherwise we might accidentally render a destroyed component
-                if (timeout) {
-                    window.cancelAnimationFrame(timeout);
-                    timeout = null;
-                }
-            });
-
-            render();
-        }
-    };
-}]);
diff --git a/frontend/src/metabase/home/components/Activity.jsx b/frontend/src/metabase/home/components/Activity.jsx
index a8067cb5c7ce633002446121108719031f31f3b4..5b7821773cda04573a4648793eae30bb69612ea3 100644
--- a/frontend/src/metabase/home/components/Activity.jsx
+++ b/frontend/src/metabase/home/components/Activity.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from 'react';
+import { Link } from "react-router";
 import _ from 'underscore';
 
 import LoadingAndErrorWrapper from 'metabase/components/LoadingAndErrorWrapper.jsx';
@@ -39,7 +40,7 @@ export default class Activity extends Component {
         const maxColorUsed = (_.isEmpty(userColors)) ? 0 : _.max(_.values(userColors));
         var currColor =  (maxColorUsed && maxColorUsed < colors.length) ? maxColorUsed : 0;
 
-        if (user) {
+        if (user && activity) {
             for (var item of activity) {
                 if (!(item.user_id in userColors)) {
                     // assign the user a color
@@ -88,7 +89,7 @@ export default class Activity extends Component {
             case "card-create":
             case "card-update":
                 if(item.table) {
-                    description.summary = (<span>saved a question about <a data-metabase-event={"Activity Feed;Header Clicked;Database -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id)}>{item.table.display_name}</a></span>);
+                    description.summary = (<span>saved a question about <Link to={Urls.tableRowsQuery(item.database_id, item.table_id)} data-metabase-event={"Activity Feed;Header Clicked;Database -> "+item.topic} className="link text-dark">{item.table.display_name}</Link></span>);
                 } else {
                     description.summary = "saved a question";
                 }
@@ -104,14 +105,14 @@ export default class Activity extends Component {
                 break;
             case "dashboard-add-cards":
                 if(item.model_exists) {
-                    description.summary = (<span>added a question to the dashboard - <a data-metabase-event={"Activity Feed;Header Clicked;Dashboard -> "+item.topic} className="link text-dark" href={Urls.dashboard(item.model_id)}>{item.details.name}</a></span>);
+                    description.summary = (<span>added a question to the dashboard - <Link to={Urls.dashboard(item.model_id)} data-metabase-event={"Activity Feed;Header Clicked;Dashboard -> "+item.topic} className="link text-dark">{item.details.name}</Link></span>);
                 } else {
                     description.summary = (<span>added a question to the dashboard - <span className="text-dark">{item.details.name}</span></span>);
                 }
                 break;
             case "dashboard-remove-cards":
                 if(item.model_exists) {
-                    description.summary = (<span>removed a question from the dashboard - <a data-metabase-event={"Activity Feed;Header Clicked;Dashboard -> "+item.topic} className="link text-dark" href={Urls.dashboard(item.model_id)}>{item.details.name}</a></span>);
+                    description.summary = (<span>removed a question from the dashboard - <Link to={Urls.dashboard(item.model_id)} data-metabase-event={"Activity Feed;Header Clicked;Dashboard -> "+item.topic} className="link text-dark">{item.details.name}</Link></span>);
                 } else {
                     description.summary = (<span>removed a question from the dashboard - <span className="text-dark">{item.details.name}</span></span>);
                 }
@@ -133,14 +134,14 @@ export default class Activity extends Component {
                 break;
             case "metric-create":
                 if(item.model_exists) {
-                    description.summary = (<span>added the metric <a data-metabase-event={"Activity Feed;Header Clicked;Metric -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id, item.model_id)}>{item.details.name}</a> to the <a data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id)}>{item.table.display_name}</a> table</span>);
+                    description.summary = (<span>added the metric <Link to={Urls.tableRowsQuery(item.database_id, item.table_id, item.model_id)} data-metabase-event={"Activity Feed;Header Clicked;Metric -> "+item.topic} className="link text-dark">{item.details.name}</Link> to the <Link to={Urls.tableRowsQuery(item.database_id, item.table_id)} data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark">{item.table.display_name}</Link> table</span>);
                 } else {
                     description.summary = (<span>added the metric <span className="text-dark">{item.details.name}</span></span>);
                 }
                 break;
             case "metric-update":
                 if(item.model_exists) {
-                    description.summary = (<span>made changes to the metric <a data-metabase-event={"Activity Feed;Header Clicked;Metric -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id, item.model_id)}>{item.details.name}</a> in the <a data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id)}>{item.table.display_name}</a> table</span>);
+                    description.summary = (<span>made changes to the metric <Link to={Urls.tableRowsQuery(item.database_id, item.table_id, item.model_id)} data-metabase-event={"Activity Feed;Header Clicked;Metric -> "+item.topic} className="link text-dark">{item.details.name}</Link> in the <Link to={Urls.tableRowsQuery(item.database_id, item.table_id)} data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark">{item.table.display_name}</Link> table</span>);
                 } else {
                     description.summary = (<span>made changes to the metric <span className="text-dark">{item.details.name}</span></span>);
                 }
@@ -156,14 +157,22 @@ export default class Activity extends Component {
                 break;
             case "segment-create":
                 if(item.model_exists) {
-                    description.summary = (<span>added the filter <a data-metabase-event={"Activity Feed;Header Clicked;Segment -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id, null, item.model_id)}>{item.details.name}</a> to the <a data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id)}>{item.table.display_name}</a> table</span>);
+                    description.summary = (
+                        <span>
+                            added the filter
+                            <Link to={Urls.tableRowsQuery(item.database_id, item.table_id, null, item.model_id)} data-metabase-event={"Activity Feed;Header Clicked;Segment -> "+item.topic} className="link text-dark">{item.details.name}</Link>
+                            to the
+                            <Link to={Urls.tableRowsQuery(item.database_id, item.table_id)} data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark">{item.table.display_name}</Link>
+                            table
+                        </span>
+                    );
                 } else {
                     description.summary = (<span>added the filter <span className="text-dark">{item.details.name}</span></span>);
                 }
                 break;
             case "segment-update":
                 if(item.model_exists) {
-                    description.summary = (<span>made changes to the filter <a data-metabase-event={"Activity Feed;Header Clicked;Segment -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id, null, item.model_id)}>{item.details.name}</a> in the <a data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark" href={Urls.tableRowsQuery(item.database_id, item.table_id)}>{item.table.display_name}</a> table</span>);
+                    description.summary = (<span>made changes to the filter <Link to={Urls.tableRowsQuery(item.database_id, item.table_id, null, item.model_id)} data-metabase-event={"Activity Feed;Header Clicked;Segment -> "+item.topic} className="link text-dark">{item.details.name}</Link> in the <Link to={Urls.tableRowsQuery(item.database_id, item.table_id)} data-metabase-event={"Activity Feed;Header Clicked;Table -> "+item.topic} className="link text-dark">{item.table.display_name}</Link> table</span>);
                 } else {
                     description.summary = (<span>made changes to the filter <span className="text-dark">{item.details.name}</span></span>);
                 }
diff --git a/frontend/src/metabase/home/components/ActivityStory.jsx b/frontend/src/metabase/home/components/ActivityStory.jsx
index 8fd50b1c0d4ca3e7ddaf00891b8176b734d8ad65..93446a019a5984604c536cb5b04c356c696836d2 100644
--- a/frontend/src/metabase/home/components/ActivityStory.jsx
+++ b/frontend/src/metabase/home/components/ActivityStory.jsx
@@ -1,5 +1,5 @@
 import React, { Component, PropTypes } from 'react';
-
+import { Link } from "react-router";
 
 export default class ActivityStory extends Component {
     constructor(props, context) {
@@ -26,7 +26,7 @@ export default class ActivityStory extends Component {
             <div className="mt1 border-left flex mr2" style={{borderWidth: '3px', marginLeft: '22px', borderColor: '#F2F5F6'}}>
                 <div className="flex full ml4 bordered rounded p2" style={this.styles}>
                     { story.bodyLink ?
-                        <a data-metabase-event={"Activity Feed;Story Clicked;"+story.topic} className="link" href={story.bodyLink}>{story.body}</a>
+                        <Link to={story.bodyLink} data-metabase-event={"Activity Feed;Story Clicked;"+story.topic} className="link">{story.body}</Link>
                     :
                         <span>{story.body}</span>
                     }
diff --git a/frontend/src/metabase/home/components/NewUserOnboardingModal.jsx b/frontend/src/metabase/home/components/NewUserOnboardingModal.jsx
index e47ecb2cdef7825f7f97fd5a567b2315031f214e..5722a7e1b4a5498f36f6729f3df68f2591062047 100644
--- a/frontend/src/metabase/home/components/NewUserOnboardingModal.jsx
+++ b/frontend/src/metabase/home/components/NewUserOnboardingModal.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import MetabaseSettings from "metabase/lib/settings";
 
@@ -83,7 +84,7 @@ export default class NewUserOnboardingModal extends Component {
                             {this.renderStep()}
                             <span className="flex-align-right">
                                 <a className="text-underline-hover cursor-pointer mr3" onClick={() => (this.closeModal())}>skip for now</a>
-                                <a className="Button Button--primary" href="/q?tutorial">Let's do it!</a>
+                                <Link to="/q?tutorial" className="Button Button--primary">Let's do it!</Link>
                             </span>
                         </div>
                     </div>
diff --git a/frontend/src/metabase/home/components/NextStep.jsx b/frontend/src/metabase/home/components/NextStep.jsx
index 806223f9dcb6e679e976df88313843075923600c..a3d1ef4a52fb6f8e118000b5b16e2db8f3f2c726 100644
--- a/frontend/src/metabase/home/components/NextStep.jsx
+++ b/frontend/src/metabase/home/components/NextStep.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 import fetch from 'isomorphic-fetch';
 
 import SidebarSection from "./SidebarSection.jsx";
@@ -30,11 +31,11 @@ export default class NextStep extends Component {
         const { next } = this.state;
         if (next) {
             return (
-                <SidebarSection title="Setup Tip" icon="info" extra={<a className="text-brand no-decoration" href="/admin/settings">View all</a>}>
-                    <a className="block p3 no-decoration" href={next.link}>
+                <SidebarSection title="Setup Tip" icon="info" extra={<Link to="/admin/settings" className="text-brand no-decoration">View all</Link>}>
+                    <Link to={next.link} className="block p3 no-decoration">
                         <h4 className="text-brand text-bold">{next.title}</h4>
                         <p className="m0 mt1">{next.description}</p>
-                    </a>
+                    </Link>
                 </SidebarSection>
             )
         } else {
diff --git a/frontend/src/metabase/home/components/RecentViews.jsx b/frontend/src/metabase/home/components/RecentViews.jsx
index 4fef7d5b860115a3c8de3723db445bf8a07932a2..6ce3a24524f5a75deb5f86f19292908232fe47b1 100644
--- a/frontend/src/metabase/home/components/RecentViews.jsx
+++ b/frontend/src/metabase/home/components/RecentViews.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import Icon from "metabase/components/Icon.jsx";
 import SidebarSection from "./SidebarSection.jsx";
@@ -54,14 +55,13 @@ export default class RecentViews extends Component {
                         {recentViews.map((item, index) =>
                             <li key={index} className="py1 ml1 flex align-center clearfix">
                                 {this.renderIllustration(item)}
-                                <a data-metabase-event={"Recent Views;"+item.model+";"+item.cnt} className="ml1 flex-full link" href={Urls.modelToUrl(item.model, item.model_id)}>{item.model_object.name}</a>
+                                <Link to={Urls.modelToUrl(item.model, item.model_id)} data-metabase-event={"Recent Views;"+item.model+";"+item.cnt} className="ml1 flex-full link">{item.model_object.name}</Link>
                             </li>
                         )}
                     </ul>
                 :
                     <div className="flex flex-column layout-centered text-normal text-grey-2">
-                        <span className="QuestionCircle mt4">!</span>
-                        <p className="p3 text-centered text-grey-4" style={{ "maxWidth": "100%" }}>You haven't looked at any Dashboards or Questions recently</p>
+                        <p className="p3 text-centered text-grey-2" style={{ "maxWidth": "100%" }}>You haven't looked at any dashboards or questions recently</p>
                     </div>
                 }
             </SidebarSection>
diff --git a/frontend/src/metabase/home/containers/HomepageApp.jsx b/frontend/src/metabase/home/containers/HomepageApp.jsx
index 53ebb22d079a0aea718d9254703f28ff4e122832..b5514b9251273654fc17a5c99d3466a2e11f726a 100644
--- a/frontend/src/metabase/home/containers/HomepageApp.jsx
+++ b/frontend/src/metabase/home/containers/HomepageApp.jsx
@@ -12,19 +12,22 @@ import NewUserOnboardingModal from '../components/NewUserOnboardingModal.jsx';
 import NextStep from "../components/NextStep.jsx";
 
 import * as homepageActions from "../actions";
-import { getActivity, getRecentViews, getUser, getShowOnboarding } from "../selectors";
+import { getActivity, getRecentViews, getUser } from "../selectors";
 
 const mapStateToProps = (state, props) => {
     return {
         activity:       getActivity(state),
         recentViews:    getRecentViews(state),
         user:           getUser(state),
-        showOnboarding: getShowOnboarding(state)
+        showOnboarding: "new" in props.location.query
     }
 }
 
+import { push } from "react-router-redux";
+
 const mapDispatchToProps = {
-    ...homepageActions
+    ...homepageActions,
+    onChangeLocation: push
 }
 
 @connect(mapStateToProps, mapDispatchToProps)
diff --git a/frontend/src/metabase/home/selectors.js b/frontend/src/metabase/home/selectors.js
index 75a8b5430efcd9318fc409b1366a07e5ae3694fc..45f2d4420af81b47c25bb8aaa6498873b79d8179 100644
--- a/frontend/src/metabase/home/selectors.js
+++ b/frontend/src/metabase/home/selectors.js
@@ -1,4 +1,3 @@
 export const getActivity 		= (state) => state.home && state.home.activity
 export const getRecentViews 	= (state) => state.home && state.home.recentViews
 export const getUser 			= (state) => state.currentUser
-export const getShowOnboarding 	= (state) => state.router && state.router.location && "new" in state.router.location.query
diff --git a/frontend/src/metabase/lib/card.js b/frontend/src/metabase/lib/card.js
index 23bf207f838a8c8283801a9c2fc3e4f227fbbdaa..cc6c209facb5de05af1e59f81dcffd61811347ff 100644
--- a/frontend/src/metabase/lib/card.js
+++ b/frontend/src/metabase/lib/card.js
@@ -82,6 +82,7 @@ export function serializeCardForUrl(card) {
 }
 
 export function deserializeCardFromUrl(serialized) {
+    serialized = serialized.replace(/^#/, "");
     return JSON.parse(b64url_to_utf8(serialized));
 }
 
diff --git a/frontend/src/metabase/lib/cookies.js b/frontend/src/metabase/lib/cookies.js
index fdfd9eca242d42e86b0943b74cb85621cc412d4c..6355b6a87591b7e1913779f98948da0cb5e05089 100644
--- a/frontend/src/metabase/lib/cookies.js
+++ b/frontend/src/metabase/lib/cookies.js
@@ -1,45 +1,40 @@
 
 import { clearGoogleAuthCredentials } from "metabase/lib/auth";
 
-export const METABASE_SESSION_COOKIE = 'metabase.SESSION_ID';
-
-var mb_cookies = {};
+// import Cookies from "js-cookie";
 
+export const METABASE_SESSION_COOKIE = 'metabase.SESSION_ID';
 
 // Handles management of Metabase cookie work
 var MetabaseCookies = {
-    // a little weird, but needed to keep us hooked in with Angular
-    bootstrap: function($rootScope, $location, ipCookie) {
-        mb_cookies.scope = $rootScope;
-        mb_cookies.location = $location;
-        mb_cookies.ipCookie = ipCookie;
-    },
-
     // set the session cookie.  if sessionId is null, clears the cookie
     setSessionCookie: function(sessionId) {
-        if (sessionId) {
-            // set a session cookie
-            var isSecure = (mb_cookies.location.protocol() === "https") ? true : false;
-            mb_cookies.ipCookie(METABASE_SESSION_COOKIE, sessionId, {
-                path: '/',
-                expires: 14,
-                secure: isSecure
-            });
-
-            // send a login notification event
-            mb_cookies.scope.$broadcast('appstate:login', sessionId);
-
-        } else {
-            sessionId = mb_cookies.ipCookie(METABASE_SESSION_COOKIE);
-
-            // delete the current session cookie and Google Auth creds
-            mb_cookies.ipCookie.remove(METABASE_SESSION_COOKIE);
-            clearGoogleAuthCredentials();
-
-            // send a logout notification event
-            mb_cookies.scope.$broadcast('appstate:logout', sessionId);
-
-            return sessionId;
+        let ipCookie = angular.element(document.body).injector().get("ipCookie");
+
+        const options = {
+            path: '/',
+            expires: 14,
+            secure: window.location.protocol === "https:"
+        };
+
+        try {
+            if (sessionId) {
+                // set a session cookie
+                // Cookies.set(METABASE_SESSION_COOKIE, sessionId);
+                ipCookie(METABASE_SESSION_COOKIE, sessionId, options);
+            } else {
+                // sessionId = Cookies.get(METABASE_SESSION_COOKIE);
+                sessionId = ipCookie(METABASE_SESSION_COOKIE);
+
+                // delete the current session cookie and Google Auth creds
+                // Cookies.remove(METABASE_SESSION_COOKIE);
+                ipCookie.remove(METABASE_SESSION_COOKIE);
+                clearGoogleAuthCredentials();
+
+                return sessionId;
+            }
+        } catch (e) {
+            console.error("setSessionCookie:", e);
         }
     }
 }
diff --git a/frontend/src/metabase/lib/pulse.js b/frontend/src/metabase/lib/pulse.js
index d3bd43d421a1af536e2607c132936948cb128483..b7bb3b501a4a9aff1999e9d87d22adaefb1fc884 100644
--- a/frontend/src/metabase/lib/pulse.js
+++ b/frontend/src/metabase/lib/pulse.js
@@ -32,7 +32,7 @@ export function pulseIsValid(pulse, channelSpecs) {
         pulse.name &&
         pulse.cards.length > 0 &&
         pulse.channels.filter((c) => channelIsValid(c, channelSpecs && channelSpecs[c.channel_type])).length > 0
-    );
+    ) || false;
 }
 
 export function cleanPulse(pulse, channelSpecs) {
diff --git a/frontend/src/metabase/lib/redux.js b/frontend/src/metabase/lib/redux.js
index ff6bee64a21739a654a57faf29ca6663d77b15ef..1492e39cd9c70c7228a14942e7dc9bf5d73d48d3 100644
--- a/frontend/src/metabase/lib/redux.js
+++ b/frontend/src/metabase/lib/redux.js
@@ -48,14 +48,14 @@ export const createStoreWithAngularScope = ($scope, $location, ...args) => {
 export function AngularResourceProxy(serviceName, methods) {
     methods.forEach((methodName) => {
         this[methodName] = function(...args) {
-            let service = angular.element(document.querySelector("body")).injector().get(serviceName);
+            let service = angular.element(document.body).injector().get(serviceName);
             return service[methodName](...args).$promise;
         }
     });
 }
 
 export function angularPromise() {
-    let $q = angular.element(document.querySelector("body")).injector().get("$q");
+    let $q = angular.element(document.body).injector().get("$q");
     return $q.defer();
 }
 
diff --git a/frontend/src/metabase/lib/settings.js b/frontend/src/metabase/lib/settings.js
index 80e5840245c7a3076fb64bd6cb3e0acda89e5c99..812ff3122c64ad8fc76c94904e601cc4b91f0a5c 100644
--- a/frontend/src/metabase/lib/settings.js
+++ b/frontend/src/metabase/lib/settings.js
@@ -4,6 +4,7 @@ import MetabaseUtils from "metabase/lib/utils";
 
 const mb_settings = _.clone(window.MetabaseBootstrap);
 
+const settingListeners = {};
 
 // provides access to Metabase application settings
 const MetabaseSettings = {
@@ -12,9 +13,20 @@ const MetabaseSettings = {
         return mb_settings[propName] !== undefined ? mb_settings[propName] : defaultValue;
     },
 
+    set: function(key, value) {
+        if (mb_settings[key] !== value) {
+            mb_settings[key] = value;
+            if (settingListeners[key]) {
+                for (const listener of settingListeners[key]) {
+                    setTimeout(() => listener(value));
+                }
+            }
+        }
+    },
+
     setAll: function(settings) {
-        for (var attrname in settings) {
-            mb_settings[attrname] = settings[attrname];
+        for (const key in settings) {
+            MetabaseSettings.set(key, settings[key]);
         }
     },
 
@@ -75,6 +87,11 @@ const MetabaseSettings = {
         } else {
             return description;
         }
+    },
+
+    on: function(setting, callback) {
+        settingListeners[setting] = settingListeners[setting] || [];
+        settingListeners[setting].push(callback);
     }
 }
 
diff --git a/frontend/src/metabase/components/ProfileLink.jsx b/frontend/src/metabase/nav/components/ProfileLink.jsx
similarity index 79%
rename from frontend/src/metabase/components/ProfileLink.jsx
rename to frontend/src/metabase/nav/components/ProfileLink.jsx
index b7562504b7c1a80b3aaa88725d66adbb163737d1..6757debda66772d2f760f0328164962f01b312dc 100644
--- a/frontend/src/metabase/components/ProfileLink.jsx
+++ b/frontend/src/metabase/nav/components/ProfileLink.jsx
@@ -1,5 +1,8 @@
 import React, { Component, PropTypes } from 'react';
-import OnClickOut from 'react-onclickout';
+import { Link } from "react-router";
+
+import OnClickOutsideWrapper from 'metabase/components/OnClickOutsideWrapper';
+
 import cx from 'classnames';
 import _ from "underscore";
 import { capitalize } from "metabase/lib/formatting";
@@ -8,10 +11,9 @@ import MetabaseSettings from "metabase/lib/settings";
 import Modal from "metabase/components/Modal.jsx";
 import Logs from "metabase/components/Logs.jsx";
 
-import UserAvatar from './UserAvatar.jsx';
-import Icon from './Icon.jsx';
-import LogoIcon from './LogoIcon.jsx';
-
+import UserAvatar from 'metabase/components/UserAvatar.jsx';
+import Icon from 'metabase/components/Icon.jsx';
+import LogoIcon from 'metabase/components/LogoIcon.jsx';
 
 export default class ProfileLink extends Component {
 
@@ -60,7 +62,7 @@ export default class ProfileLink extends Component {
         });
 
         return (
-            <OnClickOut onClickOut={this.closeDropdown}>
+            <OnClickOutsideWrapper handleDismissal={this.closeDropdown}>
                 <div className={dropDownClasses}>
                     <a data-metabase-event={"Navbar;Profile Dropdown;Toggle"} className="NavDropdown-button NavItem flex align-center p2 transition-background" onClick={this.toggleDropdown}>
                         <div className="NavDropdown-button-layer">
@@ -75,24 +77,24 @@ export default class ProfileLink extends Component {
                         <div className="NavDropdown-content right">
                             <ul className="NavDropdown-content-layer">
                                 <li>
-                                    <a data-metabase-event={"Navbar;Profile Dropdown;Edit Profile"} onClick={this.closeDropdown} className="Dropdown-item block text-white no-decoration" href="/user/edit_current">
+                                    <Link to="/user/edit_current" data-metabase-event={"Navbar;Profile Dropdown;Edit Profile"} onClick={this.closeDropdown} className="Dropdown-item block text-white no-decoration">
                                         Account Settings
-                                    </a>
+                                    </Link>
                                 </li>
 
                                 { user.is_superuser && context !== 'admin' ?
                                     <li>
-                                        <a data-metabase-event={"Navbar;Profile Dropdown;Enter Admin"} onClick={this.closeDropdown} className="Dropdown-item block text-white no-decoration" href="/admin/">
+                                        <Link to="/admin" data-metabase-event={"Navbar;Profile Dropdown;Enter Admin"} onClick={this.closeDropdown} className="Dropdown-item block text-white no-decoration">
                                             Admin Panel
-                                        </a>
+                                        </Link>
                                     </li>
                                 : null }
 
                                 { user.is_superuser && context === 'admin' ?
                                     <li>
-                                        <a data-metabase-event={"Navbar;Profile Dropdown;Exit Admin"} onClick={this.closeDropdown} className="Dropdown-item block text-white no-decoration" href="/">
+                                        <Link to="/" data-metabase-event={"Navbar;Profile Dropdown;Exit Admin"} onClick={this.closeDropdown} className="Dropdown-item block text-white no-decoration">
                                             Exit Admin
-                                        </a>
+                                        </Link>
                                     </li>
                                 : null }
 
@@ -117,14 +119,20 @@ export default class ProfileLink extends Component {
                                 </li>
 
                                 <li className="border-top border-light">
-                                    <a data-metabase-event={"Navbar;Profile Dropdown;Logout"} className="Dropdown-item block text-white no-decoration" href="/auth/logout">Logout</a>
+                                    <Link
+                                        to="/auth/logout"
+                                        data-metabase-event={"Navbar;Profile Dropdown;Logout"}
+                                        className="Dropdown-item block text-white no-decoration"
+                                    >
+                                        Logout
+                                    </Link>
                                 </li>
                             </ul>
                         </div>
                     : null }
 
                     { modalOpen === "about" ?
-                        <Modal className="Modal Modal--small">
+                        <Modal className="Modal Modal--small" onClose={this.closeModal}>
                             <div className="px4 pt4 pb2 text-centered relative">
                                 <span className="absolute top right p4 text-normal text-grey-3 cursor-pointer" onClick={this.closeModal}>
                                     <Icon name={'close'} size={16} />
@@ -156,7 +164,7 @@ export default class ProfileLink extends Component {
                         </Modal>
                     : null }
                 </div>
-            </OnClickOut>
+            </OnClickOutsideWrapper>
         );
     }
 }
diff --git a/frontend/src/metabase/components/DashboardsDropdown.jsx b/frontend/src/metabase/nav/containers/DashboardsDropdown.jsx
similarity index 77%
rename from frontend/src/metabase/components/DashboardsDropdown.jsx
rename to frontend/src/metabase/nav/containers/DashboardsDropdown.jsx
index 1a45ea0338eb804030038ea8f947fc7a9e299604..9d8b299f04047c8b2f981299812a013fbd6fde15 100644
--- a/frontend/src/metabase/components/DashboardsDropdown.jsx
+++ b/frontend/src/metabase/nav/containers/DashboardsDropdown.jsx
@@ -1,6 +1,8 @@
 import React, { Component, PropTypes } from 'react';
+import { connect } from "react-redux";
+import { Link } from "react-router";
 
-import OnClickOut from 'react-onclickout';
+import OnClickOutsideWrapper from 'metabase/components/OnClickOutsideWrapper.jsx';
 
 import MetabaseAnalytics from "metabase/lib/analytics";
 import CreateDashboardModal from "metabase/components/CreateDashboardModal.jsx";
@@ -9,6 +11,19 @@ import Modal from "metabase/components/Modal.jsx";
 import _ from "underscore";
 import cx from "classnames";
 
+import { createDashboard, fetchDashboards } from "metabase/dashboard/dashboard";
+import { getDashboards } from "../selectors";
+
+const mapStateToProps = (state, props) => ({
+    dashboards: getDashboards(state)
+});
+
+const mapDispatchToProps = {
+    createDashboard,
+    fetchDashboards
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
 export default class DashboardsDropdown extends Component {
     constructor(props, context) {
         super(props, context);
@@ -31,14 +46,25 @@ export default class DashboardsDropdown extends Component {
     }
 
     static propTypes = {
-        createDashboardFn: PropTypes.func.isRequired,
-        dashboards: PropTypes.array.isRequired
+        dashboards: PropTypes.array.isRequired,
+        createDashboard: PropTypes.func.isRequired,
+        fetchDashboards: PropTypes.func.isRequired,
     };
 
-    async onCreateDashboard(newDashboard) {
-        let { createDashboardFn } = this.props;
+    componentWillMount() {
+        this.props.fetchDashboards();
+    }
 
-        await createDashboardFn(newDashboard);
+    async onCreateDashboard(newDashboard) {
+        let { createDashboard } = this.props;
+
+        try {
+            let action = await createDashboard(newDashboard, true);
+            // FIXME: this doesn't feel right...
+            this.props.onChangeLocation(`/dash/${action.payload.id}`);
+        } catch (e) {
+            console.log("createDashboard failed", e);
+        }
 
         // close modal and add new dash to our dashboards list
         this.setState({
@@ -89,7 +115,7 @@ export default class DashboardsDropdown extends Component {
             <div>
                 { modalOpen ? this.renderCreateDashboardModal() : null }
 
-                <OnClickOut onClickOut={this.closeDropdown}>
+                <OnClickOutsideWrapper handleDismissal={this.closeDropdown}>
                     <div className={cx('NavDropdown inline-block cursor-pointer', { 'open': dropdownOpen })}>
                         <span onClick={this.toggleDropdown}>
                             {children}
@@ -110,7 +136,7 @@ export default class DashboardsDropdown extends Component {
                                     <ul className="NavDropdown-content-layer">
                                         { dashboards.map(dash =>
                                             <li key={dash.id} className="block">
-                                                <a data-metabase-event={"Navbar;Dashboard Dropdown;Open Dashboard;"+dash.id} className="Dropdown-item block text-white no-decoration" href={"/dash/"+dash.id} onClick={this.closeDropdown}>
+                                                <Link to={"/dash/"+dash.id} data-metabase-event={"Navbar;Dashboard Dropdown;Open Dashboard;"+dash.id} className="Dropdown-item block text-white no-decoration" onClick={this.closeDropdown}>
                                                     <div className="flex text-bold">
                                                         {dash.name}
                                                     </div>
@@ -119,7 +145,7 @@ export default class DashboardsDropdown extends Component {
                                                             {dash.description}
                                                         </div>
                                                     : null }
-                                                </a>
+                                                </Link>
                                             </li>
                                         )}
                                         <li className="block border-top border-light">
@@ -130,7 +156,7 @@ export default class DashboardsDropdown extends Component {
                             </div>
                         : null }
                     </div>
-                </OnClickOut>
+                </OnClickOutsideWrapper>
             </div>
         );
     }
diff --git a/frontend/src/metabase/components/Navbar.jsx b/frontend/src/metabase/nav/containers/Navbar.jsx
similarity index 53%
rename from frontend/src/metabase/components/Navbar.jsx
rename to frontend/src/metabase/nav/containers/Navbar.jsx
index 53261be20c0347c4ff7566d140c199f9312b128c..45f04d3cca0698d982645df7dd738a126f0210a6 100644
--- a/frontend/src/metabase/components/Navbar.jsx
+++ b/frontend/src/metabase/nav/containers/Navbar.jsx
@@ -1,17 +1,34 @@
 import React, { Component, PropTypes } from 'react';
 import cx from "classnames";
 
-import DashboardsDropdown from "metabase/components/DashboardsDropdown.jsx";
+import { connect } from "react-redux";
+import { push } from "react-router-redux";
+import { Link } from "react-router";
+
 import Icon from "metabase/components/Icon.jsx";
 import LogoIcon from "metabase/components/LogoIcon.jsx";
-import ProfileLink from "metabase/components/ProfileLink.jsx";
 
-// TODO - this relies on props.location, which is angular's $location service
+import DashboardsDropdown from "metabase/nav/containers/DashboardsDropdown.jsx";
+import ProfileLink from "metabase/nav/components/ProfileLink.jsx";
+
+import { getPath, getContext, getUser } from "../selectors";
+
+const mapStateToProps = (state, props) => ({
+    path:       getPath(state, props),
+    context:    getContext(state, props),
+    user:       getUser(state)
+});
+
+const mapDispatchToProps = {
+    onChangeLocation: push
+};
 
+@connect(mapStateToProps, mapDispatchToProps)
 export default class Navbar extends Component {
     static propTypes = {
+        className: PropTypes.string,
         context: PropTypes.string.isRequired,
-        location: PropTypes.object.isRequired,
+        path: PropTypes.string.isRequired,
         user: PropTypes.object
     };
 
@@ -36,14 +53,16 @@ export default class Navbar extends Component {
     }
 
     isActive(path) {
-        return this.props.location.path().startsWith(path);
+        return this.props.path.startsWith(path);
     }
 
     renderAdminNav() {
-        const classes = "NavItem py1 px2 no-decoration";
+        const getClasses = (path) => cx("NavItem py1 px2 no-decoration", {
+            "is--selected": this.isActive(path)
+        });
 
         return (
-            <nav className="AdminNav">
+            <nav className={cx("Nav AdminNav", this.props.className)}>
                 <div className="wrapper flex align-center">
                     <div className="NavTitle flex align-center">
                         <Icon name={'gear'} className="AdminGear" size={22}></Icon>
@@ -52,24 +71,24 @@ export default class Navbar extends Component {
 
                     <ul className="sm-ml4 flex flex-full">
                         <li>
-                            <a data-metabase-event={"Navbar;Settings"} className={cx(classes, {"is--selected": this.isActive("/admin/settings")})}  href="/admin/settings/">
+                            <Link to="/admin/settings" data-metabase-event={"Navbar;Settings"} className={getClasses("/admin/settings")}  >
                                 Settings
-                            </a>
+                            </Link>
                         </li>
                         <li>
-                            <a data-metabase-event={"Navbar;People"} className={cx(classes, {"is--selected": this.isActive("/admin/people")})} href="/admin/people/">
+                            <Link to="/admin/people" data-metabase-event={"Navbar;People"} className={getClasses("/admin/people")} >
                                 People
-                            </a>
+                            </Link>
                         </li>
                         <li>
-                            <a data-metabase-event={"Navbar;Data Model"} className={cx(classes, {"is--selected": this.isActive("/admin/datamodel")})} href="/admin/datamodel/database">
+                            <Link to="/admin/datamodel/database" data-metabase-event={"Navbar;Data Model"} className={getClasses("/admin/datamodel")} >
                                 Data Model
-                            </a>
+                            </Link>
                         </li>
                         <li>
-                            <a data-metabase-event={"Navbar;Databases"} className={cx(classes, {"is--selected": this.isActive("/admin/databases")})} href="/admin/databases/">
+                            <Link to="/admin/databases" data-metabase-event={"Navbar;Databases"} className={getClasses("/admin/databases")}>
                                 Databases
-                            </a>
+                            </Link>
                         </li>
                     </ul>
 
@@ -81,12 +100,12 @@ export default class Navbar extends Component {
 
     renderEmptyNav() {
         return (
-            <nav className="py2 sm-py1 xl-py3 relative">
+            <nav className={cx("Nav py2 sm-py1 xl-py3 relative", this.props.className)}>
                 <ul className="wrapper flex align-center">
                     <li>
-                        <a data-metabase-event={"Navbar;Logo"} className="NavItem cursor-pointer flex align-center" href="/">
+                        <Link to="/" data-metabase-event={"Navbar;Logo"} className="NavItem cursor-pointer flex align-center">
                             <LogoIcon className="text-brand my2"></LogoIcon>
-                        </a>
+                        </Link>
                     </li>
                 </ul>
             </nav>
@@ -95,12 +114,12 @@ export default class Navbar extends Component {
 
     renderMainNav() {
         return (
-            <nav className="CheckBg CheckBg-offset relative bg-brand sm-py2 sm-py1 xl-py3">
+            <nav className={cx("Nav CheckBg CheckBg-offset relative bg-brand sm-py2 sm-py1 xl-py3", this.props.className)}>
                 <ul className="pl4 pr1 flex align-center">
                     <li>
-                        <a data-metabase-event={"Navbar;Logo"} className="NavItem cursor-pointer text-white flex align-center my1 transition-background" href="/">
-                            <span><LogoIcon className="text-white m1"></LogoIcon></span>
-                        </a>
+                        <Link to="/" data-metabase-event={"Navbar;Logo"} className="NavItem cursor-pointer text-white flex align-center my1 transition-background">
+                            <LogoIcon className="text-white m1"></LogoIcon>
+                        </Link>
                     </li>
                     <li className="pl3">
                         <DashboardsDropdown {...this.props}>
@@ -113,16 +132,16 @@ export default class Navbar extends Component {
                         </DashboardsDropdown>
                     </li>
                     <li className="pl1">
-                        <a data-metabase-event={"Navbar;Questions"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background", {"NavItem--selected": this.isActive("/questions") })} href="/questions/all">Questions</a>
+                        <Link to="/questions/all" data-metabase-event={"Navbar;Questions"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background")} activeClassName="NavItem--selected">Questions</Link>
                     </li>
                     <li className="pl1">
-                        <a data-metabase-event={"Navbar;Pulses"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background", {"NavItem--selected": this.isActive("/pulse") })} href="/pulse/">Pulses</a>
+                        <Link to="/pulse" data-metabase-event={"Navbar;Pulses"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background")} activeClassName="NavItem--selected">Pulses</Link>
                     </li>
                     <li className="pl1">
-                        <a data-metabase-event={"Navbar;DataReference"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background", {"NavItem--selected": this.isActive("/reference") })} href="/reference/guide">Data Reference</a>
+                        <Link to="/reference/guide" data-metabase-event={"Navbar;DataReference"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background")} activeClassName="NavItem--selected">Data Reference</Link>
                     </li>
                     <li className="pl3">
-                        <a data-metabase-event={"Navbar;New Question"} style={this.styles.newQuestion} className="NavNewQuestion rounded inline-block bg-white text-brand text-bold cursor-pointer px2 no-decoration transition-all" href="/q">New <span className="hide sm-show">Question</span></a>
+                        <Link to="/q" data-metabase-event={"Navbar;New Question"} style={this.styles.newQuestion} className="NavNewQuestion rounded inline-block bg-white text-brand text-bold cursor-pointer px2 no-decoration transition-all">New <span className="hide sm-show">Question</span></Link>
                     </li>
                     <li className="flex-align-right transition-background">
                         <div className="inline-block text-white"><ProfileLink {...this.props}></ProfileLink></div>
diff --git a/frontend/src/metabase/nav/selectors.js b/frontend/src/metabase/nav/selectors.js
new file mode 100644
index 0000000000000000000000000000000000000000..612ad051c2626f8088c8f305db5664cf34c6ab0a
--- /dev/null
+++ b/frontend/src/metabase/nav/selectors.js
@@ -0,0 +1,23 @@
+
+import { createSelector } from 'reselect';
+
+export const getPath = (state, props) => props.location.pathname;
+
+export const getUser = (state) => state.currentUser;
+
+export const getContext = createSelector(
+    [getPath],
+    (path) =>
+        path.startsWith('/auth/') ?
+            'auth'
+        : path.startsWith('/setup/') ?
+            'setup'
+        : path.startsWith('/admin/') ?
+            'admin'
+        : path === '/' ?
+            'home'
+        :
+            'main'
+);
+
+export const getDashboards = (state) => state.dashboard.dashboardListing;
diff --git a/frontend/src/metabase/pulse/components/CardPicker.jsx b/frontend/src/metabase/pulse/components/CardPicker.jsx
index 06fff837e1545dacdbe973e406b374aa34989b03..ce6b885c093ae109721f1d66eef5ae8c20e8570d 100644
--- a/frontend/src/metabase/pulse/components/CardPicker.jsx
+++ b/frontend/src/metabase/pulse/components/CardPicker.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -23,6 +24,9 @@ export default class CardPicker extends Component {
         onChange: PropTypes.func.isRequired
     };
 
+    componentWillUnmount() {
+        clearTimeout(this._timer);
+    }
 
     onInputChange(e) {
         this.setState({ inputValue: e.target.value });
@@ -36,7 +40,8 @@ export default class CardPicker extends Component {
         // Without a timeout here isOpen gets set to false when an item is clicked
         // which causes the click handler to not fire. For some reason this even
         // happens with a 100ms delay, but not 200ms?
-        setTimeout(() => this.setState({ isOpen: false }), 250);
+        clearTimeout(this._timer);
+        this._timer = setTimeout(() => this.setState({ isOpen: false }), 250);
     }
 
     onChange(id) {
@@ -57,14 +62,14 @@ export default class CardPicker extends Component {
 
         if (error) {
             return (
-                <li className="px2 py1">
+                <li key={card.id} className="px2 py1">
                     <h4 className="text-grey-2">{card.name}</h4>
                     <h4 className="text-gold mt1">{error}</h4>
                 </li>
             )
         } else {
             return (
-                <li className="List-item cursor-pointer" onClickCapture={this.onChange.bind(this, card.id)}>
+                <li key={card.id} className="List-item cursor-pointer" onClickCapture={this.onChange.bind(this, card.id)}>
                     <h4 className="List-item-title px2 py1">{card.name}</h4>
                 </li>
             );
diff --git a/frontend/src/metabase/pulse/components/PulseCardPreview.jsx b/frontend/src/metabase/pulse/components/PulseCardPreview.jsx
index b3494e20662679e4f28f0122b9534c914e18205b..2afafd3dbf8116adf9fdcca8acbcb85f3a41f56e 100644
--- a/frontend/src/metabase/pulse/components/PulseCardPreview.jsx
+++ b/frontend/src/metabase/pulse/components/PulseCardPreview.jsx
@@ -1,12 +1,10 @@
+/* eslint "react/prop-types": "warn" */
 /*eslint-disable react/no-danger */
-
 import React, { Component, PropTypes } from "react";
 
 import Icon from "metabase/components/Icon.jsx";
 import LoadingSpinner from "metabase/components/LoadingSpinner.jsx";
 
-import { fetchPulseCardPreview } from "../actions";
-
 export default class PulseCardPreview extends Component {
     constructor(props, context) {
         super(props, context);
@@ -15,11 +13,12 @@ export default class PulseCardPreview extends Component {
     static propTypes = {
         card: PropTypes.object.isRequired,
         cardPreview: PropTypes.object,
-        onRemove: PropTypes.func.isRequired
+        onRemove: PropTypes.func.isRequired,
+        fetchPulseCardPreview: PropTypes.func.isRequired,
     };
 
     componentWillMount() {
-        this.props.dispatch(fetchPulseCardPreview(this.props.card.id));
+        this.props.fetchPulseCardPreview(this.props.card.id);
     }
 
     render() {
diff --git a/frontend/src/metabase/pulse/components/PulseEdit.jsx b/frontend/src/metabase/pulse/components/PulseEdit.jsx
index deed84d1d125bfff1105099a6debb109624920a6..93423110e612c7254580486e5b0cfa298aeb0a02 100644
--- a/frontend/src/metabase/pulse/components/PulseEdit.jsx
+++ b/frontend/src/metabase/pulse/components/PulseEdit.jsx
@@ -1,4 +1,6 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import PulseEditName from "./PulseEditName.jsx";
 import PulseEditCards from "./PulseEditCards.jsx";
@@ -11,15 +13,6 @@ import ModalWithTrigger from "metabase/components/ModalWithTrigger.jsx";
 import ModalContent from "metabase/components/ModalContent.jsx";
 import DeleteModalWithConfirm from "metabase/components/DeleteModalWithConfirm.jsx";
 
-import {
-    setEditingPulse,
-    updateEditingPulse,
-    saveEditingPulse,
-    deletePulse,
-    fetchCards,
-    fetchUsers,
-    fetchPulseFormInput
-} from "../actions";
 
 import { pulseIsValid, cleanPulse } from "metabase/lib/pulse";
 
@@ -35,23 +28,32 @@ export default class PulseEdit extends Component {
     }
 
     static propTypes = {
-        pulses: PropTypes.object,
-        pulseId: PropTypes.number
+        pulse: PropTypes.object.isRequired,
+        pulseId: PropTypes.number,
+        formInput: PropTypes.object.isRequired,
+        setEditingPulse: PropTypes.func.isRequired,
+        fetchCards: PropTypes.func.isRequired,
+        fetchUsers: PropTypes.func.isRequired,
+        fetchPulseFormInput: PropTypes.func.isRequired,
+        updateEditingPulse: PropTypes.func.isRequired,
+        saveEditingPulse: PropTypes.func.isRequired,
+        deletePulse: PropTypes.func.isRequired,
+        onChangeLocation: PropTypes.func.isRequired
     };
 
     componentDidMount() {
-        this.props.dispatch(setEditingPulse(this.props.pulseId));
-        this.props.dispatch(fetchCards());
-        this.props.dispatch(fetchUsers());
-        this.props.dispatch(fetchPulseFormInput());
+        this.props.setEditingPulse(this.props.pulseId);
+        this.props.fetchCards();
+        this.props.fetchUsers();
+        this.props.fetchPulseFormInput();
 
         MetabaseAnalytics.trackEvent((this.props.pulseId) ? "PulseEdit" : "PulseCreate", "Start");
     }
 
     async save() {
         let pulse = cleanPulse(this.props.pulse,  this.props.formInput.channels);
-        await this.props.dispatch(updateEditingPulse(pulse))
-        await this.props.dispatch(saveEditingPulse());
+        await this.props.updateEditingPulse(pulse);
+        await this.props.saveEditingPulse();
 
         MetabaseAnalytics.trackEvent((this.props.pulseId) ? "PulseEdit" : "PulseCreate", "Complete", this.props.pulse.cards.length);
 
@@ -59,7 +61,7 @@ export default class PulseEdit extends Component {
     }
 
     async delete() {
-        await this.props.dispatch(deletePulse(this.props.pulse.id));
+        await this.props.deletePulse(this.props.pulse.id);
 
         MetabaseAnalytics.trackEvent("PulseDelete", "Complete");
 
@@ -67,7 +69,7 @@ export default class PulseEdit extends Component {
     }
 
     setPulse(pulse) {
-        this.props.dispatch(updateEditingPulse(pulse));
+        this.props.updateEditingPulse(pulse);
     }
 
     isValid() {
@@ -148,7 +150,7 @@ export default class PulseEdit extends Component {
                         failedText="Save failed"
                         successText="Saved"
                     />
-                    <a className="text-bold flex-align-right no-decoration text-brand-hover" href="/pulse">Cancel</a>
+                    <Link to="/pulse" className="text-bold flex-align-right no-decoration text-brand-hover">Cancel</Link>
                 </div>
             </div>
         );
diff --git a/frontend/src/metabase/pulse/components/PulseEditCards.jsx b/frontend/src/metabase/pulse/components/PulseEditCards.jsx
index 299e0b979040ba309adcad0b592525fb3a1dc9d5..5d74cb80250ee627ce6b00d0e4ac6e1295de0d5b 100644
--- a/frontend/src/metabase/pulse/components/PulseEditCards.jsx
+++ b/frontend/src/metabase/pulse/components/PulseEditCards.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import CardPicker from "./CardPicker.jsx";
@@ -14,7 +15,15 @@ export default class PulseEditCards extends Component {
         this.state = {};
     }
 
-    static propTypes = {};
+    static propTypes = {
+        pulse: PropTypes.object.isRequired,
+        pulseId: PropTypes.number,
+        cardPreviews: PropTypes.object.isRequired,
+        cards: PropTypes.object.isRequired,
+        cardList: PropTypes.array.isRequired,
+        fetchPulseCardPreview: PropTypes.func.isRequired,
+        setPulse: PropTypes.func.isRequired
+    };
     static defaultProps = {};
 
     setCard(index, cardId) {
@@ -103,7 +112,7 @@ export default class PulseEditCards extends Component {
                                             card={card}
                                             cardPreview={cardPreviews[card.id]}
                                             onRemove={this.removeCard.bind(this, index)}
-                                            dispatch={this.props.dispatch}
+                                            fetchPulseCardPreview={this.props.fetchPulseCardPreview}
                                         />
                                     :
                                         <CardPicker
diff --git a/frontend/src/metabase/pulse/components/PulseEditChannels.jsx b/frontend/src/metabase/pulse/components/PulseEditChannels.jsx
index ebd006792f3a616a936a54ea706f81f7d6080636..dc588d1ea817a9aea7f6374a02fb8d86cadce2a2 100644
--- a/frontend/src/metabase/pulse/components/PulseEditChannels.jsx
+++ b/frontend/src/metabase/pulse/components/PulseEditChannels.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import _ from "underscore";
@@ -16,8 +17,6 @@ import MetabaseAnalytics from "metabase/lib/analytics";
 
 import { channelIsValid } from "metabase/lib/pulse";
 
-import { testPulse } from "../actions";
-
 import cx from "classnames";
 
 const CHANNEL_ICONS = {
@@ -31,7 +30,16 @@ export default class PulseEditChannels extends Component {
         this.state = {};
     }
 
-    static propTypes = {};
+    static propTypes = {
+        pulse: PropTypes.object.isRequired,
+        pulseId: PropTypes.number,
+        pulseIsValid: PropTypes.bool.isRequired,
+        formInput: PropTypes.object.isRequired,
+        user: PropTypes.object.isRequired,
+        userList: PropTypes.array.isRequired,
+        setPulse: PropTypes.func.isRequired,
+        testPulse: PropTypes.func.isRequired
+    };
     static defaultProps = {};
 
     addChannel(type) {
@@ -123,7 +131,7 @@ export default class PulseEditChannels extends Component {
 
     onTestPulseChannel(channel) {
         // test a single channel
-        return this.props.dispatch(testPulse({ ...this.props.pulse, channels: [channel] }));
+        return this.props.testPulse({ ...this.props.pulse, channels: [channel] });
     }
 
     renderFields(channel, index, channelSpec) {
diff --git a/frontend/src/metabase/pulse/components/PulseEditName.jsx b/frontend/src/metabase/pulse/components/PulseEditName.jsx
index 4eaefdaf37d3e1a937b0a2076150edd233a584f3..dcb9e3a4cc0105443024cac9c45acae8505f679a 100644
--- a/frontend/src/metabase/pulse/components/PulseEditName.jsx
+++ b/frontend/src/metabase/pulse/components/PulseEditName.jsx
@@ -38,7 +38,7 @@ export default class PulseEditName extends Component {
                         ref="name"
                         className={cx("input h4 text-bold text-default", { "border-error": !this.state.valid })}
                         style={{"width":"400px"}}
-                        value={pulse.name}
+                        value={pulse.name || ""}
                         onChange={this.setName}
                         onBlur={this.validate}
                         placeholder="Important metrics"
diff --git a/frontend/src/metabase/pulse/components/PulseList.jsx b/frontend/src/metabase/pulse/components/PulseList.jsx
index ac40745d49eb87b807a4e1db022a8d8971ecf2dd..4df6d170d0f5ecbb4d599f26a507957f93488eb8 100644
--- a/frontend/src/metabase/pulse/components/PulseList.jsx
+++ b/frontend/src/metabase/pulse/components/PulseList.jsx
@@ -7,8 +7,6 @@ import SetupModal from "./SetupModal.jsx";
 import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
 import Modal from "metabase/components/Modal.jsx";
 
-import { fetchPulses, fetchPulseFormInput } from "../actions";
-
 import _ from "underscore";
 
 export default class PulseList extends Component {
@@ -26,8 +24,8 @@ export default class PulseList extends Component {
     static defaultProps = {};
 
     componentDidMount() {
-        this.props.dispatch(fetchPulses());
-        this.props.dispatch(fetchPulseFormInput());
+        this.props.fetchPulses();
+        this.props.fetchPulseFormInput();
     }
 
     create() {
@@ -59,7 +57,7 @@ export default class PulseList extends Component {
                                     pulse={pulse}
                                     user={user}
                                     formInput={this.props.formInput}
-                                    dispatch={this.props.dispatch}
+                                    savePulse={this.props.savePulse}
                                 />
                             </li>
                         )}
diff --git a/frontend/src/metabase/pulse/components/PulseListChannel.jsx b/frontend/src/metabase/pulse/components/PulseListChannel.jsx
index 5848b0052e40b31e469c5830c079dfec2a757bf0..7b8c70a53e591b5d6f31ca9975d891425d87fb4d 100644
--- a/frontend/src/metabase/pulse/components/PulseListChannel.jsx
+++ b/frontend/src/metabase/pulse/components/PulseListChannel.jsx
@@ -1,9 +1,8 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import Icon from "metabase/components/Icon.jsx";
 
-import { savePulse } from "../actions";
-
 import { inflect } from "inflection";
 import _ from "underscore";
 
@@ -18,27 +17,28 @@ export default class PulseListChannel extends Component {
         pulse: PropTypes.object.isRequired,
         channel: PropTypes.object.isRequired,
         channelSpec: PropTypes.object,
-        user: PropTypes.object.isRequired
+        user: PropTypes.object.isRequired,
+        savePulse: PropTypes.func.isRequired,
     };
 
     subscribe() {
         let { pulse, channel, user } = this.props;
-        this.props.dispatch(savePulse({
+        this.props.savePulse({
             ...pulse,
             channels: pulse.channels.map(c => c !== channel ? c :
                 { ...c, recipients: [...c.recipients, user]}
             )
-        }));
+        });
     }
 
     unsubscribe() {
         let { pulse, channel, user } = this.props;
-        this.props.dispatch(savePulse({
+        this.props.savePulse({
             ...pulse,
             channels: pulse.channels.map(c => c !== channel ? c :
                 { ...c, recipients: c.recipients.filter(r => r.id !== user.id)}
             )
-        }));
+        });
     }
 
     renderChannelSchedule() {
diff --git a/frontend/src/metabase/pulse/components/PulseListItem.jsx b/frontend/src/metabase/pulse/components/PulseListItem.jsx
index 1515eb8cc8ddd0b88ddd4a00bdbd0a605228dc30..0a07eaf0286e4d3c1d41892b4b778dbe389e1d8c 100644
--- a/frontend/src/metabase/pulse/components/PulseListItem.jsx
+++ b/frontend/src/metabase/pulse/components/PulseListItem.jsx
@@ -1,5 +1,7 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
+import { Link } from "react-router";
 
 import cx from "classnames";
 
@@ -10,7 +12,9 @@ export default class PulseListItem extends Component {
     static propTypes = {
         pulse: PropTypes.object.isRequired,
         formInput: PropTypes.object.isRequired,
-        user: PropTypes.object.isRequired
+        user: PropTypes.object.isRequired,
+        scrollTo: PropTypes.bool.isRequired,
+        savePulse: PropTypes.func.isRequired
     };
 
     componentDidMount() {
@@ -31,15 +35,15 @@ export default class PulseListItem extends Component {
                         <span>Pulse by <span className="text-bold">{pulse.creator && pulse.creator.common_name}</span></span>
                     </div>
                     <div className="flex-align-right">
-                        <a className="PulseEditButton PulseButton Button no-decoration text-bold" href={"/pulse/" + pulse.id}>Edit</a>
+                        <Link to={"/pulse/" + pulse.id} className="PulseEditButton PulseButton Button no-decoration text-bold">Edit</Link>
                     </div>
                 </div>
                 <ol className="mb2 px4 flex flex-wrap">
                     { pulse.cards.map((card, index) =>
                         <li key={index} className="mr1 mb1">
-                            <a className="Button" href={Urls.card(card.id)}>
+                            <Link to={Urls.card(card.id)} className="Button">
                                 {card.name}
-                            </a>
+                            </Link>
                         </li>
                     )}
                 </ol>
@@ -50,8 +54,8 @@ export default class PulseListItem extends Component {
                                 pulse={pulse}
                                 channel={channel}
                                 channelSpec={formInput.channels && formInput.channels[channel.channel_type]}
-                                dispatch={this.props.dispatch}
                                 user={user}
+                                savePulse={this.props.savePulse}
                             />
                         </li>
                     )}
diff --git a/frontend/src/metabase/pulse/components/RecipientPicker.jsx b/frontend/src/metabase/pulse/components/RecipientPicker.jsx
index bfb0e2d2724ea18112cfa581f2826fc121a6c69c..3b69caf3a5aea5dfd6b7f6fe977278bbb5bec09e 100644
--- a/frontend/src/metabase/pulse/components/RecipientPicker.jsx
+++ b/frontend/src/metabase/pulse/components/RecipientPicker.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -31,8 +32,9 @@ export default class RecipientPicker extends Component {
     static propTypes = {
         recipients: PropTypes.array,
         recipientTypes: PropTypes.array.isRequired,
+        users: PropTypes.array,
+        isNewPulse: PropTypes.bool.isRequired,
         onRecipientsChange: PropTypes.func.isRequired,
-        users: PropTypes.array
     };
 
     static defaultProps = {
diff --git a/frontend/src/metabase/pulse/components/SchedulePicker.jsx b/frontend/src/metabase/pulse/components/SchedulePicker.jsx
index 4b462e7ec8d632f561d8bb4fd42a59922d45757c..7e1df516236f86ad69dcff9f451edb25a50d75c0 100644
--- a/frontend/src/metabase/pulse/components/SchedulePicker.jsx
+++ b/frontend/src/metabase/pulse/components/SchedulePicker.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import Select from "metabase/components/Select.jsx";
diff --git a/frontend/src/metabase/pulse/components/SetupMessage.jsx b/frontend/src/metabase/pulse/components/SetupMessage.jsx
index 36fde9b7cc8c133222db9d5ea86fa91b607fe0dd..71b158529a044520a7ff887891a0a9e525ee043c 100644
--- a/frontend/src/metabase/pulse/components/SetupMessage.jsx
+++ b/frontend/src/metabase/pulse/components/SetupMessage.jsx
@@ -1,4 +1,6 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import Icon from "metabase/components/Icon.jsx";
 
@@ -30,7 +32,7 @@ export default class SetupMessage extends Component {
                     </div>
                     <div className="mt2">
                         {channels.map(c =>
-                            <a className="Button Button--primary mr1" href={"/admin/settings?section="+c} target={window.OSX ? null : "_blank"}>Configure {c}</a>
+                            <Link to={"/admin/settings/"+c.toLowerCase()} key={c.toLowerCase()} className="Button Button--primary mr1" target={window.OSX ? null : "_blank"}>Configure {c}</Link>
                         )}
                     </div>
                 </div>
diff --git a/frontend/src/metabase/pulse/components/SetupModal.jsx b/frontend/src/metabase/pulse/components/SetupModal.jsx
index 0e3cc9b5c5ecdf7ac98fc458f80e057cd2b1635b..a9bf6d240fd3499d7b853f149030bd8969fb50d0 100644
--- a/frontend/src/metabase/pulse/components/SetupModal.jsx
+++ b/frontend/src/metabase/pulse/components/SetupModal.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import SetupMessage from "./SetupMessage.jsx";
diff --git a/frontend/src/metabase/pulse/components/WhatsAPulse.jsx b/frontend/src/metabase/pulse/components/WhatsAPulse.jsx
index e954d3bc88fe916f5c8efc5b29fa6a4e04d44d8a..b2be5faf3d05cc020ebd76e3d6b0e0dafe623d04 100644
--- a/frontend/src/metabase/pulse/components/WhatsAPulse.jsx
+++ b/frontend/src/metabase/pulse/components/WhatsAPulse.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import RetinaImage from "react-retina-image";
diff --git a/frontend/src/metabase/pulse/containers/PulseEditApp.jsx b/frontend/src/metabase/pulse/containers/PulseEditApp.jsx
index 86f56f94d6eb236244ce58734e5b265c2a70d730..fc7510993e1fe53817dcceb2f9abea3a30e77964 100644
--- a/frontend/src/metabase/pulse/containers/PulseEditApp.jsx
+++ b/frontend/src/metabase/pulse/containers/PulseEditApp.jsx
@@ -1,18 +1,44 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+import { push } from "react-router-redux";
 
 import PulseEdit from "../components/PulseEdit.jsx";
+
 import { editPulseSelectors } from "../selectors";
+import {
+    setEditingPulse,
+    updateEditingPulse,
+    saveEditingPulse,
+    deletePulse,
+    fetchCards,
+    fetchUsers,
+    fetchPulseFormInput,
+    fetchPulseCardPreview,
+    testPulse,
+} from "../actions";
 
 const mapStateToProps = (state, props) => {
     return {
-        ...editPulseSelectors(state),
+        ...editPulseSelectors(state, props),
         user: state.currentUser
-        // onChangeLocation: onChangeLocation
     }
 }
 
-@connect(mapStateToProps)
+const mapDispatchToProps = {
+    setEditingPulse,
+    updateEditingPulse,
+    saveEditingPulse,
+    deletePulse,
+    fetchCards,
+    fetchUsers,
+    fetchPulseFormInput,
+    fetchPulseCardPreview,
+    testPulse,
+    onChangeLocation: push
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
 export default class PulseEditApp extends Component {
     render() {
         return (
diff --git a/frontend/src/metabase/pulse/containers/PulseListApp.jsx b/frontend/src/metabase/pulse/containers/PulseListApp.jsx
index 593702023f82d450c810a0b989f7f994f3917be9..bc01b350b7c702cf68433deae0bf273124ff7677 100644
--- a/frontend/src/metabase/pulse/containers/PulseListApp.jsx
+++ b/frontend/src/metabase/pulse/containers/PulseListApp.jsx
@@ -1,19 +1,30 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
+import { push } from "react-router-redux";
 
 import PulseList from "../components/PulseList.jsx";
 import { listPulseSelectors } from "../selectors";
 
 
+import { fetchPulses, fetchPulseFormInput, savePulse } from "../actions";
+
 const mapStateToProps = (state, props) => {
     return {
-        ...listPulseSelectors(state),
+        ...listPulseSelectors(state, props),
         user: state.currentUser,
         // onChangeLocation: onChangeLocation
     }
 }
 
-@connect(mapStateToProps)
+const mapDispatchToProps = {
+    fetchPulses,
+    fetchPulseFormInput,
+    savePulse,
+    onChangeLocation: push
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
 export default class PulseListApp extends Component {
     render() {
         return (
diff --git a/frontend/src/metabase/pulse/selectors.js b/frontend/src/metabase/pulse/selectors.js
index a1a0bfa44ab3c15e12ba49f979e64d48e9575e19..7386a312f2a43ac4f3f96aa9a8beb3f882bee1dd 100644
--- a/frontend/src/metabase/pulse/selectors.js
+++ b/frontend/src/metabase/pulse/selectors.js
@@ -30,19 +30,7 @@ const userListSelector = createSelector(
     (users) => Object.values(users)
 );
 
-const getPulseId = createSelector(
-    state => state.router,
-    (router) => {
-        if (router && router.params && router.params.pulseId) {
-            return parseInt(router.params.pulseId);
-        } else if (router && router.location && router.location.hash) {
-            return parseInt(router.location.hash.substr(1));
-        } else {
-            return null;
-        }
-    }
-);
-
+const getPulseId = (state, props) => props.params.pulseId ? parseInt(props.params.pulseId) : null;
 
 // LIST
 export const listPulseSelectors = createSelector(
diff --git a/frontend/src/metabase/query_builder/QueryHeader.jsx b/frontend/src/metabase/query_builder/QueryHeader.jsx
index d47768b4930df289cf5197370da934210c8eab6b..e4a9e29e4dae8a321850bdf53ec2d262484d1446 100644
--- a/frontend/src/metabase/query_builder/QueryHeader.jsx
+++ b/frontend/src/metabase/query_builder/QueryHeader.jsx
@@ -357,6 +357,10 @@ export default class QueryHeader extends Component {
         );
     }
 
+    onCloseModal = () => {
+        this.setState({ modal: null });
+    }
+
     render() {
         return (
             <div>
@@ -369,18 +373,18 @@ export default class QueryHeader extends Component {
                     setItemAttributeFn={this.props.onSetCardAttribute}
                 />
 
-                <Modal className="Modal Modal--small" isOpen={this.state.modal === "saved"}>
+                <Modal className="Modal Modal--small" isOpen={this.state.modal === "saved"} onClose={this.onCloseModal}>
                     <QuestionSavedModal
                         addToDashboardFn={() => this.setState({ modal: "add-to-dashboard" })}
-                        closeFn={() => this.setState({ modal: null })}
+                        closeFn={this.onCloseModal}
                     />
                 </Modal>
 
-                <Modal isOpen={this.state.modal === "add-to-dashboard"}>
+                <Modal isOpen={this.state.modal === "add-to-dashboard"} onClose={this.onCloseModal}>
                     <AddToDashSelectDashModal
                         card={this.props.card}
                         dashboardApi={this.props.dashboardApi}
-                        closeFn={() => this.setState({ modal: null })}
+                        closeFn={this.onCloseModal}
                         onChangeLocation={this.props.onChangeLocation}
                     />
                 </Modal>
diff --git a/frontend/src/metabase/query_builder/QueryVisualization.jsx b/frontend/src/metabase/query_builder/QueryVisualization.jsx
index ba9ee1632148d7368275ec9f120742bfcee2ff76..060f274718c7b47187f1aaf07e02d35a5c956a34 100644
--- a/frontend/src/metabase/query_builder/QueryVisualization.jsx
+++ b/frontend/src/metabase/query_builder/QueryVisualization.jsx
@@ -1,5 +1,6 @@
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
+import { Link } from "react-router";
 
 import Icon from "metabase/components/Icon.jsx";
 import LoadingSpinner from 'metabase/components/LoadingSpinner.jsx';
@@ -259,5 +260,5 @@ export default class QueryVisualization extends Component {
 const VisualizationEmptyState = ({showTutorialLink}) =>
     <div className="flex full layout-centered text-grey-1 flex-column">
         <h1>If you give me some data I can show you something cool. Run a Query!</h1>
-        { showTutorialLink && <a className="link cursor-pointer my2" href="/q?tutorial">How do I use this thing?</a> }
+        { showTutorialLink && <Link to="/q?tutorial" className="link cursor-pointer my2">How do I use this thing?</Link> }
     </div>
diff --git a/frontend/src/metabase/query_builder/actions.js b/frontend/src/metabase/query_builder/actions.js
index 2fb6568904d6c2708ebb52d49fdfc1500947acb4..965bc60135a0d797284a978acb889ec56404f08c 100644
--- a/frontend/src/metabase/query_builder/actions.js
+++ b/frontend/src/metabase/query_builder/actions.js
@@ -6,9 +6,10 @@ import i from "icepick";
 import moment from "moment";
 
 import { AngularResourceProxy, angularPromise, createThunkAction } from "metabase/lib/redux";
+import { push, replace } from "react-router-redux";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
-import { loadCard, isCardDirty, startNewCard, deserializeCardFromUrl } from "metabase/lib/card";
+import { loadCard, isCardDirty, startNewCard, deserializeCardFromUrl, serializeCardForUrl, cleanCopyCard, urlForCardState } from "metabase/lib/card";
 import { formatSQL, humanize } from "metabase/lib/formatting";
 import Query from "metabase/lib/query";
 import { createQuery } from "metabase/lib/query";
@@ -21,11 +22,78 @@ import { getParameters } from "./selectors";
 const Metabase = new AngularResourceProxy("Metabase", ["db_list_with_tables", "db_fields", "dataset", "table_query_metadata"]);
 const User = new AngularResourceProxy("User", ["update_qbnewb"]);
 
+import { parse as urlParse } from "url";
+
+export const SET_CURRENT_STATE = "metabase/qb/SET_CURRENT_STATE";
+const setCurrentState = createAction(SET_CURRENT_STATE);
+
+export const POP_STATE = "metabase/qb/POP_STATE";
+export const popState = createThunkAction(POP_STATE, (location) =>
+    async (dispatch, getState) => {
+        const { card } = getState().qb;
+        if (location.state && location.state.card) {
+            if (!angular.equals(card, location.state.card)) {
+                dispatch(setCardAndRun(location.state.card, false));
+                dispatch(setCurrentState(location.state));
+            }
+        }
+    }
+);
+
+export const UPDATE_URL = "metabase/qb/UPDATE_URL";
+export const updateUrl = createThunkAction(UPDATE_URL, (card, isDirty = false, replaceState = false) =>
+    (dispatch, getState) => {
+        if (!card) {
+            return;
+        }
+        var copy = cleanCopyCard(card);
+        var newState = {
+            card: copy,
+            cardId: copy.id,
+            serializedCard: serializeCardForUrl(copy)
+        };
+
+        const { currentState } = getState().qb;
+
+        if (angular.equals(currentState, newState)) {
+            return;
+        }
+
+        var url = urlForCardState(newState, isDirty);
+
+        // if the serialized card is identical replace the previous state instead of adding a new one
+        // e.x. when saving a new card we want to replace the state and URL with one with the new card ID
+        replaceState = replaceState || (currentState && currentState.serializedCard === newState.serializedCard);
+
+        const urlParsed = urlParse(url);
+        const locationDescriptor = {
+            pathname: urlParsed.pathname,
+            search: urlParsed.search,
+            hash: urlParsed.hash,
+            state: newState
+        };
+
+        if (locationDescriptor.pathname === window.location.pathname &&
+            (locationDescriptor.search || "") === (window.location.search || "") &&
+            (locationDescriptor.hash || "") === (window.location.hash || "")
+        ) {
+            replaceState = true;
+        }
+
+        // this is necessary because we can't get the state from history.state
+        dispatch(setCurrentState(newState));
+        if (replaceState) {
+            dispatch(replace(locationDescriptor));
+        } else {
+            dispatch(push(locationDescriptor));
+        }
+    }
+);
 
 export const INITIALIZE_QB = "INITIALIZE_QB";
-export const initializeQB = createThunkAction(INITIALIZE_QB, (updateUrl) => {
+export const initializeQB = createThunkAction(INITIALIZE_QB, (location, params) => {
     return async (dispatch, getState) => {
-        const { router: { location, params: { cardId } }, currentUser } = getState();
+        const { currentUser } = getState();
 
         let card, databases, originalCard, uiControls = {};
 
@@ -46,11 +114,11 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (updateUrl) => {
         // load up or initialize the card we'll be working on
         const serializedCard = location.hash || null;
         const sampleDataset = _.findWhere(databases, { is_sample: true });
-        if (cardId || serializedCard) {
+        if (params.cardId || serializedCard) {
             // existing card being loaded
             try {
-                if (cardId) {
-                    card = await loadCard(cardId);
+                if (params.cardId) {
+                    card = await loadCard(params.cardId);
 
                     // when we are loading from a card id we want an explict clone of the card we loaded which is unmodified
                     originalCard = JSON.parse(JSON.stringify(card));
@@ -65,10 +133,10 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (updateUrl) => {
                 MetabaseAnalytics.trackEvent("QueryBuilder", "Query Loaded", card.dataset_query.type);
 
                 // if we have deserialized card from the url AND loaded a card by id then the user should be dropped into edit mode
-                uiControls.isEditing = (location.query.edit || (cardId && serializedCard)) ? true : false;
+                uiControls.isEditing = (location.query.edit || (params.cardId && serializedCard)) ? true : false;
 
                 // if this is the users first time loading a saved card on the QB then show them the newb modal
-                if (cardId && currentUser.is_qbnewb) {
+                if (params.cardId && currentUser.is_qbnewb) {
                     uiControls.isShowingNewbModal = true;
                     MetabaseAnalytics.trackEvent("QueryBuilder", "Show Newb Modal");
                 }
@@ -83,7 +151,7 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (updateUrl) => {
                 }
             }
 
-        } else if (location.query.tutorial && sampleDataset) {
+        } else if (location.query.tutorial !== undefined && sampleDataset) {
             // we are launching the QB tutorial
             card = startNewCard("query", sampleDataset.id);
 
@@ -121,14 +189,13 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (updateUrl) => {
         }
 
         // clean up the url and make sure it reflects our card state
-        updateUrl(card, isCardDirty(card, originalCard));
+        dispatch(updateUrl(card, isCardDirty(card, originalCard)));
 
         return {
             card,
             originalCard,
             databases,
-            uiControls,
-            updateUrl
+            uiControls
         };
     };
 });
@@ -168,7 +235,7 @@ export const beginEditing = createAction(BEGIN_EDITING, () => {
 export const CANCEL_EDITING = "CANCEL_EDITING";
 export const cancelEditing = createThunkAction(CANCEL_EDITING, () => {
     return (dispatch, getState) => {
-        const { qb: { originalCard, updateUrl } } = getState();
+        const { qb: { originalCard } } = getState();
 
         // clone
         let card = JSON.parse(JSON.stringify(originalCard));
@@ -177,7 +244,7 @@ export const cancelEditing = createThunkAction(CANCEL_EDITING, () => {
 
         // we do this to force the indication of the fact that the card should not be considered dirty when the url is updated
         dispatch(runQuery(card, false));
-        updateUrl(card, false);
+        dispatch(updateUrl(card, false));
 
         MetabaseAnalytics.trackEvent("QueryBuilder", "Edit Cancel");
         return card;
@@ -265,9 +332,9 @@ export const setCardAttribute = createAction(SET_CARD_ATTRIBUTE, (attr, value) =
 export const SET_CARD_VISUALIZATION = "SET_CARD_VISUALIZATION";
 export const setCardVisualization = createThunkAction(SET_CARD_VISUALIZATION, (display) => {
     return (dispatch, getState) => {
-        const { qb: { card, uiControls, updateUrl } } = getState();
+        const { qb: { card, uiControls } } = getState();
         let updatedCard = updateVisualizationSettings(card, uiControls.isEditing, display, card.visualization_settings);
-        updateUrl(updatedCard, true);
+        dispatch(updateUrl(updatedCard, true));
         return updatedCard;
     }
 });
@@ -275,9 +342,9 @@ export const setCardVisualization = createThunkAction(SET_CARD_VISUALIZATION, (d
 export const SET_CARD_VISUALIZATION_SETTING = "SET_CARD_VISUALIZATION_SETTING";
 export const setCardVisualizationSetting = createThunkAction(SET_CARD_VISUALIZATION_SETTING, (key, value) => {
     return (dispatch, getState) => {
-        const { qb: { card, uiControls, updateUrl } } = getState();
-        let updatedCard = updateVisualizationSettings(card, uiControls.isEditing, card.display, i.assoc(card.visualization_settings, key, value));
-        updateUrl(updatedCard, true);
+        const { qb: { card, uiControls } } = getState();
+        let updatedCard = updateVisualizationSettings(card, uiControls.isEditing, card.display, i.assocIn(card.visualization_settings, key, value));
+        dispatch(updateUrl(updatedCard, true));
         return updatedCard;
     };
 });
@@ -285,9 +352,9 @@ export const setCardVisualizationSetting = createThunkAction(SET_CARD_VISUALIZAT
 export const SET_CARD_VISUALIZATION_SETTINGS = "SET_CARD_VISUALIZATION_SETTINGS";
 export const setCardVisualizationSettings = createThunkAction(SET_CARD_VISUALIZATION_SETTINGS, (settings) => {
     return (dispatch, getState) => {
-        const { qb: { card, uiControls, updateUrl } } = getState();
+        const { qb: { card, uiControls } } = getState();
         let updatedCard = updateVisualizationSettings(card, uiControls.isEditing, card.display, settings);
-        updateUrl(updatedCard, true);
+        dispatch(updateUrl(updatedCard, true));
         return updatedCard;
     };
 });
@@ -318,13 +385,11 @@ export const setParameterValue = createAction(SET_PARAMETER_VALUE, (parameterId,
 export const NOTIFY_CARD_CREATED = "NOTIFY_CARD_CREATED";
 export const notifyCardCreatedFn = createThunkAction(NOTIFY_CARD_CREATED, (card) => {
     return (dispatch, getState) => {
-        const { qb: { updateUrl } } = getState();
-
         dispatch(loadMetadataForCard(card));
 
         // we do this to force the indication of the fact that the card should not be considered dirty when the url is updated
         dispatch(runQuery(card, false));
-        updateUrl(card, false);
+        dispatch(updateUrl(card, false));
 
         MetabaseAnalytics.trackEvent("QueryBuilder", "Create Card", card.dataset_query.type);
 
@@ -335,13 +400,11 @@ export const notifyCardCreatedFn = createThunkAction(NOTIFY_CARD_CREATED, (card)
 export const NOTIFY_CARD_UPDATED = "NOTIFY_CARD_UPDATED";
 export const notifyCardUpdatedFn = createThunkAction("NOTIFY_CARD_UPDATED", (card) => {
     return (dispatch, getState) => {
-        const { qb: { updateUrl } } = getState();
-
         dispatch(loadMetadataForCard(card));
 
         // we do this to force the indication of the fact that the card should not be considered dirty when the url is updated
         dispatch(runQuery(card, false));
-        updateUrl(card, false);
+        dispatch(updateUrl(card, false));
 
         MetabaseAnalytics.trackEvent("QueryBuilder", "Update Card", card.dataset_query.type);
 
@@ -353,7 +416,7 @@ export const notifyCardUpdatedFn = createThunkAction("NOTIFY_CARD_UPDATED", (car
 export const RELOAD_CARD = "RELOAD_CARD";
 export const reloadCard = createThunkAction(RELOAD_CARD, () => {
     return async (dispatch, getState) => {
-        const { qb: { originalCard, updateUrl } } = getState();
+        const { qb: { originalCard } } = getState();
 
         // clone
         let card = JSON.parse(JSON.stringify(originalCard));
@@ -362,7 +425,7 @@ export const reloadCard = createThunkAction(RELOAD_CARD, () => {
 
         // we do this to force the indication of the fact that the card should not be considered dirty when the url is updated
         dispatch(runQuery(card, false));
-        updateUrl(card, false);
+        dispatch(updateUrl(card, false));
 
         return card;
     };
@@ -370,14 +433,14 @@ export const reloadCard = createThunkAction(RELOAD_CARD, () => {
 
 // setCardAndRun
 export const SET_CARD_AND_RUN = "SET_CARD_AND_RUN";
-export const setCardAndRun = createThunkAction(SET_CARD_AND_RUN, (runCard) => {
+export const setCardAndRun = createThunkAction(SET_CARD_AND_RUN, (runCard, shouldUpdateUrl = true) => {
     return async (dispatch, getState) => {
         // clone
         let card = JSON.parse(JSON.stringify(runCard));
 
         dispatch(loadMetadataForCard(card));
 
-        dispatch(runQuery(card));
+        dispatch(runQuery(card, shouldUpdateUrl));
 
         return card;
     };
@@ -680,7 +743,7 @@ export const setQuerySort = createThunkAction(SET_QUERY_SORT, (column) => {
 
 // runQuery
 export const RUN_QUERY = "RUN_QUERY";
-export const runQuery = createThunkAction(RUN_QUERY, (card, updateUrl=true, parameterValues) => {
+export const runQuery = createThunkAction(RUN_QUERY, (card, shouldUpdateUrl = true, parameterValues) => {
     return async (dispatch, getState) => {
         const state = getState();
         const parameters = getParameters(state);
@@ -696,8 +759,8 @@ export const runQuery = createThunkAction(RUN_QUERY, (card, updateUrl=true, para
             dataset_query: applyParameters(card, parameters, parameterValues)
         };
 
-        if (updateUrl) {
-            state.qb.updateUrl(card, cardIsDirty);
+        if (shouldUpdateUrl) {
+            dispatch(updateUrl(card, cardIsDirty));
         }
 
         let cancelQueryDeferred = angularPromise();
diff --git a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
index 19ed593e25dd7f139be106d3818bda8b99de5ee2..4a02444e047f6b9a64ae214565ea77357bd96be4 100644
--- a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
+++ b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
@@ -38,7 +38,7 @@ import {
 } from "../selectors";
 
 import * as actions from "../actions";
-
+import { push } from "react-router-redux";
 
 const cardApi = new AngularResourceProxy("Card", ["create", "update", "delete"]);
 const dashboardApi = new AngularResourceProxy("Dashboard", ["list", "create"]);
@@ -71,10 +71,9 @@ function autocompleteResults(card, prefix) {
 
 const mapStateToProps = (state, props) => {
     return {
-        updateUrl:                 props.updateUrl,
         user:                      state.currentUser,
-        fromUrl:                   state.router && state.router.location && state.router.location.query.from,
-        location:                  state.router && state.router.location,
+        fromUrl:                   props.location.query.from,
+        location:                  props.location,
 
         card:                      card(state),
         originalCard:              originalCard(state),
@@ -108,9 +107,13 @@ const mapStateToProps = (state, props) => {
     }
 }
 
+const getURL = (location) =>
+    location.pathname + location.search + location.hash;
+
 
 const mapDispatchToProps = {
     ...actions,
+    onChangeLocation: push
 };
 
 @connect(mapStateToProps, mapDispatchToProps)
@@ -119,18 +122,17 @@ export default class QueryBuilder extends Component {
     constructor(props, context) {
         super(props, context);
 
-        _.bindAll(this, "popStateListener", "handleResize");
+        _.bindAll(this, "handleResize");
 
         // TODO: React tells us that forceUpdate() is not the best thing to use, so ideally we can find a different way to trigger this
         this.forceUpdateDebounced = _.debounce(this.forceUpdate.bind(this), 400);
     }
 
     componentWillMount() {
-        this.props.initializeQB(this.props.updateUrl);
+        this.props.initializeQB(this.props.location, this.props.params);
     }
 
     componentDidMount() {
-        window.addEventListener('popstate', this.popStateListener);
         window.addEventListener('resize', this.handleResize);
     }
 
@@ -141,14 +143,17 @@ export default class QueryBuilder extends Component {
             // ensure that some components are updated after the animation completes (e.g. card visualization)
             window.setTimeout(this.forceUpdateDebounced, 300);
         }
-        // HACK: if we switch to the tutorial from within the QB we need to manually re-initialize
-        if (!this.props.location.query.tutorial && nextProps.location.query.tutorial) {
-            this.props.initializeQB(nextProps.updateUrl);
+
+        if (nextProps.location.action === "POP" && getURL(nextProps.location) !== getURL(this.props.location)) {
+            this.props.popState(nextProps.location);
+        } else if (this.props.location.query.tutorial === undefined && nextProps.location.query.tutorial !== undefined) {
+            this.props.initializeQB(nextProps.location, nextProps.params);
+        } else if (getURL(nextProps.location) === "/q" && getURL(this.props.location) !== "/q") {
+            this.props.initializeQB(nextProps.location, nextProps.params);
         }
     }
 
     componentWillUnmount() {
-        window.removeEventListener('popstate', this.popStateListener);
         window.removeEventListener('resize', this.handleResize);
     }
 
@@ -158,13 +163,6 @@ export default class QueryBuilder extends Component {
         this.forceUpdateDebounced();
     }
 
-    popStateListener(e) {
-        if (e.state && e.state.card) {
-            e.preventDefault();
-            this.props.setCardAndRun(e.state.card);
-        }
-    }
-
     render() {
         const { card, isDirty, databases, uiControls } = this.props;
 
@@ -187,7 +185,7 @@ export default class QueryBuilder extends Component {
 
         const showDrawer = uiControls.isShowingDataReference || uiControls.isShowingTemplateTagsEditor;
         return (
-            <div>
+            <div className="flex-full relative">
                 <div className={cx("QueryBuilder flex flex-column bg-white spread", {"QueryBuilder--showSideDrawer": showDrawer})}>
                     <div id="react_qb_header">
                         <QueryHeader {...this.props}/>
diff --git a/frontend/src/metabase/query_builder/dataref/FieldPane.jsx b/frontend/src/metabase/query_builder/dataref/FieldPane.jsx
index d40b05ad15914f5cfbc77d3d1f86dead474aed02..fabcb350a8d42b2f093f0c4da529def24cacbb14 100644
--- a/frontend/src/metabase/query_builder/dataref/FieldPane.jsx
+++ b/frontend/src/metabase/query_builder/dataref/FieldPane.jsx
@@ -2,7 +2,7 @@
 import React, { Component, PropTypes } from "react";
 
 import DetailPane from "./DetailPane.jsx";
-import QueryButton from "./QueryButton.jsx";
+import QueryButton from "metabase/components/QueryButton.jsx";
 import UseForButton from "./UseForButton.jsx";
 
 import Query from "metabase/lib/query";
diff --git a/frontend/src/metabase/query_builder/dataref/MetricPane.jsx b/frontend/src/metabase/query_builder/dataref/MetricPane.jsx
index 039443060b858fd24299e521dcd4e2a3c56cd304..8e3abba55974437842b27959df7fcb46d2ec7264 100644
--- a/frontend/src/metabase/query_builder/dataref/MetricPane.jsx
+++ b/frontend/src/metabase/query_builder/dataref/MetricPane.jsx
@@ -2,7 +2,7 @@
 import React, { Component, PropTypes } from "react";
 
 import DetailPane from "./DetailPane.jsx";
-import QueryButton from "./QueryButton.jsx";
+import QueryButton from "metabase/components/QueryButton.jsx";
 import QueryDefinition from "./QueryDefinition.jsx";
 
 import { createCard } from "metabase/lib/card";
@@ -74,7 +74,12 @@ export default class MetricPane extends Component {
                 useForCurrentQuestion={useForCurrentQuestion}
                 usefulQuestions={usefulQuestions}
                 error={error}
-                extra={table && <QueryDefinition objectType="Metric" object={metric} tableMetadata={table} />}
+                extra={table &&
+                    <div>
+                        <p className="text-bold">Metric Definition</p>
+                        <QueryDefinition object={metric} tableMetadata={table} />
+                    </div>
+                }
             />
         );
     }
diff --git a/frontend/src/metabase/query_builder/dataref/QueryButton.jsx b/frontend/src/metabase/query_builder/dataref/QueryButton.jsx
deleted file mode 100644
index 12a8916361ddabb153bf1db0f292a96ccda44d5d..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/query_builder/dataref/QueryButton.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React, { Component, PropTypes } from "react";
-
-import Icon from "metabase/components/Icon.jsx";
-
-export default class QueryButton extends Component {
-    static propTypes = {
-        icon: PropTypes.string.isRequired,
-        text: PropTypes.string.isRequired,
-        onClick: PropTypes.func
-    };
-
-    render(page) {
-        return (
-            <div className={this.props.className}>
-                <a className="DataRefererenceQueryButton flex align-center no-decoration py1" onClick={this.props.onClick} >
-                    <Icon name={this.props.icon} />
-                    <span className="DataRefererenceQueryButton-text mx2 text-default text-brand-hover">{this.props.text}</span>
-                    <span className="DataRefererenceQueryButton-circle flex-align-right text-brand">
-                        <Icon size={8} name="chevronright" />
-                    </span>
-                </a>
-            </div>
-        );
-    }
-}
diff --git a/frontend/src/metabase/query_builder/dataref/QueryDefinition.jsx b/frontend/src/metabase/query_builder/dataref/QueryDefinition.jsx
index 2fbc293a89e4ee5daf21c737322425815fc36081..7b2c49b6f0953929249a211098636a7878f1768c 100644
--- a/frontend/src/metabase/query_builder/dataref/QueryDefinition.jsx
+++ b/frontend/src/metabase/query_builder/dataref/QueryDefinition.jsx
@@ -5,20 +5,25 @@ import AggregationWidget from "../AggregationWidget.jsx";
 
 import Query from "metabase/lib/query";
 
-const QueryDefinition = ({ objectType, object, tableMetadata }) =>
-    <div style={{ pointerEvents: "none" }}>
-        <p className="text-bold">{objectType} Definition</p>
-        { object.definition.aggregation &&
-            <AggregationWidget
-                aggregation={object.definition.aggregation}
-                tableMetadata={tableMetadata}
-            />
-        }
-        <FilterList
-            filters={Query.getFilters(object.definition)}
-            tableMetadata={tableMetadata}
-            maxDisplayValues={Infinity}
-        />
-    </div>
+const QueryDefinition = ({ className, object, tableMetadata }) => {
+    const filters = Query.getFilters(object.definition);
+    return (
+        <div className={className} style={{ pointerEvents: "none" }}>
+            { object.definition.aggregation &&
+                <AggregationWidget
+                    aggregation={object.definition.aggregation}
+                    tableMetadata={tableMetadata}
+                />
+            }
+            { filters.length > 0 &&
+                <FilterList
+                    filters={filters}
+                    tableMetadata={tableMetadata}
+                    maxDisplayValues={Infinity}
+                />
+            }
+        </div>
+    );
+}
 
 export default QueryDefinition;
diff --git a/frontend/src/metabase/query_builder/dataref/SegmentPane.jsx b/frontend/src/metabase/query_builder/dataref/SegmentPane.jsx
index 09a0d2ab2afe30cbcec4721979a04b81fa7c7f5b..ab561ba35c157110b193810059224bd2127524d9 100644
--- a/frontend/src/metabase/query_builder/dataref/SegmentPane.jsx
+++ b/frontend/src/metabase/query_builder/dataref/SegmentPane.jsx
@@ -2,7 +2,7 @@
 import React, { Component, PropTypes } from "react";
 
 import DetailPane from "./DetailPane.jsx";
-import QueryButton from "./QueryButton.jsx";
+import QueryButton from "metabase/components/QueryButton.jsx";
 import UseForButton from "./UseForButton.jsx";
 import QueryDefinition from "./QueryDefinition.jsx";
 
@@ -101,7 +101,12 @@ export default class SegmentPane extends Component {
                 useForCurrentQuestion={useForCurrentQuestion}
                 usefulQuestions={usefulQuestions}
                 error={error}
-                extra={table && <QueryDefinition objectType="Segment" object={segment} tableMetadata={table} />}
+                extra={table &&
+                    <div>
+                        <p className="text-bold">Segment Definition</p>
+                        <QueryDefinition object={segment} tableMetadata={table} />
+                    </div>
+                }
             />
         );
     }
diff --git a/frontend/src/metabase/query_builder/dataref/TablePane.jsx b/frontend/src/metabase/query_builder/dataref/TablePane.jsx
index 2b9c9119695b8df3b52ed35ef98214aa94a04440..917abc90cf4bd81f6e68d442410dce10f811a530 100644
--- a/frontend/src/metabase/query_builder/dataref/TablePane.jsx
+++ b/frontend/src/metabase/query_builder/dataref/TablePane.jsx
@@ -1,7 +1,7 @@
 /* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
-import QueryButton from './QueryButton.jsx';
+import QueryButton from "metabase/components/QueryButton.jsx";
 import { createCard } from "metabase/lib/card";
 import { createQuery } from "metabase/lib/query";
 import { foreignKeyCountsByOriginTable } from 'metabase/lib/schema_metadata';
diff --git a/frontend/src/metabase/query_builder/reducers.js b/frontend/src/metabase/query_builder/reducers.js
index 2092bbfc5325c458d919f1513adbd52566bb9f5f..d3a915c4178260e30ff0efcc719341ba254dfe31 100644
--- a/frontend/src/metabase/query_builder/reducers.js
+++ b/frontend/src/metabase/query_builder/reducers.js
@@ -32,14 +32,11 @@ import {
     CANCEL_QUERY,
     QUERY_COMPLETED,
     QUERY_ERRORED,
-    LOAD_OBJECT_DETAIL_FK_REFERENCES
-} from "./actions";
+    LOAD_OBJECT_DETAIL_FK_REFERENCES,
 
+    SET_CURRENT_STATE
+} from "./actions";
 
-// TODO: these are here as work arounds until we are transitioned over to ReduxRouter and using their history approach
-export const updateUrl = handleActions({
-    [INITIALIZE_QB]: { next: (state, { payload }) => payload ? payload.updateUrl : state }
-}, () => console.log("default"));
 
 // TODO: once we are using the global redux store we can get this from there
 export const user = handleActions({
@@ -160,3 +157,7 @@ export const queryExecutionPromise = handleActions({
 export const parameterValues = handleActions({
     [SET_PARAMETER_VALUE]: { next: (state, { payload: { id, value }}) => i.assoc(state, id, value) }
 }, {});
+
+export const currentState = handleActions({
+    [SET_CURRENT_STATE]: { next: (state, { payload }) => payload }
+}, null);
diff --git a/frontend/src/metabase/questions/containers/EntityBrowser.jsx b/frontend/src/metabase/questions/containers/EntityBrowser.jsx
index 6f69eefba9d70e8e148eb7b5215d3e16f9c3744b..2336fb6cb32a5fa0d1559e9c6e9b45c10a9f4394 100644
--- a/frontend/src/metabase/questions/containers/EntityBrowser.jsx
+++ b/frontend/src/metabase/questions/containers/EntityBrowser.jsx
@@ -52,7 +52,8 @@ export default class EntityBrowser extends Component {
     render() {
         return (
             <SidebarLayout
-                sidebar={<Sidebar {...this.props} children={undefined}/>}
+                className="flex-full"
+                sidebar={<Sidebar {...this.props}/>}
             >
                 {this.props.children}
             </SidebarLayout>
diff --git a/frontend/src/metabase/questions/containers/EntityList.jsx b/frontend/src/metabase/questions/containers/EntityList.jsx
index cb8a6b8068f8628d8b61edc6d0269dd2e8f99c6d..7942a1e9f2d15cab6ea4c0990b4faa4dbc77484b 100644
--- a/frontend/src/metabase/questions/containers/EntityList.jsx
+++ b/frontend/src/metabase/questions/containers/EntityList.jsx
@@ -83,7 +83,7 @@ export default class EntityList extends Component {
       switch (this.props.name) {
         case 'All questions':
           return {
-            icon: '',
+            icon: 'all',
             message: 'No questions have been saved yet.'
           }
         case 'Recently viewed':
@@ -109,7 +109,7 @@ export default class EntityList extends Component {
         case 'Archive':
           return {
             icon: 'archive',
-            message: 'If you no longer need a question you can archive it.'
+            message: 'If you no longer need a question, you can archive it.'
           }
         default:
           return {
diff --git a/frontend/src/metabase/questions/containers/UndoListing.css b/frontend/src/metabase/questions/containers/UndoListing.css
index ca95ef69945b55503e7265f417e8a7301e213b3b..f32245dd586438f7e49a7d3c524a1f3c92dbbc6b 100644
--- a/frontend/src/metabase/questions/containers/UndoListing.css
+++ b/frontend/src/metabase/questions/containers/UndoListing.css
@@ -7,13 +7,13 @@
 }
 
 :local(.undo) {
-    composes: mx2 mt2 p2 from "style";
+    composes: mt2 p2 from "style";
     composes: bordered from "style";
     composes: rounded from "style";
     composes: shadowed from "style";
     composes: relative from "style";
     composes: bg-white from "style";
-    width: 300px;
+    width: 320px;
 }
 
 :local(.actions) {
diff --git a/frontend/src/metabase/reducers.js b/frontend/src/metabase/reducers.js
new file mode 100644
index 0000000000000000000000000000000000000000..5759d1bec38b8eea76fea3d6c8911ec86436f9a0
--- /dev/null
+++ b/frontend/src/metabase/reducers.js
@@ -0,0 +1,65 @@
+
+import { combineReducers } from 'redux';
+
+import auth from "metabase/auth/auth";
+
+/* ducks */
+import metadata from "metabase/redux/metadata";
+import requests from "metabase/redux/requests";
+
+/* admin */
+import settings from "metabase/admin/settings/settings";
+import * as people from "metabase/admin/people/reducers";
+import databases from "metabase/admin/databases/database";
+import datamodel from "metabase/admin/datamodel/metadata";
+
+/* dashboards */
+import dashboard from "metabase/dashboard/dashboard";
+import * as home from "metabase/home/reducers";
+
+/* questions / query builder */
+import questions from "metabase/questions/questions";
+import labels from "metabase/questions/labels";
+import undo from "metabase/questions/undo";
+import * as qb from "metabase/query_builder/reducers";
+
+/* data reference */
+import reference from "metabase/reference/reference";
+
+/* pulses */
+import * as pulse from "metabase/pulse/reducers";
+
+/* setup */
+import * as setup from "metabase/setup/reducers";
+
+/* user */
+import * as user from "metabase/user/reducers";
+import { currentUser } from "metabase/user";
+
+const reducers = {
+    // global reducers
+    auth,
+    currentUser,
+    metadata,
+    requests,
+
+    // main app reducers
+    dashboard,
+    home: combineReducers(home),
+    labels,
+    pulse: combineReducers(pulse),
+    qb: combineReducers(qb),
+    questions,
+    reference,
+    setup: combineReducers(setup),
+    undo,
+    user: combineReducers(user),
+
+    // admin reducers
+    databases,
+    datamodel: datamodel,
+    people: combineReducers(people),
+    settings
+};
+
+export default reducers;
diff --git a/frontend/src/metabase/redux/metadata.js b/frontend/src/metabase/redux/metadata.js
index 8db499a8cf04aea6a7328378ba609181b9d31baf..b710190bcbd4ea148c0f8c9c39805ef5a1c10fbf 100644
--- a/frontend/src/metabase/redux/metadata.js
+++ b/frontend/src/metabase/redux/metadata.js
@@ -333,11 +333,23 @@ const revisions = handleActions({
 }, {});
 
 // for fetches with data dependencies in /reference
+const FETCH_METRIC_TABLE = "metabase/metadata/FETCH_METRIC_TABLE";
+export const fetchMetricTable = createThunkAction(FETCH_METRIC_TABLE, (metricId, reload = false) => {
+    return async (dispatch, getState) => {
+        await dispatch(fetchMetrics());
+        const metric = i.getIn(getState(), ['metadata', 'metrics', metricId]);
+        const tableId = metric.table_id;
+        await dispatch(fetchTableMetadata(tableId));
+    };
+});
+
 const FETCH_METRIC_REVISIONS = "metabase/metadata/FETCH_METRIC_REVISIONS";
 export const fetchMetricRevisions = createThunkAction(FETCH_METRIC_REVISIONS, (metricId, reload = false) => {
     return async (dispatch, getState) => {
-        dispatch(fetchRevisions('metric', metricId));
-        await dispatch(fetchMetrics());
+        await Promise.all([
+            dispatch(fetchRevisions('metric', metricId)),
+            dispatch(fetchMetrics())
+        ]);
         const metric = i.getIn(getState(), ['metadata', 'metrics', metricId]);
         const tableId = metric.table_id;
         await dispatch(fetchTableMetadata(tableId));
@@ -357,11 +369,23 @@ export const fetchSegmentFields = createThunkAction(FETCH_SEGMENT_FIELDS, (segme
     };
 });
 
+const FETCH_SEGMENT_TABLE = "metabase/metadata/FETCH_SEGMENT_TABLE";
+export const fetchSegmentTable = createThunkAction(FETCH_SEGMENT_TABLE, (segmentId, reload = false) => {
+    return async (dispatch, getState) => {
+        await dispatch(fetchSegments());
+        const segment = i.getIn(getState(), ['metadata', 'segments', segmentId]);
+        const tableId = segment.table_id;
+        await dispatch(fetchTableMetadata(tableId));
+    };
+});
+
 const FETCH_SEGMENT_REVISIONS = "metabase/metadata/FETCH_SEGMENT_REVISIONS";
 export const fetchSegmentRevisions = createThunkAction(FETCH_SEGMENT_REVISIONS, (segmentId, reload = false) => {
     return async (dispatch, getState) => {
-        dispatch(fetchRevisions('segment', segmentId));
-        await dispatch(fetchSegments());
+        await Promise.all([
+            dispatch(fetchRevisions('segment', segmentId)),
+            dispatch(fetchSegments())
+        ]);
         const segment = i.getIn(getState(), ['metadata', 'segments', segmentId]);
         const tableId = segment.table_id;
         await dispatch(fetchTableMetadata(tableId));
diff --git a/frontend/src/metabase/reference/Reference.css b/frontend/src/metabase/reference/Reference.css
index 75266b87110709b5d19866541580f9a56bcba019..b363a19205fadab9f4c10376916ad701a6f04133 100644
--- a/frontend/src/metabase/reference/Reference.css
+++ b/frontend/src/metabase/reference/Reference.css
@@ -1,6 +1,5 @@
 :root {
-    --title-color: #606E7B;
-    --subheader-color: #6CAFED;
+    --icon-width: calc(48px + 1rem);
 }
 
 :local(.guideEmpty) {
@@ -19,80 +18,24 @@
     line-height: 1.457em;
 }
 
-:local(.headerBody) {
-    composes: flex flex-full border-bottom from "style";
-    overflow: hidden;
-    align-items: center;
-    border-color: #EDF5FB;
-}
-
-:local(.headerTextInput) {
-    composes: input p1 from "style";
-    font-size: 18px;
-    color: var(--title-color);
-    width: 100%;
-    max-width: 550px;
-}
-
-:local(.subheader) {
-    composes: text-white flex align-center from "style";
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    height: 43px;
-    background-color: var(--subheader-color);
-}
-
-:local(.subheaderButtons) {
-    composes: flex-align-right from "style";
-}
-
-:local(.subheaderButton) {
-    border: none;
-    color: var(--subheader-color);
-}
-
 :local(.columnHeader) {
-    composes: flex flex-full pl2 from "style";
-    margin-left: 48px;
+    composes: flex flex-full from "style";
+    margin-left: var(--icon-width);
     padding-top: 20px;
     padding-bottom: 20px;
 }
 
-:local(.saveButton) {
-    composes: subheaderButton;
-}
-
-:local(.cancelButton) {
-    composes: subheaderButton;
-    opacity: 0.5;
-}
-
-:local(.editButton) {
-    composes: p0 mx1 from "style";
-    color: var(--primary-button-bg-color);
-}
-
-:local(.editButton):hover {
-    color: color(var(--primary-button-border-color) shade(10%));
-    transition: color .3s linear;
-}
-
 :local(.revisionsWrapper) {
     padding-top: 20px;
-    padding-left: 70px;
+    padding-left: var(--icon-width);
 }
 
 :local(.schemaSeparator) {
     composes: text-grey-2 mt2 from "style";
-    margin-left: 70px;
+    margin-left: var(--icon-width);
     font-size: 18px;
 }
 
-:local(.headerSchema) {
-    composes: text-grey-2 absolute from "style";
-    left: 70px;
-    top: -10px;
-    font-size: 12px;
+:local(.tableActualName) {
+    color: #AAB7C3;
 }
diff --git a/frontend/src/metabase/reference/components/EditHeader.css b/frontend/src/metabase/reference/components/EditHeader.css
new file mode 100644
index 0000000000000000000000000000000000000000..2e6e704fb09e8fe36b297bdd6000b3f41e0a6077
--- /dev/null
+++ b/frontend/src/metabase/reference/components/EditHeader.css
@@ -0,0 +1,32 @@
+:root {
+    --edit-header-color: #6CAFED;
+}
+
+
+:local(.editHeader) {
+    composes: text-white flex align-center from "style";
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    height: 43px;
+    background-color: var(--edit-header-color);
+}
+
+:local(.editHeaderButtons) {
+    composes: flex-align-right from "style";
+}
+
+:local(.editHeaderButton) {
+    border: none;
+    color: var(--edit-header-color);
+}
+
+:local(.saveButton) {
+    composes: editHeaderButton;
+}
+
+:local(.cancelButton) {
+    composes: editHeaderButton;
+    opacity: 0.5;
+}
diff --git a/frontend/src/metabase/reference/components/EditHeader.jsx b/frontend/src/metabase/reference/components/EditHeader.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8c72546bcecdcbc261eedba55279b412f677c69b
--- /dev/null
+++ b/frontend/src/metabase/reference/components/EditHeader.jsx
@@ -0,0 +1,61 @@
+import React, { Component, PropTypes } from "react";
+import cx from "classnames";
+import pure from "recompose/pure";
+
+import S from "./EditHeader.css";
+
+import RevisionMessageModal from "metabase/reference/components/RevisionMessageModal.jsx";
+
+const EditHeader = ({
+    hasRevisionHistory,
+    endEditing,
+    submitting,
+    onSubmit,
+    revisionMessageFormField
+}) =>
+    <div className={cx("EditHeader wrapper py1", S.editHeader)}>
+        <div>
+            You are editing this page
+        </div>
+        <div className={S.editHeaderButtons}>
+            { hasRevisionHistory ?
+                <RevisionMessageModal
+                    action={() => onSubmit()}
+                    field={revisionMessageFormField}
+                    submitting={submitting}
+                >
+                    <button
+                        className={cx("Button", "Button--primary", "Button--white", "Button--small", S.saveButton)}
+                        type="button"
+                        disabled={submitting}
+                    >
+                        SAVE
+                    </button>
+                </RevisionMessageModal> :
+                <button
+                    className={cx("Button", "Button--primary", "Button--white", "Button--small", S.saveButton)}
+                    type="submit"
+                    disabled={submitting}
+                >
+                    SAVE
+                </button>
+            }
+
+            <button
+                type="button"
+                className={cx("Button", "Button--white", "Button--small", S.cancelButton)}
+                onClick={endEditing}
+            >
+                CANCEL
+            </button>
+        </div>
+    </div>;
+EditHeader.propTypes = {
+    hasRevisionHistory: PropTypes.bool.isRequired,
+    endEditing: PropTypes.func.isRequired,
+    submitting: PropTypes.bool.isRequired,
+    onSubmit: PropTypes.func,
+    revisionMessageFormField: PropTypes.object
+};
+
+export default pure(EditHeader);
diff --git a/frontend/src/metabase/reference/components/Field.jsx b/frontend/src/metabase/reference/components/Field.jsx
index a440d630225eb7d4cf244dc67fc6e159d658919d..366c548acd0d02440723dadecbb6030ca1df48a5 100644
--- a/frontend/src/metabase/reference/components/Field.jsx
+++ b/frontend/src/metabase/reference/components/Field.jsx
@@ -23,8 +23,8 @@ const Field = ({
     icon,
     isEditing,
     formField
-}) => {
-    return <div className={cx(S.item)}>
+}) => 
+    <div className={cx(S.item)}>
         <div className={S.leftIcons}>
             { icon && <Icon className={S.chartIcon} name={icon} size={20} /> }
         </div>
@@ -108,8 +108,7 @@ const Field = ({
                 </div>
             </div>
         </div>
-    </div>
-}
+    </div>;
 Field.propTypes = {
     field: PropTypes.object.isRequired,
     foreignKeys: PropTypes.object.isRequired,
diff --git a/frontend/src/metabase/reference/components/FieldToGroupBy.css b/frontend/src/metabase/reference/components/FieldToGroupBy.css
new file mode 100644
index 0000000000000000000000000000000000000000..fc52b5652b9d325a50ffc688ddb630c03762b537
--- /dev/null
+++ b/frontend/src/metabase/reference/components/FieldToGroupBy.css
@@ -0,0 +1,5 @@
+:local(.fieldToGroupByText) {
+    composes: flex-full from "style";
+    font-size: 16px;
+    color: #AAB7C3;
+}
\ No newline at end of file
diff --git a/frontend/src/metabase/reference/components/FieldToGroupBy.jsx b/frontend/src/metabase/reference/components/FieldToGroupBy.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..33fb42cbb1bc9a86eedc6d03cdcd435d8a58f3df
--- /dev/null
+++ b/frontend/src/metabase/reference/components/FieldToGroupBy.jsx
@@ -0,0 +1,45 @@
+import React, { Component, PropTypes } from "react";
+import pure from "recompose/pure";
+
+import S from "./FieldToGroupBy.css";
+import Q from "metabase/components/QueryButton.css";
+
+import Icon from "metabase/components/Icon.jsx";
+
+const FieldToGroupBy = ({
+    className,
+    metric,
+    field,
+    icon,
+    iconClass,
+    onClick,
+    secondaryOnClick,
+}) => 
+    <div className={className}>
+        <a className={Q.queryButton} onClick={onClick}>
+            <span className={S.fieldToGroupByText}>
+                <span>
+                    {`${metric.name} by `}
+                </span>
+                <span className="ml1 text-brand">
+                    {field.display_name}
+                </span>
+            </span>
+            <Icon 
+                className={iconClass} 
+                size={20} 
+                name="reference"
+                onClick={secondaryOnClick}
+            />
+        </a>
+    </div>;
+FieldToGroupBy.propTypes = {
+    className: PropTypes.string,
+    metric: PropTypes.object.isRequired,
+    field: PropTypes.object.isRequired,
+    iconClass: PropTypes.string,
+    onClick: PropTypes.func,
+    secondaryOnClick: PropTypes.func
+};
+
+export default pure(FieldToGroupBy);
\ No newline at end of file
diff --git a/frontend/src/metabase/reference/components/FieldTypeDetail.jsx b/frontend/src/metabase/reference/components/FieldTypeDetail.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..737f218e3e7815c593749036d15fbc0bdcf87569
--- /dev/null
+++ b/frontend/src/metabase/reference/components/FieldTypeDetail.jsx
@@ -0,0 +1,91 @@
+import React, { Component, PropTypes } from "react";
+import cx from "classnames";
+import i from "icepick";
+import pure from "recompose/pure";
+
+import * as MetabaseCore from "metabase/lib/core";
+import { isNumericBaseType } from "metabase/lib/schema_metadata";
+
+import Select from "metabase/components/Select.jsx";
+
+import D from "metabase/components/Detail.css";
+
+const FieldTypeDetail = ({
+    field,
+    foreignKeys,
+    fieldTypeFormField,
+    foreignKeyFormField,
+    isEditing
+}) =>
+    <div className={cx(D.detail)}>
+        <div className={D.detailBody}>
+            <div className={D.detailTitle}>
+                <span className={D.detailName}>Field type</span>
+            </div>
+            <div className={cx(D.detailSubtitle, { "mt1" : true })}>
+                <span>
+                    { isEditing ?
+                        <Select
+                            triggerClasses="rounded bordered p1 inline-block"
+                            placeholder="Select a field type"
+                            value={
+                                MetabaseCore.field_special_types_map[fieldTypeFormField.value] ||
+                                MetabaseCore.field_special_types_map[field.special_type]
+                            }
+                            options={
+                                MetabaseCore.field_special_types
+                                    .concat({
+                                        'id': null,
+                                        'name': 'No field type',
+                                        'section': 'Other'
+                                    })
+                                    .filter(type => !isNumericBaseType(field) ?
+                                        !(type.id && type.id.startsWith("timestamp_")) :
+                                        true
+                                    )
+                            }
+                            onChange={(type) => fieldTypeFormField.onChange(type.id)}
+                        /> :
+                        <span>
+                            { i.getIn(
+                                    MetabaseCore.field_special_types_map,
+                                    [field.special_type, 'name']
+                                ) || 'No field type'
+                            }
+                        </span>
+                    }
+                </span>
+                <span className="ml4">
+                    { isEditing ?
+                        (fieldTypeFormField.value === 'fk' ||
+                        (field.special_type === 'fk' && fieldTypeFormField.value === undefined)) &&
+                        <Select
+                            triggerClasses="rounded bordered p1 inline-block"
+                            placeholder="Select a field type"
+                            value={
+                                foreignKeys[foreignKeyFormField.value] ||
+                                foreignKeys[field.fk_target_field_id] ||
+                                {name: "Select a Foreign Key"}
+                            }
+                            options={Object.values(foreignKeys)}
+                            onChange={(foreignKey) => foreignKeyFormField.onChange(foreignKey.id)}
+                            optionNameFn={(foreignKey) => foreignKey.name}
+                        /> :
+                        field.special_type === 'fk' &&
+                        <span>
+                            {i.getIn(foreignKeys, [field.fk_target_field_id, "name"])}
+                        </span>
+                    }
+                </span>
+            </div>
+        </div>
+    </div>;
+FieldTypeDetail.propTypes = {
+    field: PropTypes.object.isRequired,
+    foreignKeys: PropTypes.object.isRequired,
+    fieldTypeFormField: PropTypes.object.isRequired,
+    foreignKeyFormField: PropTypes.object.isRequired,
+    isEditing: PropTypes.bool.isRequired,
+};
+
+export default pure(FieldTypeDetail);
diff --git a/frontend/src/metabase/reference/components/FieldsToGroupBy.jsx b/frontend/src/metabase/reference/components/FieldsToGroupBy.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8a7f409222f55db76ee0329a93f6efac787491af
--- /dev/null
+++ b/frontend/src/metabase/reference/components/FieldsToGroupBy.jsx
@@ -0,0 +1,59 @@
+import React, { Component, PropTypes } from "react";
+import cx from "classnames";
+import pure from "recompose/pure";
+
+import S from "./UsefulQuestions.css";
+import D from "metabase/components/Detail.css";
+import L from "metabase/components/List.css";
+
+import {
+    getQuestionUrl
+} from '../utils';
+
+import FieldToGroupBy from "metabase/reference/components/FieldToGroupBy.jsx";
+
+const FieldsToGroupBy = ({
+    table,
+    metric,
+    title,
+    onChangeLocation
+}) =>
+    <div className={cx(D.detail)}>
+        <div className={D.detailBody}>
+            <div className={D.detailTitle}>
+                <span className={D.detailName}>{title}</span>
+            </div>
+            <div className={S.usefulQuestions}>
+                { table && table.fields_lookup &&
+                    Object.values(table.fields_lookup)
+                        .map((field, index, fields) =>
+                            <FieldToGroupBy
+                                key={field.id}
+                                className={cx("border-bottom", "pt1", "pb1")}
+                                iconClass={L.icon}
+                                field={field}
+                                metric={metric}
+                                onClick={() => onChangeLocation(getQuestionUrl({
+                                        dbId: table.db_id,
+                                        tableId: table.id,
+                                        fieldId: field.id,
+                                        metricId: metric.id
+                                    }))}
+                                secondaryOnClick={(event) => {
+                                    event.stopPropagation();
+                                    onChangeLocation(`/reference/databases/${table.db_id}/tables/${table.id}/fields/${field.id}`);
+                                }}
+                            />
+                        )
+                }
+            </div>
+        </div>
+    </div>;
+FieldsToGroupBy.propTypes = {
+    table: PropTypes.object.isRequired,
+    metric: PropTypes.object.isRequired,
+    title: PropTypes.string.isRequired,
+    onChangeLocation: PropTypes.func.isRequired
+};
+
+export default pure(FieldsToGroupBy);
diff --git a/frontend/src/metabase/reference/components/Formula.css b/frontend/src/metabase/reference/components/Formula.css
new file mode 100644
index 0000000000000000000000000000000000000000..9471ec8253b8942d72e9af2a919838b349a4c77c
--- /dev/null
+++ b/frontend/src/metabase/reference/components/Formula.css
@@ -0,0 +1,47 @@
+:root {
+    --icon-width: calc(48px + 1rem);
+}
+
+:local(.formula) {
+    composes: bordered rounded my2 from "style";
+    background-color: #FBFCFD;
+    margin-left: var(--icon-width);
+    max-width: 550px;
+    cursor: pointer;
+}
+
+:local(.formulaHeader) {
+    composes: flex align-center text-brand py1 px2 from "style";
+}
+
+:local(.formulaTitle) {
+    composes: ml2 from "style";
+    font-size: 16px;
+}
+
+:local(.formulaDefinition) {
+    overflow: hidden;
+}
+:local(.formulaDefinitionInner) {
+    composes: p2 from "style";
+}
+
+.formulaDefinition {
+    overflow: hidden;
+}
+
+.formulaDefinition-enter {
+    max-height: 0px;
+}
+.formulaDefinition-enter.formulaDefinition-enter-active {
+    /* using 100% max-height breaks the transition */
+    max-height: 150px;
+    transition: max-height 300ms ease-out;
+}
+.formulaDefinition-leave {
+    max-height: 150px;
+}
+.formulaDefinition-leave.formulaDefinition-leave-active {
+    max-height: 0px;
+    transition: max-height 300ms ease-out;
+}
diff --git a/frontend/src/metabase/reference/components/Formula.jsx b/frontend/src/metabase/reference/components/Formula.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..5c0d6b9b2c23240fad45f136d61a2304c340faf4
--- /dev/null
+++ b/frontend/src/metabase/reference/components/Formula.jsx
@@ -0,0 +1,54 @@
+import React, { Component, PropTypes } from "react";
+import pure from "recompose/pure";
+import cx from "classnames";
+
+import ReactCSSTransitionGroup from "react-addons-css-transition-group";
+
+import S from "./Formula.css";
+
+import Icon from "metabase/components/Icon.jsx";
+
+import QueryDefinition from "metabase/query_builder/dataref/QueryDefinition.jsx";
+
+const Formula = ({
+    type,
+    entity,
+    table,
+    isExpanded,
+    expandFormula,
+    collapseFormula
+}) =>
+    <div
+        className={cx(S.formula)}
+        onClick={isExpanded ? collapseFormula : expandFormula}
+    >
+        <div className={S.formulaHeader}>
+            <Icon name="beaker" size={24} />
+            <span className={S.formulaTitle}>View the {type} formula</span>
+        </div>
+        <ReactCSSTransitionGroup
+            transitionName="formulaDefinition"
+            transitionEnterTimeout={300}
+            transitionLeaveTimeout={300}
+        >
+            { isExpanded &&
+                <div key="formulaDefinition" className={S.formulaDefinition}>
+                    <QueryDefinition
+                        className={S.formulaDefinitionInner}
+                        object={entity}
+                        tableMetadata={table}
+                    />
+                </div>
+            }
+        </ReactCSSTransitionGroup>
+    </div>
+
+Formula.propTypes = {
+    type: PropTypes.string.isRequired,
+    entity: PropTypes.object.isRequired,
+    table: PropTypes.object.isRequired,
+    isExpanded: PropTypes.bool.isRequired,
+    expandFormula: PropTypes.func.isRequired
+};
+
+export default pure(Formula);
diff --git a/frontend/src/metabase/reference/components/ReferenceHeader.css b/frontend/src/metabase/reference/components/ReferenceHeader.css
new file mode 100644
index 0000000000000000000000000000000000000000..05d27f0d2ad78b37b522a8f29c70816db142064c
--- /dev/null
+++ b/frontend/src/metabase/reference/components/ReferenceHeader.css
@@ -0,0 +1,58 @@
+:root {
+    --title-color: #606E7B;
+    --icon-width: calc(48px + 1rem);
+}
+
+:local(.headerBody) {
+    composes: flex flex-full border-bottom from "style";
+    overflow: hidden;
+    align-items: center;
+    border-color: #EDF5FB;
+}
+
+:local(.headerTextInput) {
+    composes: input p1 pl2 pr2 from "style";
+    font-size: 18px;
+    color: var(--title-color);
+    width: 100%;
+    max-width: 550px;
+}
+
+:local(.subheader) {
+    composes: mt1 mb2 from "style";
+}
+
+:local(.subheaderBody) {
+    composes: text-dark from "style";
+    margin-left: var(--icon-width);
+    font-size: 16px;
+}
+
+:local(.subheaderLink) {
+    color: var(--primary-button-bg-color);
+    text-decoration: none;
+}
+
+:local(.subheaderLink):hover {
+    color: color(var(--primary-button-border-color) shade(10%));
+    transition: color .3s linear;
+}
+
+:local(.editButton) {
+    composes: text-dark p0 mx1 from "style";
+    color: var(--primary-button-bg-color);
+    font-weight: normal;
+    font-size: 16px;
+}
+
+:local(.editButton):hover {
+    color: color(var(--primary-button-border-color) shade(10%));
+    transition: color .3s linear;
+}
+
+:local(.headerSchema) {
+    composes: text-grey-2 absolute from "style";
+    left: var(--icon-width);
+    top: -10px;
+    font-size: 12px;
+}
diff --git a/frontend/src/metabase/reference/components/ReferenceHeader.jsx b/frontend/src/metabase/reference/components/ReferenceHeader.jsx
index 05c6563dc5f079a6c4ede2ccecab74f2a193ad24..bc14089bfc99e472161645a65ab7ce71222dd17f 100644
--- a/frontend/src/metabase/reference/components/ReferenceHeader.jsx
+++ b/frontend/src/metabase/reference/components/ReferenceHeader.jsx
@@ -1,18 +1,30 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
+import cx from "classnames";
+import pure from "recompose/pure";
 
-import S from "metabase/components/List.css";
-import R from "metabase/reference/Reference.css";
+import S from "./ReferenceHeader.css";
+import L from "metabase/components/List.css";
 
 import IconBorder from "metabase/components/IconBorder.jsx";
 import Icon from "metabase/components/Icon.jsx";
 import Ellipsified from "metabase/components/Ellipsified.jsx";
 
-import cx from "classnames";
-
-const ReferenceHeader = ({ section, user, isEditing, startEditing }) =>
+const ReferenceHeader = ({
+    entity = {},
+    table,
+    section,
+    user,
+    isEditing,
+    hasSingleSchema,
+    hasDisplayName,
+    startEditing,
+    displayNameFormField,
+    nameFormField
+}) =>
     <div className="wrapper wrapper--trim">
-        <div className={S.header}>
-            <div className={S.leftIcons}>
+        <div className={cx("relative", L.header)} style={section.type === 'segment' ? {marginBottom: 0} : {}}>
+            <div className={L.leftIcons}>
                 { section.headerIcon &&
                     <IconBorder
                         borderWidth="0"
@@ -27,15 +39,62 @@ const ReferenceHeader = ({ section, user, isEditing, startEditing }) =>
                     </IconBorder>
                 }
             </div>
-            <div className={R.headerBody}>
-                <Ellipsified className="flex-full" tooltipMaxWidth="100%">
-                    {section.name}
-                </Ellipsified>
+            { section.type === 'table' && !hasSingleSchema && !isEditing &&
+                <div className={S.headerSchema}>{entity.schema}</div>
+            }
+            <div
+                className={S.headerBody}
+                style={isEditing && section.name === 'Details' ? {alignItems: "flex-start"} : {}}
+            >
+                { isEditing && section.name === 'Details' ?
+                    hasDisplayName ?
+                        <input
+                            className={S.headerTextInput}
+                            type="text"
+                            placeholder={entity.name}
+                            {...displayNameFormField}
+                            defaultValue={entity.display_name}
+                        /> :
+                        <input
+                            className={S.headerTextInput}
+                            type="text"
+                            placeholder={entity.name}
+                            {...nameFormField}
+                            defaultValue={entity.name}
+                        /> :
+                    [
+                        <Ellipsified
+                            key="1"
+                            className={!section.headerLink && "flex-full"}
+                            tooltipMaxWidth="100%"
+                        >
+                            { section.name === 'Details' ?
+                                hasDisplayName ?
+                                    entity.display_name || entity.name :
+                                    entity.name :
+                                section.name
+                            }
+                        </Ellipsified>,
+                        section.headerLink &&
+                            <div key="2" className={cx("flex-full", L.headerButton)}>
+                                <Link
+                                    to={section.headerLink}
+                                    className={cx("Button", "Button--borderless", S.editButton)}
+                                    data-metabase-event={`Data Reference;Entity -> QB click;${section.type}`}
+                                >
+                                    <div className="flex align-center relative">
+                                        <span className="mr1">See this {section.type}</span>
+                                        <Icon name="chevronright" size={16} />
+                                    </div>
+                                </Link>
+                            </div>
+                    ]
+                }
                 { user && user.is_superuser && !isEditing &&
-                    <div className={S.headerButton}>
+                    <div className={L.headerButton}>
                         <a
                             onClick={startEditing}
-                            className={cx("Button", "Button--borderless", R.editButton)}
+                            className={cx("Button", "Button--borderless", S.editButton)}
                         >
                             <div className="flex align-center relative">
                                 <Icon name="pencil" size={16} />
@@ -46,6 +105,30 @@ const ReferenceHeader = ({ section, user, isEditing, startEditing }) =>
                 }
             </div>
         </div>
-    </div>
+        { section.type === 'segment' && table &&
+            <div className={S.subheader}>
+                <div className={cx(S.subheaderBody)}>
+                    A subset of <Link
+                        className={S.subheaderLink}
+                        to={`/reference/databases/${table.db_id}/tables/${table.id}`}
+                    >
+                        {table.display_name}
+                    </Link>
+                </div>
+            </div>
+        }
+    </div>;
+ReferenceHeader.propTypes = {
+    entity: PropTypes.object,
+    table: PropTypes.object,
+    section: PropTypes.object.isRequired,
+    user: PropTypes.object,
+    isEditing: PropTypes.bool,
+    hasSingleSchema: PropTypes.bool,
+    hasDisplayName: PropTypes.bool,
+    startEditing: PropTypes.func,
+    displayNameFormField: PropTypes.object,
+    nameFormField: PropTypes.object
+};
 
-export default ReferenceHeader;
+export default pure(ReferenceHeader);
diff --git a/frontend/src/metabase/reference/components/RevisionMessageModal.css b/frontend/src/metabase/reference/components/RevisionMessageModal.css
index 5f7e858128d1bfbd8e0bd7ddad236ee8fc6c1ee4..aa711f9015df7d779019a815645fd1e0d27e1121 100644
--- a/frontend/src/metabase/reference/components/RevisionMessageModal.css
+++ b/frontend/src/metabase/reference/components/RevisionMessageModal.css
@@ -6,7 +6,7 @@
 }
 
 :local(.modalTextArea) {
-    composes: flex-full text-dark rounded bordered p2 from "style";
+    composes: flex-full text-dark input p2 from "style";
     resize: none;
     font-size: 16px;
     min-height: 100px;
diff --git a/frontend/src/metabase/reference/components/UsefulQuestions.css b/frontend/src/metabase/reference/components/UsefulQuestions.css
new file mode 100644
index 0000000000000000000000000000000000000000..981d0441e2dd41a3470665e26ff65dec95e0c255
--- /dev/null
+++ b/frontend/src/metabase/reference/components/UsefulQuestions.css
@@ -0,0 +1,4 @@
+:local(.usefulQuestions) {
+    composes: text-brand mt1 from "style";
+    font-size: 14px;
+}
diff --git a/frontend/src/metabase/reference/components/UsefulQuestions.jsx b/frontend/src/metabase/reference/components/UsefulQuestions.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7e996cf40106d0ce9c25b34b9f66dcd70608259a
--- /dev/null
+++ b/frontend/src/metabase/reference/components/UsefulQuestions.jsx
@@ -0,0 +1,35 @@
+import React, { Component, PropTypes } from "react";
+import cx from "classnames";
+import pure from "recompose/pure";
+
+import S from "./UsefulQuestions.css";
+import D from "metabase/components/Detail.css";
+import L from "metabase/components/List.css";
+
+import QueryButton from "metabase/components/QueryButton.jsx";
+
+const UsefulQuestions = ({
+    questions
+}) =>
+    <div className={cx(D.detail)}>
+        <div className={D.detailBody}>
+            <div className={D.detailTitle}>
+                <span className={D.detailName}>Potentially useful questions</span>
+            </div>
+            <div className={S.usefulQuestions}>
+                { questions.map((question, index, questions) =>
+                    <QueryButton
+                        key={index}
+                        className={cx("border-bottom", "pt1", "pb1")}
+                        iconClass={L.icon}
+                        {...question}
+                    />
+                )}
+            </div>
+        </div>
+    </div>;
+UsefulQuestions.propTypes = {
+    questions: PropTypes.array.isRequired
+};
+
+export default pure(UsefulQuestions);
diff --git a/frontend/src/metabase/reference/containers/ReferenceApp.jsx b/frontend/src/metabase/reference/containers/ReferenceApp.jsx
index 0d68cf7990d6232c02a25706c5c998a4b80b8f9f..b214c74d7432f1b44d739ea837e6552102f0a6ed 100644
--- a/frontend/src/metabase/reference/containers/ReferenceApp.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceApp.jsx
@@ -27,12 +27,12 @@ import {
 } from 'metabase/questions/questions';
 
 const mapStateToProps = (state, props) => ({
-    sectionId: getSectionId(state),
-    databaseId: getDatabaseId(state),
-    sections: getSections(state),
-    section: getSection(state),
-    breadcrumbs: getBreadcrumbs(state),
-    isEditing: getIsEditing(state)
+    sectionId: getSectionId(state, props),
+    databaseId: getDatabaseId(state, props),
+    sections: getSections(state, props),
+    section: getSection(state, props),
+    breadcrumbs: getBreadcrumbs(state, props),
+    isEditing: getIsEditing(state, props)
 });
 
 const mapDispatchToProps = {
@@ -65,6 +65,7 @@ export default class ReferenceApp extends Component {
         newProps.endEditing();
         newProps.endLoading();
         newProps.clearError();
+        newProps.collapseFormula();
 
         await tryFetchData(newProps);
     }
@@ -77,14 +78,13 @@ export default class ReferenceApp extends Component {
             isEditing
         } = this.props;
         return (
-            <div>
-                <SidebarLayout
-                    style={ isEditing ? { paddingTop: '43px' } : {}}
-                    sidebar={<Sidebar sections={sections} breadcrumbs={breadcrumbs} />}
-                >
-                    {children}
-                </SidebarLayout>
-            </div>
+            <SidebarLayout
+                className="flex-full relative"
+                style={ isEditing ? { paddingTop: '43px' } : {}}
+                sidebar={<Sidebar sections={sections} breadcrumbs={breadcrumbs} />}
+            >
+                {children}
+            </SidebarLayout>
         )
     }
 }
diff --git a/frontend/src/metabase/reference/containers/ReferenceEntity.jsx b/frontend/src/metabase/reference/containers/ReferenceEntity.jsx
index 867e5b981b1719ee1cc5828ca130fd016c69588e..bf4622a03d5dd355e6f962ffd5f1c038f156658d 100644
--- a/frontend/src/metabase/reference/containers/ReferenceEntity.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceEntity.jsx
@@ -1,29 +1,22 @@
 /* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
-import { Link } from "react-router";
 import ReactDOM from "react-dom";
 import { connect } from "react-redux";
 import { reduxForm } from "redux-form";
-import i from "icepick";
+import { push } from "react-router-redux";
 
-import * as MetabaseCore from "metabase/lib/core";
-import { isNumericBaseType } from "metabase/lib/schema_metadata";
-
-import S from "metabase/components/List.css";
-import D from "metabase/components/Detail.css";
-import R from "metabase/reference/Reference.css";
+import S from "metabase/reference/Reference.css";
 
 import List from "metabase/components/List.jsx";
 import Detail from "metabase/components/Detail.jsx";
-import Icon from "metabase/components/Icon.jsx";
-import Ellipsified from "metabase/components/Ellipsified.jsx";
-import IconBorder from "metabase/components/IconBorder.jsx";
-import Select from "metabase/components/Select.jsx";
 import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
 
-import RevisionMessageModal from "metabase/reference/components/RevisionMessageModal.jsx";
-
-import cx from "classnames";
+import EditHeader from "metabase/reference/components/EditHeader.jsx";
+import ReferenceHeader from "metabase/reference/components/ReferenceHeader.jsx";
+import FieldTypeDetail from "metabase/reference/components/FieldTypeDetail.jsx";
+import UsefulQuestions from "metabase/reference/components/UsefulQuestions.jsx";
+import FieldsToGroupBy from "metabase/reference/components/FieldsToGroupBy.jsx";
+import Formula from "metabase/reference/components/Formula.jsx";
 
 import {
     tryUpdateData
@@ -32,13 +25,16 @@ import {
 import {
     getSection,
     getData,
+    getTable,
     getError,
     getLoading,
     getUser,
+    getHasQuestions,
     getIsEditing,
     getHasDisplayName,
     getHasRevisionHistory,
     getHasSingleSchema,
+    getIsFormulaExpanded,
     getForeignKeys
 } from "../selectors";
 
@@ -46,22 +42,26 @@ import * as metadataActions from 'metabase/redux/metadata';
 import * as actions from 'metabase/reference/reference';
 
 const mapStateToProps = (state, props) => ({
-    section: getSection(state),
-    entity: getData(state) || {},
-    loading: getLoading(state),
+    section: getSection(state, props),
+    entity: getData(state, props) || {},
+    table: getTable(state, props),
+    loading: getLoading(state, props),
     // naming this 'error' will conflict with redux form
-    loadingError: getError(state),
-    user: getUser(state),
-    foreignKeys: getForeignKeys(state),
-    isEditing: getIsEditing(state),
-    hasSingleSchema: getHasSingleSchema(state),
-    hasDisplayName: getHasDisplayName(state),
-    hasRevisionHistory: getHasRevisionHistory(state)
+    loadingError: getError(state, props),
+    user: getUser(state, props),
+    foreignKeys: getForeignKeys(state, props),
+    isEditing: getIsEditing(state, props),
+    hasSingleSchema: getHasSingleSchema(state, props),
+    hasQuestions: getHasQuestions(state, props),
+    hasDisplayName: getHasDisplayName(state, props),
+    isFormulaExpanded: getIsFormulaExpanded(state, props),
+    hasRevisionHistory: getHasRevisionHistory(state, props)
 });
 
 const mapDispatchToProps = {
     ...metadataActions,
-    ...actions
+    ...actions,
+    onChangeLocation: push
 };
 
 const validate = (values, props) => props.hasRevisionHistory ?
@@ -79,13 +79,17 @@ export default class ReferenceEntity extends Component {
     static propTypes = {
         style: PropTypes.object.isRequired,
         entity: PropTypes.object.isRequired,
+        table: PropTypes.object,
         user: PropTypes.object.isRequired,
         foreignKeys: PropTypes.object,
         isEditing: PropTypes.bool,
+        hasQuestions: PropTypes.bool,
         startEditing: PropTypes.func.isRequired,
         endEditing: PropTypes.func.isRequired,
         startLoading: PropTypes.func.isRequired,
         endLoading: PropTypes.func.isRequired,
+        expandFormula: PropTypes.func.isRequired,
+        collapseFormula: PropTypes.func.isRequired,
         setError: PropTypes.func.isRequired,
         updateField: PropTypes.func.isRequired,
         handleSubmit: PropTypes.func.isRequired,
@@ -94,10 +98,12 @@ export default class ReferenceEntity extends Component {
         section: PropTypes.object.isRequired,
         hasSingleSchema: PropTypes.bool,
         hasDisplayName: PropTypes.bool,
+        isFormulaExpanded: PropTypes.bool,
         hasRevisionHistory: PropTypes.bool,
         loading: PropTypes.bool,
         loadingError: PropTypes.object,
-        submitting: PropTypes.bool
+        submitting: PropTypes.bool,
+        onChangeLocation: PropTypes.func.isRequired
     };
 
     render() {
@@ -106,18 +112,24 @@ export default class ReferenceEntity extends Component {
             style,
             section,
             entity,
+            table,
             loadingError,
             loading,
             user,
             foreignKeys,
             isEditing,
+            hasQuestions,
             startEditing,
             endEditing,
+            expandFormula,
+            collapseFormula,
             hasSingleSchema,
             hasDisplayName,
+            isFormulaExpanded,
             hasRevisionHistory,
             handleSubmit,
-            submitting
+            submitting,
+            onChangeLocation
         } = this.props;
 
         const onSubmit = handleSubmit(async (fields) =>
@@ -129,117 +141,26 @@ export default class ReferenceEntity extends Component {
                 onSubmit={onSubmit}
             >
                 { isEditing &&
-                    <div className={cx("EditHeader wrapper py1", R.subheader)}>
-                        <div>
-                            You are editing this page
-                        </div>
-                        <div className={R.subheaderButtons}>
-                            { hasRevisionHistory ?
-                                <RevisionMessageModal
-                                    action={() => onSubmit()}
-                                    field={revision_message}
-                                    submitting={submitting}
-                                >
-                                    <button
-                                        className={cx("Button", "Button--primary", "Button--white", "Button--small", R.saveButton)}
-                                        type="button"
-                                        disabled={submitting}
-                                    >
-                                        SAVE
-                                    </button>
-                                </RevisionMessageModal> :
-                                <button
-                                    className={cx("Button", "Button--primary", "Button--white", "Button--small", R.saveButton)}
-                                    type="submit"
-                                    disabled={submitting}
-                                >
-                                    SAVE
-                                </button>
-                            }
-
-                            <button
-                                type="button"
-                                className={cx("Button", "Button--white", "Button--small", R.cancelButton)}
-                                onClick={endEditing}
-                            >
-                                CANCEL
-                            </button>
-                        </div>
-                    </div>
+                    <EditHeader
+                        hasRevisionHistory={hasRevisionHistory}
+                        onSubmit={onSubmit}
+                        endEditing={endEditing}
+                        submitting={submitting}
+                        revisionMessageFormField={revision_message}
+                    />
                 }
-                { /* NOTE: this doesn't currently use ReferenceHeader since it is much more complicated */ }
-                <div className="wrapper wrapper--trim">
-                    <div className={cx("relative", S.header)}>
-                        <div className={S.leftIcons}>
-                            { section.headerIcon &&
-                                <IconBorder borderWidth="0" style={{backgroundColor: "#E9F4F8"}}>
-                                    <Icon
-                                        className="text-brand"
-                                        name={section.headerIcon}
-                                        width={24}
-                                        height={24}
-                                    />
-                                </IconBorder>
-                            }
-                        </div>
-                        { section.type === 'table' && !hasSingleSchema && !isEditing &&
-                            <div className={R.headerSchema}>{entity.schema}</div>
-                        }
-                        <div className={R.headerBody} style={isEditing ? {alignItems: "flex-start"} : {}}>
-                            { isEditing ?
-                                hasDisplayName ?
-                                    <input
-                                        className={R.headerTextInput}
-                                        type="text"
-                                        placeholder={entity.name}
-                                        {...display_name}
-                                        defaultValue={entity.display_name}
-                                    /> :
-                                    <input
-                                        className={R.headerTextInput}
-                                        type="text"
-                                        placeholder={entity.name}
-                                        {...name}
-                                        defaultValue={entity.name}
-                                    /> :
-                                [
-                                    <Ellipsified key="1" className={!section.headerLink && "flex-full"} tooltipMaxWidth="100%">
-                                        { hasDisplayName ?
-                                            entity.display_name || entity.name :
-                                            entity.name
-                                        }
-                                    </Ellipsified>,
-                                    section.headerLink &&
-                                        <div key="2" className={cx("flex-full", S.headerButton)}>
-                                            <Link
-                                                to={section.headerLink}
-                                                className={cx("Button", "Button--borderless", R.editButton)}
-                                                data-metabase-event={`Data Reference;Entity -> QB click;${section.type}`}
-                                            >
-                                                <div className="flex align-center relative">
-                                                    <span className="mr1">See this {section.type}</span>
-                                                    <Icon name="chevronright" size={16} />
-                                                </div>
-                                            </Link>
-                                        </div>
-                                ]
-                            }
-                            { user.is_superuser && !isEditing &&
-                                <div className={S.headerButton}>
-                                    <a
-                                        onClick={startEditing}
-                                        className={cx("Button", "Button--borderless", R.editButton)}
-                                    >
-                                        <div className="flex align-center relative">
-                                            <Icon name="pencil" size={16} />
-                                            <span className="ml1">Edit</span>
-                                        </div>
-                                    </a>
-                                </div>
-                            }
-                        </div>
-                    </div>
-                </div>
+                <ReferenceHeader
+                    entity={entity}
+                    table={table}
+                    section={section}
+                    user={user}
+                    isEditing={isEditing}
+                    hasSingleSchema={hasSingleSchema}
+                    hasDisplayName={hasDisplayName}
+                    startEditing={startEditing}
+                    displayNameFormField={display_name}
+                    nameFormField={name}
+                />
                 <LoadingAndErrorWrapper loading={!loadingError && loading} error={loadingError}>
                 { () =>
                     <div className="wrapper wrapper--trim">
@@ -260,6 +181,7 @@ export default class ReferenceEntity extends Component {
                                         id="name"
                                         name="Actual name in database"
                                         description={entity.name}
+                                        subtitleClass={S.tableActualName}
                                     />
                                 </li>
                             }
@@ -295,6 +217,19 @@ export default class ReferenceEntity extends Component {
                                     />
                                 </li>
                             }
+                            { (section.type === 'metric' || section.type === 'segment') &&
+                                table && !isEditing &&
+                                <li className="relative">
+                                    <Formula
+                                        type={section.type}
+                                        entity={entity}
+                                        table={table}
+                                        isExpanded={isFormulaExpanded}
+                                        expandFormula={expandFormula}
+                                        collapseFormula={collapseFormula}
+                                    />
+                                </li>
+                            }
                             { !isEditing && section.type === 'field' &&
                                 <li className="relative">
                                     <Detail
@@ -305,71 +240,29 @@ export default class ReferenceEntity extends Component {
                                 </li>
                             }
                             { section.type === 'field' &&
-                                //TODO: could use some refactoring. a lot of overlap with Field.jsx and ListItem.jsx
                                 <li className="relative">
-                                    <div className={cx(D.detail)}>
-                                        <div className={D.detailBody}>
-                                            <div className={D.detailTitle}>
-                                                <span className={D.detailName}>Field type</span>
-                                            </div>
-                                            <div className={cx(D.detailSubtitle, { "mt1" : true })}>
-                                                <span>
-                                                    { isEditing ?
-                                                        <Select
-                                                            triggerClasses="rounded bordered p1 inline-block"
-                                                            placeholder="Select a field type"
-                                                            value={
-                                                                MetabaseCore.field_special_types_map[special_type.value] ||
-                                                                MetabaseCore.field_special_types_map[entity.special_type]
-                                                            }
-                                                            options={
-                                                                MetabaseCore.field_special_types
-                                                                    .concat({
-                                                                        'id': null,
-                                                                        'name': 'No field type',
-                                                                        'section': 'Other'
-                                                                    })
-                                                                    .filter(type => !isNumericBaseType(entity) ?
-                                                                        !(type.id && type.id.startsWith("timestamp_")) :
-                                                                        true
-                                                                    )
-                                                            }
-                                                            onChange={(type) => special_type.onChange(type.id)}
-                                                        /> :
-                                                        <span>
-                                                            { i.getIn(
-                                                                    MetabaseCore.field_special_types_map,
-                                                                    [entity.special_type, 'name']
-                                                                ) || 'No field type'
-                                                            }
-                                                        </span>
-                                                    }
-                                                </span>
-                                                <span className="ml4">
-                                                    { isEditing ?
-                                                        (special_type.value === 'fk' ||
-                                                        (entity.special_type === 'fk' && special_type.value === undefined)) &&
-                                                        <Select
-                                                            triggerClasses="rounded bordered p1 inline-block"
-                                                            placeholder="Select a field type"
-                                                            value={
-                                                                foreignKeys[fk_target_field_id.value] ||
-                                                                foreignKeys[entity.fk_target_field_id] ||
-                                                                {name: "Select a Foreign Key"}
-                                                            }
-                                                            options={Object.values(foreignKeys)}
-                                                            onChange={(foreignKey) => fk_target_field_id.onChange(foreignKey.id)}
-                                                            optionNameFn={(foreignKey) => foreignKey.name}
-                                                        /> :
-                                                        entity.special_type === 'fk' &&
-                                                        <span>
-                                                            {i.getIn(foreignKeys, [entity.fk_target_field_id, "name"])}
-                                                        </span>
-                                                    }
-                                                </span>
-                                            </div>
-                                        </div>
-                                    </div>
+                                    <FieldTypeDetail
+                                        field={entity}
+                                        foreignKeys={foreignKeys}
+                                        fieldTypeFormField={special_type}
+                                        foreignKeyFormField={fk_target_field_id}
+                                        isEditing={isEditing}
+                                    />
+                                </li>
+                            }
+                            { hasQuestions && !isEditing &&
+                                <li className="relative">
+                                    <UsefulQuestions questions={section.questions} />
+                                </li>
+                            }
+                            { section.type === 'metric' && !isEditing &&
+                                <li className="relative">
+                                    <FieldsToGroupBy
+                                        table={table}
+                                        metric={entity}
+                                        title={"Fields you can group this metric by"}
+                                        onChangeLocation={onChangeLocation}
+                                    />
                                 </li>
                             }
                         </List>
diff --git a/frontend/src/metabase/reference/containers/ReferenceEntityList.jsx b/frontend/src/metabase/reference/containers/ReferenceEntityList.jsx
index 0eae0f9462444f7a5b7c8fa0bd53ec31e6aa3f9b..0d45f4e72556728c242dfb15a700110f048e7176 100644
--- a/frontend/src/metabase/reference/containers/ReferenceEntityList.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceEntityList.jsx
@@ -33,12 +33,12 @@ import {
 import * as metadataActions from "metabase/redux/metadata";
 
 const mapStateToProps = (state, props) => ({
-    section: getSection(state),
-    entities: getData(state),
-    user: getUser(state),
-    hasSingleSchema: getHasSingleSchema(state),
-    loading: getLoading(state),
-    loadingError: getError(state)
+    section: getSection(state, props),
+    entities: getData(state, props),
+    user: getUser(state, props),
+    hasSingleSchema: getHasSingleSchema(state, props),
+    loading: getLoading(state, props),
+    loadingError: getError(state, props)
 });
 
 const mapDispatchToProps = {
diff --git a/frontend/src/metabase/reference/containers/ReferenceFieldsList.jsx b/frontend/src/metabase/reference/containers/ReferenceFieldsList.jsx
index 79af13f641b93da8fbde958d9233aa8f37ae83aa..b6a7eaa65705a4cdf63bbdaaf4850878f7e64228 100644
--- a/frontend/src/metabase/reference/containers/ReferenceFieldsList.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceFieldsList.jsx
@@ -12,6 +12,8 @@ import Field from "metabase/reference/components/Field.jsx";
 import List from "metabase/components/List.jsx";
 import EmptyState from "metabase/components/EmptyState.jsx";
 import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
+
+import EditHeader from "metabase/reference/components/EditHeader.jsx";
 import ReferenceHeader from "metabase/reference/components/ReferenceHeader.jsx";
 
 import cx from "classnames";
@@ -24,6 +26,7 @@ import {
     getLoading,
     getUser,
     getIsEditing,
+    getHasRevisionHistory,
 } from "../selectors";
 
 import {
@@ -37,15 +40,16 @@ import * as metadataActions from "metabase/redux/metadata";
 import * as actions from 'metabase/reference/reference';
 
 const mapStateToProps = (state, props) => {
-    const data = getData(state);
+    const data = getData(state, props);
     return {
-        section: getSection(state),
+        section: getSection(state, props),
         entities: data,
-        foreignKeys: getForeignKeys(state),
-        loading: getLoading(state),
-        loadingError: getError(state),
-        user: getUser(state),
-        isEditing: getIsEditing(state),
+        foreignKeys: getForeignKeys(state, props),
+        loading: getLoading(state, props),
+        loadingError: getError(state, props),
+        user: getUser(state, props),
+        isEditing: getIsEditing(state, props),
+        hasRevisionHistory: getHasRevisionHistory(state, props),
         fields: fieldsToFormFields(data)
     };
 }
@@ -70,6 +74,7 @@ export default class ReferenceEntityList extends Component {
         entities: PropTypes.object.isRequired,
         foreignKeys: PropTypes.object.isRequired,
         isEditing: PropTypes.bool,
+        hasRevisionHistory: PropTypes.bool,
         startEditing: PropTypes.func.isRequired,
         endEditing: PropTypes.func.isRequired,
         startLoading: PropTypes.func.isRequired,
@@ -96,6 +101,7 @@ export default class ReferenceEntityList extends Component {
             loading,
             user,
             isEditing,
+            hasRevisionHistory,
             startEditing,
             endEditing,
             handleSubmit,
@@ -109,27 +115,11 @@ export default class ReferenceEntityList extends Component {
                 )}
             >
                 { isEditing &&
-                    <div className={cx("EditHeader wrapper py1", R.subheader)}>
-                        <div>
-                            You are editing this page
-                        </div>
-                        <div className={R.subheaderButtons}>
-                            <button
-                                className={cx("Button", "Button--primary", "Button--white", "Button--small", R.saveButton)}
-                                type="submit"
-                                disabled={submitting}
-                            >
-                                SAVE
-                            </button>
-                            <button
-                                type="button"
-                                className={cx("Button", "Button--white", "Button--small", R.cancelButton)}
-                                onClick={endEditing}
-                            >
-                                CANCEL
-                            </button>
-                        </div>
-                    </div>
+                    <EditHeader
+                        hasRevisionHistory={hasRevisionHistory}
+                        endEditing={endEditing}
+                        submitting={submitting}
+                    />
                 }
                 <ReferenceHeader section={section} user={user} isEditing={isEditing} startEditing={startEditing} />
                 <LoadingAndErrorWrapper loading={!loadingError && loading} error={loadingError}>
diff --git a/frontend/src/metabase/reference/containers/ReferenceRevisionsList.jsx b/frontend/src/metabase/reference/containers/ReferenceRevisionsList.jsx
index c37ebd395d3105caaf1aebcaa4c838e713489745..0f592bb09b5fa572b56381360e2b72b17b86d887 100644
--- a/frontend/src/metabase/reference/containers/ReferenceRevisionsList.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceRevisionsList.jsx
@@ -27,14 +27,14 @@ import ReferenceHeader from "../components/ReferenceHeader.jsx";
 
 const mapStateToProps = (state, props) => {
     return {
-        section: getSection(state),
-        revisions: getData(state),
-        metric: getMetric(state),
-        segment: getSegment(state),
-        tables: getTables(state),
-        user: getUser(state),
-        loading: getLoading(state),
-        loadingError: getError(state)
+        section: getSection(state, props),
+        revisions: getData(state, props),
+        metric: getMetric(state, props),
+        segment: getSegment(state, props),
+        tables: getTables(state, props),
+        user: getUser(state, props),
+        loading: getLoading(state, props),
+        loadingError: getError(state, props)
     }
 }
 
diff --git a/frontend/src/metabase/reference/reference.js b/frontend/src/metabase/reference/reference.js
index 469c5da746f5534bb055a7553f7013a1d7badae9..8bddeae54dc70c29560a74540083a2cdd43b945f 100644
--- a/frontend/src/metabase/reference/reference.js
+++ b/frontend/src/metabase/reference/reference.js
@@ -25,10 +25,17 @@ export const endEditing = createAction(END_EDITING, () => {
     MetabaseAnalytics.trackEvent('Data Reference', 'Ended Editing');
 });
 
+const EXPAND_FORMULA = "metabase/reference/EXPAND_FORMULA";
+export const expandFormula = createAction(EXPAND_FORMULA);
+
+const COLLAPSE_FORMULA = "metabase/reference/COLLAPSE_FORMULA";
+export const collapseFormula = createAction(COLLAPSE_FORMULA);
+
 const initialState = {
     error: null,
     isLoading: false,
-    isEditing: false
+    isEditing: false,
+    isFormulaExpanded: false,
 };
 export default handleActions({
     [SET_ERROR]: {
@@ -48,5 +55,11 @@ export default handleActions({
     },
     [END_EDITING]: {
         next: (state) => i.assoc(state, 'isEditing', false)
+    },
+    [EXPAND_FORMULA]: {
+        next: (state) => i.assoc(state, 'isFormulaExpanded', true)
+    },
+    [COLLAPSE_FORMULA]: {
+        next: (state) => i.assoc(state, 'isFormulaExpanded', false)
     }
 }, initialState);
diff --git a/frontend/src/metabase/reference/selectors.js b/frontend/src/metabase/reference/selectors.js
index 946ce2c76aa1e20663731429566b83494f7ae73f..15fb4bcb9cccb3f3ed6f34c1f44828e73363756e 100644
--- a/frontend/src/metabase/reference/selectors.js
+++ b/frontend/src/metabase/reference/selectors.js
@@ -2,18 +2,25 @@ import { createSelector } from 'reselect';
 import i from "icepick";
 
 import Query, { AggregationClause } from 'metabase/lib/query';
-import { titleize, humanize } from "metabase/lib/formatting";
+import {
+    idsToObjectMap,
+    buildBreadcrumbs,
+    databaseToForeignKeys,
+    getQuestionUrl
+} from "./utils";
 
 // there might be a better way to organize sections
 // it feels like I'm duplicating a lot of routing logic here
 //TODO: refactor to use different container components for each section
 // initialize section metadata in there
+// may not be worthwhile due to the extra boilerplate required
+// ideal solution is to pass metadata to each section through router
 const referenceSections = {
     [`/reference/guide`]: {
         id: `/reference/guide`,
         name: "Understanding our data",
         breadcrumb: "Guide",
-        icon: "all"
+        icon: "reference"
     },
     [`/reference/metrics`]: {
         id: `/reference/metrics`,
@@ -67,7 +74,7 @@ const referenceSections = {
     }
 };
 
-const getReferenceSections = (state) => referenceSections;
+const getReferenceSections = (state, props) => referenceSections;
 
 const getMetricSections = (metric, table, user) => metric ? {
     [`/reference/metrics/${metric.id}`]: {
@@ -76,11 +83,15 @@ const getMetricSections = (metric, table, user) => metric ? {
         update: 'updateMetric',
         type: 'metric',
         breadcrumb: `${metric.name}`,
-        fetch: {fetchMetrics: [], fetchTables: []},
+        fetch: {fetchMetricTable: [metric.id]},
         get: 'getMetric',
         icon: "document",
         headerIcon: "ruler",
-        headerLink: `/q?db=${table && table.db_id}&table=${metric.table_id}&metric=${metric.id}`,
+        headerLink: getQuestionUrl({
+            dbId: table && table.db_id,
+            tableId: metric.table_id,
+            metricId: metric.id
+        }),
         parent: referenceSections[`/reference/metrics`]
     },
     [`/reference/metrics/${metric.id}/questions`]: {
@@ -90,12 +101,16 @@ const getMetricSections = (metric, table, user) => metric ? {
             message: `Questions about this metric will appear here as they're added`,
             icon: "all",
             action: "Ask a question",
-            link: `/q?db=${table && table.db_id}&table=${metric.table_id}&metric=${metric.id}`
+            link: getQuestionUrl({
+                dbId: table && table.db_id,
+                tableId: metric.table_id,
+                metricId: metric.id
+            })
         },
         type: 'questions',
         sidebar: 'Questions about this metric',
         breadcrumb: `${metric.name}`,
-        fetch: {fetchMetrics: [], fetchTables: [], fetchQuestions: []},
+        fetch: {fetchMetricTable: [metric.id], fetchQuestions: []},
         get: 'getMetricQuestions',
         icon: "all",
         headerIcon: "ruler",
@@ -121,12 +136,37 @@ const getSegmentSections = (segment, table, user) => segment ? {
         name: 'Details',
         update: 'updateSegment',
         type: 'segment',
+        questions: [
+            {
+                text: `Number of ${segment.name}`,
+                icon: { name: "number", scale: 1, viewBox: "8 8 16 16" },
+                link: getQuestionUrl({
+                    dbId: table && table.db_id,
+                    tableId: segment.table_id,
+                    segmentId: segment.id,
+                    getCount: true
+                })
+            },
+            {
+                text: `See all ${segment.name}`,
+                icon: "table2",
+                link: getQuestionUrl({
+                    dbId: table && table.db_id,
+                    tableId: segment.table_id,
+                    segmentId: segment.id
+                })
+            }
+        ],
         breadcrumb: `${segment.name}`,
-        fetch: {fetchSegments: [], fetchTables: []},
+        fetch: {fetchSegmentTable: [segment.id]},
         get: 'getSegment',
         icon: "document",
         headerIcon: "segment",
-        headerLink: `/q?db=${table && table.db_id}&table=${segment.table_id}&segment=${segment.id}`,
+        headerLink: getQuestionUrl({
+            dbId: table && table.db_id,
+            tableId: segment.table_id,
+            segmentId: segment.id
+        }),
         parent: referenceSections[`/reference/segments`]
     },
     [`/reference/segments/${segment.id}/fields`]: {
@@ -151,12 +191,16 @@ const getSegmentSections = (segment, table, user) => segment ? {
             message: `Questions about this segment will appear here as they're added`,
             icon: "all",
             action: "Ask a question",
-            link: `/q?db=${table && table.db_id}&table=${segment.table_id}&segment=${segment.id}`
+            link: getQuestionUrl({
+                dbId: table && table.db_id,
+                tableId: segment.table_id,
+                segmentId: segment.id
+            })
         },
         type: 'questions',
         sidebar: 'Questions about this segment',
         breadcrumb: `${segment.name}`,
-        fetch: {fetchSegments: [], fetchTables: [], fetchQuestions: []},
+        fetch: {fetchSegmentTable: [segment.id], fetchQuestions: []},
         get: 'getSegmentQuestions',
         icon: "all",
         headerIcon: "segment",
@@ -176,12 +220,33 @@ const getSegmentSections = (segment, table, user) => segment ? {
     }
 } : {};
 
-const getSegmentFieldSections = (segment, field, user) => segment && field ? {
+const getSegmentFieldSections = (segment, table, field, user) => segment && field ? {
     [`/reference/segments/${segment.id}/fields/${field.id}`]: {
         id: `/reference/segments/${segment.id}/fields/${field.id}`,
         name: 'Details',
         update: 'updateField',
         type: 'field',
+        questions: [
+            {
+                text: `Number of ${table && table.display_name} grouped by ${field.display_name}`,
+                icon: { name: "number", scale: 1, viewBox: "8 8 16 16" },
+                link: getQuestionUrl({
+                    dbId: table && table.db_id,
+                    tableId: field.table_id,
+                    fieldId: field.id,
+                    getCount: true
+                })
+            },
+            {
+                text: `All distinct values of ${field.display_name}`,
+                icon: "table2",
+                link: getQuestionUrl({
+                    dbId: table && table.db_id,
+                    tableId: field.table_id,
+                    fieldId: field.id
+                })
+            }
+        ],
         breadcrumb: `${field.display_name}`,
         fetch: {fetchSegmentFields: [segment.id]},
         get: "getFieldBySegment",
@@ -228,12 +293,34 @@ const getTableSections = (database, table) => database && table ? {
         name: 'Details',
         update: 'updateTable',
         type: 'table',
+        questions: [
+            {
+                text: `Count of ${table.display_name}`,
+                icon: { name: "number", scale: 1, viewBox: "8 8 16 16" },
+                link: getQuestionUrl({
+                    dbId: table.db_id,
+                    tableId: table.id,
+                    getCount: true
+                })
+            },
+            {
+                text: `See raw data for ${table.display_name}`,
+                icon: "table2",
+                link: getQuestionUrl({
+                    dbId: table.db_id,
+                    tableId: table.id,
+                })
+            }
+        ],
         breadcrumb: `${table.display_name}`,
         fetch: {fetchDatabaseMetadata: [database.id]},
         get: 'getTable',
         icon: "document",
         headerIcon: "table2",
-        headerLink: `/q?db=${table.db_id}&table=${table.id}`,
+        headerLink: getQuestionUrl({
+            dbId: table.db_id,
+            tableId: table.id,
+        }),
         parent: getDatabaseSections(database)[`/reference/databases/${database.id}/tables`]
     },
     [`/reference/databases/${database.id}/tables/${table.id}/fields`]: {
@@ -258,7 +345,10 @@ const getTableSections = (database, table) => database && table ? {
             message: `Questions about this table will appear here as they're added`,
             icon: "all",
             action: "Ask a question",
-            link: `/q?db=${table.db_id}&table=${table.id}`
+            link: getQuestionUrl({
+                dbId: table.db_id,
+                tableId: table.id,
+            })
         },
         type: 'questions',
         sidebar: 'Questions about this table',
@@ -277,6 +367,39 @@ const getTableFieldSections = (database, table, field) => database && table && f
         name: 'Details',
         update: 'updateField',
         type: 'field',
+        questions: [
+            {
+                text: `Number of ${table.display_name} grouped by ${field.display_name}`,
+                icon: { name: "bar", scale: 1, viewBox: "8 8 16 16" },
+                link: getQuestionUrl({
+                    dbId: database.id,
+                    tableId: table.id,
+                    fieldId: field.id,
+                    getCount: true,
+                    visualization: 'bar'
+                })
+            },
+            {
+                text: `Number of ${table.display_name} grouped by ${field.display_name}`,
+                icon: { name: "pie", scale: 1, viewBox: "8 8 16 16" },
+                link: getQuestionUrl({
+                    dbId: database.id,
+                    tableId: table.id,
+                    fieldId: field.id,
+                    getCount: true,
+                    visualization: 'pie'
+                })
+            },
+            {
+                text: `All distinct values of ${field.display_name}`,
+                icon: "table2",
+                link: getQuestionUrl({
+                    dbId: database.id,
+                    tableId: table.id,
+                    fieldId: field.id
+                })
+            }
+        ],
         breadcrumb: `${field.display_name}`,
         fetch: {fetchDatabaseMetadata: [database.id]},
         get: "getField",
@@ -286,61 +409,57 @@ const getTableFieldSections = (database, table, field) => database && table && f
     }
 } : {};
 
-const idsToObjectMap = (ids, objects) => ids
-    .map(id => objects[id])
-    .reduce((map, object) => Object.assign({}, map, {[object.id]: object}), {});
-    // recursive freezing done by i.assoc here is too expensive
-    // hangs browser for large databases
-    // .reduce((map, object) => i.assoc(map, object.id, object), {});
+export const getUser = (state, props) => state.currentUser;
 
-export const getUser = (state) => state.currentUser;
+export const getSectionId = (state, props) => props.location.pathname;
 
-export const getSectionId = (state) => state.router.location.pathname;
-
-export const getMetricId = (state) => Number.parseInt(state.router.params.metricId);
-const getMetrics = (state) => state.metadata.metrics;
+export const getMetricId = (state, props) => Number.parseInt(props.params.metricId);
+const getMetrics = (state, props) => state.metadata.metrics;
 export const getMetric = createSelector(
     [getMetricId, getMetrics],
     (metricId, metrics) => metrics[metricId] || { id: metricId }
 );
 
-export const getSegmentId = (state) => Number.parseInt(state.router.params.segmentId);
-const getSegments = (state) => state.metadata.segments;
+export const getSegmentId = (state, props) => Number.parseInt(props.params.segmentId);
+const getSegments = (state, props) => state.metadata.segments;
 export const getSegment = createSelector(
     [getSegmentId, getSegments],
     (segmentId, segments) => segments[segmentId] || { id: segmentId }
 );
 
-export const getDatabaseId = (state) => Number.parseInt(state.router.params.databaseId);
-const getDatabases = (state) => state.metadata.databases;
+export const getDatabaseId = (state, props) => Number.parseInt(props.params.databaseId);
+const getDatabases = (state, props) => state.metadata.databases;
 const getDatabase = createSelector(
     [getDatabaseId, getDatabases],
     (databaseId, databases) => databases[databaseId] || { id: databaseId }
 );
 
-export const getTableId = (state) => Number.parseInt(state.router.params.tableId);
-// export const getTableId = (state) => Number.parseInt(state.router.params.tableId);
-export const getTables = (state) => state.metadata.tables;
+export const getTableId = (state, props) => Number.parseInt(props.params.tableId);
+// export const getTableId = (state, props) => Number.parseInt(props.params.tableId);
+export const getTables = (state, props) => state.metadata.tables;
 const getTablesByDatabase = createSelector(
     [getTables, getDatabase],
     (tables, database) => tables && database && database.tables ?
         idsToObjectMap(database.tables, tables) : {}
 );
-const getTable = createSelector(
-    [getTableId, getTables],
-    (tableId, tables) => tables[tableId] || { id: tableId }
-);
 const getTableBySegment = createSelector(
     [getSegment, getTables],
-    (segment, tables) => segment ? tables[segment.table_id] : {}
+    (segment, tables) => segment && segment.table_id ? tables[segment.table_id] : {}
 );
 const getTableByMetric = createSelector(
     [getMetric, getTables],
-    (metric, tables) => metric ? tables[metric.table_id] : {}
+    (metric, tables) => metric && metric.table_id ? tables[metric.table_id] : {}
+);
+export const getTable = createSelector(
+    [getTableId, getTables, getMetricId, getTableByMetric, getSegmentId, getTableBySegment],
+    (tableId, tables, metricId, tableByMetric, segmentId, tableBySegment) => tableId ?
+        tables[tableId] || { id: tableId } :
+        metricId ? tableByMetric :
+            segmentId ? tableBySegment : {}
 );
 
-export const getFieldId = (state) => Number.parseInt(state.router.params.fieldId);
-const getFields = (state) => state.metadata.fields;
+export const getFieldId = (state, props) => Number.parseInt(props.params.fieldId);
+const getFields = (state, props) => state.metadata.fields;
 const getFieldsByTable = createSelector(
     [getTable, getFields],
     (table, fields) => table && table.fields ? idsToObjectMap(table.fields, fields) : {}
@@ -358,7 +477,7 @@ const getFieldBySegment = createSelector(
     (fieldId, fields) => fields[fieldId] || { id: fieldId }
 );
 
-const getQuestions = (state) => i.getIn(state, ['questions', 'entities', 'cards']) || {};
+const getQuestions = (state, props) => i.getIn(state, ['questions', 'entities', 'cards']) || {};
 
 const getMetricQuestions = createSelector(
     [getMetricId, getQuestions],
@@ -370,7 +489,7 @@ const getMetricQuestions = createSelector(
         .reduce((map, question) => i.assoc(map, question.id, question), {})
 );
 
-const getRevisions = (state) => state.metadata.revisions;
+const getRevisions = (state, props) => state.metadata.revisions;
 
 const getMetricRevisions = createSelector(
     [getMetricId, getRevisions],
@@ -405,28 +524,6 @@ const getDatabaseBySegment = createSelector(
         databases[tables[segment.table_id].db_id] || {}
 );
 
-export const databaseToForeignKeys = (database) => database && database.tables_lookup ?
-    Object.values(database.tables_lookup)
-        // ignore tables without primary key
-        .filter(table => table && table.fields_lookup &&
-            Object.values(table.fields_lookup)
-                .find(field => field.special_type === 'id')
-        )
-        .map(table => ({
-            table: table,
-            field: table && table.fields_lookup && Object.values(table.fields_lookup)
-                .find(field => field.special_type === 'id')
-        }))
-        .map(({ table, field }) => ({
-            id: field.id,
-            name: table.schema && table.schema !== "public" ?
-                `${titleize(humanize(table.schema))}.${table.display_name} → ${field.display_name}` :
-                `${table.display_name} → ${field.display_name}`,
-            description: field.description
-        }))
-        .reduce((map, foreignKey) => i.assoc(map, foreignKey.id, foreignKey), {}) :
-    {};
-
 const getForeignKeysBySegment = createSelector(
     [getDatabaseBySegment],
     databaseToForeignKeys
@@ -461,7 +558,7 @@ export const getSections = createSelector(
             return segmentSections;
         }
 
-        const segmentFieldSections = getSegmentFieldSections(segment, fieldBySegment);
+        const segmentFieldSections = getSegmentFieldSections(segment, tableBySegment, fieldBySegment);
         if (segmentFieldSections[sectionId]) {
             return segmentFieldSections;
         }
@@ -512,8 +609,8 @@ const dataSelectors = {
     getFieldsBySegment
 };
 
-export const getData = (state) => {
-    const section = getSection(state);
+export const getData = (state, props) => {
+    const section = getSection(state, props);
     if (!section) {
         return {};
     }
@@ -522,30 +619,12 @@ export const getData = (state) => {
         return {};
     }
 
-    return selector(state);
+    return selector(state, props);
 };
 
-export const getLoading = (state) => state.reference.isLoading;
-
-export const getError = (state) => state.reference.error;
-
-const getBreadcrumb = (section, index, sections) => index !== sections.length - 1 ?
-    [section.breadcrumb, section.id] : [section.breadcrumb];
-
-const getParentSections = (section) => {
-    if (!section.parent) {
-        return [section];
-    }
-
-    const parentSections = []
-        .concat(getParentSections(section.parent), section);
-
-    return parentSections;
-};
+export const getLoading = (state, props) => state.reference.isLoading;
 
-export const buildBreadcrumbs = (section) => getParentSections(section)
-    .map(getBreadcrumb)
-    .slice(-3);
+export const getError = (state, props) => state.reference.error;
 
 export const getBreadcrumbs = createSelector(
     [getSection],
@@ -573,4 +652,11 @@ export const getHasRevisionHistory = createSelector(
         section.type === 'segment'
 )
 
-export const getIsEditing = (state) => state.reference.isEditing;
+export const getHasQuestions = createSelector(
+    [getSection],
+    (section) => section.questions && section.questions.length > 0
+)
+
+export const getIsEditing = (state, props) => state.reference.isEditing;
+
+export const getIsFormulaExpanded = (state, props) => state.reference.isFormulaExpanded;
\ No newline at end of file
diff --git a/frontend/src/metabase/reference/utils.js b/frontend/src/metabase/reference/utils.js
index 56cee7938f97e9035c73881cb6d79bf64a8872b1..5e89dd9dbabf5ac2a926feafc2343de08614a3fe 100644
--- a/frontend/src/metabase/reference/utils.js
+++ b/frontend/src/metabase/reference/utils.js
@@ -1,5 +1,15 @@
 import i from "icepick";
 
+import { titleize, humanize } from "metabase/lib/formatting";
+import { startNewCard, serializeCardForUrl } from "metabase/lib/card";
+
+export const idsToObjectMap = (ids, objects) => ids
+    .map(id => objects[id])
+    .reduce((map, object) => Object.assign({}, map, {[object.id]: object}), {});
+    // recursive freezing done by i.assoc here is too expensive
+    // hangs browser for large databases
+    // .reduce((map, object) => i.assoc(map, object.id, object), {});
+
 export const tryFetchData = async (props) => {
     const {
         section,
@@ -95,6 +105,46 @@ export const tryUpdateFields = async (formFields, props) => {
     endEditing();
 }
 
+const getBreadcrumb = (section, index, sections) => index !== sections.length - 1 ?
+    [section.breadcrumb, section.id] : [section.breadcrumb];
+
+const getParentSections = (section) => {
+    if (!section.parent) {
+        return [section];
+    }
+
+    const parentSections = []
+        .concat(getParentSections(section.parent), section);
+
+    return parentSections;
+};
+
+export const buildBreadcrumbs = (section) => getParentSections(section)
+    .map(getBreadcrumb)
+    .slice(-3);
+
+export const databaseToForeignKeys = (database) => database && database.tables_lookup ?
+    Object.values(database.tables_lookup)
+        // ignore tables without primary key
+        .filter(table => table && table.fields_lookup &&
+            Object.values(table.fields_lookup)
+                .find(field => field.special_type === 'id')
+        )
+        .map(table => ({
+            table: table,
+            field: table && table.fields_lookup && Object.values(table.fields_lookup)
+                .find(field => field.special_type === 'id')
+        }))
+        .map(({ table, field }) => ({
+            id: field.id,
+            name: table.schema && table.schema !== "public" ?
+                `${titleize(humanize(table.schema))}.${table.display_name} → ${field.display_name}` :
+                `${table.display_name} → ${field.display_name}`,
+            description: field.description
+        }))
+        .reduce((map, foreignKey) => i.assoc(map, foreignKey.id, foreignKey), {}) :
+    {};
+
 export const fieldsToFormFields = (fields) => Object.keys(fields)
     .map(key => [
         `${key}.display_name`,
@@ -126,3 +176,33 @@ export const separateTablesBySchema = (
                 ] :
                 createListItem(table, index, section);
     });
+
+export const getQuestion = ({dbId, tableId, fieldId, metricId, segmentId, getCount, visualization}) => {
+    const newQuestion = startNewCard('query', dbId, tableId);
+
+    // consider taking a look at Ramda as a possible underscore alternative?
+    // http://ramdajs.com/0.21.0/index.html
+    const question = i.chain(newQuestion)
+        .updateIn(
+            ['dataset_query', 'query', 'aggregation'],
+            aggregation => getCount ? ['count'] : aggregation
+        )
+        .updateIn(['display'], display => visualization || display)
+        .updateIn(
+            ['dataset_query', 'query', 'breakout'],
+            breakout => fieldId ? [fieldId] : breakout
+        )
+        .value();
+
+    if (metricId) {
+        return i.assocIn(question, ['dataset_query', 'query', 'aggregation'], ['METRIC', metricId]);
+    }
+
+    if (segmentId) {
+        return i.assocIn(question, ['dataset_query', 'query', 'filter'], ['AND', ['SEGMENT', segmentId]]);
+    }
+
+    return question;
+};
+
+export const getQuestionUrl = getQuestionArgs => `/q#${serializeCardForUrl(getQuestion(getQuestionArgs))}`;
diff --git a/frontend/src/metabase/routes.jsx b/frontend/src/metabase/routes.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..9c06387f7fb15aa19733e1417a491a6cdfed3a97
--- /dev/null
+++ b/frontend/src/metabase/routes.jsx
@@ -0,0 +1,201 @@
+import React, { Component, PropTypes } from "react";
+
+import { Route, IndexRedirect, Redirect } from 'react-router';
+import { routerActions } from 'react-router-redux';
+import { UserAuthWrapper } from 'redux-auth-wrapper';
+
+import { refreshCurrentUser } from "metabase/user";
+import MetabaseSettings from "metabase/lib/settings";
+
+import App from "metabase/App.jsx";
+
+// auth containers
+import ForgotPasswordApp from "metabase/auth/containers/ForgotPasswordApp.jsx";
+import LoginApp from "metabase/auth/containers/LoginApp.jsx";
+import LogoutApp from "metabase/auth/containers/LogoutApp.jsx";
+import PasswordResetApp from "metabase/auth/containers/PasswordResetApp.jsx";
+import GoogleNoAccount from "metabase/auth/components/GoogleNoAccount.jsx";
+
+// main app containers
+import DashboardApp from "metabase/dashboard/containers/DashboardApp.jsx";
+import HomepageApp from "metabase/home/containers/HomepageApp.jsx";
+import EntityBrowser from "metabase/questions/containers/EntityBrowser.jsx";
+import EntityList from "metabase/questions/containers/EntityList.jsx";
+import EditLabels from "metabase/questions/containers/EditLabels.jsx";
+import PulseEditApp from "metabase/pulse/containers/PulseEditApp.jsx";
+import PulseListApp from "metabase/pulse/containers/PulseListApp.jsx";
+import QueryBuilder from "metabase/query_builder/containers/QueryBuilder.jsx";
+import SetupApp from "metabase/setup/containers/SetupApp.jsx";
+import UserSettingsApp from "metabase/user/containers/UserSettingsApp.jsx";
+
+// admin containers
+import DatabaseListApp from "metabase/admin/databases/containers/DatabaseListApp.jsx";
+import DatabaseEditApp from "metabase/admin/databases/containers/DatabaseEditApp.jsx";
+import MetadataEditorApp from "metabase/admin/datamodel/containers/MetadataEditorApp.jsx";
+import MetricApp from "metabase/admin/datamodel/containers/MetricApp.jsx";
+import SegmentApp from "metabase/admin/datamodel/containers/SegmentApp.jsx";
+import RevisionHistoryApp from "metabase/admin/datamodel/containers/RevisionHistoryApp.jsx";
+import AdminPeopleApp from "metabase/admin/people/containers/AdminPeopleApp.jsx";
+import SettingsEditorApp from "metabase/admin/settings/containers/SettingsEditorApp.jsx";
+
+import NotFound from "metabase/components/NotFound.jsx";
+import Unauthorized from "metabase/components/Unauthorized.jsx";
+
+import ReferenceApp from "metabase/reference/containers/ReferenceApp.jsx";
+import ReferenceEntity from "metabase/reference/containers/ReferenceEntity.jsx";
+import ReferenceEntityList from "metabase/reference/containers/ReferenceEntityList.jsx";
+import ReferenceFieldsList from "metabase/reference/containers/ReferenceFieldsList.jsx";
+import ReferenceRevisionsList from "metabase/reference/containers/ReferenceRevisionsList.jsx";
+import ReferenceGettingStartedGuide from "metabase/reference/containers/ReferenceGettingStartedGuide.jsx";
+
+const MetabaseIsSetup = UserAuthWrapper({
+    predicate: authData => !authData.hasSetupToken,
+    failureRedirectPath: "/setup",
+    authSelector: state => ({ hasSetupToken: MetabaseSettings.hasSetupToken() }), // HACK
+    wrapperDisplayName: 'MetabaseIsSetup',
+    allowRedirectBack: false,
+    redirectAction: routerActions.replace,
+});
+
+const UserIsAuthenticated = UserAuthWrapper({
+    failureRedirectPath: '/auth/login',
+    authSelector: state => state.currentUser,
+    wrapperDisplayName: 'UserIsAuthenticated',
+    redirectAction: routerActions.replace,
+});
+
+const UserIsAdmin = UserAuthWrapper({
+    predicate: currentUser => currentUser && currentUser.is_superuser,
+    failureRedirectPath: '/unauthorized',
+    authSelector: state => state.currentUser,
+    allowRedirectBack: false,
+    wrapperDisplayName: 'UserIsAdmin',
+    redirectAction: routerActions.replace,
+});
+
+const UserIsNotAuthenticated = UserAuthWrapper({
+    predicate: currentUser => !currentUser,
+    failureRedirectPath: '/',
+    authSelector: state => state.currentUser,
+    allowRedirectBack: false,
+    wrapperDisplayName: 'UserIsNotAuthenticated',
+    redirectAction: routerActions.replace,
+});
+
+const IsAuthenticated = MetabaseIsSetup(UserIsAuthenticated(({ children }) => children));
+const IsAdmin = MetabaseIsSetup(UserIsAuthenticated(UserIsAdmin(({ children }) => children)));
+const IsNotAuthenticated = MetabaseIsSetup(UserIsNotAuthenticated(({ children }) => children));
+
+export const getRoutes = (store) =>
+    <Route component={App}>
+        {/* SETUP */}
+        <Route path="/setup" component={SetupApp} onEnter={(nextState, replace) => {
+            if (!MetabaseSettings.hasSetupToken()) {
+                replace("/");
+            }
+        }} />
+
+        {/* APP */}
+        <Route onEnter={async (nextState, replace, done) => {
+            await store.dispatch(refreshCurrentUser());
+            done();
+        }}>
+            {/* AUTH */}
+            <Route path="/auth">
+                <IndexRedirect to="/auth/login" />
+                <Route component={IsNotAuthenticated}>
+                    <Route path="login" component={LoginApp} />
+                </Route>
+                <Route path="logout" component={LogoutApp} />
+                <Route path="forgot_password" component={ForgotPasswordApp} />
+                <Route path="reset_password/:token" component={PasswordResetApp} />
+                <Route path="google_no_mb_account" component={GoogleNoAccount} />
+            </Route>
+
+            {/* MAIN */}
+            <Route component={IsAuthenticated}>
+                {/* HOME */}
+                <Route path="/" component={HomepageApp} />
+
+                {/* DASHBOARD */}
+                <Route path="/dash/:dashboardId" component={DashboardApp} />
+
+                {/* QUERY BUILDER */}
+                <Route path="/card/:cardId" component={QueryBuilder} />
+                <Route path="/q" component={QueryBuilder} />
+
+                {/* QUESTIONS */}
+                <Route path="/questions" component={EntityBrowser}>
+                    <Route path="edit/labels" component={EditLabels} />
+                    <Route path=":section" component={EntityList} />
+                    <Route path=":section/:slug" component={EntityList} />
+                </Route>
+
+                {/* REFERENCE */}
+                <Route path="/reference" component={ReferenceApp}>
+                    <IndexRedirect to="/reference/guide" />
+                    <Route path="guide" component={ReferenceGettingStartedGuide} />
+                    <Route path="metrics" component={ReferenceEntityList} />
+                    <Route path="metrics/:metricId" component={ReferenceEntity} />
+                    <Route path="metrics/:metricId/questions" component={ReferenceEntityList} />
+                    <Route path="metrics/:metricId/revisions" component={ReferenceRevisionsList} />
+                    <Route path="segments" component={ReferenceEntityList} />
+                    <Route path="segments/:segmentId" component={ReferenceEntity} />
+                    <Route path="segments/:segmentId/fields" component={ReferenceFieldsList} />
+                    <Route path="segments/:segmentId/fields/:fieldId" component={ReferenceEntity} />
+                    <Route path="segments/:segmentId/questions" component={ReferenceEntityList} />
+                    <Route path="segments/:segmentId/revisions" component={ReferenceRevisionsList} />
+                    <Route path="databases" component={ReferenceEntityList} />
+                    <Route path="databases/:databaseId" component={ReferenceEntity} />
+                    <Route path="databases/:databaseId/tables" component={ReferenceEntityList} />
+                    <Route path="databases/:databaseId/tables/:tableId" component={ReferenceEntity} />
+                    <Route path="databases/:databaseId/tables/:tableId/fields" component={ReferenceFieldsList} />
+                    <Route path="databases/:databaseId/tables/:tableId/fields/:fieldId" component={ReferenceEntity} />
+                    <Route path="databases/:databaseId/tables/:tableId/questions" component={ReferenceEntityList} />
+                </Route>
+
+                {/* PULSE */}
+                <Route path="/pulse" component={PulseListApp} />
+                <Route path="/pulse/create" component={PulseEditApp} />
+                <Route path="/pulse/:pulseId" component={PulseEditApp} />
+
+                {/* USER */}
+                <Route path="/user/edit_current" component={UserSettingsApp} />
+            </Route>
+
+            {/* ADMIN */}
+            <Route path="/admin" component={IsAdmin}>
+                <IndexRedirect to="/admin/settings" />
+
+                <Route path="databases" component={DatabaseListApp} />
+                <Route path="databases/create" component={DatabaseEditApp} />
+                <Route path="databases/:databaseId" component={DatabaseEditApp} />
+
+                <Route path="datamodel">
+                    <Route path="database" component={MetadataEditorApp} />
+                    <Route path="database/:databaseId" component={MetadataEditorApp} />
+                    <Route path="database/:databaseId/:mode" component={MetadataEditorApp} />
+                    <Route path="database/:databaseId/:mode/:tableId" component={MetadataEditorApp} />
+                    <Route path="metric/create" component={MetricApp} />
+                    <Route path="metric/:id" component={MetricApp} />
+                    <Route path="segment/create" component={SegmentApp} />
+                    <Route path="segment/:id" component={SegmentApp} />
+                    <Route path=":entity/:id/revisions" component={RevisionHistoryApp} />
+                </Route>
+
+                <Route path="people" component={AdminPeopleApp} />
+
+                <Route path="settings" component={SettingsEditorApp} />
+                <Route path="settings/:section" component={SettingsEditorApp} />
+            </Route>
+
+            {/* MISC */}
+            <Route path="/unauthorized" component={Unauthorized} />
+            <Route path="/*" component={NotFound} />
+
+            {/* LEGACY */}
+            <Redirect from="/card" to="/questions" />
+            <Redirect from="/card/:cardId/:serializedCard" to="/questions/:cardId#:serializedCard" />
+            <Redirect from="/q/:serializedCard" to="/q#:serializedCard" />
+        </Route>
+    </Route>
diff --git a/frontend/src/metabase/services.js b/frontend/src/metabase/services.js
index a0aaafbcb5d4acf2b2c542bfa1e8bbd219edcbbd..50cc9063c845f475375fb27e5ad60a5f0ddf10f1 100644
--- a/frontend/src/metabase/services.js
+++ b/frontend/src/metabase/services.js
@@ -1,266 +1,11 @@
-import _ from "underscore";
-
-import MetabaseAnalytics from 'metabase/lib/analytics';
-import MetabaseCookies from 'metabase/lib/cookies';
-import * as MetabaseCore from 'metabase/lib/core';
-import MetabaseSettings from 'metabase/lib/settings';
-
-
-var MetabaseServices = angular.module('metabase.services', ['http-auth-interceptor', 'ipCookie', 'metabase.core.services']);
-
-MetabaseServices.factory('AppState', ['$rootScope', '$q', '$location', '$interval', '$timeout', 'ipCookie', 'Session', 'User', 'Settings',
-    function($rootScope, $q, $location, $interval, $timeout, ipCookie, Session, User, Settings) {
-        // this is meant to be a global service used for keeping track of our overall app state
-        // we fire 2 events as things change in the app
-        // 1. appstate:user
-
-        var initPromise;
-        var currentUserPromise;
-
-        var service = {
-
-            model: {
-                setupToken: null,
-                currentUser: null,
-                appContext: 'none',
-                requestedUrl: null
-            },
-
-            init: function() {
-
-                if (!initPromise) {
-                    // hackery to allow MetabaseCookies to tie into Angular
-                    MetabaseCookies.bootstrap($rootScope, $location, ipCookie);
-
-                    var deferred = $q.defer();
-                    initPromise = deferred.promise;
-
-                    // grab our global settings
-                    service.refreshSiteSettings();
-
-                    // just make sure we grab the current user
-                    service.refreshCurrentUser().then(function(user) {
-                        deferred.resolve();
-                    }, function(error) {
-                        deferred.resolve();
-                    });
-                }
-
-                return initPromise;
-            },
-
-            clearState: function() {
-                currentUserPromise = null;
-                service.model.currentUser = null;
-
-                // clear any existing session cookies if they exist
-                ipCookie.remove('metabase.SESSION_ID');
-            },
-
-            refreshCurrentUser: function() {
-
-                // this is meant to be called once on app startup
-                var userRefresh = User.current(function(result) {
-                    service.model.currentUser = result;
-
-                    $rootScope.$broadcast('appstate:user', result);
-
-                }, function(error) {
-                    console.log('unable to get current user', error);
-                });
-
-                // NOTE: every time we refresh the user we update our current promise to ensure that
-                //       we can guarantee we've resolved the current user
-                currentUserPromise = userRefresh.$promise;
-
-                return currentUserPromise;
-            },
-
-            refreshSiteSettings: function() {
-
-                var settingsRefresh = Session.properties(function(settings) {
-
-                    MetabaseSettings.setAll(_.omit(settings, function(value, key, object) {
-                        return (key.indexOf('$') === 0);
-                    }));
-
-                    $rootScope.$broadcast('appstate:site-settings', settings);
-
-                }, function(error) {
-                    console.log('unable to get site settings', error);
-                });
-
-                return settingsRefresh.$promise;
-            },
-
-            // This function performs whatever state cleanup and next steps are required when a user tries to access
-            // something they are not allowed to.
-            invalidAccess: function(user, url, message) {
-                $location.path('/unauthorized/');
-            },
-
-            setAppContext: function(appContext) {
-                service.model.appContext = appContext;
-                $rootScope.$broadcast('appstate:context-changed', service.model.appContext);
-            },
-
-            locationChanged: function(event) {
-                // establish our application context based on the route (URI)
-                // valid app contexts are: 'setup', 'auth', 'main', 'admin', or 'unknown'
-                var routeContext;
-                if ($location.path().indexOf('/auth/') === 0) {
-                    routeContext = 'auth';
-                } else if ($location.path().indexOf('/setup/') === 0) {
-                    routeContext = 'setup';
-                } else if ($location.path().indexOf('/admin/') === 0) {
-                    routeContext = 'admin';
-                } else if ($location.path() === '/') {
-                    routeContext = 'home';
-                } else {
-                    routeContext = 'main';
-                }
-
-                // if the context of the app has changed due to this route change then send out an event
-                if (service.model.appContext !== routeContext) {
-                    service.setAppContext(routeContext);
-                }
-
-                // this code is here to ensure that we have resolved our currentUser BEFORE we execute any other
-                // code meant to establish app context based on the current route
-                if (currentUserPromise) {
-                    currentUserPromise.then(function(user) {
-                        service.locationChangedImpl(event);
-                    }, function(error) {
-                        service.locationChangedImpl(event);
-                    });
-                } else {
-                    service.locationChangedImpl(event);
-                }
-            },
-
-            locationChangedImpl: function(event) {
-                // whenever we have a route change (including initial page load) we need to establish some context
-
-                // handle routing protections for /setup/
-                if ($location.path().indexOf('/setup') === 0 && !MetabaseSettings.hasSetupToken()) {
-                    // someone trying to access setup process without having a setup token, so block that.
-                    $location.path('/');
-                    return;
-                } else if ($location.path().indexOf('/setup') !== 0 && MetabaseSettings.hasSetupToken()) {
-                    // someone who has a setup token but isn't routing to setup yet, so send them there!
-                    $location.path('/setup/');
-                    return;
-                }
-
-                // if we don't have a current user then the only sensible destination is the login page
-                if (!service.model.currentUser) {
-                    // make sure we clear out any current state just to be safe
-                    service.clearState();
-
-                    if ($location.path().indexOf('/auth/') !== 0 && $location.path().indexOf('/setup/') !== 0) {
-                        // if the user is asking for a url outside of /auth/* then record the url then send them
-                        // to login page, otherwise we will let the user continue on to their requested page
-                        service.model.requestedUrl = $location.path();
-                        $location.path('/auth/login');
-                    }
-
-                    return;
-                }
-
-                if ($location.path().indexOf('/admin/') === 0) {
-                    // the user is trying to change to a superuser page
-                    if (!service.model.currentUser.is_superuser) {
-                        service.invalidAccess(service.model.currentUser, $location.url(), "user is not a superuser!!!");
-                        return;
-                    }
-
-                }
-            },
-
-            redirectAfterLogin: function() {
-                if (service.model.requestedUrl) {
-                    $location.path(service.model.requestedUrl);
-                    delete service.model.requestedUrl;
-                } else {
-                    $location.path('/');
-                }
-            }
-        };
-
-        // listen for location changes and use that as a trigger for page view tracking
-        $rootScope.$on('$locationChangeSuccess', function(event) {
-        service.locationChanged(event);
-            // NOTE: we are only taking the path right now to avoid accidentally grabbing sensitive data like table/field ids
-            MetabaseAnalytics.trackPageView($location.path());
-        });
-
-        // login just took place, so lets force a refresh of the current user
-        $rootScope.$on("appstate:login", function(event, session_id) {
-            service.refreshCurrentUser();
-        });
-
-        // logout just took place, do some cleanup
-        $rootScope.$on("appstate:logout", function(event, session_id) {
-
-            // clear out any current state
-            service.clearState();
-
-            // NOTE that we don't really care about callbacks in this case
-            Session.delete({
-                'session_id': session_id
-            });
-        });
-
-        // enable / disable GA based on opt-out of anonymous tracking
-        $rootScope.$on("appstate:site-settings", function(event, settings) {
-            const ga_code = MetabaseSettings.get('ga_code');
-            if (MetabaseSettings.isTrackingEnabled()) {
-                // we are doing tracking
-                window['ga-disable-'+ga_code] = null;
-            } else {
-                // tracking is disabled
-                window['ga-disable-'+ga_code] = true;
-            }
-        });
-
-        // NOTE: the below events are generated from the http-auth-interceptor which listens on our $http calls
-        //       and intercepts calls that result in a 401 or 403 so that we can handle them here.  You must be
-        //       careful to consider the implications of this because any endpoint that returns a 401/403 can
-        //       have its call stack interrupted now and handled here instead of its normal callback sequence.
-
-        // $http interceptor received a 401 response
-        $rootScope.$on("event:auth-loginRequired", function() {
-            // this is effectively just like a logout, we want to reset everything to a base state, then force login
-            service.clearState();
-
-            // this is ridiculously stupid.  we have to wait (300ms) for the cookie to actually be set in the browser :(
-            $timeout(function() {
-                $location.path('/auth/login');
-            }, 300);
-        });
-
-        // $http interceptor received a 403 response
-        $rootScope.$on("event:auth-forbidden", function() {
-            $location.path("/unauthorized");
-        });
-
-        return service;
-    }
-]);
-
-MetabaseServices.service('MetabaseCore', ['User', function(User) {
-    // this just makes it easier to access the current user
-    this.currentUser = User.current;
-
-    // copy over MetabaseCore properties and functions
-    angular.forEach(MetabaseCore, (value, key) => this[key] = value);
-}]);
+import 'angular-http-auth';
 
+angular.module('metabase.services', ['metabase.core.services', 'http-auth-interceptor']);
 
 // API Services
-var CoreServices = angular.module('metabase.core.services', ['ngResource', 'ngCookies']);
+var CoreServices = angular.module('metabase.core.services', ['ngResource']);
 
-CoreServices.factory('Activity', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Activity', ['$resource', function($resource) {
     return $resource('/api/activity', {}, {
         list: {
             method: 'GET',
@@ -274,7 +19,7 @@ CoreServices.factory('Activity', ['$resource', '$cookies', function($resource, $
     });
 }]);
 
-CoreServices.factory('Card', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Card', ['$resource', function($resource) {
     return $resource('/api/card/:cardId', {}, {
         list: {
             url: '/api/card',
@@ -335,7 +80,7 @@ CoreServices.factory('Card', ['$resource', '$cookies', function($resource, $cook
     });
 }]);
 
-CoreServices.factory('Dashboard', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Dashboard', ['$resource', function($resource) {
     return $resource('/api/dashboard/:dashId', {}, {
         list: {
             url:'/api/dashboard',
@@ -401,7 +146,7 @@ CoreServices.factory('Slack', ['$resource', function($resource) {
     });
 }]);
 
-CoreServices.factory('Metabase', ['$resource', '$cookies', 'MetabaseCore', function($resource, $cookies, MetabaseCore) {
+CoreServices.factory('Metabase', ['$resource', function($resource) {
     return $resource('/api/meta', {}, {
         db_list: {
             url: '/api/database/',
@@ -607,7 +352,7 @@ CoreServices.factory('Metabase', ['$resource', '$cookies', 'MetabaseCore', funct
     });
 }]);
 
-CoreServices.factory('Pulse', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Pulse', ['$resource', function($resource) {
     return $resource('/api/pulse/:pulseId', {}, {
         list: {
             url: '/api/pulse',
@@ -646,7 +391,7 @@ CoreServices.factory('Pulse', ['$resource', '$cookies', function($resource, $coo
     });
 }]);
 
-CoreServices.factory('Segment', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Segment', ['$resource', function($resource) {
     return $resource('/api/segment/:segmentId', {}, {
         list: {
             url: '/api/segment',
@@ -672,7 +417,7 @@ CoreServices.factory('Segment', ['$resource', '$cookies', function($resource, $c
     });
 }]);
 
-CoreServices.factory('Metric', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Metric', ['$resource', function($resource) {
     return $resource('/api/metric/:metricId', {}, {
         list: {
             url: '/api/metric',
@@ -761,7 +506,7 @@ CoreServices.factory('Label', ['$resource', function($resource) {
     });
 }]);
 
-CoreServices.factory('Session', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Session', ['$resource', function($resource) {
     return $resource('/api/session/', {}, {
         create: {
             method: 'POST',
@@ -825,7 +570,7 @@ CoreServices.factory('Settings', ['$resource', function($resource) {
     });
 }]);
 
-CoreServices.factory('Setup', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Setup', ['$resource', function($resource) {
     return $resource('/api/setup/', {}, {
         create: {
             method: 'POST'
@@ -837,7 +582,7 @@ CoreServices.factory('Setup', ['$resource', '$cookies', function($resource, $coo
     });
 }]);
 
-CoreServices.factory('User', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('User', ['$resource', function($resource) {
     return $resource('/api/user/:userId', {}, {
         create: {
             url: '/api/user',
@@ -897,7 +642,7 @@ CoreServices.factory('User', ['$resource', '$cookies', function($resource, $cook
     });
 }]);
 
-CoreServices.factory('Util', ['$resource', '$cookies', function($resource, $cookies) {
+CoreServices.factory('Util', ['$resource', function($resource) {
     return $resource('/api/util/', {}, {
         password_check: {
             url: '/api/util/password_check',
diff --git a/frontend/src/metabase/setup/components/CollapsedStep.jsx b/frontend/src/metabase/setup/components/CollapsedStep.jsx
index 434b126975a18b48ee0b602e6db2093e9e61118b..90ecad4374d914cc10adc81ceab900dec7a0a9e3 100644
--- a/frontend/src/metabase/setup/components/CollapsedStep.jsx
+++ b/frontend/src/metabase/setup/components/CollapsedStep.jsx
@@ -1,19 +1,20 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import cx from "classnames";
 import Icon from "metabase/components/Icon.jsx";
-import { setActiveStep } from "../actions";
 
 
-export default class SetupCollapsedStep extends Component {
+export default class CollapsedStep extends Component {
     static propTypes = {
         stepNumber: PropTypes.number.isRequired,
         stepText: PropTypes.string.isRequired,
-        isCompleted: PropTypes.bool.isRequired
+        setActiveStep: PropTypes.func.isRequired,
+        isCompleted: PropTypes.bool.isRequired,
     }
 
     gotoStep() {
         if (this.props.isCompleted) {
-            this.props.dispatch(setActiveStep(this.props.stepNumber));
+            this.props.setActiveStep(this.props.stepNumber);
         }
     }
 
diff --git a/frontend/src/metabase/setup/components/DatabaseStep.jsx b/frontend/src/metabase/setup/components/DatabaseStep.jsx
index ddca5e33bc60c3b941b71db55885d511d59d4fc6..5bf60b9c2340522889f31d8ed4dcae340403884b 100644
--- a/frontend/src/metabase/setup/components/DatabaseStep.jsx
+++ b/frontend/src/metabase/setup/components/DatabaseStep.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -9,8 +10,6 @@ import FormField from "metabase/components/form/FormField.jsx";
 import MetabaseAnalytics from "metabase/lib/analytics";
 import MetabaseSettings from "metabase/lib/settings";
 
-import { setDatabaseDetails, validateDatabase } from "../actions";
-
 import _ from "underscore";
 
 export default class DatabaseStep extends Component {
@@ -20,8 +19,13 @@ export default class DatabaseStep extends Component {
     }
 
     static propTypes = {
-        dispatch: PropTypes.func.isRequired,
-        stepNumber: PropTypes.number.isRequired
+        stepNumber: PropTypes.number.isRequired,
+        activeStep: PropTypes.number.isRequired,
+        setActiveStep: PropTypes.func.isRequired,
+
+        databaseDetails: PropTypes.object,
+        validateDatabase: PropTypes.func.isRequired,
+        setDatabaseDetails: PropTypes.func.isRequired,
     }
 
     chooseDatabaseEngine() {
@@ -44,7 +48,7 @@ export default class DatabaseStep extends Component {
 
         try {
             // validate the details before we move forward
-            await this.props.dispatch(validateDatabase(details));
+            await this.props.validateDatabase(details);
 
         } catch (error) {
             let formError = error;
@@ -52,7 +56,7 @@ export default class DatabaseStep extends Component {
 
             try {
                 // ssl connection failed, lets try non-ssl
-                await this.props.dispatch(validateDatabase(details));
+                await this.props.validateDatabase(details);
 
                 formError = null;
 
@@ -72,10 +76,10 @@ export default class DatabaseStep extends Component {
         }
 
         // now that they are good, store them
-        this.props.dispatch(setDatabaseDetails({
+        this.props.setDatabaseDetails({
             'nextStep': this.props.stepNumber + 1,
             'details': details
-        }));
+        });
 
         MetabaseAnalytics.trackEvent('Setup', 'Database Step', this.state.engine);
     }
@@ -85,10 +89,10 @@ export default class DatabaseStep extends Component {
             'engine': ""
         });
 
-        this.props.dispatch(setDatabaseDetails({
+        this.props.setDatabaseDetails({
             'nextStep': this.props.stepNumber + 1,
             'details': null
-        }));
+        });
 
         MetabaseAnalytics.trackEvent('Setup', 'Database Step');
     }
@@ -109,7 +113,7 @@ export default class DatabaseStep extends Component {
     }
 
     render() {
-        let { activeStep, databaseDetails, dispatch, stepNumber } = this.props;
+        let { activeStep, databaseDetails, setActiveStep, stepNumber } = this.props;
         let { engine, formError } = this.state;
         let engines = MetabaseSettings.get('engines');
 
@@ -119,7 +123,7 @@ export default class DatabaseStep extends Component {
         }
 
         if (activeStep !== stepNumber) {
-            return (<CollapsedStep dispatch={dispatch} stepNumber={stepNumber} stepText={stepText} isCompleted={activeStep > stepNumber}></CollapsedStep>)
+            return (<CollapsedStep stepNumber={stepNumber} stepText={stepText} isCompleted={activeStep > stepNumber} setActiveStep={setActiveStep}></CollapsedStep>)
         } else {
             return (
                 <section className="SetupStep rounded full relative SetupStep--active">
diff --git a/frontend/src/metabase/setup/components/PreferencesStep.jsx b/frontend/src/metabase/setup/components/PreferencesStep.jsx
index 95fac785d199cd8838534d81d83245b5f379cd21..70a21fe00bca237c6ff46e3d2c2abdae6a931c00 100644
--- a/frontend/src/metabase/setup/components/PreferencesStep.jsx
+++ b/frontend/src/metabase/setup/components/PreferencesStep.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 
 import MetabaseAnalytics from "metabase/lib/analytics";
@@ -6,33 +7,38 @@ import Toggle from "metabase/components/Toggle.jsx";
 
 import StepTitle from './StepTitle.jsx';
 import CollapsedStep from "./CollapsedStep.jsx";
-import { setAllowTracking, submitSetup } from "../actions";
 
 
 export default class PreferencesStep extends Component {
 
     static propTypes = {
-        dispatch: PropTypes.func.isRequired,
-        stepNumber: PropTypes.number.isRequired
+        stepNumber: PropTypes.number.isRequired,
+        activeStep: PropTypes.number.isRequired,
+        setActiveStep: PropTypes.func.isRequired,
+
+        allowTracking: PropTypes.bool.isRequired,
+        setAllowTracking: PropTypes.func.isRequired,
+        setupComplete: PropTypes.bool.isRequired,
+        submitSetup: PropTypes.func.isRequired,
     }
 
     toggleTracking() {
         let { allowTracking } = this.props;
 
-        this.props.dispatch(setAllowTracking(!allowTracking));
+        this.props.setAllowTracking(!allowTracking);
     }
 
     async formSubmitted(e) {
         e.preventDefault();
 
         // okay, this is the big one.  we actually submit everything to the api now and complete the process.
-        this.props.dispatch(submitSetup());
+        this.props.submitSetup();
 
         MetabaseAnalytics.trackEvent('Setup', 'Preferences Step', this.props.allowTracking);
     }
 
     render() {
-        let { activeStep, allowTracking, setupComplete, stepNumber } = this.props;
+        let { activeStep, allowTracking, setupComplete, stepNumber, setActiveStep } = this.props;
         const { tag } = MetabaseSettings.get('version');
 
         let stepText = 'Usage data preferences';
@@ -41,7 +47,7 @@ export default class PreferencesStep extends Component {
         }
 
         if (activeStep !== stepNumber || setupComplete) {
-            return (<CollapsedStep stepNumber={stepNumber} stepText={stepText} isCompleted={setupComplete}></CollapsedStep>)
+            return (<CollapsedStep stepNumber={stepNumber} stepText={stepText} isCompleted={setupComplete} setActiveStep={setActiveStep}></CollapsedStep>)
         } else {
             return (
                 <section className="SetupStep rounded full relative SetupStep--active">
diff --git a/frontend/src/metabase/setup/components/Setup.jsx b/frontend/src/metabase/setup/components/Setup.jsx
index e7aab9dcdc2e666e1a927bddfe7ba35eb40eed78..0437ae223d8f347d212824f1b20ecdf9441c0c09 100644
--- a/frontend/src/metabase/setup/components/Setup.jsx
+++ b/frontend/src/metabase/setup/components/Setup.jsx
@@ -1,4 +1,6 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 
 import LogoIcon from 'metabase/components/LogoIcon.jsx';
 import NewsletterForm from 'metabase/components/NewsletterForm.jsx';
@@ -9,8 +11,6 @@ import UserStep from './UserStep.jsx';
 import DatabaseStep from './DatabaseStep.jsx';
 import PreferencesStep from './PreferencesStep.jsx';
 
-import { setActiveStep } from '../actions';
-
 const WELCOME_STEP_NUMBER = 0;
 const USER_STEP_NUMBER = 1;
 const DATABASE_STEP_NUMBER = 2;
@@ -19,11 +19,14 @@ const PREFERENCES_STEP_NUMBER = 3;
 
 export default class Setup extends Component {
     static propTypes = {
-        dispatch: PropTypes.func.isRequired
+        activeStep: PropTypes.number.isRequired,
+        setupComplete: PropTypes.bool.isRequired,
+        userDetails: PropTypes.object,
+        setActiveStep: PropTypes.func.isRequired,
     }
 
     completeWelcome() {
-        this.props.dispatch(setActiveStep(USER_STEP_NUMBER));
+        this.props.setActiveStep(USER_STEP_NUMBER);
         MetabaseAnalytics.trackEvent('Setup', 'Welcome');
     }
 
@@ -79,10 +82,10 @@ export default class Setup extends Component {
                                 <section className="SetupStep rounded SetupStep--active flex flex-column layout-centered p4">
                                     <h1 style={{fontSize: "xx-large"}} className="text-light pt2 pb2">You're all set up!</h1>
                                     <div className="pt4">
-                                        <NewsletterForm initialEmail={userDetails.email} />
+                                        <NewsletterForm initialEmail={userDetails && userDetails.email} />
                                     </div>
                                     <div className="pt4 pb2">
-                                        <a className="Button Button--primary" href="/?new" onClick={this.completeSetup.bind(this)}>Take me to Metabase</a>
+                                        <Link to="/?new" className="Button Button--primary" onClick={this.completeSetup.bind(this)}>Take me to Metabase</Link>
                                     </div>
                                 </section>
                             : null }
diff --git a/frontend/src/metabase/setup/components/StepTitle.jsx b/frontend/src/metabase/setup/components/StepTitle.jsx
index f23e76e2a6c29f09207903d132fd73704659f543..3f1cf52ba8cc5521987b58e5bbc109ab0ace4e53 100644
--- a/frontend/src/metabase/setup/components/StepTitle.jsx
+++ b/frontend/src/metabase/setup/components/StepTitle.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from 'react'
 import Icon from "metabase/components/Icon.jsx";
 
diff --git a/frontend/src/metabase/setup/components/UserStep.jsx b/frontend/src/metabase/setup/components/UserStep.jsx
index 37673f9511fe60dcdf62ee09785a941e819c5eb8..0c44f1ac49df64f3e5f28063ec6763b0a9a73eb7 100644
--- a/frontend/src/metabase/setup/components/UserStep.jsx
+++ b/frontend/src/metabase/setup/components/UserStep.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -11,8 +12,6 @@ import MetabaseUtils from "metabase/lib/utils";
 import StepTitle from './StepTitle.jsx'
 import CollapsedStep from "./CollapsedStep.jsx";
 
-import { setUserDetails, validatePassword } from "../actions";
-
 import _ from "underscore";
 import cx from "classnames";
 
@@ -23,8 +22,13 @@ export default class UserStep extends Component {
     }
 
     static propTypes = {
-        dispatch: PropTypes.func.isRequired,
-        stepNumber: PropTypes.number.isRequired
+        stepNumber: PropTypes.number.isRequired,
+        activeStep: PropTypes.number.isRequired,
+        setActiveStep: PropTypes.func.isRequired,
+
+        userDetails: PropTypes.object,
+        setUserDetails: PropTypes.func.isRequired,
+        validatePassword: PropTypes.func.isRequired,
     }
 
     validateForm() {
@@ -50,7 +54,7 @@ export default class UserStep extends Component {
 
     async onPasswordBlur() {
         try {
-            await this.props.dispatch(validatePassword(ReactDOM.findDOMNode(this.refs.password).value));
+            await this.props.validatePassword(ReactDOM.findDOMNode(this.refs.password).value);
 
             this.setState({
                 passwordError: null,
@@ -98,7 +102,7 @@ export default class UserStep extends Component {
             return;
         }
 
-        this.props.dispatch(setUserDetails({
+        this.props.setUserDetails({
             'nextStep': this.props.stepNumber + 1,
             'details': {
                 'first_name': ReactDOM.findDOMNode(this.refs.firstName).value,
@@ -107,20 +111,20 @@ export default class UserStep extends Component {
                 'password': ReactDOM.findDOMNode(this.refs.password).value,
                 'site_name': ReactDOM.findDOMNode(this.refs.siteName).value
             }
-        }));
+        });
 
         MetabaseAnalytics.trackEvent('Setup', 'User Details Step');
     }
 
     render() {
-        let { activeStep, dispatch, stepNumber, userDetails } = this.props;
+        let { activeStep, setActiveStep, stepNumber, userDetails } = this.props;
         let { formError, passwordError, valid } = this.state;
 
         const passwordComplexityDesc = MetabaseSettings.passwordComplexity();
         const stepText = (activeStep <= stepNumber) ? 'What should we call you?' : 'Hi, ' + userDetails.first_name + '. nice to meet you!';
 
         if (activeStep !== stepNumber) {
-            return (<CollapsedStep dispatch={dispatch} stepNumber={stepNumber} stepText={stepText} isCompleted={activeStep > stepNumber}></CollapsedStep>)
+            return (<CollapsedStep stepNumber={stepNumber} stepText={stepText} isCompleted={activeStep > stepNumber} setActiveStep={setActiveStep}></CollapsedStep>)
         } else {
             return (
                 <section className="SetupStep SetupStep--active rounded full relative">
diff --git a/frontend/src/metabase/setup/containers/SetupApp.jsx b/frontend/src/metabase/setup/containers/SetupApp.jsx
index 4042c816131790ef7f899632f0bce5ad6be88e5e..bd9a7dcba0e481452e87fb0e1977b1af71340859 100644
--- a/frontend/src/metabase/setup/containers/SetupApp.jsx
+++ b/frontend/src/metabase/setup/containers/SetupApp.jsx
@@ -1,10 +1,33 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
 
 import Setup from "../components/Setup.jsx";
+
 import { setupSelectors } from "../selectors";
+import {
+    setUserDetails,
+    validatePassword,
+    setActiveStep,
+    validateDatabase,
+    setDatabaseDetails,
+    setAllowTracking,
+    submitSetup,
+} from "../actions";
+
+const mapStateToProps = setupSelectors;
+
+const mapDispatchToProps = {
+    setUserDetails,
+    validatePassword,
+    setActiveStep,
+    validateDatabase,
+    setDatabaseDetails,
+    setAllowTracking,
+    submitSetup
+};
 
-@connect(setupSelectors)
+@connect(mapStateToProps, mapDispatchToProps)
 export default class SetupApp extends Component {
     render() {
         return <Setup {...this.props} />;
diff --git a/frontend/src/metabase/store.js b/frontend/src/metabase/store.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe73cdfc1d9b1fd7649ff8f5dcade1ba5a36ba62
--- /dev/null
+++ b/frontend/src/metabase/store.js
@@ -0,0 +1,33 @@
+import { combineReducers, applyMiddleware, createStore, compose } from 'redux'
+import { reducer as form } from "redux-form";
+import { routerReducer as routing, routerMiddleware } from 'react-router-redux'
+
+import thunk from "redux-thunk";
+import promise from "redux-promise";
+import logger from "redux-logger";
+
+import { DEBUG } from "metabase/lib/debug";
+
+const devToolsExtension = window.devToolsExtension ? window.devToolsExtension() : (f => f);
+
+let middleware = [thunk, promise];
+if (DEBUG) {
+    middleware.push(logger());
+}
+
+import reducers from './reducers';
+
+export function getStore(history, intialState) {
+    const reducer = combineReducers({
+        ...reducers,
+        form,
+        routing,
+    });
+
+    middleware.push(routerMiddleware(history));
+
+    return createStore(reducer, intialState, compose(
+        applyMiddleware(...middleware),
+        devToolsExtension
+    ));
+}
diff --git a/frontend/src/metabase/user.js b/frontend/src/metabase/user.js
index 4aa015311cb7a3879929613763d04763d9f47722..1871ba606b3134876ff4f2af0b9c05378692bce8 100644
--- a/frontend/src/metabase/user.js
+++ b/frontend/src/metabase/user.js
@@ -4,7 +4,20 @@ import { handleActions } from 'redux-actions';
 
 export const setUser = createAction("SET_USER");
 
+export const refreshCurrentUser = createAction("REFRESH_CURRENT_USER", async function getCurrentUser() {
+    try {
+        let response = await fetch("/api/user/current", { credentials: 'same-origin' });
+        if (response.status === 200) {
+            return await response.json();
+        }
+    } catch (e) {
+        console.warn("couldn't get user", e)
+    }
+    return null;
+})
 
 export const currentUser = handleActions({
-    ["SET_USER"]: { next: (state, { payload }) => payload }
+    ["SET_USER"]: { next: (state, { payload }) => payload },
+    ["REFRESH_CURRENT_USER"]: { next: (state, { payload }) => payload },
+    ["AUTH_LOGOUT"]: { next: (state, { payload }) => null }
 }, null);
diff --git a/frontend/src/metabase/user/actions.js b/frontend/src/metabase/user/actions.js
index d4c77a4349174548322ca451e648d287d55f3d89..0f6bc7f6230bf9803a77468ace51ce5f3bc12058 100644
--- a/frontend/src/metabase/user/actions.js
+++ b/frontend/src/metabase/user/actions.js
@@ -3,9 +3,10 @@ import { createAction } from "redux-actions";
 import { AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
 
 // resource wrappers
-const AppState = new AngularResourceProxy("AppState", ["refreshCurrentUser"]);
+// const AppState = new AngularResourceProxy("AppState", ["refreshCurrentUser"]);
 const UserApi = new AngularResourceProxy("User", ["update", "update_password"]);
 
+import { refreshCurrentUser } from "metabase/user";
 
 // action constants
 export const CHANGE_TAB = 'CHANGE_TAB';
@@ -44,7 +45,8 @@ export const updateUser = createThunkAction(UPDATE_USER, function(user) {
         try {
             await UserApi.update(user);
 
-            AppState.refreshCurrentUser();
+            // AppState.refreshCurrentUser();
+            dispatch(refreshCurrentUser());
 
             return {
                 success: true,
diff --git a/frontend/src/metabase/user/components/SetUserPassword.jsx b/frontend/src/metabase/user/components/SetUserPassword.jsx
index 3a9b9a5eff8f1136bef190330830388b702ce1dd..bcb2c03c3771116bd84d3edf69d467412398288b 100644
--- a/frontend/src/metabase/user/components/SetUserPassword.jsx
+++ b/frontend/src/metabase/user/components/SetUserPassword.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -20,7 +21,8 @@ export default class SetUserPassword extends Component {
 
     static propTypes = {
         submitFn: PropTypes.func.isRequired,
-        user: PropTypes.object
+        user: PropTypes.object,
+        updatePasswordResult: PropTypes.object.isRequired
     };
 
     componentDidMount() {
diff --git a/frontend/src/metabase/user/components/UpdateUserDetails.jsx b/frontend/src/metabase/user/components/UpdateUserDetails.jsx
index f351d330a4007c7142f314ec55da9d518f290159..c5950c24fb0bb5608d98946f78b3bdeb4eb9d01c 100644
--- a/frontend/src/metabase/user/components/UpdateUserDetails.jsx
+++ b/frontend/src/metabase/user/components/UpdateUserDetails.jsx
@@ -1,3 +1,4 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
@@ -19,7 +20,8 @@ export default class UpdateUserDetails extends Component {
 
     static propTypes = {
         submitFn: PropTypes.func.isRequired,
-        user: PropTypes.object
+        user: PropTypes.object,
+        updateUserResult: PropTypes.object.isRequired
     };
 
     componentDidMount() {
diff --git a/frontend/src/metabase/user/components/UserSettings.jsx b/frontend/src/metabase/user/components/UserSettings.jsx
index 9237edcaa30d2e6bc1f84845bee8617583fd212d..a06bc0807cf2e1d45ca535b1f27c8aa9ae6323da 100644
--- a/frontend/src/metabase/user/components/UserSettings.jsx
+++ b/frontend/src/metabase/user/components/UserSettings.jsx
@@ -1,29 +1,31 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import cx from "classnames";
 
 import SetUserPassword from "./SetUserPassword.jsx";
 import UpdateUserDetails from "./UpdateUserDetails.jsx";
 
-import { setTab, updatePassword, updateUser } from "../actions";
-
 
 export default class UserSettings extends Component {
 
     static propTypes = {
         tab: PropTypes.string.isRequired,
-        user: PropTypes.object.isRequired
+        user: PropTypes.object.isRequired,
+        setTab: PropTypes.func.isRequired,
+        updateUser: PropTypes.func.isRequired,
+        updatePassword: PropTypes.func.isRequired,
     };
 
     onSetTab(tab) {
-        this.props.dispatch(setTab(tab));
+        this.props.setTab(tab);
     }
 
     onUpdatePassword(details) {
-        this.props.dispatch(updatePassword(details.user_id, details.password, details.old_password));
+        this.props.updatePassword(details.user_id, details.password, details.old_password);
     }
 
     onUpdateDetails(user) {
-        this.props.dispatch(updateUser(user));
+        this.props.updateUser(user);
     }
 
     render() {
diff --git a/frontend/src/metabase/user/containers/UserSettingsApp.jsx b/frontend/src/metabase/user/containers/UserSettingsApp.jsx
index 942fd39325b65dc581ff03780b7d4997b4b14fc2..971d547953f06267eb1f79694deb960dda97b736 100644
--- a/frontend/src/metabase/user/containers/UserSettingsApp.jsx
+++ b/frontend/src/metabase/user/containers/UserSettingsApp.jsx
@@ -1,9 +1,11 @@
+/* eslint "react/prop-types": "warn" */
 import React, { Component, PropTypes } from "react";
 import { connect } from "react-redux";
 
 import UserSettings from "../components/UserSettings.jsx";
 import { selectors } from "../selectors";
 
+import { setTab, updatePassword, updateUser } from "../actions";
 
 const mapStateToProps = (state, props) => {
     return {
@@ -12,7 +14,13 @@ const mapStateToProps = (state, props) => {
     }
 }
 
-@connect(mapStateToProps)
+const mapDispatchToProps = {
+    setTab,
+    updatePassword,
+    updateUser
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
 export default class UserSettingsApp extends Component {
     render() {
         return <UserSettings {...this.props} />;
diff --git a/frontend/src/metabase/vendor.js b/frontend/src/metabase/vendor.js
index afbfd93a6fc1b3aefec8c5a886b8c5e796578752..f6a74a5fff718fcabadc5030b0e42fc3398e3199 100644
--- a/frontend/src/metabase/vendor.js
+++ b/frontend/src/metabase/vendor.js
@@ -2,11 +2,7 @@ import 'babel-polyfill';
 
 // angular:
 import 'angular';
-import 'angular-cookies';
 import 'angular-resource';
-import 'angular-route';
-
-// angular 3rd-party:
 import 'angular-cookie';
 import 'angular-http-auth';
 
diff --git a/frontend/src/metabase/visualizations/Scalar.jsx b/frontend/src/metabase/visualizations/Scalar.jsx
index 14b89d1d6bbe9918db0db786a6757ed6e177c2cc..87e8e0e799d5aa2b757f8f455249389239ee8033 100644
--- a/frontend/src/metabase/visualizations/Scalar.jsx
+++ b/frontend/src/metabase/visualizations/Scalar.jsx
@@ -1,4 +1,5 @@
 import React, { Component, PropTypes } from "react";
+import { Link } from "react-router";
 import styles from "./Scalar.css";
 
 import Ellipsified from "metabase/components/Ellipsified.jsx";
@@ -166,7 +167,7 @@ export default class Scalar extends Component {
                     {compactScalarValue}
                 </Ellipsified>
                 <Ellipsified className={styles.Title} tooltip={card.name}>
-                    <a className="no-decoration fullscreen-normal-text fullscreen-night-text" href={Urls.card(card.id)}>{card.name}</a>
+                    <Link to={Urls.card(card.id)} className="no-decoration fullscreen-normal-text fullscreen-night-text">{card.name}</Link>
                 </Ellipsified>
             </div>
         );
diff --git a/frontend/src/metabase/visualizations/components/settings/ColorSetting.jsx b/frontend/src/metabase/visualizations/components/settings/ColorSetting.jsx
deleted file mode 100644
index 4a9d93ecd301ab5ca52ad46b5d870556e35346df..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/visualizations/components/settings/ColorSetting.jsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, { Component, PropTypes } from "react";
-
-import Icon from "metabase/components/Icon.jsx";
-import PopoverWithTrigger from "metabase/components/PopoverWithTrigger.jsx";
-
-import { getDefaultColor, getDefaultColorHarmony } from "metabase/lib/visualization_settings";
-
-export default (options = {}) => class ColorSetting extends Component {
-    constructor(props, context) {
-        super(props, context);
-        this.state = {};
-    }
-
-    static propTypes = {};
-    static defaultProps = {};
-
-    setChartColor(color) {
-        const { settings } = this.props;
-
-        if (color === getDefaultColor()) {
-            color = undefined;
-        }
-
-        this.props.onUpdateVisualizationSettings({
-            ...settings,
-            line: {
-                ...(settings.line || {}),
-                lineColor: color,
-                marker_fillColor: color,
-                marker_lineColor: color,
-            },
-            area: {
-                ...(settings.area || {}),
-                fillColor: color
-            },
-            bar: {
-                ...(settings.bar || {}),
-                color: color
-            }
-        });
-
-        this.refs.colorPopover.toggle();
-    }
-
-    render() {
-        var colors = getDefaultColorHarmony();
-
-        // TODO: currently we set all chart type colors to the same value so bar color always works
-        var currentColor = this.props.settings.bar && this.props.settings.bar.color || getDefaultColor();
-        var triggerElement = (
-            <span className="px2 py1 text-bold cursor-pointer text-default flex align-center">
-                <div className="ColorWell rounded bordered" style={{ backgroundColor: currentColor }}></div>
-                Color
-                <Icon className="ml1" name="chevrondown" size={8}/>
-            </span>
-        );
-
-        return (
-            <div className="relative">
-                <span className="GuiBuilder-section-label Query-label">Color</span>
-                <PopoverWithTrigger ref="colorPopover"
-                                    hasArrow={false}
-                                    tetherOptions={{
-                                        attachment: 'middle left',
-                                        targetAttachment: 'middle right',
-                                        targetOffset: '0 0',
-                                        constraints: [{ to: 'window', attachment: 'together', pin: ['left', 'right']}]
-                                    }}
-                                    triggerElement={triggerElement}
-                                    triggerClasses="flex align-center">
-                    <ol className="p1">
-                        {colors.map((color, i) =>
-                            <li key={i} className="CardSettings-colorBlock" style={{ backgroundColor: color }} onClick={() => this.setChartColor(color)}></li>
-                        )}
-                    </ol>
-                </PopoverWithTrigger>
-            </div>
-        );
-    }
-}
diff --git a/frontend/test/karma.conf.js b/frontend/test/karma.conf.js
index b43e2b6f218faf1c217faa331f05c812f30f1e0c..6cdf67a0e5d644f20d1c5ef512f1ef22dd7e1ec8 100644
--- a/frontend/test/karma.conf.js
+++ b/frontend/test/karma.conf.js
@@ -8,14 +8,13 @@ module.exports = function(config) {
         basePath: '../',
         files: [
             'test/metabase-bootstrap.js',
-            '../resources/frontend_client/app/dist/vendor.bundle.js',
-            '../resources/frontend_client/app/dist/app.bundle.js',
             '../node_modules/angular-mocks/angular-mocks.js',
             'test/unit/**/*.spec.js'
         ],
         exclude: [
         ],
         preprocessors: {
+            'test/metabase-bootstrap.js': ['webpack'],
             'test/unit/**/*.spec.js': ['webpack']
         },
         frameworks: [
diff --git a/frontend/test/metabase-bootstrap.js b/frontend/test/metabase-bootstrap.js
index f3b97f4c0c87d6907604917c0a705db513bd40e1..8e284485462c1a014a998bfdd19f8a691e4e1aab 100644
--- a/frontend/test/metabase-bootstrap.js
+++ b/frontend/test/metabase-bootstrap.js
@@ -1,3 +1,5 @@
+import "metabase/vendor";
+
 window.MetabaseBootstrap = {
   "timezones": [
     "GMT",
diff --git a/frontend/test/unit/reference/selectors.spec.js b/frontend/test/unit/reference/selectors.spec.js
deleted file mode 100644
index 80ce1f545ec65a89347e913c459d726958f1b041..0000000000000000000000000000000000000000
--- a/frontend/test/unit/reference/selectors.spec.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import { databaseToForeignKeys, buildBreadcrumbs } from 'metabase/reference/selectors';
-
-describe("Reference selectors.js", () => {
-    describe("databaseToForeignKeys()", () => {
-        it("should build foreignKey viewmodels from database", () => {
-            const database = {
-                tables_lookup: {
-                    1: {
-                        id: 1,
-                        display_name: 'foo',
-                        schema: 'PUBLIC',
-                        fields_lookup: {
-                            1: {
-                                id: 1,
-                                special_type: 'id',
-                                display_name: 'bar',
-                                description: 'foobar'
-                            }
-                        }
-                    },
-                    2: {
-                        id: 2,
-                        display_name: 'bar',
-                        schema: 'public',
-                        fields_lookup: {
-                            2: {
-                                id: 2,
-                                special_type: 'id',
-                                display_name: 'foo',
-                                description: 'barfoo'
-                            }
-                        }
-                    },
-                    3: {
-                        id: 3,
-                        display_name: 'boo',
-                        schema: 'TEST',
-                        fields_lookup: {
-                            3: {
-                                id: 3,
-                                display_name: 'boo',
-                                description: 'booboo'
-                            }
-                        }
-                    }
-                }
-            };
-
-            const foreignKeys = databaseToForeignKeys(database);
-
-            expect(foreignKeys).toEqual({
-                1: { id: 1, name: 'Public.foo → bar', description: 'foobar' },
-                2: { id: 2, name: 'bar → foo', description: 'barfoo' }
-            });
-        });
-    });
-
-    describe("buildBreadcrumbs()", () => {
-        const section1 = {
-            id: 1,
-            breadcrumb: 'section1'
-        };
-
-        const section2 = {
-            id: 2,
-            breadcrumb: 'section2',
-            parent: section1
-        };
-
-        const section3 = {
-            id: 3,
-            breadcrumb: 'section3',
-            parent: section2
-        };
-
-        const section4 = {
-            id: 4,
-            breadcrumb: 'section4',
-            parent: section3
-        };
-
-        const section5 = {
-            id: 5,
-            breadcrumb: 'section5',
-            parent: section4
-        };
-
-        it("should build correct breadcrumbs from parent section", () => {
-            const breadcrumbs = buildBreadcrumbs(section1);
-            expect(breadcrumbs).toEqual([
-                [ 'section1' ]
-            ]);
-        });
-
-        it("should build correct breadcrumbs from child section", () => {
-            const breadcrumbs = buildBreadcrumbs(section3);
-            expect(breadcrumbs).toEqual([
-                [ 'section1', 1 ],
-                [ 'section2', 2 ],
-                [ 'section3' ]
-            ]);
-        });
-
-        it("should keep at most 3 highest level breadcrumbs", () => {
-            const breadcrumbs = buildBreadcrumbs(section5);
-            expect(breadcrumbs).toEqual([
-                [ 'section3', 3 ],
-                [ 'section4', 4 ],
-                [ 'section5' ]
-            ]);
-        });
-    });
-});
diff --git a/frontend/test/unit/reference/utils.spec.js b/frontend/test/unit/reference/utils.spec.js
index 2dc22dc32d1181c75d1611f2646477fa4f9fb42e..13cc7ae20c279f2c6bc0b8154d7c6de90e345b6f 100644
--- a/frontend/test/unit/reference/utils.spec.js
+++ b/frontend/test/unit/reference/utils.spec.js
@@ -2,7 +2,10 @@ import {
     tryFetchData,
     tryUpdateData,
     tryUpdateFields,
-    separateTablesBySchema
+    buildBreadcrumbs,
+    databaseToForeignKeys,
+    separateTablesBySchema,
+    getQuestion
 } from 'metabase/reference/utils';
 
 describe("Reference utils.js", () => {
@@ -139,6 +142,116 @@ describe("Reference utils.js", () => {
         });
     });
 
+    describe("databaseToForeignKeys()", () => {
+        it("should build foreignKey viewmodels from database", () => {
+            const database = {
+                tables_lookup: {
+                    1: {
+                        id: 1,
+                        display_name: 'foo',
+                        schema: 'PUBLIC',
+                        fields_lookup: {
+                            1: {
+                                id: 1,
+                                special_type: 'id',
+                                display_name: 'bar',
+                                description: 'foobar'
+                            }
+                        }
+                    },
+                    2: {
+                        id: 2,
+                        display_name: 'bar',
+                        schema: 'public',
+                        fields_lookup: {
+                            2: {
+                                id: 2,
+                                special_type: 'id',
+                                display_name: 'foo',
+                                description: 'barfoo'
+                            }
+                        }
+                    },
+                    3: {
+                        id: 3,
+                        display_name: 'boo',
+                        schema: 'TEST',
+                        fields_lookup: {
+                            3: {
+                                id: 3,
+                                display_name: 'boo',
+                                description: 'booboo'
+                            }
+                        }
+                    }
+                }
+            };
+
+            const foreignKeys = databaseToForeignKeys(database);
+
+            expect(foreignKeys).toEqual({
+                1: { id: 1, name: 'Public.foo → bar', description: 'foobar' },
+                2: { id: 2, name: 'bar → foo', description: 'barfoo' }
+            });
+        });
+    });
+
+    describe("buildBreadcrumbs()", () => {
+        const section1 = {
+            id: 1,
+            breadcrumb: 'section1'
+        };
+
+        const section2 = {
+            id: 2,
+            breadcrumb: 'section2',
+            parent: section1
+        };
+
+        const section3 = {
+            id: 3,
+            breadcrumb: 'section3',
+            parent: section2
+        };
+
+        const section4 = {
+            id: 4,
+            breadcrumb: 'section4',
+            parent: section3
+        };
+
+        const section5 = {
+            id: 5,
+            breadcrumb: 'section5',
+            parent: section4
+        };
+
+        it("should build correct breadcrumbs from parent section", () => {
+            const breadcrumbs = buildBreadcrumbs(section1);
+            expect(breadcrumbs).toEqual([
+                [ 'section1' ]
+            ]);
+        });
+
+        it("should build correct breadcrumbs from child section", () => {
+            const breadcrumbs = buildBreadcrumbs(section3);
+            expect(breadcrumbs).toEqual([
+                [ 'section1', 1 ],
+                [ 'section2', 2 ],
+                [ 'section3' ]
+            ]);
+        });
+
+        it("should keep at most 3 highest level breadcrumbs", () => {
+            const breadcrumbs = buildBreadcrumbs(section5);
+            expect(breadcrumbs).toEqual([
+                [ 'section3', 3 ],
+                [ 'section4', 4 ],
+                [ 'section5' ]
+            ]);
+        });
+    });
+
     describe("tablesToSchemaSeparatedTables()", () => {
         it("should add schema separator to appropriate locations", () => {
             const tables = {
@@ -172,4 +285,162 @@ describe("Reference utils.js", () => {
             ]);
         });
     });
+
+    describe("getQuestion()", () => {
+        const getNewQuestion = ({
+            database = 1,
+            table = 2,
+            display = "table",
+            aggregation = [ "rows" ],
+            breakout = [],
+            filter = []
+        }) => ({
+            "name": null,
+            "public_perms": 0,
+            "display": display,
+            "visualization_settings": {},
+            "dataset_query": {
+                "database": database,
+                "type": "query",
+                "query": {
+                    "source_table": table,
+                    "aggregation": aggregation,
+                    "breakout": breakout,
+                    "filter": filter
+                }
+            }
+        });
+
+        it("should generate correct question for table raw data", () => {
+            const question = getQuestion({
+                dbId: 3,
+                tableId: 4
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 3,
+                table: 4
+            }));
+        });
+
+        it("should generate correct question for table counts", () => {
+            const question = getQuestion({
+                dbId: 3,
+                tableId: 4,
+                getCount: true
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 3,
+                table: 4,
+                aggregation: [ "count" ]
+            }));
+        });
+
+        it("should generate correct question for field raw data", () => {
+            const question = getQuestion({
+                dbId: 3,
+                tableId: 4,
+                fieldId: 5
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 3,
+                table: 4,
+                breakout: [ 5 ]
+            }));
+        });
+
+        it("should generate correct question for field group by bar chart", () => {
+            const question = getQuestion({
+                dbId: 3,
+                tableId: 4,
+                fieldId: 5,
+                getCount: true,
+                visualization: 'bar'
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 3,
+                table: 4,
+                display: 'bar',
+                breakout: [ 5 ],
+                aggregation: [ "count" ]
+            }));
+        });
+
+        it("should generate correct question for field group by pie chart", () => {
+            const question = getQuestion({
+                dbId: 3,
+                tableId: 4,
+                fieldId: 5,
+                getCount: true,
+                visualization: 'pie'
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 3,
+                table: 4,
+                display: 'pie',
+                breakout: [ 5 ],
+                aggregation: [ "count" ]
+            }));
+        });
+
+        it("should generate correct question for metric raw data", () => {
+            const question = getQuestion({
+                dbId: 1,
+                tableId: 2,
+                metricId: 3
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                aggregation: [ "METRIC", 3 ]
+            }));
+        });
+
+        it("should generate correct question for metric group by fields", () => {
+            const question = getQuestion({
+                dbId: 1,
+                tableId: 2,
+                fieldId: 4,
+                metricId: 3
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                aggregation: [ "METRIC", 3 ],
+                breakout: [ 4 ]
+            }));
+        });
+
+        it("should generate correct question for segment raw data", () => {
+            const question = getQuestion({
+                dbId: 2,
+                tableId: 3,
+                segmentId: 4
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 2,
+                table: 3,
+                filter: [ "AND", [ "SEGMENT", 4 ] ]
+            }));
+        });
+
+        it("should generate correct question for segment counts", () => {
+            const question = getQuestion({
+                dbId: 2,
+                tableId: 3,
+                segmentId: 4,
+                getCount: true
+            });
+
+            expect(question).toEqual(getNewQuestion({
+                database: 2,
+                table: 3,
+                aggregation: [ "count" ],
+                filter: [ "AND", [ "SEGMENT", 4 ] ]
+            }));
+        });
+    });
 });
diff --git a/frontend/test/unit/services.spec.js b/frontend/test/unit/services.spec.js
deleted file mode 100644
index 6007083b972edf3273b10a2c6ed29dc7c568e5ca..0000000000000000000000000000000000000000
--- a/frontend/test/unit/services.spec.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import 'metabase/services';
-
-describe('metabase.services', function() {
-    beforeEach(angular.mock.module('metabase.services'));
-
-    describe('Metabase', function() {
-        it('should return empty list of databases', inject(function(Metabase, $httpBackend) {
-            $httpBackend.expect('GET', '/api/database')
-                .respond(200, '[]');
-
-            Metabase.db_list().$promise.then(function(data) {
-                expect(data.length).toEqual(0);
-            });
-
-            $httpBackend.flush();
-        }));
-    });
-});
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 05b5ec7330cec29ec856f68bee73dad41b4fd965..0c060253bdcb88df04f5b944d2dcdfae28915838 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1119,10 +1119,10 @@
           "version": "6.8.0"
         },
         "babel-runtime": {
-          "version": "6.9.2",
+          "version": "6.11.6",
           "dependencies": {
             "core-js": {
-              "version": "2.4.0"
+              "version": "2.4.1"
             },
             "regenerator-runtime": {
               "version": "0.9.5"
@@ -1133,7 +1133,7 @@
           "version": "6.9.0",
           "dependencies": {
             "babel-traverse": {
-              "version": "6.10.4",
+              "version": "6.12.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -1217,10 +1217,10 @@
               }
             },
             "babylon": {
-              "version": "6.8.3"
+              "version": "6.8.4"
             },
             "lodash": {
-              "version": "4.13.1"
+              "version": "4.14.1"
             }
           }
         }
@@ -1233,10 +1233,10 @@
           "version": "6.8.0"
         },
         "babel-runtime": {
-          "version": "6.9.2",
+          "version": "6.11.6",
           "dependencies": {
             "core-js": {
-              "version": "2.4.0"
+              "version": "2.4.1"
             },
             "regenerator-runtime": {
               "version": "0.9.5"
@@ -1249,10 +1249,10 @@
       "version": "6.9.1",
       "dependencies": {
         "babel-runtime": {
-          "version": "6.9.2"
+          "version": "6.11.6"
         },
         "core-js": {
-          "version": "2.4.0"
+          "version": "2.4.1"
         },
         "regenerator-runtime": {
           "version": "0.9.5"
@@ -1266,10 +1266,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1282,10 +1282,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1298,10 +1298,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1314,10 +1314,10 @@
           "version": "6.10.1",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1328,12 +1328,12 @@
               "version": "6.9.0",
               "dependencies": {
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 }
               }
             },
             "babel-traverse": {
-              "version": "6.10.4",
+              "version": "6.12.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -1380,7 +1380,7 @@
                   "version": "6.8.0"
                 },
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "debug": {
                   "version": "2.2.0",
@@ -1420,7 +1420,7 @@
               }
             },
             "lodash": {
-              "version": "4.13.1"
+              "version": "4.14.1"
             }
           }
         },
@@ -1431,7 +1431,7 @@
               "version": "6.9.0",
               "dependencies": {
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
@@ -1453,10 +1453,10 @@
               "version": "6.8.0"
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1467,15 +1467,15 @@
               "version": "6.9.0",
               "dependencies": {
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
             "babel-traverse": {
-              "version": "6.10.4",
+              "version": "6.12.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -1519,7 +1519,7 @@
                   }
                 },
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "debug": {
                   "version": "2.2.0",
@@ -1546,7 +1546,7 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
@@ -1557,7 +1557,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -1579,7 +1579,7 @@
                       "version": "6.8.0"
                     },
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -1626,7 +1626,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.3"
+                          "version": "6.8.4"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -1660,7 +1660,7 @@
                   "version": "6.11.1",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -1704,7 +1704,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.3"
+                          "version": "6.8.4"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -1741,15 +1741,15 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1760,7 +1760,7 @@
               "version": "6.9.0",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -1844,10 +1844,10 @@
                   }
                 },
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             }
@@ -1857,10 +1857,10 @@
           "version": "6.9.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1873,10 +1873,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -1887,7 +1887,7 @@
               "version": "6.11.1",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -1931,7 +1931,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -1963,7 +1963,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -1976,10 +1976,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2001,15 +2001,15 @@
                   "version": "6.9.0",
                   "dependencies": {
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 },
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2056,7 +2056,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2083,17 +2083,17 @@
                       }
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 }
               }
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2104,7 +2104,7 @@
               "version": "6.11.1",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2148,7 +2148,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2180,7 +2180,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2193,10 +2193,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2206,16 +2206,16 @@
           }
         },
         "babel-plugin-transform-es2015-modules-commonjs": {
-          "version": "6.10.3",
+          "version": "6.11.5",
           "dependencies": {
             "babel-plugin-transform-strict-mode": {
-              "version": "6.8.0"
+              "version": "6.11.3"
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2226,7 +2226,7 @@
               "version": "6.9.0",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2299,10 +2299,10 @@
                   }
                 },
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
@@ -2310,7 +2310,7 @@
               "version": "6.11.1",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2354,7 +2354,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2386,7 +2386,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2411,15 +2411,15 @@
                   "version": "6.9.0",
                   "dependencies": {
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 },
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2463,7 +2463,7 @@
                       }
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2490,7 +2490,7 @@
                       }
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 },
@@ -2501,7 +2501,7 @@
                       "version": "2.0.2"
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     },
                     "to-fast-properties": {
                       "version": "1.0.2"
@@ -2511,10 +2511,10 @@
               }
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2524,7 +2524,7 @@
           }
         },
         "babel-plugin-transform-es2015-parameters": {
-          "version": "6.9.0",
+          "version": "6.11.4",
           "dependencies": {
             "babel-helper-call-delegate": {
               "version": "6.8.0",
@@ -2538,10 +2538,10 @@
               "version": "6.8.0"
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2552,15 +2552,15 @@
               "version": "6.9.0",
               "dependencies": {
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
             "babel-traverse": {
-              "version": "6.10.4",
+              "version": "6.12.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -2607,7 +2607,7 @@
                   "version": "6.8.0"
                 },
                 "babylon": {
-                  "version": "6.8.3"
+                  "version": "6.8.4"
                 },
                 "debug": {
                   "version": "2.2.0",
@@ -2634,7 +2634,7 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
@@ -2645,7 +2645,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2658,10 +2658,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2672,7 +2672,7 @@
               "version": "6.11.1",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2716,7 +2716,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2748,7 +2748,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2761,10 +2761,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2780,15 +2780,15 @@
               "version": "6.9.0",
               "dependencies": {
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2799,7 +2799,7 @@
               "version": "6.11.1",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.10.4",
+                  "version": "6.12.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2843,7 +2843,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2875,7 +2875,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2888,10 +2888,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2904,10 +2904,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -2926,7 +2926,7 @@
                   "version": "6.11.1",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -2970,7 +2970,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.3"
+                          "version": "6.8.4"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -3007,15 +3007,15 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3044,16 +3044,148 @@
           }
         },
         "babel-plugin-transform-regenerator": {
-          "version": "6.9.0",
+          "version": "6.11.4",
           "dependencies": {
+            "babel-core": {
+              "version": "6.11.4",
+              "dependencies": {
+                "babel-code-frame": {
+                  "version": "6.11.0",
+                  "dependencies": {
+                    "chalk": {
+                      "version": "1.1.3",
+                      "dependencies": {
+                        "ansi-styles": {
+                          "version": "2.2.1"
+                        },
+                        "escape-string-regexp": {
+                          "version": "1.0.5"
+                        },
+                        "has-ansi": {
+                          "version": "2.0.0",
+                          "dependencies": {
+                            "ansi-regex": {
+                              "version": "2.0.0"
+                            }
+                          }
+                        },
+                        "strip-ansi": {
+                          "version": "3.0.1",
+                          "dependencies": {
+                            "ansi-regex": {
+                              "version": "2.0.0"
+                            }
+                          }
+                        },
+                        "supports-color": {
+                          "version": "2.0.0"
+                        }
+                      }
+                    },
+                    "esutils": {
+                      "version": "2.0.2"
+                    },
+                    "js-tokens": {
+                      "version": "2.0.0"
+                    }
+                  }
+                },
+                "babel-generator": {
+                  "version": "6.11.4",
+                  "dependencies": {
+                    "detect-indent": {
+                      "version": "3.0.1",
+                      "dependencies": {
+                        "get-stdin": {
+                          "version": "4.0.1"
+                        },
+                        "minimist": {
+                          "version": "1.2.0"
+                        },
+                        "repeating": {
+                          "version": "1.1.3",
+                          "dependencies": {
+                            "is-finite": {
+                              "version": "1.0.1",
+                              "dependencies": {
+                                "number-is-nan": {
+                                  "version": "1.0.0"
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                },
+                "babel-helpers": {
+                  "version": "6.8.0"
+                },
+                "babel-messages": {
+                  "version": "6.8.0"
+                },
+                "babel-template": {
+                  "version": "6.9.0"
+                },
+                "convert-source-map": {
+                  "version": "1.3.0"
+                },
+                "debug": {
+                  "version": "2.2.0",
+                  "dependencies": {
+                    "ms": {
+                      "version": "0.7.1"
+                    }
+                  }
+                },
+                "json5": {
+                  "version": "0.4.0"
+                },
+                "lodash": {
+                  "version": "4.14.1"
+                },
+                "minimatch": {
+                  "version": "3.0.2",
+                  "dependencies": {
+                    "brace-expansion": {
+                      "version": "1.1.6",
+                      "dependencies": {
+                        "balanced-match": {
+                          "version": "0.4.2"
+                        },
+                        "concat-map": {
+                          "version": "0.0.1"
+                        }
+                      }
+                    }
+                  }
+                },
+                "path-exists": {
+                  "version": "1.0.0"
+                },
+                "path-is-absolute": {
+                  "version": "1.0.0"
+                },
+                "shebang-regex": {
+                  "version": "1.0.0"
+                },
+                "slash": {
+                  "version": "1.0.0"
+                },
+                "source-map": {
+                  "version": "0.5.6"
+                }
+              }
+            },
             "babel-plugin-syntax-async-functions": {
               "version": "6.8.0"
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3061,7 +3193,7 @@
               }
             },
             "babel-traverse": {
-              "version": "6.10.4",
+              "version": "6.12.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -3132,7 +3264,7 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
@@ -3143,7 +3275,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -3151,7 +3283,7 @@
               }
             },
             "babylon": {
-              "version": "6.8.3"
+              "version": "6.8.4"
             },
             "private": {
               "version": "0.1.6"
@@ -3167,10 +3299,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3183,10 +3315,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3199,10 +3331,10 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3221,7 +3353,7 @@
                   "version": "6.11.1",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -3265,7 +3397,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.3"
+                          "version": "6.8.4"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -3302,15 +3434,15 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.13.1"
+                  "version": "4.14.1"
                 }
               }
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3323,10 +3455,10 @@
           "version": "6.11.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3339,10 +3471,10 @@
           "version": "6.9.0",
           "dependencies": {
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3363,10 +3495,10 @@
               "version": "6.8.0"
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3382,10 +3514,10 @@
               "version": "6.8.0"
             },
             "babel-runtime": {
-              "version": "6.9.2",
+              "version": "6.11.6",
               "dependencies": {
                 "core-js": {
-                  "version": "2.4.0"
+                  "version": "2.4.1"
                 },
                 "regenerator-runtime": {
                   "version": "0.9.5"
@@ -3404,10 +3536,10 @@
                   "version": "6.8.0"
                 },
                 "babel-runtime": {
-                  "version": "6.9.2",
+                  "version": "6.11.6",
                   "dependencies": {
                     "core-js": {
-                      "version": "2.4.0"
+                      "version": "2.4.1"
                     },
                     "regenerator-runtime": {
                       "version": "0.9.5"
@@ -3418,7 +3550,7 @@
                   "version": "6.9.0",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -3502,73 +3634,185 @@
                       }
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 }
               }
             },
             "babel-plugin-transform-class-properties": {
-              "version": "6.10.2",
+              "version": "6.11.5",
               "dependencies": {
-                "babel-plugin-syntax-class-properties": {
-                  "version": "6.8.0"
-                },
-                "babel-runtime": {
-                  "version": "6.9.2",
+                "babel-helper-function-name": {
+                  "version": "6.8.0",
                   "dependencies": {
-                    "core-js": {
-                      "version": "2.4.0"
+                    "babel-helper-get-function-arity": {
+                      "version": "6.8.0"
                     },
-                    "regenerator-runtime": {
-                      "version": "0.9.5"
-                    }
-                  }
-                }
-              }
-            },
-            "babel-plugin-transform-decorators": {
-              "version": "6.8.0",
-              "dependencies": {
-                "babel-helper-define-map": {
-                  "version": "6.9.0",
-                  "dependencies": {
-                    "babel-helper-function-name": {
-                      "version": "6.8.0",
+                    "babel-template": {
+                      "version": "6.9.0",
                       "dependencies": {
-                        "babel-helper-get-function-arity": {
-                          "version": "6.8.0"
+                        "babylon": {
+                          "version": "6.8.4"
                         },
-                        "babel-traverse": {
-                          "version": "6.10.4",
+                        "lodash": {
+                          "version": "4.14.1"
+                        }
+                      }
+                    },
+                    "babel-traverse": {
+                      "version": "6.12.0",
+                      "dependencies": {
+                        "babel-code-frame": {
+                          "version": "6.11.0",
                           "dependencies": {
-                            "babel-code-frame": {
-                              "version": "6.11.0",
+                            "chalk": {
+                              "version": "1.1.3",
                               "dependencies": {
-                                "chalk": {
-                                  "version": "1.1.3",
+                                "ansi-styles": {
+                                  "version": "2.2.1"
+                                },
+                                "escape-string-regexp": {
+                                  "version": "1.0.5"
+                                },
+                                "has-ansi": {
+                                  "version": "2.0.0",
                                   "dependencies": {
-                                    "ansi-styles": {
-                                      "version": "2.2.1"
-                                    },
-                                    "escape-string-regexp": {
-                                      "version": "1.0.5"
-                                    },
-                                    "has-ansi": {
-                                      "version": "2.0.0",
-                                      "dependencies": {
-                                        "ansi-regex": {
-                                          "version": "2.0.0"
-                                        }
-                                      }
-                                    },
-                                    "strip-ansi": {
-                                      "version": "3.0.1",
-                                      "dependencies": {
-                                        "ansi-regex": {
+                                    "ansi-regex": {
+                                      "version": "2.0.0"
+                                    }
+                                  }
+                                },
+                                "strip-ansi": {
+                                  "version": "3.0.1",
+                                  "dependencies": {
+                                    "ansi-regex": {
+                                      "version": "2.0.0"
+                                    }
+                                  }
+                                },
+                                "supports-color": {
+                                  "version": "2.0.0"
+                                }
+                              }
+                            },
+                            "esutils": {
+                              "version": "2.0.2"
+                            },
+                            "js-tokens": {
+                              "version": "2.0.0"
+                            }
+                          }
+                        },
+                        "babel-messages": {
+                          "version": "6.8.0"
+                        },
+                        "babylon": {
+                          "version": "6.8.4"
+                        },
+                        "debug": {
+                          "version": "2.2.0",
+                          "dependencies": {
+                            "ms": {
+                              "version": "0.7.1"
+                            }
+                          }
+                        },
+                        "globals": {
+                          "version": "8.18.0"
+                        },
+                        "invariant": {
+                          "version": "2.2.1",
+                          "dependencies": {
+                            "loose-envify": {
+                              "version": "1.2.0",
+                              "dependencies": {
+                                "js-tokens": {
+                                  "version": "1.0.3"
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "lodash": {
+                          "version": "4.14.1"
+                        }
+                      }
+                    },
+                    "babel-types": {
+                      "version": "6.11.1",
+                      "dependencies": {
+                        "esutils": {
+                          "version": "2.0.2"
+                        },
+                        "lodash": {
+                          "version": "4.14.1"
+                        },
+                        "to-fast-properties": {
+                          "version": "1.0.2"
+                        }
+                      }
+                    }
+                  }
+                },
+                "babel-plugin-syntax-class-properties": {
+                  "version": "6.8.0"
+                },
+                "babel-runtime": {
+                  "version": "6.11.6",
+                  "dependencies": {
+                    "core-js": {
+                      "version": "2.4.1"
+                    },
+                    "regenerator-runtime": {
+                      "version": "0.9.5"
+                    }
+                  }
+                }
+              }
+            },
+            "babel-plugin-transform-decorators": {
+              "version": "6.8.0",
+              "dependencies": {
+                "babel-helper-define-map": {
+                  "version": "6.9.0",
+                  "dependencies": {
+                    "babel-helper-function-name": {
+                      "version": "6.8.0",
+                      "dependencies": {
+                        "babel-helper-get-function-arity": {
+                          "version": "6.8.0"
+                        },
+                        "babel-traverse": {
+                          "version": "6.12.0",
+                          "dependencies": {
+                            "babel-code-frame": {
+                              "version": "6.11.0",
+                              "dependencies": {
+                                "chalk": {
+                                  "version": "1.1.3",
+                                  "dependencies": {
+                                    "ansi-styles": {
+                                      "version": "2.2.1"
+                                    },
+                                    "escape-string-regexp": {
+                                      "version": "1.0.5"
+                                    },
+                                    "has-ansi": {
+                                      "version": "2.0.0",
+                                      "dependencies": {
+                                        "ansi-regex": {
+                                          "version": "2.0.0"
+                                        }
+                                      }
+                                    },
+                                    "strip-ansi": {
+                                      "version": "3.0.1",
+                                      "dependencies": {
+                                        "ansi-regex": {
                                           "version": "2.0.0"
                                         }
                                       }
@@ -3590,7 +3834,7 @@
                               "version": "6.8.0"
                             },
                             "babylon": {
-                              "version": "6.8.3"
+                              "version": "6.8.4"
                             },
                             "debug": {
                               "version": "2.2.0",
@@ -3621,7 +3865,7 @@
                       }
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 },
@@ -3632,7 +3876,7 @@
                       "version": "6.8.0"
                     },
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -3679,7 +3923,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.3"
+                          "version": "6.8.4"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -3706,7 +3950,7 @@
                           }
                         },
                         "lodash": {
-                          "version": "4.13.1"
+                          "version": "4.14.1"
                         }
                       }
                     }
@@ -3716,10 +3960,10 @@
                   "version": "6.8.0"
                 },
                 "babel-runtime": {
-                  "version": "6.9.2",
+                  "version": "6.11.6",
                   "dependencies": {
                     "core-js": {
-                      "version": "2.4.0"
+                      "version": "2.4.1"
                     },
                     "regenerator-runtime": {
                       "version": "0.9.5"
@@ -3730,7 +3974,7 @@
                   "version": "6.9.0",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -3803,10 +4047,10 @@
                       }
                     },
                     "babylon": {
-                      "version": "6.8.3"
+                      "version": "6.8.4"
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     }
                   }
                 },
@@ -3814,7 +4058,7 @@
                   "version": "6.11.1",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.10.4",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -3858,7 +4102,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.3"
+                          "version": "6.8.4"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -3890,7 +4134,7 @@
                       "version": "2.0.2"
                     },
                     "lodash": {
-                      "version": "4.13.1"
+                      "version": "4.14.1"
                     },
                     "to-fast-properties": {
                       "version": "1.0.2"
@@ -3906,10 +4150,10 @@
                   "version": "6.8.0"
                 },
                 "babel-runtime": {
-                  "version": "6.9.2",
+                  "version": "6.11.6",
                   "dependencies": {
                     "core-js": {
-                      "version": "2.4.0"
+                      "version": "2.4.1"
                     },
                     "regenerator-runtime": {
                       "version": "0.9.5"
@@ -3928,10 +4172,10 @@
                       "version": "6.8.0"
                     },
                     "babel-runtime": {
-                      "version": "6.9.2",
+                      "version": "6.11.6",
                       "dependencies": {
                         "core-js": {
-                          "version": "2.4.0"
+                          "version": "2.4.1"
                         },
                         "regenerator-runtime": {
                           "version": "0.9.5"
@@ -3947,10 +4191,10 @@
                       "version": "6.8.0",
                       "dependencies": {
                         "babel-runtime": {
-                          "version": "6.9.2",
+                          "version": "6.11.6",
                           "dependencies": {
                             "core-js": {
-                              "version": "2.4.0"
+                              "version": "2.4.1"
                             },
                             "regenerator-runtime": {
                               "version": "0.9.5"
@@ -3977,15 +4221,15 @@
                               "version": "6.9.0",
                               "dependencies": {
                                 "babylon": {
-                                  "version": "6.8.3"
+                                  "version": "6.8.4"
                                 },
                                 "lodash": {
-                                  "version": "4.13.1"
+                                  "version": "4.14.1"
                                 }
                               }
                             },
                             "babel-traverse": {
-                              "version": "6.10.4",
+                              "version": "6.12.0",
                               "dependencies": {
                                 "babel-code-frame": {
                                   "version": "6.11.0",
@@ -4032,7 +4276,7 @@
                                   "version": "6.8.0"
                                 },
                                 "babylon": {
-                                  "version": "6.8.3"
+                                  "version": "6.8.4"
                                 },
                                 "debug": {
                                   "version": "2.2.0",
@@ -4059,7 +4303,7 @@
                                   }
                                 },
                                 "lodash": {
-                                  "version": "4.13.1"
+                                  "version": "4.14.1"
                                 }
                               }
                             },
@@ -4070,7 +4314,7 @@
                                   "version": "2.0.2"
                                 },
                                 "lodash": {
-                                  "version": "4.13.1"
+                                  "version": "4.14.1"
                                 },
                                 "to-fast-properties": {
                                   "version": "1.0.2"
@@ -4083,10 +4327,10 @@
                           "version": "6.8.0"
                         },
                         "babel-runtime": {
-                          "version": "6.9.2",
+                          "version": "6.11.6",
                           "dependencies": {
                             "core-js": {
-                              "version": "2.4.0"
+                              "version": "2.4.1"
                             },
                             "regenerator-runtime": {
                               "version": "0.9.5"
@@ -4105,7 +4349,7 @@
                               "version": "6.8.0",
                               "dependencies": {
                                 "babel-traverse": {
-                                  "version": "6.10.4",
+                                  "version": "6.12.0",
                                   "dependencies": {
                                     "babel-code-frame": {
                                       "version": "6.11.0",
@@ -4152,7 +4396,7 @@
                                       "version": "6.8.0"
                                     },
                                     "babylon": {
-                                      "version": "6.8.3"
+                                      "version": "6.8.4"
                                     },
                                     "debug": {
                                       "version": "2.2.0",
@@ -4179,7 +4423,7 @@
                                       }
                                     },
                                     "lodash": {
-                                      "version": "4.13.1"
+                                      "version": "4.14.1"
                                     }
                                   }
                                 }
@@ -4189,7 +4433,7 @@
                               "version": "6.11.1",
                               "dependencies": {
                                 "babel-traverse": {
-                                  "version": "6.10.4",
+                                  "version": "6.12.0",
                                   "dependencies": {
                                     "babel-code-frame": {
                                       "version": "6.11.0",
@@ -4233,7 +4477,7 @@
                                       "version": "6.8.0"
                                     },
                                     "babylon": {
-                                      "version": "6.8.3"
+                                      "version": "6.8.4"
                                     },
                                     "debug": {
                                       "version": "2.2.0",
@@ -4265,7 +4509,7 @@
                                   "version": "2.0.2"
                                 },
                                 "lodash": {
-                                  "version": "4.13.1"
+                                  "version": "4.14.1"
                                 },
                                 "to-fast-properties": {
                                   "version": "1.0.2"
@@ -4278,10 +4522,10 @@
                           "version": "6.8.0"
                         },
                         "babel-runtime": {
-                          "version": "6.9.2",
+                          "version": "6.11.6",
                           "dependencies": {
                             "core-js": {
-                              "version": "2.4.0"
+                              "version": "2.4.1"
                             },
                             "regenerator-runtime": {
                               "version": "0.9.5"
@@ -4298,6 +4542,60 @@
         }
       }
     },
+    "babel-register": {
+      "version": "6.11.6",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.11.6",
+          "dependencies": {
+            "regenerator-runtime": {
+              "version": "0.9.5"
+            }
+          }
+        },
+        "core-js": {
+          "version": "2.4.1"
+        },
+        "home-or-tmp": {
+          "version": "1.0.0",
+          "dependencies": {
+            "os-tmpdir": {
+              "version": "1.0.1"
+            },
+            "user-home": {
+              "version": "1.1.1"
+            }
+          }
+        },
+        "lodash": {
+          "version": "4.14.1"
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "dependencies": {
+            "minimist": {
+              "version": "0.0.8"
+            }
+          }
+        },
+        "path-exists": {
+          "version": "1.0.0"
+        },
+        "source-map-support": {
+          "version": "0.2.10",
+          "dependencies": {
+            "source-map": {
+              "version": "0.1.32",
+              "dependencies": {
+                "amdefine": {
+                  "version": "1.0.0"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "classnames": {
       "version": "2.2.5"
     },
@@ -4338,16 +4636,16 @@
           }
         },
         "cssnano": {
-          "version": "3.7.1",
+          "version": "3.7.3",
           "dependencies": {
             "autoprefixer": {
               "version": "6.3.7",
               "dependencies": {
                 "browserslist": {
-                  "version": "1.3.4"
+                  "version": "1.3.5"
                 },
                 "caniuse-db": {
-                  "version": "1.0.30000495"
+                  "version": "1.0.30000512"
                 },
                 "normalize-range": {
                   "version": "0.1.2"
@@ -4367,7 +4665,7 @@
               "version": "1.0.1"
             },
             "postcss-calc": {
-              "version": "5.2.1",
+              "version": "5.3.0",
               "dependencies": {
                 "postcss-message-helpers": {
                   "version": "2.0.0"
@@ -4425,10 +4723,15 @@
               }
             },
             "postcss-filter-plugins": {
-              "version": "2.0.0",
+              "version": "2.0.1",
               "dependencies": {
                 "uniqid": {
-                  "version": "1.0.0"
+                  "version": "3.1.0",
+                  "dependencies": {
+                    "macaddress": {
+                      "version": "0.2.8"
+                    }
+                  }
                 }
               }
             },
@@ -4444,7 +4747,12 @@
               "version": "2.0.1"
             },
             "postcss-merge-rules": {
-              "version": "2.0.9"
+              "version": "2.0.10",
+              "dependencies": {
+                "vendors": {
+                  "version": "1.0.0"
+                }
+              }
             },
             "postcss-minify-font-values": {
               "version": "1.0.5"
@@ -4470,7 +4778,7 @@
                   "version": "1.0.2"
                 },
                 "postcss-selector-parser": {
-                  "version": "2.1.0",
+                  "version": "2.1.1",
                   "dependencies": {
                     "flatten": {
                       "version": "1.0.2"
@@ -4492,7 +4800,7 @@
                   "version": "2.0.0"
                 },
                 "normalize-url": {
-                  "version": "1.5.3",
+                  "version": "1.6.0",
                   "dependencies": {
                     "prepend-http": {
                       "version": "1.0.4"
@@ -4530,13 +4838,13 @@
               "version": "1.0.3"
             },
             "postcss-svgo": {
-              "version": "2.1.3",
+              "version": "2.1.4",
               "dependencies": {
                 "is-svg": {
                   "version": "2.0.1",
                   "dependencies": {
                     "html-comment-regex": {
-                      "version": "1.1.0"
+                      "version": "1.1.1"
                     }
                   }
                 },
@@ -4685,7 +4993,7 @@
           "version": "4.1.0"
         },
         "postcss": {
-          "version": "5.0.21",
+          "version": "5.1.1",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -4707,10 +5015,74 @@
           "version": "1.0.1"
         },
         "postcss-modules-local-by-default": {
-          "version": "1.1.0"
+          "version": "1.1.1",
+          "dependencies": {
+            "css-selector-tokenizer": {
+              "version": "0.6.0",
+              "dependencies": {
+                "cssesc": {
+                  "version": "0.1.0"
+                },
+                "fastparse": {
+                  "version": "1.1.1"
+                },
+                "regexpu-core": {
+                  "version": "1.0.0",
+                  "dependencies": {
+                    "regenerate": {
+                      "version": "1.3.1"
+                    },
+                    "regjsgen": {
+                      "version": "0.2.0"
+                    },
+                    "regjsparser": {
+                      "version": "0.1.5",
+                      "dependencies": {
+                        "jsesc": {
+                          "version": "0.5.0"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
         },
         "postcss-modules-scope": {
-          "version": "1.0.1"
+          "version": "1.0.2",
+          "dependencies": {
+            "css-selector-tokenizer": {
+              "version": "0.6.0",
+              "dependencies": {
+                "cssesc": {
+                  "version": "0.1.0"
+                },
+                "fastparse": {
+                  "version": "1.1.1"
+                },
+                "regexpu-core": {
+                  "version": "1.0.0",
+                  "dependencies": {
+                    "regenerate": {
+                      "version": "1.3.1"
+                    },
+                    "regjsgen": {
+                      "version": "0.2.0"
+                    },
+                    "regjsparser": {
+                      "version": "0.1.5",
+                      "dependencies": {
+                        "jsesc": {
+                          "version": "0.5.0"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
         },
         "postcss-modules-values": {
           "version": "1.1.3",
@@ -4879,10 +5251,10 @@
           }
         },
         "espree": {
-          "version": "3.1.6",
+          "version": "3.1.7",
           "dependencies": {
             "acorn": {
-              "version": "3.2.0"
+              "version": "3.3.0"
             },
             "acorn-jsx": {
               "version": "3.0.1"
@@ -4896,11 +5268,14 @@
           "version": "2.0.2"
         },
         "file-entry-cache": {
-          "version": "1.2.4",
+          "version": "1.3.1",
           "dependencies": {
             "flat-cache": {
-              "version": "1.0.10",
+              "version": "1.2.1",
               "dependencies": {
+                "circular-json": {
+                  "version": "0.3.1"
+                },
                 "del": {
                   "version": "2.2.1",
                   "dependencies": {
@@ -4943,15 +5318,12 @@
                       }
                     },
                     "rimraf": {
-                      "version": "2.5.3"
+                      "version": "2.5.4"
                     }
                   }
                 },
                 "graceful-fs": {
-                  "version": "4.1.4"
-                },
-                "read-json-sync": {
-                  "version": "1.1.1"
+                  "version": "4.1.5"
                 },
                 "write": {
                   "version": "0.2.1"
@@ -4984,10 +5356,10 @@
               "version": "3.0.2",
               "dependencies": {
                 "brace-expansion": {
-                  "version": "1.1.5",
+                  "version": "1.1.6",
                   "dependencies": {
                     "balanced-match": {
-                      "version": "0.4.1"
+                      "version": "0.4.2"
                     },
                     "concat-map": {
                       "version": "0.0.1"
@@ -5189,7 +5561,7 @@
           }
         },
         "lodash": {
-          "version": "4.13.1"
+          "version": "4.14.1"
         },
         "mkdirp": {
           "version": "0.5.1",
@@ -5206,7 +5578,7 @@
               "version": "0.1.3"
             },
             "fast-levenshtein": {
-              "version": "1.1.3"
+              "version": "1.1.4"
             },
             "prelude-ls": {
               "version": "1.1.2"
@@ -5414,7 +5786,7 @@
                               }
                             },
                             "semver": {
-                              "version": "5.2.0"
+                              "version": "5.3.0"
                             },
                             "validate-npm-package-license": {
                               "version": "3.0.1",
@@ -5423,7 +5795,7 @@
                                   "version": "1.0.2",
                                   "dependencies": {
                                     "spdx-license-ids": {
-                                      "version": "1.2.1"
+                                      "version": "1.2.2"
                                     }
                                   }
                                 },
@@ -5431,10 +5803,10 @@
                                   "version": "1.0.2",
                                   "dependencies": {
                                     "spdx-exceptions": {
-                                      "version": "1.0.4"
+                                      "version": "1.0.5"
                                     },
                                     "spdx-license-ids": {
-                                      "version": "1.2.1"
+                                      "version": "1.2.2"
                                     }
                                   }
                                 }
@@ -5471,7 +5843,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.4"
+                                      "version": "4.1.5"
                                     },
                                     "parse-json": {
                                       "version": "2.2.0",
@@ -5511,7 +5883,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.4"
+                                      "version": "4.1.5"
                                     },
                                     "pify": {
                                       "version": "2.3.0"
@@ -5639,7 +6011,7 @@
                                       "version": "1.0.2",
                                       "dependencies": {
                                         "spdx-license-ids": {
-                                          "version": "1.2.1"
+                                          "version": "1.2.2"
                                         }
                                       }
                                     },
@@ -5647,10 +6019,10 @@
                                       "version": "1.0.2",
                                       "dependencies": {
                                         "spdx-exceptions": {
-                                          "version": "1.0.4"
+                                          "version": "1.0.5"
                                         },
                                         "spdx-license-ids": {
-                                          "version": "1.2.1"
+                                          "version": "1.2.2"
                                         }
                                       }
                                     }
@@ -5687,7 +6059,7 @@
                                       "version": "1.1.0",
                                       "dependencies": {
                                         "graceful-fs": {
-                                          "version": "4.1.4"
+                                          "version": "4.1.5"
                                         },
                                         "parse-json": {
                                           "version": "2.2.0",
@@ -5727,7 +6099,7 @@
                                       "version": "1.1.0",
                                       "dependencies": {
                                         "graceful-fs": {
-                                          "version": "4.1.4"
+                                          "version": "4.1.5"
                                         },
                                         "pify": {
                                           "version": "2.3.0"
@@ -5794,7 +6166,7 @@
                   "version": "1.1.0",
                   "dependencies": {
                     "semver": {
-                      "version": "5.2.0"
+                      "version": "5.3.0"
                     }
                   }
                 }
@@ -6668,7 +7040,7 @@
                                       }
                                     },
                                     "semver": {
-                                      "version": "5.2.0"
+                                      "version": "5.3.0"
                                     },
                                     "validate-npm-package-license": {
                                       "version": "3.0.1",
@@ -6677,7 +7049,7 @@
                                           "version": "1.0.2",
                                           "dependencies": {
                                             "spdx-license-ids": {
-                                              "version": "1.2.1"
+                                              "version": "1.2.2"
                                             }
                                           }
                                         },
@@ -6685,10 +7057,10 @@
                                           "version": "1.0.2",
                                           "dependencies": {
                                             "spdx-exceptions": {
-                                              "version": "1.0.4"
+                                              "version": "1.0.5"
                                             },
                                             "spdx-license-ids": {
-                                              "version": "1.2.1"
+                                              "version": "1.2.2"
                                             }
                                           }
                                         }
@@ -6725,7 +7097,7 @@
                                           "version": "1.1.0",
                                           "dependencies": {
                                             "graceful-fs": {
-                                              "version": "4.1.4"
+                                              "version": "4.1.5"
                                             },
                                             "parse-json": {
                                               "version": "2.2.0",
@@ -6765,7 +7137,7 @@
                                           "version": "1.1.0",
                                           "dependencies": {
                                             "graceful-fs": {
-                                              "version": "4.1.4"
+                                              "version": "4.1.5"
                                             },
                                             "pify": {
                                               "version": "2.3.0"
@@ -6885,7 +7257,7 @@
                                   "version": "3.9.1"
                                 },
                                 "lodash.isarguments": {
-                                  "version": "3.0.8"
+                                  "version": "3.0.9"
                                 },
                                 "lodash.isarray": {
                                   "version": "3.0.4"
@@ -6986,7 +7358,7 @@
                   "version": "1.2.2"
                 },
                 "is-url": {
-                  "version": "1.2.1"
+                  "version": "1.2.2"
                 },
                 "object-assign": {
                   "version": "4.1.0"
@@ -7039,7 +7411,7 @@
                   }
                 },
                 "vinyl": {
-                  "version": "1.1.1",
+                  "version": "1.2.0",
                   "dependencies": {
                     "clone": {
                       "version": "1.0.2"
@@ -7056,7 +7428,7 @@
                   "version": "2.4.3",
                   "dependencies": {
                     "duplexify": {
-                      "version": "3.4.3",
+                      "version": "3.4.5",
                       "dependencies": {
                         "end-of-stream": {
                           "version": "1.0.0",
@@ -7073,6 +7445,9 @@
                         },
                         "inherits": {
                           "version": "2.0.1"
+                        },
+                        "stream-shift": {
+                          "version": "1.0.0"
                         }
                       }
                     },
@@ -7096,7 +7471,7 @@
                           }
                         },
                         "micromatch": {
-                          "version": "2.3.10",
+                          "version": "2.3.11",
                           "dependencies": {
                             "arr-diff": {
                               "version": "2.0.0",
@@ -7168,7 +7543,7 @@
                               "version": "2.0.1"
                             },
                             "kind-of": {
-                              "version": "3.0.3",
+                              "version": "3.0.4",
                               "dependencies": {
                                 "is-buffer": {
                                   "version": "1.1.3"
@@ -7280,13 +7655,13 @@
                       }
                     },
                     "graceful-fs": {
-                      "version": "4.1.4"
+                      "version": "4.1.5"
                     },
                     "gulp-sourcemaps": {
                       "version": "1.6.0",
                       "dependencies": {
                         "convert-source-map": {
-                          "version": "1.2.0"
+                          "version": "1.3.0"
                         }
                       }
                     },
@@ -7297,15 +7672,7 @@
                       "version": "1.0.0"
                     },
                     "lodash.isequal": {
-                      "version": "4.2.0",
-                      "dependencies": {
-                        "lodash._root": {
-                          "version": "3.0.1"
-                        },
-                        "lodash.keys": {
-                          "version": "4.0.7"
-                        }
-                      }
+                      "version": "4.3.1"
                     },
                     "merge-stream": {
                       "version": "1.0.0"
@@ -7525,7 +7892,7 @@
                               }
                             },
                             "semver": {
-                              "version": "5.2.0"
+                              "version": "5.3.0"
                             },
                             "validate-npm-package-license": {
                               "version": "3.0.1",
@@ -7534,7 +7901,7 @@
                                   "version": "1.0.2",
                                   "dependencies": {
                                     "spdx-license-ids": {
-                                      "version": "1.2.1"
+                                      "version": "1.2.2"
                                     }
                                   }
                                 },
@@ -7542,10 +7909,10 @@
                                   "version": "1.0.2",
                                   "dependencies": {
                                     "spdx-exceptions": {
-                                      "version": "1.0.4"
+                                      "version": "1.0.5"
                                     },
                                     "spdx-license-ids": {
-                                      "version": "1.2.1"
+                                      "version": "1.2.2"
                                     }
                                   }
                                 }
@@ -7582,7 +7949,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.4"
+                                      "version": "4.1.5"
                                     },
                                     "parse-json": {
                                       "version": "2.2.0",
@@ -7622,7 +7989,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.4"
+                                      "version": "4.1.5"
                                     },
                                     "pify": {
                                       "version": "2.3.0"
@@ -7709,10 +8076,10 @@
           "version": "3.0.2",
           "dependencies": {
             "brace-expansion": {
-              "version": "1.1.5",
+              "version": "1.1.6",
               "dependencies": {
                 "balanced-match": {
-                  "version": "0.4.1"
+                  "version": "0.4.2"
                 },
                 "concat-map": {
                   "version": "0.0.1"
@@ -7735,11 +8102,8 @@
       }
     },
     "history": {
-      "version": "1.12.0",
+      "version": "3.0.0",
       "dependencies": {
-        "deep-equal": {
-          "version": "1.0.1"
-        },
         "invariant": {
           "version": "2.2.1",
           "dependencies": {
@@ -7753,8 +8117,16 @@
             }
           }
         },
-        "qs": {
-          "version": "4.0.0"
+        "query-string": {
+          "version": "4.2.2",
+          "dependencies": {
+            "object-assign": {
+              "version": "4.1.0"
+            },
+            "strict-uri-encode": {
+              "version": "1.1.0"
+            }
+          }
         },
         "warning": {
           "version": "2.1.0",
@@ -7840,7 +8212,7 @@
               }
             },
             "clean-css": {
-              "version": "3.4.18",
+              "version": "3.4.19",
               "dependencies": {
                 "commander": {
                   "version": "2.8.1",
@@ -7880,7 +8252,7 @@
               }
             },
             "relateurl": {
-              "version": "0.2.6"
+              "version": "0.2.7"
             },
             "uglify-js": {
               "version": "2.6.4",
@@ -7910,7 +8282,7 @@
                               "version": "0.1.4",
                               "dependencies": {
                                 "kind-of": {
-                                  "version": "3.0.3",
+                                  "version": "3.0.4",
                                   "dependencies": {
                                     "is-buffer": {
                                       "version": "1.1.3"
@@ -7937,7 +8309,7 @@
                               "version": "0.1.4",
                               "dependencies": {
                                 "kind-of": {
-                                  "version": "3.0.3",
+                                  "version": "3.0.4",
                                   "dependencies": {
                                     "is-buffer": {
                                       "version": "1.1.3"
@@ -7972,7 +8344,7 @@
           }
         },
         "lodash": {
-          "version": "4.13.1"
+          "version": "4.14.1"
         },
         "pretty-error": {
           "version": "2.0.0",
@@ -8131,7 +8503,7 @@
                       "version": "0.1.3"
                     },
                     "fast-levenshtein": {
-                      "version": "1.1.3"
+                      "version": "1.1.4"
                     },
                     "levn": {
                       "version": "0.3.0"
@@ -8164,10 +8536,10 @@
                   "version": "2.0.10",
                   "dependencies": {
                     "brace-expansion": {
-                      "version": "1.1.5",
+                      "version": "1.1.6",
                       "dependencies": {
                         "balanced-match": {
-                          "version": "0.4.1"
+                          "version": "0.4.2"
                         },
                         "concat-map": {
                           "version": "0.0.1"
@@ -8228,7 +8600,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "kind-of": {
-                                      "version": "3.0.3",
+                                      "version": "3.0.4",
                                       "dependencies": {
                                         "is-buffer": {
                                           "version": "1.1.3"
@@ -8255,7 +8627,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "kind-of": {
-                                      "version": "3.0.3",
+                                      "version": "3.0.4",
                                       "dependencies": {
                                         "is-buffer": {
                                           "version": "1.1.3"
@@ -8350,9 +8722,39 @@
         }
       }
     },
+    "jasmine": {
+      "version": "2.4.1",
+      "dependencies": {
+        "exit": {
+          "version": "0.1.2"
+        },
+        "glob": {
+          "version": "3.2.11",
+          "dependencies": {
+            "inherits": {
+              "version": "2.0.1"
+            },
+            "minimatch": {
+              "version": "0.3.0",
+              "dependencies": {
+                "lru-cache": {
+                  "version": "2.7.3"
+                },
+                "sigmund": {
+                  "version": "1.0.1"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
     "jasmine-core": {
       "version": "2.4.1"
     },
+    "js-cookie": {
+      "version": "2.1.2"
+    },
     "json-loader": {
       "version": "0.5.4"
     },
@@ -8449,7 +8851,7 @@
                   "version": "1.0.1"
                 },
                 "micromatch": {
-                  "version": "2.3.10",
+                  "version": "2.3.11",
                   "dependencies": {
                     "arr-diff": {
                       "version": "2.0.0",
@@ -8518,7 +8920,7 @@
                       "version": "1.0.0"
                     },
                     "kind-of": {
-                      "version": "3.0.3",
+                      "version": "3.0.4",
                       "dependencies": {
                         "is-buffer": {
                           "version": "1.1.3"
@@ -8574,10 +8976,10 @@
               "version": "1.0.0"
             },
             "fsevents": {
-              "version": "1.0.12",
+              "version": "1.0.14",
               "dependencies": {
-                "ansi": {
-                  "version": "0.3.1"
+                "abbrev": {
+                  "version": "1.0.9"
                 },
                 "ansi-regex": {
                   "version": "2.0.0"
@@ -8585,6 +8987,9 @@
                 "ansi-styles": {
                   "version": "2.2.1"
                 },
+                "aproba": {
+                  "version": "1.0.4"
+                },
                 "are-we-there-yet": {
                   "version": "1.1.2"
                 },
@@ -8601,42 +9006,52 @@
                   "version": "0.6.0"
                 },
                 "aws4": {
-                  "version": "1.3.2",
+                  "version": "1.4.1"
+                },
+                "balanced-match": {
+                  "version": "0.4.2"
+                },
+                "bl": {
+                  "version": "1.1.2",
                   "dependencies": {
-                    "lru-cache": {
-                      "version": "4.0.1",
-                      "dependencies": {
-                        "pseudomap": {
-                          "version": "1.0.2"
-                        },
-                        "yallist": {
-                          "version": "2.0.0"
-                        }
-                      }
+                    "readable-stream": {
+                      "version": "2.0.6"
                     }
                   }
                 },
-                "bl": {
-                  "version": "1.0.3"
-                },
                 "block-stream": {
-                  "version": "0.0.8"
+                  "version": "0.0.9"
                 },
                 "boom": {
                   "version": "2.10.1"
                 },
+                "brace-expansion": {
+                  "version": "1.1.5"
+                },
+                "buffer-shims": {
+                  "version": "1.0.0"
+                },
                 "caseless": {
                   "version": "0.11.0"
                 },
                 "chalk": {
                   "version": "1.1.3"
                 },
+                "code-point-at": {
+                  "version": "1.0.0"
+                },
                 "combined-stream": {
                   "version": "1.0.5"
                 },
                 "commander": {
                   "version": "2.9.0"
                 },
+                "concat-map": {
+                  "version": "0.0.1"
+                },
+                "console-control-strings": {
+                  "version": "1.1.0"
+                },
                 "core-util-is": {
                   "version": "1.0.2"
                 },
@@ -8644,7 +9059,7 @@
                   "version": "2.0.5"
                 },
                 "dashdash": {
-                  "version": "1.13.0",
+                  "version": "1.14.0",
                   "dependencies": {
                     "assert-plus": {
                       "version": "1.0.0"
@@ -8681,32 +9096,17 @@
                 "form-data": {
                   "version": "1.0.0-rc4"
                 },
+                "fs.realpath": {
+                  "version": "1.0.0"
+                },
                 "fstream": {
-                  "version": "1.0.8"
+                  "version": "1.0.10"
                 },
                 "fstream-ignore": {
-                  "version": "1.0.3",
-                  "dependencies": {
-                    "minimatch": {
-                      "version": "3.0.0",
-                      "dependencies": {
-                        "brace-expansion": {
-                          "version": "1.1.3",
-                          "dependencies": {
-                            "balanced-match": {
-                              "version": "0.3.0"
-                            },
-                            "concat-map": {
-                              "version": "0.0.1"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
+                  "version": "1.0.5"
                 },
                 "gauge": {
-                  "version": "1.2.7"
+                  "version": "2.6.0"
                 },
                 "generate-function": {
                   "version": "2.0.0"
@@ -8714,8 +9114,19 @@
                 "generate-object-property": {
                   "version": "1.2.0"
                 },
+                "getpass": {
+                  "version": "0.1.6",
+                  "dependencies": {
+                    "assert-plus": {
+                      "version": "1.0.0"
+                    }
+                  }
+                },
+                "glob": {
+                  "version": "7.0.5"
+                },
                 "graceful-fs": {
-                  "version": "4.1.3"
+                  "version": "4.1.4"
                 },
                 "graceful-readlink": {
                   "version": "1.0.1"
@@ -8726,8 +9137,11 @@
                 "has-ansi": {
                   "version": "2.0.0"
                 },
+                "has-color": {
+                  "version": "0.1.7"
+                },
                 "has-unicode": {
-                  "version": "2.0.0"
+                  "version": "2.0.1"
                 },
                 "hawk": {
                   "version": "3.1.3"
@@ -8738,12 +9152,18 @@
                 "http-signature": {
                   "version": "1.1.1"
                 },
+                "inflight": {
+                  "version": "1.0.5"
+                },
                 "inherits": {
                   "version": "2.0.1"
                 },
                 "ini": {
                   "version": "1.3.4"
                 },
+                "is-fullwidth-code-point": {
+                  "version": "1.0.0"
+                },
                 "is-my-json-valid": {
                   "version": "2.13.1"
                 },
@@ -8775,28 +9195,16 @@
                   "version": "2.0.0"
                 },
                 "jsprim": {
-                  "version": "1.2.2"
-                },
-                "lodash.pad": {
-                  "version": "4.1.0"
-                },
-                "lodash.padend": {
-                  "version": "4.2.0"
-                },
-                "lodash.padstart": {
-                  "version": "4.2.0"
-                },
-                "lodash.repeat": {
-                  "version": "4.0.0"
-                },
-                "lodash.tostring": {
-                  "version": "4.1.2"
+                  "version": "1.3.0"
                 },
                 "mime-db": {
-                  "version": "1.22.0"
+                  "version": "1.23.0"
                 },
                 "mime-types": {
-                  "version": "2.1.10"
+                  "version": "2.1.11"
+                },
+                "minimatch": {
+                  "version": "3.0.2"
                 },
                 "minimist": {
                   "version": "0.0.8"
@@ -8808,44 +9216,46 @@
                   "version": "0.7.1"
                 },
                 "nan": {
-                  "version": "2.3.5"
+                  "version": "2.4.0"
                 },
                 "node-pre-gyp": {
-                  "version": "0.6.25",
-                  "dependencies": {
-                    "nopt": {
-                      "version": "3.0.6",
-                      "dependencies": {
-                        "abbrev": {
-                          "version": "1.0.7"
-                        }
-                      }
-                    }
-                  }
+                  "version": "0.6.29"
                 },
                 "node-uuid": {
                   "version": "1.4.7"
                 },
+                "nopt": {
+                  "version": "3.0.6"
+                },
                 "npmlog": {
-                  "version": "2.0.3"
+                  "version": "3.1.2"
+                },
+                "number-is-nan": {
+                  "version": "1.0.0"
                 },
                 "oauth-sign": {
-                  "version": "0.8.1"
+                  "version": "0.8.2"
+                },
+                "object-assign": {
+                  "version": "4.1.0"
                 },
                 "once": {
                   "version": "1.3.3"
                 },
+                "path-is-absolute": {
+                  "version": "1.0.0"
+                },
                 "pinkie": {
                   "version": "2.0.4"
                 },
                 "pinkie-promise": {
-                  "version": "2.0.0"
+                  "version": "2.0.1"
                 },
                 "process-nextick-args": {
-                  "version": "1.0.6"
+                  "version": "1.0.7"
                 },
                 "qs": {
-                  "version": "6.0.2"
+                  "version": "6.2.0"
                 },
                 "rc": {
                   "version": "1.1.6",
@@ -8856,67 +9266,36 @@
                   }
                 },
                 "readable-stream": {
-                  "version": "2.0.6"
+                  "version": "2.1.4"
                 },
                 "request": {
-                  "version": "2.69.0"
+                  "version": "2.73.0"
                 },
                 "rimraf": {
-                  "version": "2.5.2",
-                  "dependencies": {
-                    "glob": {
-                      "version": "7.0.3",
-                      "dependencies": {
-                        "inflight": {
-                          "version": "1.0.4",
-                          "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.1"
-                            }
-                          }
-                        },
-                        "inherits": {
-                          "version": "2.0.1"
-                        },
-                        "minimatch": {
-                          "version": "3.0.0",
-                          "dependencies": {
-                            "brace-expansion": {
-                              "version": "1.1.3",
-                              "dependencies": {
-                                "balanced-match": {
-                                  "version": "0.3.0"
-                                },
-                                "concat-map": {
-                                  "version": "0.0.1"
-                                }
-                              }
-                            }
-                          }
-                        },
-                        "once": {
-                          "version": "1.3.3",
-                          "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.1"
-                            }
-                          }
-                        },
-                        "path-is-absolute": {
-                          "version": "1.0.0"
-                        }
-                      }
-                    }
-                  }
+                  "version": "2.5.3"
                 },
                 "semver": {
-                  "version": "5.1.0"
+                  "version": "5.2.0"
+                },
+                "set-blocking": {
+                  "version": "2.0.0"
+                },
+                "signal-exit": {
+                  "version": "3.0.0"
                 },
                 "sntp": {
                   "version": "1.0.9"
                 },
                 "sshpk": {
-                  "version": "1.7.4"
+                  "version": "1.8.3",
+                  "dependencies": {
+                    "assert-plus": {
+                      "version": "1.0.0"
+                    }
+                  }
+                },
+                "string-width": {
+                  "version": "1.0.1"
                 },
                 "string_decoder": {
                   "version": "0.10.31"
@@ -8937,16 +9316,16 @@
                   "version": "2.2.1"
                 },
                 "tar-pack": {
-                  "version": "3.1.3"
+                  "version": "3.1.4"
                 },
                 "tough-cookie": {
                   "version": "2.2.2"
                 },
                 "tunnel-agent": {
-                  "version": "0.4.2"
+                  "version": "0.4.3"
                 },
                 "tweetnacl": {
-                  "version": "0.14.3"
+                  "version": "0.13.3"
                 },
                 "uid-number": {
                   "version": "0.0.6"
@@ -8957,8 +9336,11 @@
                 "verror": {
                   "version": "1.3.6"
                 },
+                "wide-align": {
+                  "version": "1.1.0"
+                },
                 "wrappy": {
-                  "version": "1.0.1"
+                  "version": "1.0.2"
                 },
                 "xtend": {
                   "version": "4.0.1"
@@ -9065,7 +9447,7 @@
           }
         },
         "core-js": {
-          "version": "2.4.0"
+          "version": "2.4.1"
         },
         "di": {
           "version": "0.0.1"
@@ -9145,7 +9527,7 @@
           }
         },
         "graceful-fs": {
-          "version": "4.1.4"
+          "version": "4.1.5"
         },
         "http-proxy": {
           "version": "1.14.0",
@@ -9165,7 +9547,7 @@
           "version": "3.10.1"
         },
         "log4js": {
-          "version": "0.6.37",
+          "version": "0.6.38",
           "dependencies": {
             "readable-stream": {
               "version": "1.0.34",
@@ -9196,10 +9578,10 @@
           "version": "3.0.2",
           "dependencies": {
             "brace-expansion": {
-              "version": "1.1.5",
+              "version": "1.1.6",
               "dependencies": {
                 "balanced-match": {
-                  "version": "0.4.1"
+                  "version": "0.4.2"
                 },
                 "concat-map": {
                   "version": "0.0.1"
@@ -9220,7 +9602,7 @@
           }
         },
         "rimraf": {
-          "version": "2.5.3"
+          "version": "2.5.4"
         },
         "socket.io": {
           "version": "1.4.8",
@@ -9563,7 +9945,7 @@
                       }
                     },
                     "semver": {
-                      "version": "5.2.0"
+                      "version": "5.3.0"
                     },
                     "validate-npm-package-license": {
                       "version": "3.0.1",
@@ -9572,7 +9954,7 @@
                           "version": "1.0.2",
                           "dependencies": {
                             "spdx-license-ids": {
-                              "version": "1.2.1"
+                              "version": "1.2.2"
                             }
                           }
                         },
@@ -9580,10 +9962,10 @@
                           "version": "1.0.2",
                           "dependencies": {
                             "spdx-exceptions": {
-                              "version": "1.0.4"
+                              "version": "1.0.5"
                             },
                             "spdx-license-ids": {
-                              "version": "1.2.1"
+                              "version": "1.2.2"
                             }
                           }
                         }
@@ -9620,7 +10002,7 @@
                           "version": "1.1.0",
                           "dependencies": {
                             "graceful-fs": {
-                              "version": "4.1.4"
+                              "version": "4.1.5"
                             },
                             "parse-json": {
                               "version": "2.2.0",
@@ -9660,7 +10042,7 @@
                           "version": "1.1.0",
                           "dependencies": {
                             "graceful-fs": {
-                              "version": "4.1.4"
+                              "version": "4.1.5"
                             },
                             "pify": {
                               "version": "2.3.0"
@@ -9737,7 +10119,7 @@
                       "version": "0.1.3"
                     },
                     "fast-levenshtein": {
-                      "version": "1.1.3"
+                      "version": "1.1.4"
                     },
                     "levn": {
                       "version": "0.3.0"
@@ -9770,10 +10152,10 @@
                   "version": "2.0.10",
                   "dependencies": {
                     "brace-expansion": {
-                      "version": "1.1.5",
+                      "version": "1.1.6",
                       "dependencies": {
                         "balanced-match": {
-                          "version": "0.4.1"
+                          "version": "0.4.2"
                         },
                         "concat-map": {
                           "version": "0.0.1"
@@ -9834,7 +10216,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "kind-of": {
-                                      "version": "3.0.3",
+                                      "version": "3.0.4",
                                       "dependencies": {
                                         "is-buffer": {
                                           "version": "1.1.3"
@@ -9861,7 +10243,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "kind-of": {
-                                      "version": "3.0.3",
+                                      "version": "3.0.4",
                                       "dependencies": {
                                         "is-buffer": {
                                           "version": "1.1.3"
@@ -9955,10 +10337,10 @@
           "version": "3.0.2",
           "dependencies": {
             "brace-expansion": {
-              "version": "1.1.5",
+              "version": "1.1.6",
               "dependencies": {
                 "balanced-match": {
-                  "version": "0.4.1"
+                  "version": "0.4.2"
                 },
                 "concat-map": {
                   "version": "0.0.1"
@@ -10131,7 +10513,7 @@
           "version": "0.1.4",
           "dependencies": {
             "pako": {
-              "version": "0.2.8"
+              "version": "0.2.9"
             }
           }
         },
@@ -10201,7 +10583,7 @@
           "version": "0.0.0"
         },
         "process": {
-          "version": "0.11.5"
+          "version": "0.11.6"
         },
         "punycode": {
           "version": "1.4.1"
@@ -10303,10 +10685,10 @@
           "version": "6.3.7",
           "dependencies": {
             "browserslist": {
-              "version": "1.3.4"
+              "version": "1.3.5"
             },
             "caniuse-db": {
-              "version": "1.0.30000495"
+              "version": "1.0.30000512"
             },
             "normalize-range": {
               "version": "0.1.2"
@@ -10323,37 +10705,19 @@
           "version": "1.5.0",
           "dependencies": {
             "browserslist": {
-              "version": "1.3.4"
+              "version": "1.3.5"
             },
             "caniuse-db": {
-              "version": "1.0.30000495"
+              "version": "1.0.30000512"
             },
             "lodash.memoize": {
-              "version": "4.1.0",
-              "dependencies": {
-                "lodash._root": {
-                  "version": "3.0.1"
-                }
-              }
+              "version": "4.1.1"
             },
             "lodash.uniq": {
-              "version": "4.3.0",
-              "dependencies": {
-                "lodash._baseuniq": {
-                  "version": "4.6.0",
-                  "dependencies": {
-                    "lodash._createset": {
-                      "version": "4.0.3"
-                    },
-                    "lodash._root": {
-                      "version": "3.0.1"
-                    }
-                  }
-                }
-              }
+              "version": "4.4.0"
             },
             "shelljs": {
-              "version": "0.7.0",
+              "version": "0.7.3",
               "dependencies": {
                 "glob": {
                   "version": "7.0.5",
@@ -10376,10 +10740,10 @@
                       "version": "3.0.2",
                       "dependencies": {
                         "brace-expansion": {
-                          "version": "1.1.5",
+                          "version": "1.1.6",
                           "dependencies": {
                             "balanced-match": {
-                              "version": "0.4.1"
+                              "version": "0.4.2"
                             },
                             "concat-map": {
                               "version": "0.0.1"
@@ -10450,10 +10814,10 @@
           "version": "3.0.1",
           "dependencies": {
             "browserslist": {
-              "version": "1.3.4",
+              "version": "1.3.5",
               "dependencies": {
                 "caniuse-db": {
-                  "version": "1.0.30000495"
+                  "version": "1.0.30000512"
                 }
               }
             },
@@ -10479,7 +10843,7 @@
           }
         },
         "postcss": {
-          "version": "5.0.21",
+          "version": "5.1.1",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -10501,12 +10865,12 @@
           "version": "0.3.0",
           "dependencies": {
             "balanced-match": {
-              "version": "0.4.1"
+              "version": "0.4.2"
             }
           }
         },
         "postcss-calc": {
-          "version": "5.2.1",
+          "version": "5.3.0",
           "dependencies": {
             "postcss-message-helpers": {
               "version": "2.0.0"
@@ -10689,41 +11053,19 @@
           }
         },
         "postcss-font-variant": {
-          "version": "2.0.0"
+          "version": "2.0.1"
         },
         "postcss-initial": {
-          "version": "1.5.1",
+          "version": "1.5.2",
           "dependencies": {
             "lodash.template": {
-              "version": "4.2.5",
+              "version": "4.3.0",
               "dependencies": {
                 "lodash._reinterpolate": {
                   "version": "3.0.0"
                 },
-                "lodash.assigninwith": {
-                  "version": "4.0.7",
-                  "dependencies": {
-                    "lodash.keysin": {
-                      "version": "4.1.4"
-                    }
-                  }
-                },
-                "lodash.keys": {
-                  "version": "4.0.7"
-                },
-                "lodash.rest": {
-                  "version": "4.0.3"
-                },
                 "lodash.templatesettings": {
-                  "version": "4.0.1",
-                  "dependencies": {
-                    "lodash.escape": {
-                      "version": "4.0.0"
-                    }
-                  }
-                },
-                "lodash.tostring": {
-                  "version": "4.1.3"
+                  "version": "4.1.0"
                 }
               }
             }
@@ -10788,7 +11130,7 @@
           "version": "0.1.14",
           "dependencies": {
             "jspm": {
-              "version": "0.17.0-beta.22",
+              "version": "0.17.0-beta.25",
               "dependencies": {
                 "bluebird": {
                   "version": "3.4.1"
@@ -10824,7 +11166,7 @@
                   }
                 },
                 "core-js": {
-                  "version": "1.2.6"
+                  "version": "1.2.7"
                 },
                 "glob": {
                   "version": "6.0.4",
@@ -10854,7 +11196,7 @@
                   }
                 },
                 "graceful-fs": {
-                  "version": "4.1.4"
+                  "version": "4.1.5"
                 },
                 "jspm-github": {
                   "version": "0.14.9",
@@ -10978,7 +11320,7 @@
                           "version": "0.0.5"
                         },
                         "tough-cookie": {
-                          "version": "2.2.2"
+                          "version": "2.3.1"
                         },
                         "tunnel-agent": {
                           "version": "0.4.3"
@@ -11006,10 +11348,10 @@
                               "version": "2.0.10",
                               "dependencies": {
                                 "brace-expansion": {
-                                  "version": "1.1.5",
+                                  "version": "1.1.6",
                                   "dependencies": {
                                     "balanced-match": {
-                                      "version": "0.4.1"
+                                      "version": "0.4.2"
                                     },
                                     "concat-map": {
                                       "version": "0.0.1"
@@ -11055,7 +11397,7 @@
                   }
                 },
                 "jspm-npm": {
-                  "version": "0.29.1",
+                  "version": "0.29.2",
                   "dependencies": {
                     "readdirp": {
                       "version": "2.1.0",
@@ -11248,7 +11590,7 @@
                           "version": "0.0.5"
                         },
                         "tough-cookie": {
-                          "version": "2.2.2"
+                          "version": "2.3.1"
                         },
                         "tunnel-agent": {
                           "version": "0.4.3"
@@ -11276,17 +11618,99 @@
                         }
                       }
                     },
-                    "tar": {
-                      "version": "2.2.1",
+                    "tar-fs": {
+                      "version": "1.13.0",
                       "dependencies": {
-                        "block-stream": {
-                          "version": "0.0.9"
-                        },
-                        "fstream": {
-                          "version": "1.0.10"
+                        "pump": {
+                          "version": "1.0.1",
+                          "dependencies": {
+                            "end-of-stream": {
+                              "version": "1.1.0"
+                            },
+                            "once": {
+                              "version": "1.3.3",
+                              "dependencies": {
+                                "wrappy": {
+                                  "version": "1.0.2"
+                                }
+                              }
+                            }
+                          }
                         },
-                        "inherits": {
-                          "version": "2.0.1"
+                        "tar-stream": {
+                          "version": "1.5.2",
+                          "dependencies": {
+                            "bl": {
+                              "version": "1.1.2",
+                              "dependencies": {
+                                "readable-stream": {
+                                  "version": "2.0.6",
+                                  "dependencies": {
+                                    "core-util-is": {
+                                      "version": "1.0.2"
+                                    },
+                                    "inherits": {
+                                      "version": "2.0.1"
+                                    },
+                                    "isarray": {
+                                      "version": "1.0.0"
+                                    },
+                                    "process-nextick-args": {
+                                      "version": "1.0.7"
+                                    },
+                                    "string_decoder": {
+                                      "version": "0.10.31"
+                                    },
+                                    "util-deprecate": {
+                                      "version": "1.0.2"
+                                    }
+                                  }
+                                }
+                              }
+                            },
+                            "end-of-stream": {
+                              "version": "1.1.0",
+                              "dependencies": {
+                                "once": {
+                                  "version": "1.3.3",
+                                  "dependencies": {
+                                    "wrappy": {
+                                      "version": "1.0.2"
+                                    }
+                                  }
+                                }
+                              }
+                            },
+                            "readable-stream": {
+                              "version": "2.1.4",
+                              "dependencies": {
+                                "buffer-shims": {
+                                  "version": "1.0.0"
+                                },
+                                "core-util-is": {
+                                  "version": "1.0.2"
+                                },
+                                "inherits": {
+                                  "version": "2.0.1"
+                                },
+                                "isarray": {
+                                  "version": "1.0.0"
+                                },
+                                "process-nextick-args": {
+                                  "version": "1.0.7"
+                                },
+                                "string_decoder": {
+                                  "version": "0.10.31"
+                                },
+                                "util-deprecate": {
+                                  "version": "1.0.2"
+                                }
+                              }
+                            },
+                            "xtend": {
+                              "version": "4.0.1"
+                            }
+                          }
                         }
                       }
                     },
@@ -11312,38 +11736,262 @@
                   }
                 },
                 "liftoff": {
-                  "version": "2.2.4",
+                  "version": "2.3.0",
                   "dependencies": {
                     "extend": {
                       "version": "3.0.0"
                     },
                     "findup-sync": {
-                      "version": "0.3.0",
+                      "version": "0.4.2",
                       "dependencies": {
-                        "glob": {
-                          "version": "5.0.15",
+                        "detect-file": {
+                          "version": "0.1.0",
                           "dependencies": {
-                            "inflight": {
-                              "version": "1.0.5",
+                            "fs-exists-sync": {
+                              "version": "0.1.0"
+                            }
+                          }
+                        },
+                        "is-glob": {
+                          "version": "2.0.1",
+                          "dependencies": {
+                            "is-extglob": {
+                              "version": "1.0.0"
+                            }
+                          }
+                        },
+                        "micromatch": {
+                          "version": "2.3.11",
+                          "dependencies": {
+                            "arr-diff": {
+                              "version": "2.0.0",
                               "dependencies": {
-                                "wrappy": {
-                                  "version": "1.0.2"
+                                "arr-flatten": {
+                                  "version": "1.0.1"
                                 }
                               }
                             },
-                            "inherits": {
+                            "array-unique": {
+                              "version": "0.2.1"
+                            },
+                            "braces": {
+                              "version": "1.8.5",
+                              "dependencies": {
+                                "expand-range": {
+                                  "version": "1.8.2",
+                                  "dependencies": {
+                                    "fill-range": {
+                                      "version": "2.2.3",
+                                      "dependencies": {
+                                        "is-number": {
+                                          "version": "2.1.0"
+                                        },
+                                        "isobject": {
+                                          "version": "2.1.0",
+                                          "dependencies": {
+                                            "isarray": {
+                                              "version": "1.0.0"
+                                            }
+                                          }
+                                        },
+                                        "randomatic": {
+                                          "version": "1.1.5"
+                                        },
+                                        "repeat-string": {
+                                          "version": "1.5.4"
+                                        }
+                                      }
+                                    }
+                                  }
+                                },
+                                "preserve": {
+                                  "version": "0.2.0"
+                                },
+                                "repeat-element": {
+                                  "version": "1.1.2"
+                                }
+                              }
+                            },
+                            "expand-brackets": {
+                              "version": "0.1.5",
+                              "dependencies": {
+                                "is-posix-bracket": {
+                                  "version": "0.1.1"
+                                }
+                              }
+                            },
+                            "extglob": {
+                              "version": "0.3.2"
+                            },
+                            "filename-regex": {
+                              "version": "2.0.0"
+                            },
+                            "is-extglob": {
+                              "version": "1.0.0"
+                            },
+                            "kind-of": {
+                              "version": "3.0.4",
+                              "dependencies": {
+                                "is-buffer": {
+                                  "version": "1.1.3"
+                                }
+                              }
+                            },
+                            "normalize-path": {
                               "version": "2.0.1"
                             },
-                            "once": {
-                              "version": "1.3.3",
+                            "object.omit": {
+                              "version": "2.0.0",
                               "dependencies": {
-                                "wrappy": {
+                                "for-own": {
+                                  "version": "0.1.4",
+                                  "dependencies": {
+                                    "for-in": {
+                                      "version": "0.1.5"
+                                    }
+                                  }
+                                },
+                                "is-extendable": {
+                                  "version": "0.1.1"
+                                }
+                              }
+                            },
+                            "parse-glob": {
+                              "version": "3.0.4",
+                              "dependencies": {
+                                "glob-base": {
+                                  "version": "0.3.0",
+                                  "dependencies": {
+                                    "glob-parent": {
+                                      "version": "2.0.0"
+                                    }
+                                  }
+                                },
+                                "is-dotfile": {
                                   "version": "1.0.2"
                                 }
                               }
                             },
-                            "path-is-absolute": {
-                              "version": "1.0.0"
+                            "regex-cache": {
+                              "version": "0.4.3",
+                              "dependencies": {
+                                "is-equal-shallow": {
+                                  "version": "0.1.3"
+                                },
+                                "is-primitive": {
+                                  "version": "2.0.0"
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "resolve-dir": {
+                          "version": "0.1.1",
+                          "dependencies": {
+                            "expand-tilde": {
+                              "version": "1.2.2",
+                              "dependencies": {
+                                "os-homedir": {
+                                  "version": "1.0.1"
+                                }
+                              }
+                            },
+                            "global-modules": {
+                              "version": "0.2.3",
+                              "dependencies": {
+                                "global-prefix": {
+                                  "version": "0.1.4",
+                                  "dependencies": {
+                                    "ini": {
+                                      "version": "1.3.4"
+                                    },
+                                    "osenv": {
+                                      "version": "0.1.3",
+                                      "dependencies": {
+                                        "os-homedir": {
+                                          "version": "1.0.1"
+                                        },
+                                        "os-tmpdir": {
+                                          "version": "1.0.1"
+                                        }
+                                      }
+                                    },
+                                    "which": {
+                                      "version": "1.2.10",
+                                      "dependencies": {
+                                        "isexe": {
+                                          "version": "1.1.2"
+                                        }
+                                      }
+                                    }
+                                  }
+                                },
+                                "is-windows": {
+                                  "version": "0.2.0"
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "fined": {
+                      "version": "1.0.1",
+                      "dependencies": {
+                        "expand-tilde": {
+                          "version": "1.2.2",
+                          "dependencies": {
+                            "os-homedir": {
+                              "version": "1.0.1"
+                            }
+                          }
+                        },
+                        "lodash.assignwith": {
+                          "version": "4.1.0"
+                        },
+                        "lodash.isarray": {
+                          "version": "4.0.0"
+                        },
+                        "lodash.isempty": {
+                          "version": "4.3.1"
+                        },
+                        "lodash.pick": {
+                          "version": "4.3.0"
+                        },
+                        "parse-filepath": {
+                          "version": "1.0.1",
+                          "dependencies": {
+                            "is-absolute": {
+                              "version": "0.2.5",
+                              "dependencies": {
+                                "is-relative": {
+                                  "version": "0.2.1",
+                                  "dependencies": {
+                                    "is-unc-path": {
+                                      "version": "0.1.1",
+                                      "dependencies": {
+                                        "unc-path-regex": {
+                                          "version": "0.1.2"
+                                        }
+                                      }
+                                    }
+                                  }
+                                },
+                                "is-windows": {
+                                  "version": "0.1.1"
+                                }
+                              }
+                            },
+                            "map-cache": {
+                              "version": "0.2.2"
+                            },
+                            "path-root": {
+                              "version": "0.1.1",
+                              "dependencies": {
+                                "path-root-regex": {
+                                  "version": "0.1.2"
+                                }
+                              }
                             }
                           }
                         }
@@ -11352,6 +12000,15 @@
                     "flagged-respawn": {
                       "version": "0.3.2"
                     },
+                    "lodash.isplainobject": {
+                      "version": "4.0.5"
+                    },
+                    "lodash.isstring": {
+                      "version": "4.0.1"
+                    },
+                    "lodash.mapvalues": {
+                      "version": "4.5.1"
+                    },
                     "rechoir": {
                       "version": "0.6.2"
                     }
@@ -11361,10 +12018,10 @@
                   "version": "3.0.2",
                   "dependencies": {
                     "brace-expansion": {
-                      "version": "1.1.5",
+                      "version": "1.1.6",
                       "dependencies": {
                         "balanced-match": {
-                          "version": "0.4.1"
+                          "version": "0.4.2"
                         },
                         "concat-map": {
                           "version": "0.0.1"
@@ -11399,7 +12056,7 @@
                   }
                 },
                 "request": {
-                  "version": "2.72.0",
+                  "version": "2.74.0",
                   "dependencies": {
                     "aws-sign2": {
                       "version": "0.6.0"
@@ -11541,7 +12198,7 @@
                           }
                         },
                         "sshpk": {
-                          "version": "1.8.3",
+                          "version": "1.9.2",
                           "dependencies": {
                             "asn1": {
                               "version": "0.2.3"
@@ -11595,13 +12252,13 @@
                       "version": "0.8.2"
                     },
                     "qs": {
-                      "version": "6.1.0"
+                      "version": "6.2.1"
                     },
                     "stringstream": {
                       "version": "0.0.5"
                     },
                     "tough-cookie": {
-                      "version": "2.2.2"
+                      "version": "2.3.1"
                     },
                     "tunnel-agent": {
                       "version": "0.4.3"
@@ -11609,7 +12266,7 @@
                   }
                 },
                 "rimraf": {
-                  "version": "2.5.3",
+                  "version": "2.5.4",
                   "dependencies": {
                     "glob": {
                       "version": "7.0.5",
@@ -11689,10 +12346,10 @@
                   }
                 },
                 "semver": {
-                  "version": "5.2.0"
+                  "version": "5.3.0"
                 },
                 "systemjs": {
-                  "version": "0.19.31",
+                  "version": "0.19.36",
                   "dependencies": {
                     "when": {
                       "version": "3.7.7"
@@ -11700,10 +12357,142 @@
                   }
                 },
                 "systemjs-builder": {
-                  "version": "0.15.23",
+                  "version": "0.15.26",
                   "dependencies": {
+                    "babel-core": {
+                      "version": "6.11.4",
+                      "dependencies": {
+                        "babel-code-frame": {
+                          "version": "6.11.0",
+                          "dependencies": {
+                            "esutils": {
+                              "version": "2.0.2"
+                            },
+                            "js-tokens": {
+                              "version": "2.0.0"
+                            }
+                          }
+                        },
+                        "babel-generator": {
+                          "version": "6.11.4",
+                          "dependencies": {
+                            "detect-indent": {
+                              "version": "3.0.1",
+                              "dependencies": {
+                                "get-stdin": {
+                                  "version": "4.0.1"
+                                },
+                                "minimist": {
+                                  "version": "1.2.0"
+                                },
+                                "repeating": {
+                                  "version": "1.1.3",
+                                  "dependencies": {
+                                    "is-finite": {
+                                      "version": "1.0.1",
+                                      "dependencies": {
+                                        "number-is-nan": {
+                                          "version": "1.0.0"
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "babel-helpers": {
+                          "version": "6.8.0"
+                        },
+                        "babel-messages": {
+                          "version": "6.8.0"
+                        },
+                        "babel-runtime": {
+                          "version": "6.11.6",
+                          "dependencies": {
+                            "core-js": {
+                              "version": "2.4.1"
+                            },
+                            "regenerator-runtime": {
+                              "version": "0.9.5"
+                            }
+                          }
+                        },
+                        "babel-template": {
+                          "version": "6.9.0"
+                        },
+                        "babel-traverse": {
+                          "version": "6.12.0",
+                          "dependencies": {
+                            "globals": {
+                              "version": "8.18.0"
+                            },
+                            "invariant": {
+                              "version": "2.2.1",
+                              "dependencies": {
+                                "loose-envify": {
+                                  "version": "1.2.0",
+                                  "dependencies": {
+                                    "js-tokens": {
+                                      "version": "1.0.3"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "babel-types": {
+                          "version": "6.11.1",
+                          "dependencies": {
+                            "esutils": {
+                              "version": "2.0.2"
+                            },
+                            "to-fast-properties": {
+                              "version": "1.0.2"
+                            }
+                          }
+                        },
+                        "babylon": {
+                          "version": "6.8.4"
+                        },
+                        "convert-source-map": {
+                          "version": "1.3.0"
+                        },
+                        "debug": {
+                          "version": "2.2.0",
+                          "dependencies": {
+                            "ms": {
+                              "version": "0.7.1"
+                            }
+                          }
+                        },
+                        "json5": {
+                          "version": "0.4.0"
+                        },
+                        "lodash": {
+                          "version": "4.14.1"
+                        },
+                        "path-exists": {
+                          "version": "1.0.0"
+                        },
+                        "path-is-absolute": {
+                          "version": "1.0.0"
+                        },
+                        "private": {
+                          "version": "0.1.6"
+                        },
+                        "shebang-regex": {
+                          "version": "1.0.0"
+                        },
+                        "slash": {
+                          "version": "1.0.0"
+                        }
+                      }
+                    },
                     "babel-plugin-transform-es2015-modules-systemjs": {
-                      "version": "6.9.0",
+                      "version": "6.12.0",
                       "dependencies": {
                         "babel-helper-hoist-variables": {
                           "version": "6.8.0",
@@ -11712,7 +12501,7 @@
                               "version": "6.11.1",
                               "dependencies": {
                                 "babel-traverse": {
-                                  "version": "6.10.4",
+                                  "version": "6.12.0",
                                   "dependencies": {
                                     "babel-code-frame": {
                                       "version": "6.11.0",
@@ -11726,7 +12515,7 @@
                                       "version": "6.8.0"
                                     },
                                     "babylon": {
-                                      "version": "6.8.3"
+                                      "version": "6.8.4"
                                     },
                                     "debug": {
                                       "version": "2.2.0",
@@ -11758,7 +12547,7 @@
                                   "version": "2.0.2"
                                 },
                                 "lodash": {
-                                  "version": "4.13.1"
+                                  "version": "4.14.1"
                                 },
                                 "to-fast-properties": {
                                   "version": "1.0.2"
@@ -11768,10 +12557,10 @@
                           }
                         },
                         "babel-runtime": {
-                          "version": "6.9.2",
+                          "version": "6.11.6",
                           "dependencies": {
                             "core-js": {
-                              "version": "2.4.0"
+                              "version": "2.4.1"
                             },
                             "regenerator-runtime": {
                               "version": "0.9.5"
@@ -11782,7 +12571,88 @@
                           "version": "6.9.0",
                           "dependencies": {
                             "babel-traverse": {
-                              "version": "6.10.4",
+                              "version": "6.12.0",
+                              "dependencies": {
+                                "babel-code-frame": {
+                                  "version": "6.11.0",
+                                  "dependencies": {
+                                    "esutils": {
+                                      "version": "2.0.2"
+                                    },
+                                    "js-tokens": {
+                                      "version": "2.0.0"
+                                    }
+                                  }
+                                },
+                                "babel-messages": {
+                                  "version": "6.8.0"
+                                },
+                                "debug": {
+                                  "version": "2.2.0",
+                                  "dependencies": {
+                                    "ms": {
+                                      "version": "0.7.1"
+                                    }
+                                  }
+                                },
+                                "globals": {
+                                  "version": "8.18.0"
+                                },
+                                "invariant": {
+                                  "version": "2.2.1",
+                                  "dependencies": {
+                                    "loose-envify": {
+                                      "version": "1.2.0",
+                                      "dependencies": {
+                                        "js-tokens": {
+                                          "version": "1.0.3"
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            },
+                            "babel-types": {
+                              "version": "6.11.1",
+                              "dependencies": {
+                                "esutils": {
+                                  "version": "2.0.2"
+                                },
+                                "to-fast-properties": {
+                                  "version": "1.0.2"
+                                }
+                              }
+                            },
+                            "babylon": {
+                              "version": "6.8.4"
+                            },
+                            "lodash": {
+                              "version": "4.14.1"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "babel-plugin-transform-global-system-wrapper": {
+                      "version": "0.0.1",
+                      "dependencies": {
+                        "babel-template": {
+                          "version": "6.9.0",
+                          "dependencies": {
+                            "babel-runtime": {
+                              "version": "6.11.6",
+                              "dependencies": {
+                                "core-js": {
+                                  "version": "2.4.1"
+                                },
+                                "regenerator-runtime": {
+                                  "version": "0.9.5"
+                                }
+                              }
+                            },
+                            "babel-traverse": {
+                              "version": "6.12.0",
                               "dependencies": {
                                 "babel-code-frame": {
                                   "version": "6.11.0",
@@ -11836,15 +12706,18 @@
                               }
                             },
                             "babylon": {
-                              "version": "6.8.3"
+                              "version": "6.8.4"
                             },
                             "lodash": {
-                              "version": "4.13.1"
+                              "version": "4.14.1"
                             }
                           }
                         }
                       }
                     },
+                    "babel-plugin-transform-system-register": {
+                      "version": "0.0.1"
+                    },
                     "data-uri-to-buffer": {
                       "version": "0.0.4"
                     },
@@ -11916,7 +12789,7 @@
                       "version": "0.31.2",
                       "dependencies": {
                         "source-map-support": {
-                          "version": "0.4.1",
+                          "version": "0.4.2",
                           "dependencies": {
                             "source-map": {
                               "version": "0.1.32",
@@ -12022,7 +12895,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "kind-of": {
-                                      "version": "3.0.3",
+                                      "version": "3.0.4",
                                       "dependencies": {
                                         "is-buffer": {
                                           "version": "1.1.3"
@@ -12049,7 +12922,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "kind-of": {
-                                      "version": "3.0.3",
+                                      "version": "3.0.4",
                                       "dependencies": {
                                         "is-buffer": {
                                           "version": "1.1.3"
@@ -12086,7 +12959,7 @@
           }
         },
         "postcss": {
-          "version": "5.0.21",
+          "version": "5.1.1",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -12124,7 +12997,7 @@
       "version": "0.8.2",
       "dependencies": {
         "postcss": {
-          "version": "5.0.21",
+          "version": "5.1.1",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -12154,13 +13027,13 @@
               "version": "0.23.1",
               "dependencies": {
                 "graceful-fs": {
-                  "version": "4.1.4"
+                  "version": "4.1.5"
                 },
                 "jsonfile": {
                   "version": "2.3.1"
                 },
                 "rimraf": {
-                  "version": "2.5.3",
+                  "version": "2.5.4",
                   "dependencies": {
                     "glob": {
                       "version": "7.0.5",
@@ -12242,10 +13115,10 @@
           "version": "3.0.2",
           "dependencies": {
             "brace-expansion": {
-              "version": "1.1.5",
+              "version": "1.1.6",
               "dependencies": {
                 "balanced-match": {
-                  "version": "0.4.1"
+                  "version": "0.4.2"
                 },
                 "concat-map": {
                   "version": "0.0.1"
@@ -12266,7 +13139,7 @@
           "version": "1.0.0"
         },
         "postcss": {
-          "version": "5.0.21",
+          "version": "5.1.1",
           "dependencies": {
             "source-map": {
               "version": "0.5.6"
@@ -12362,33 +13235,6 @@
             }
           }
         },
-        "jasmine": {
-          "version": "2.4.1",
-          "dependencies": {
-            "exit": {
-              "version": "0.1.2"
-            },
-            "glob": {
-              "version": "3.2.11",
-              "dependencies": {
-                "inherits": {
-                  "version": "2.0.1"
-                },
-                "minimatch": {
-                  "version": "0.3.0",
-                  "dependencies": {
-                    "lru-cache": {
-                      "version": "2.7.3"
-                    },
-                    "sigmund": {
-                      "version": "1.0.1"
-                    }
-                  }
-                }
-              }
-            }
-          }
-        },
         "jasminewd2": {
           "version": "0.0.9"
         },
@@ -12834,9 +13680,6 @@
         }
       }
     },
-    "react-onclickout": {
-      "version": "2.0.4"
-    },
     "react-redux": {
       "version": "4.4.5",
       "dependencies": {
@@ -12847,7 +13690,7 @@
           "version": "2.2.1"
         },
         "lodash": {
-          "version": "4.13.1"
+          "version": "4.14.1"
         },
         "loose-envify": {
           "version": "1.2.0",
@@ -12863,7 +13706,7 @@
       "version": "1.4.2",
       "dependencies": {
         "react-draggable": {
-          "version": "2.1.2"
+          "version": "2.2.0"
         }
       }
     },
@@ -12888,36 +13731,49 @@
       }
     },
     "react-router": {
-      "version": "1.0.0",
+      "version": "2.6.1",
       "dependencies": {
-        "invariant": {
-          "version": "2.2.1",
+        "history": {
+          "version": "2.1.2",
           "dependencies": {
-            "loose-envify": {
-              "version": "1.2.0",
+            "deep-equal": {
+              "version": "1.0.1"
+            },
+            "query-string": {
+              "version": "3.0.3",
               "dependencies": {
-                "js-tokens": {
-                  "version": "1.0.3"
+                "strict-uri-encode": {
+                  "version": "1.1.0"
                 }
               }
+            },
+            "warning": {
+              "version": "2.1.0"
             }
           }
         },
-        "warning": {
-          "version": "2.1.0",
+        "hoist-non-react-statics": {
+          "version": "1.2.0"
+        },
+        "invariant": {
+          "version": "2.2.1"
+        },
+        "loose-envify": {
+          "version": "1.2.0",
           "dependencies": {
-            "loose-envify": {
-              "version": "1.2.0",
-              "dependencies": {
-                "js-tokens": {
-                  "version": "1.0.3"
-                }
-              }
+            "js-tokens": {
+              "version": "1.0.3"
             }
           }
+        },
+        "warning": {
+          "version": "3.0.0"
         }
       }
     },
+    "react-router-redux": {
+      "version": "4.0.5"
+    },
     "react-sortable": {
       "version": "1.0.1"
     },
@@ -12988,10 +13844,10 @@
       "version": "3.5.2",
       "dependencies": {
         "lodash": {
-          "version": "4.13.1"
+          "version": "4.14.1"
         },
         "lodash-es": {
-          "version": "4.13.1"
+          "version": "4.14.1"
         },
         "loose-envify": {
           "version": "1.2.0",
@@ -13019,7 +13875,7 @@
                   "version": "3.0.3"
                 },
                 "lodash.isarguments": {
-                  "version": "3.0.8"
+                  "version": "3.0.9"
                 },
                 "lodash.keysin": {
                   "version": "3.0.8",
@@ -13038,6 +13894,25 @@
         }
       }
     },
+    "redux-auth-wrapper": {
+      "version": "0.6.0",
+      "dependencies": {
+        "hoist-non-react-statics": {
+          "version": "1.2.0"
+        },
+        "lodash.isempty": {
+          "version": "4.2.1",
+          "dependencies": {
+            "lodash._root": {
+              "version": "3.0.1"
+            },
+            "lodash.keys": {
+              "version": "4.0.8"
+            }
+          }
+        }
+      }
+    },
     "redux-form": {
       "version": "4.2.2",
       "dependencies": {
@@ -13071,7 +13946,7 @@
                   "version": "3.0.3"
                 },
                 "lodash.isarguments": {
-                  "version": "3.0.8"
+                  "version": "3.0.9"
                 },
                 "lodash.keysin": {
                   "version": "3.0.8",
@@ -13088,7 +13963,7 @@
       }
     },
     "redux-router": {
-      "version": "1.0.0",
+      "version": "2.1.2",
       "dependencies": {
         "deep-equal": {
           "version": "1.0.1"
@@ -13179,7 +14054,7 @@
       "version": "1.13.1",
       "dependencies": {
         "acorn": {
-          "version": "3.2.0"
+          "version": "3.3.0"
         },
         "async": {
           "version": "1.5.2"
@@ -13191,7 +14066,7 @@
           "version": "0.9.1",
           "dependencies": {
             "graceful-fs": {
-              "version": "4.1.4"
+              "version": "4.1.5"
             },
             "memory-fs": {
               "version": "0.2.0"
@@ -13298,7 +14173,7 @@
                           "version": "0.1.4",
                           "dependencies": {
                             "kind-of": {
-                              "version": "3.0.3",
+                              "version": "3.0.4",
                               "dependencies": {
                                 "is-buffer": {
                                   "version": "1.1.3"
@@ -13325,7 +14200,7 @@
                           "version": "0.1.4",
                           "dependencies": {
                             "kind-of": {
-                              "version": "3.0.3",
+                              "version": "3.0.4",
                               "dependencies": {
                                 "is-buffer": {
                                   "version": "1.1.3"
@@ -13373,7 +14248,7 @@
                       "version": "1.0.1"
                     },
                     "micromatch": {
-                      "version": "2.3.10",
+                      "version": "2.3.11",
                       "dependencies": {
                         "arr-diff": {
                           "version": "2.0.0",
@@ -13442,7 +14317,7 @@
                           "version": "1.0.0"
                         },
                         "kind-of": {
-                          "version": "3.0.3",
+                          "version": "3.0.4",
                           "dependencies": {
                             "is-buffer": {
                               "version": "1.1.3"
@@ -13498,10 +14373,10 @@
                   "version": "1.0.0"
                 },
                 "fsevents": {
-                  "version": "1.0.12",
+                  "version": "1.0.14",
                   "dependencies": {
-                    "ansi": {
-                      "version": "0.3.1"
+                    "abbrev": {
+                      "version": "1.0.9"
                     },
                     "ansi-regex": {
                       "version": "2.0.0"
@@ -13509,6 +14384,9 @@
                     "ansi-styles": {
                       "version": "2.2.1"
                     },
+                    "aproba": {
+                      "version": "1.0.4"
+                    },
                     "are-we-there-yet": {
                       "version": "1.1.2"
                     },
@@ -13525,42 +14403,52 @@
                       "version": "0.6.0"
                     },
                     "aws4": {
-                      "version": "1.3.2",
+                      "version": "1.4.1"
+                    },
+                    "balanced-match": {
+                      "version": "0.4.2"
+                    },
+                    "bl": {
+                      "version": "1.1.2",
                       "dependencies": {
-                        "lru-cache": {
-                          "version": "4.0.1",
-                          "dependencies": {
-                            "pseudomap": {
-                              "version": "1.0.2"
-                            },
-                            "yallist": {
-                              "version": "2.0.0"
-                            }
-                          }
+                        "readable-stream": {
+                          "version": "2.0.6"
                         }
                       }
                     },
-                    "bl": {
-                      "version": "1.0.3"
-                    },
                     "block-stream": {
-                      "version": "0.0.8"
+                      "version": "0.0.9"
                     },
                     "boom": {
                       "version": "2.10.1"
                     },
+                    "brace-expansion": {
+                      "version": "1.1.5"
+                    },
+                    "buffer-shims": {
+                      "version": "1.0.0"
+                    },
                     "caseless": {
                       "version": "0.11.0"
                     },
                     "chalk": {
                       "version": "1.1.3"
                     },
+                    "code-point-at": {
+                      "version": "1.0.0"
+                    },
                     "combined-stream": {
                       "version": "1.0.5"
                     },
                     "commander": {
                       "version": "2.9.0"
                     },
+                    "concat-map": {
+                      "version": "0.0.1"
+                    },
+                    "console-control-strings": {
+                      "version": "1.1.0"
+                    },
                     "core-util-is": {
                       "version": "1.0.2"
                     },
@@ -13568,7 +14456,7 @@
                       "version": "2.0.5"
                     },
                     "dashdash": {
-                      "version": "1.13.0",
+                      "version": "1.14.0",
                       "dependencies": {
                         "assert-plus": {
                           "version": "1.0.0"
@@ -13605,32 +14493,17 @@
                     "form-data": {
                       "version": "1.0.0-rc4"
                     },
+                    "fs.realpath": {
+                      "version": "1.0.0"
+                    },
                     "fstream": {
-                      "version": "1.0.8"
+                      "version": "1.0.10"
                     },
                     "fstream-ignore": {
-                      "version": "1.0.3",
-                      "dependencies": {
-                        "minimatch": {
-                          "version": "3.0.0",
-                          "dependencies": {
-                            "brace-expansion": {
-                              "version": "1.1.3",
-                              "dependencies": {
-                                "balanced-match": {
-                                  "version": "0.3.0"
-                                },
-                                "concat-map": {
-                                  "version": "0.0.1"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
+                      "version": "1.0.5"
                     },
                     "gauge": {
-                      "version": "1.2.7"
+                      "version": "2.6.0"
                     },
                     "generate-function": {
                       "version": "2.0.0"
@@ -13638,8 +14511,19 @@
                     "generate-object-property": {
                       "version": "1.2.0"
                     },
+                    "getpass": {
+                      "version": "0.1.6",
+                      "dependencies": {
+                        "assert-plus": {
+                          "version": "1.0.0"
+                        }
+                      }
+                    },
+                    "glob": {
+                      "version": "7.0.5"
+                    },
                     "graceful-fs": {
-                      "version": "4.1.3"
+                      "version": "4.1.4"
                     },
                     "graceful-readlink": {
                       "version": "1.0.1"
@@ -13650,8 +14534,11 @@
                     "has-ansi": {
                       "version": "2.0.0"
                     },
+                    "has-color": {
+                      "version": "0.1.7"
+                    },
                     "has-unicode": {
-                      "version": "2.0.0"
+                      "version": "2.0.1"
                     },
                     "hawk": {
                       "version": "3.1.3"
@@ -13662,12 +14549,18 @@
                     "http-signature": {
                       "version": "1.1.1"
                     },
+                    "inflight": {
+                      "version": "1.0.5"
+                    },
                     "inherits": {
                       "version": "2.0.1"
                     },
                     "ini": {
                       "version": "1.3.4"
                     },
+                    "is-fullwidth-code-point": {
+                      "version": "1.0.0"
+                    },
                     "is-my-json-valid": {
                       "version": "2.13.1"
                     },
@@ -13699,28 +14592,16 @@
                       "version": "2.0.0"
                     },
                     "jsprim": {
-                      "version": "1.2.2"
-                    },
-                    "lodash.pad": {
-                      "version": "4.1.0"
-                    },
-                    "lodash.padend": {
-                      "version": "4.2.0"
-                    },
-                    "lodash.padstart": {
-                      "version": "4.2.0"
-                    },
-                    "lodash.repeat": {
-                      "version": "4.0.0"
-                    },
-                    "lodash.tostring": {
-                      "version": "4.1.2"
+                      "version": "1.3.0"
                     },
                     "mime-db": {
-                      "version": "1.22.0"
+                      "version": "1.23.0"
                     },
                     "mime-types": {
-                      "version": "2.1.10"
+                      "version": "2.1.11"
+                    },
+                    "minimatch": {
+                      "version": "3.0.2"
                     },
                     "minimist": {
                       "version": "0.0.8"
@@ -13732,44 +14613,46 @@
                       "version": "0.7.1"
                     },
                     "nan": {
-                      "version": "2.3.5"
+                      "version": "2.4.0"
                     },
                     "node-pre-gyp": {
-                      "version": "0.6.25",
-                      "dependencies": {
-                        "nopt": {
-                          "version": "3.0.6",
-                          "dependencies": {
-                            "abbrev": {
-                              "version": "1.0.7"
-                            }
-                          }
-                        }
-                      }
+                      "version": "0.6.29"
                     },
                     "node-uuid": {
                       "version": "1.4.7"
                     },
+                    "nopt": {
+                      "version": "3.0.6"
+                    },
                     "npmlog": {
-                      "version": "2.0.3"
+                      "version": "3.1.2"
+                    },
+                    "number-is-nan": {
+                      "version": "1.0.0"
                     },
                     "oauth-sign": {
-                      "version": "0.8.1"
+                      "version": "0.8.2"
+                    },
+                    "object-assign": {
+                      "version": "4.1.0"
                     },
                     "once": {
                       "version": "1.3.3"
                     },
+                    "path-is-absolute": {
+                      "version": "1.0.0"
+                    },
                     "pinkie": {
                       "version": "2.0.4"
                     },
                     "pinkie-promise": {
-                      "version": "2.0.0"
+                      "version": "2.0.1"
                     },
                     "process-nextick-args": {
-                      "version": "1.0.6"
+                      "version": "1.0.7"
                     },
                     "qs": {
-                      "version": "6.0.2"
+                      "version": "6.2.0"
                     },
                     "rc": {
                       "version": "1.1.6",
@@ -13780,67 +14663,36 @@
                       }
                     },
                     "readable-stream": {
-                      "version": "2.0.6"
+                      "version": "2.1.4"
                     },
                     "request": {
-                      "version": "2.69.0"
+                      "version": "2.73.0"
                     },
                     "rimraf": {
-                      "version": "2.5.2",
-                      "dependencies": {
-                        "glob": {
-                          "version": "7.0.3",
-                          "dependencies": {
-                            "inflight": {
-                              "version": "1.0.4",
-                              "dependencies": {
-                                "wrappy": {
-                                  "version": "1.0.1"
-                                }
-                              }
-                            },
-                            "inherits": {
-                              "version": "2.0.1"
-                            },
-                            "minimatch": {
-                              "version": "3.0.0",
-                              "dependencies": {
-                                "brace-expansion": {
-                                  "version": "1.1.3",
-                                  "dependencies": {
-                                    "balanced-match": {
-                                      "version": "0.3.0"
-                                    },
-                                    "concat-map": {
-                                      "version": "0.0.1"
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "once": {
-                              "version": "1.3.3",
-                              "dependencies": {
-                                "wrappy": {
-                                  "version": "1.0.1"
-                                }
-                              }
-                            },
-                            "path-is-absolute": {
-                              "version": "1.0.0"
-                            }
-                          }
-                        }
-                      }
+                      "version": "2.5.3"
                     },
                     "semver": {
-                      "version": "5.1.0"
+                      "version": "5.2.0"
+                    },
+                    "set-blocking": {
+                      "version": "2.0.0"
+                    },
+                    "signal-exit": {
+                      "version": "3.0.0"
                     },
                     "sntp": {
                       "version": "1.0.9"
                     },
                     "sshpk": {
-                      "version": "1.7.4"
+                      "version": "1.8.3",
+                      "dependencies": {
+                        "assert-plus": {
+                          "version": "1.0.0"
+                        }
+                      }
+                    },
+                    "string-width": {
+                      "version": "1.0.1"
                     },
                     "string_decoder": {
                       "version": "0.10.31"
@@ -13861,16 +14713,16 @@
                       "version": "2.2.1"
                     },
                     "tar-pack": {
-                      "version": "3.1.3"
+                      "version": "3.1.4"
                     },
                     "tough-cookie": {
                       "version": "2.2.2"
                     },
                     "tunnel-agent": {
-                      "version": "0.4.2"
+                      "version": "0.4.3"
                     },
                     "tweetnacl": {
-                      "version": "0.14.3"
+                      "version": "0.13.3"
                     },
                     "uid-number": {
                       "version": "0.0.6"
@@ -13881,8 +14733,11 @@
                     "verror": {
                       "version": "1.3.6"
                     },
+                    "wide-align": {
+                      "version": "1.1.0"
+                    },
                     "wrappy": {
-                      "version": "1.0.1"
+                      "version": "1.0.2"
                     },
                     "xtend": {
                       "version": "4.0.1"
@@ -13921,10 +14776,10 @@
                       "version": "3.0.2",
                       "dependencies": {
                         "brace-expansion": {
-                          "version": "1.1.5",
+                          "version": "1.1.6",
                           "dependencies": {
                             "balanced-match": {
-                              "version": "0.4.1"
+                              "version": "0.4.2"
                             },
                             "concat-map": {
                               "version": "0.0.1"
@@ -13964,7 +14819,7 @@
               }
             },
             "graceful-fs": {
-              "version": "4.1.4"
+              "version": "4.1.5"
             }
           }
         },
diff --git a/package.json b/package.json
index 9efe1f4b2108177924988a8fd5b12802cd43bfff..7978a8e6786fa6a9f8b5805d42ca66c448a44f62 100644
--- a/package.json
+++ b/package.json
@@ -25,11 +25,12 @@
     "dc": "^2.0.0-beta.25",
     "diff": "^2.2.1",
     "fixed-data-table": "^0.6.0",
-    "history": "1.12.0",
+    "history": "^3.0.0",
     "humanize-plus": "^1.8.1",
     "icepick": "^1.1.0",
     "inflection": "^1.7.1",
     "isomorphic-fetch": "^2.2.1",
+    "js-cookie": "^2.1.2",
     "moment": "^2.12.0",
     "node-libs-browser": "^0.5.3",
     "normalizr": "^2.0.0",
@@ -42,20 +43,21 @@
     "react-ansi-style": "^1.0.0",
     "react-dom": "^15.2.1",
     "react-draggable": "^1.1.3",
-    "react-onclickout": "^2.0.4",
-    "react-redux": "^4.4.0",
+    "react-redux": "^4.4.5",
     "react-resizable": "^1.0.1",
     "react-retina-image": "^2.0.0",
-    "react-router": "1.0.0",
+    "react-router": "^2.6.0",
+    "react-router-redux": "^4.0.5",
     "react-sortable": "^1.0.1",
     "react-virtualized": "^6.1.2",
     "recompose": "^0.20.2",
-    "redux": "^3.0.4",
+    "redux": "^3.5.2",
     "redux-actions": "^0.9.1",
+    "redux-auth-wrapper": "^0.6.0",
     "redux-form": "^4.2.0",
     "redux-logger": "^2.6.1",
     "redux-promise": "^0.5.0",
-    "redux-router": "^1.0.0-beta4",
+    "redux-router": "^2.1.2",
     "redux-thunk": "^2.0.1",
     "reselect": "^2.0.1",
     "screenfull": "^3.0.0",
diff --git a/resources/frontend_client/index_template.html b/resources/frontend_client/index_template.html
index e82c09a667791ebf36b770c31588baa4fef67c50..ff15eac3fbcb62323a24e4b3fe1384bde8b74c04 100644
--- a/resources/frontend_client/index_template.html
+++ b/resources/frontend_client/index_template.html
@@ -14,9 +14,9 @@
         </script>
     </head>
 
-    <body ng-controller="Metabase">
-        <div class="Nav" ng-controller="Nav" mb-react-component="Navbar"></div>
-        <main class="relative full-height z1" ng-view></main>
+    <body>
+        <div id="root" />
+        <div style="display: none;" ng-controller="Metabase" ng-view />
     </body>
 
     <script type="text/javascript">
diff --git a/resources/kanye-quotes.edn b/resources/kanye-quotes.edn
index 8105a2a4f800e8f87d4a67d22a5a526d17267533..5f72a468840e8add74ce8ded0f1368180a5b2dd1 100644
--- a/resources/kanye-quotes.edn
+++ b/resources/kanye-quotes.edn
@@ -1,7 +1,9 @@
-["But for me to have the opportunity to stand in front of a bunch of executives and present myself, I had to hustle in my own way. I can't tell you how frustrating it was that they didn't get that. No joke - I'd leave meetings crying all the time."
+["And with me, I don’t give a f**k, bro; it is what it is. I’m the best—now what? I don’t know if that’s a vain statement. I don’t particularly like photos of myself, though."
+ "But for me to have the opportunity to stand in front of a bunch of executives and present myself, I had to hustle in my own way. I can't tell you how frustrating it was that they didn't get that. No joke - I'd leave meetings crying all the time."
  "Damn Yeezy, they all gotta be dimes? Well, Adam gave up a rib so mine better be prime."
  "Exes can be mad but just know I never let them play with my ass... I don't do that... I stay away from that area all together."
  "Fashion breaks my heart."
+ "Here’s something that’s contrary to popular belief: I actually don’t like thinking. I think people think I like to think a lot. And I don’t. I do not like to think at all."
  "How many m*****f***ers you done seen with a leather jogging pant?"
  "I am God's vessel. But my greatest pain in life is that I will never be able to see myself perform live."
  "I am not a fan of books. I would never want a book's autograph. I am a proud non-reader of books."
@@ -13,11 +15,13 @@
  "I feel like the type of girl I would be with is a fellow superhero. So we get that 'already flying and now we're just flying together' thing."
  "I hate when I'm on a flight and I wake up with a water bottle next to me like oh great now I gotta be responsible for this water bottle."
  "I know I got angels watchin me from the other side."
+ "I love her nude selfies. Like, I love ones from the side, the back ones, and the front. I just love seeing her naked; I love nudity. And I love beautiful shapes. I feel like it's almost a Renaissance thing, a painting, a modern version of a painting. I think it's important for Kim to have her figure. To not show it would be like Adele not singing."
  "I really appreciate the moments that I was able to win rap album of the year or whatever."
  "I refuse to accept other people's ideas of happiness for me. As if there's a 'one size fits all' standard for happiness."
  "I still think I am the greatest."
  "I thank Marc Jacobs so much for giving me the opportunity to design a shoe for Louis Vuitton, but the thing that broke my heart most was when they said, 'You're finished. The shoe's finished.'"
  "I think I do myself a disservice by comparing myself to Steve Jobs and Walt Disney and human beings that we've seen before. It should be more like Willy Wonka... and welcome to my chocolate factory."
+ "I used to have insecurity about my finances, then I announced that I had debt, and now I don’t have any insecurities."
  "I will go down as the voice of this generation, of this decade, I will be the loudest voice."
  "I would hear stories about Steve Jobs and feel like he was at 100 percent exactly what he wanted to do, but I'm sure even a Steve Jobs has compromised. Even a Rick Owens has compromised. You know, even a Kanye West has compromised. Sometimes you don't even know when you're being compromised till after the fact, and that's what you regret."
  "I'll say things that are serious and put them in a joke form so people can enjoy them. We laugh to keep from crying."
diff --git a/src/metabase/api/setup.clj b/src/metabase/api/setup.clj
index 35df0c67e05cff67e04b14af46f160a03e0c4809..23e1551bda3b5614700987c9ef35b1870a2ab305 100644
--- a/src/metabase/api/setup.clj
+++ b/src/metabase/api/setup.clj
@@ -111,13 +111,13 @@
      {:title       "Set up email"
       :group       "Get connected"
       :description "Add email credentials so you can more easily invite team members and get updates via Pulses."
-      :link        "/admin/settings/?section=Email"
+      :link        "/admin/settings/email"
       :completed   (email/email-configured?)
       :triggered   :always}
      {:title       "Set Slack credentials"
       :group       "Get connected"
       :description "Does your team use Slack?  If so, you can send automated updates via pulses and ask questions with Metabot."
-      :link        "/admin/settings/?section=Slack"
+      :link        "/admin/settings/slack"
       :completed   (slack/slack-configured?)
       :triggered   :always}
      {:title       "Invite team members"
diff --git a/src/metabase/sample_data.clj b/src/metabase/sample_data.clj
index 56abf6989ab3bee6fe1d97f53b680cc9f6f9fd92..a89e97274c7e8e89ec47345dfbac1d1dc2bf02d2 100644
--- a/src/metabase/sample_data.clj
+++ b/src/metabase/sample_data.clj
@@ -7,9 +7,17 @@
             [metabase.sync-database :as sync-database]
             [metabase.util :as u]))
 
+(def ^:private ^:const ^String sample-dataset-name     "Sample Dataset")
+(def ^:private ^:const ^String sample-dataset-filename "sample-dataset.db.mv.db")
 
-(def ^:private ^:const sample-dataset-name     "Sample Dataset")
-(def ^:private ^:const sample-dataset-filename "sample-dataset.db.mv.db")
+(defn- db-details []
+  (let [resource (io/resource sample-dataset-filename)]
+    (when-not resource
+      (throw (Exception. (format "Can't load sample dataset: the DB file '%s' can't be found." sample-dataset-filename))))
+    {:db (-> (.getPath resource)
+             (s/replace #"^file:" "zip:")           ; to connect to an H2 DB inside a JAR just replace file: with zip:
+             (s/replace #"\.mv\.db$" "")            ; strip the .mv.db suffix from the path
+             (str ";USER=GUEST;PASSWORD=guest"))})) ; specify the GUEST user account created for the DB
 
 (defn add-sample-dataset!
   "Add the sample dataset as a Metabase DB if it doesn't already exist."
@@ -17,28 +25,17 @@
   (when-not (db/exists? Database :is_sample true)
     (try
       (log/info "Loading sample dataset...")
-      (let [resource (io/resource sample-dataset-filename)]
-        (if-not resource
-          (log/error (u/format-color 'red "Can't load sample dataset: the DB file '%s' can't be found." sample-dataset-filename))
-          (let [h2-file (-> (.getPath resource)
-                            (s/replace #"^file:" "zip:")        ; to connect to an H2 DB inside a JAR just replace file: with zip:
-                            (s/replace #"\.mv\.db$" "")         ; strip the .mv.db suffix from the path
-                            (str ";USER=GUEST;PASSWORD=guest")) ; specify the GUEST user account created for the DB
-                db      (db/insert! Database
-                          :name      sample-dataset-name
-                          :details   {:db h2-file}
-                          :engine    :h2
-                          :is_sample true)]
-            (sync-database/sync-database! db))))
+      (sync-database/sync-database! (db/insert! Database
+                                      :name      sample-dataset-name
+                                      :details   (db-details)
+                                      :engine    :h2
+                                      :is_sample true))
       (catch Throwable e
         (log/error (u/format-color 'red "Failed to load sample dataset: %s\n%s" (.getMessage e) (u/pprint-to-str (u/filtered-stacktrace e))))))))
 
 (defn update-sample-dataset-if-needed!
-  "Re-sync the sample dataset DB if it exists."
+  "Update the path to the sample dataset DB if it exists in case the JAR has moved."
   []
-  ;; TODO - it would be a bit nicer if we skipped this when the data hasn't changed
   (when-let [db (Database :is_sample true)]
-    (try
-      (sync-database/sync-database! db)
-      (catch Throwable e
-        (log/error (u/format-color 'red "Failed to update sample dataset: %s\n%s" (.getMessage e) (u/pprint-to-str (u/filtered-stacktrace e))))))))
+    (db/update! Database (:id db)
+      :details (db-details))))