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/version b/bin/version
index 74de086bb60b978c4f2e90c7084f2c4a0412001e..6c7568f06a9becc31663bea6d7fc16cf2d65b276 100755
--- a/bin/version
+++ b/bin/version
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-VERSION="v0.19.0-snapshot"
+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/users-guide/start.md b/docs/users-guide/start.md
index a424b719741503a259427b5901bbcf3de999ea98..30055e03cc6f5c19ff990163fce22bed9451dfc9 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/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/EmptyState.jsx b/frontend/src/metabase/components/EmptyState.jsx
index 0e66f2d34a1d67b0407d8e91278505b88ecbacf8..2a4e5d56c68162c1fa6ec44ac74729c53e4d01de 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";
 
@@ -17,7 +18,7 @@ const EmptyState = ({ title, message, icon, image, action, link }) =>
             <h3 className="text-grey-2 mt4" style={{maxWidth: "350px"}}>{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/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/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/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 c9a6eeb9fe2caf7171ecc7407658326f9a64bcbb..a313a7e13883c6215c2122fec407360a97ce3330 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];
@@ -181,19 +188,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()
@@ -207,10 +221,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
@@ -263,7 +277,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");
 
@@ -271,12 +285,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 }) {
@@ -314,6 +335,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);
@@ -400,7 +425,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,
@@ -410,5 +443,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 68392ddf9da2b9f5d104a416bcafaa8ca28fa6ef..cd616e012b3286739ca599b9316271626290a659 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;
@@ -33,8 +33,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..f21955be677c40e49f53a1fcc61f5b5e8c38a601 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,7 +55,7 @@ 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>
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/lib/visualization_settings.js b/frontend/src/metabase/lib/visualization_settings.js
index 79c57088057962f6fe0d94902775902c5191513b..8518f90adc2d4e01885b71565038c2fe931dde04 100644
--- a/frontend/src/metabase/lib/visualization_settings.js
+++ b/frontend/src/metabase/lib/visualization_settings.js
@@ -274,7 +274,7 @@ const SETTINGS = {
     },
     "pie.dimension": {
         section: "Data",
-        title: "Measure",
+        title: "Dimension",
         widget: ChartSettingSelect,
         isValid: ([{ card, data }], vizSettings) =>
             columnsAreValid(card.visualization_settings["pie.dimension"], data, isDimension),
@@ -286,7 +286,7 @@ const SETTINGS = {
     },
     "pie.metric": {
         section: "Data",
-        title: "Slice by",
+        title: "Measure",
         widget: ChartSettingSelect,
         isValid: ([{ card, data }], vizSettings) =>
             columnsAreValid(card.visualization_settings["pie.metric"], data, isMetric),
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 c1b9226320fe20e99ae360bcc16caea1d7278d4e..ad137db4543dea4b4b64362d4abdd5044e79448a 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/VisualizationSettings.jsx b/frontend/src/metabase/query_builder/VisualizationSettings.jsx
index 1998c2ea3f665956c8c0c607954d9da017c00b0c..d7db17ee26de4beb083a7d197c0e132fee382853 100644
--- a/frontend/src/metabase/query_builder/VisualizationSettings.jsx
+++ b/frontend/src/metabase/query_builder/VisualizationSettings.jsx
@@ -92,7 +92,7 @@ export default class VisualizationSettings extends React.Component {
                     {this.renderChartTypePicker()}
                     <ModalWithTrigger
                         className="Modal Modal--wide Modal--tall"
-                        triggerElement={<Icon name="gear" />}
+                        triggerElement={<span data-metabase-event="Query Builder;Chart Settings"><Icon name="gear"/></span>}
                         triggerClasses="text-brand-hover"
                     >
                         <ChartSettings
diff --git a/frontend/src/metabase/query_builder/actions.js b/frontend/src/metabase/query_builder/actions.js
index 5a1e5c8fa253be94ff0639ae03be9f836b1794ea..0109d8ff329351b8ae352915ade812327894596b 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";
@@ -20,11 +21,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 = {};
 
@@ -45,11 +113,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));
@@ -64,10 +132,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");
                 }
@@ -82,7 +150,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);
 
@@ -120,14 +188,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
         };
     };
 });
@@ -167,7 +234,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));
@@ -176,7 +243,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;
@@ -264,9 +331,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;
     }
 });
@@ -274,9 +341,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, (path, value) => {
     return (dispatch, getState) => {
-        const { qb: { card, uiControls, updateUrl } } = getState();
+        const { qb: { card, uiControls } } = getState();
         let updatedCard = updateVisualizationSettings(card, uiControls.isEditing, card.display, i.assocIn(card.visualization_settings, path, value));
-        updateUrl(updatedCard, true);
+        dispatch(updateUrl(updatedCard, true));
         return updatedCard;
     };
 });
@@ -284,9 +351,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;
     };
 });
@@ -312,13 +379,7 @@ export const updateTemplateTag = createThunkAction(UPDATE_TEMPLATE_TAG, (templat
 export const SET_PARAMETER_VALUE = "SET_PARAMETER_VALUE";
 export const setParameterValue = createThunkAction(SET_PARAMETER_VALUE, (parameterId, value) => {
     return (dispatch, getState) => {
-        let { qb: { parameterValues } } = getState();
-
-        // apply this specific value
-        parameterValues = { ...parameterValues, [parameterId]: value};
-
-        // the return value from our action is still just the id/value of the parameter set
-        return {id: parameterId, value};
+        return { id: parameterId, value };
     };
 });
 
@@ -326,13 +387,11 @@ export const setParameterValue = createThunkAction(SET_PARAMETER_VALUE, (paramet
 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);
 
@@ -343,13 +402,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);
 
@@ -361,7 +418,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));
@@ -370,7 +427,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;
     };
@@ -378,14 +435,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;
     };
@@ -687,7 +744,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, paramValues) => {
+export const runQuery = createThunkAction(RUN_QUERY, (card, shouldUpdateUrl=true, paramValues) => {
     return async (dispatch, getState) => {
         const state = getState();
         const parameters = getParameters(state);
@@ -720,8 +777,8 @@ export const runQuery = createThunkAction(RUN_QUERY, (card, updateUrl=true, para
             }).filter(p => p);
         }
 
-        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 2b3f2af3cba9f3822bc6350c9f2a5bd5daa9f0b3..869ad84fe0edbfe707fc82a30ca082aa45611284 100644
--- a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
+++ b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
@@ -37,7 +37,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"]);
@@ -70,10 +70,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),
@@ -106,9 +105,13 @@ const mapStateToProps = (state, props) => {
     }
 }
 
+const getURL = (location) =>
+    location.pathname + location.search + location.hash;
+
 
 const mapDispatchToProps = {
     ...actions,
+    onChangeLocation: push
 };
 
 @connect(mapStateToProps, mapDispatchToProps)
@@ -117,18 +120,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);
     }
 
@@ -139,14 +141,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);
     }
 
@@ -156,13 +161,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;
 
@@ -185,7 +183,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/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/query_builder/template_tags/TagEditorHelp.jsx b/frontend/src/metabase/query_builder/template_tags/TagEditorHelp.jsx
index c929909b52f4537b475c9b41f42f58adf261e3ae..153bb3b5376e0efda390eeb26f1ce1c314bb4b17 100644
--- a/frontend/src/metabase/query_builder/template_tags/TagEditorHelp.jsx
+++ b/frontend/src/metabase/query_builder/template_tags/TagEditorHelp.jsx
@@ -56,7 +56,7 @@ const TagExample = ({ datasetQuery, setQuery }) =>
             { setQuery && (
                 <div
                     className="Button Button--small"
-                    data-metabase-event="QueryBuilder;Template Tage Example Query Used"
+                    data-metabase-event="QueryBuilder;Template Tag Example Query Used"
                     onClick={() => setQuery(datasetQuery, true) }
                 >
                     Try it
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/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/reference/containers/ReferenceApp.jsx b/frontend/src/metabase/reference/containers/ReferenceApp.jsx
index d67aabd691b27e3374395bbf13dc05cd66d1ca94..a3043a4a56b7490ec7211ec215521212c7c370ed 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 = {
@@ -78,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"
+                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 558ab1d1a8975ec2af981a33c260dcc2ce1023e3..2fe7f7357b76a9d96573e5ec4dc611510263e237 100644
--- a/frontend/src/metabase/reference/containers/ReferenceEntity.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceEntity.jsx
@@ -41,20 +41,20 @@ import * as metadataActions from 'metabase/redux/metadata';
 import * as actions from 'metabase/reference/reference';
 
 const mapStateToProps = (state, props) => ({
-    section: getSection(state),
-    entity: getData(state) || {},
-    table: getTable(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),
-    hasQuestions: getHasQuestions(state),
-    hasDisplayName: getHasDisplayName(state),
-    isFormulaExpanded: getIsFormulaExpanded(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 = {
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 5925c76c86f78d4c4a1e532a90d1224b0ebbbc0a..b6a7eaa65705a4cdf63bbdaaf4850878f7e64228 100644
--- a/frontend/src/metabase/reference/containers/ReferenceFieldsList.jsx
+++ b/frontend/src/metabase/reference/containers/ReferenceFieldsList.jsx
@@ -40,16 +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),
-        hasRevisionHistory: getHasRevisionHistory(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)
     };
 }
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/selectors.js b/frontend/src/metabase/reference/selectors.js
index 5039e6b040b378422a85d4f3c674d4a0fc281e90..15fb4bcb9cccb3f3ed6f34c1f44828e73363756e 100644
--- a/frontend/src/metabase/reference/selectors.js
+++ b/frontend/src/metabase/reference/selectors.js
@@ -74,7 +74,7 @@ const referenceSections = {
     }
 };
 
-const getReferenceSections = (state) => referenceSections;
+const getReferenceSections = (state, props) => referenceSections;
 
 const getMetricSections = (metric, table, user) => metric ? {
     [`/reference/metrics/${metric.id}`]: {
@@ -409,34 +409,34 @@ const getTableFieldSections = (database, table, field) => database && table && f
     }
 } : {};
 
-export const getUser = (state) => state.currentUser;
+export const getUser = (state, props) => state.currentUser;
 
-export const getSectionId = (state) => state.router.location.pathname;
+export const getSectionId = (state, props) => props.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 ?
@@ -458,8 +458,8 @@ export const getTable = createSelector(
             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) : {}
@@ -477,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],
@@ -489,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],
@@ -609,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 {};
     }
@@ -619,12 +619,12 @@ export const getData = (state) => {
         return {};
     }
 
-    return selector(state);
+    return selector(state, props);
 };
 
-export const getLoading = (state) => state.reference.isLoading;
+export const getLoading = (state, props) => state.reference.isLoading;
 
-export const getError = (state) => state.reference.error;
+export const getError = (state, props) => state.reference.error;
 
 export const getBreadcrumbs = createSelector(
     [getSection],
@@ -657,6 +657,6 @@ export const getHasQuestions = createSelector(
     (section) => section.questions && section.questions.length > 0
 )
 
-export const getIsEditing = (state) => state.reference.isEditing;
+export const getIsEditing = (state, props) => state.reference.isEditing;
 
-export const getIsFormulaExpanded = (state) => state.reference.isFormulaExpanded;
+export const getIsFormulaExpanded = (state, props) => state.reference.isFormulaExpanded;
\ No newline at end of file
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/ChartSettings.jsx b/frontend/src/metabase/visualizations/components/ChartSettings.jsx
index c3df210e3c1e0c7705856db833eb8892cad117cc..e2a48cec5c475ae65b1b564d083fb90df1d84589 100644
--- a/frontend/src/metabase/visualizations/components/ChartSettings.jsx
+++ b/frontend/src/metabase/visualizations/components/ChartSettings.jsx
@@ -5,6 +5,7 @@ import _ from "underscore";
 
 import Visualization from "metabase/visualizations/components/Visualization.jsx"
 import { getSettingsWidgets } from "metabase/lib/visualization_settings";
+import MetabaseAnalytics from "metabase/lib/analytics";
 
 const ChartSettingsTab = ({name, active, onClick}) =>
   <a
@@ -54,6 +55,9 @@ class ChartSettings extends Component {
     }
 
     onChangeSettings = (newSettings) => {
+        for (const key of Object.keys(newSettings)) {
+            MetabaseAnalytics.trackEvent("Chart Settings", "Change Setting", key);
+        }
         this.setState({
             settings: {
                 ...this.state.settings,
@@ -109,10 +113,10 @@ class ChartSettings extends Component {
                   </div>
               </div>
               <div className="pt1">
-                <a className={cx("Button Button--primary", { disabled: !isDirty })} href="" onClick={() => this.onDone()}>Done</a>
-                <a className="text-grey-2 ml2" onClick={onClose}>Cancel</a>
+                <a className={cx("Button Button--primary", { disabled: !isDirty })} onClick={() => this.onDone()} data-metabase-event="Chart Settings;Done">Done</a>
+                <a className="text-grey-2 ml2" onClick={onClose} data-metabase-event="Chart Settings;Cancel">Cancel</a>
                 { !_.isEqual(this.state.settings, {}) &&
-                    <a className="Button Button--warning float-right" onClick={() => this.setState({ settings: {} })}>Reset to defaults</a>
+                    <a className="Button Button--warning float-right" onClick={() => this.setState({ settings: {} })} data-metabase-event="Chart Settings;Reset">Reset to defaults</a>
                 }
               </div>
           </div>
diff --git a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx
index 3671281c595b364b60380621203900c574d69539..10e39139eb76d07809401cac9210ac04f94d73c2 100644
--- a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx
+++ b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx
@@ -239,6 +239,7 @@ export default class LineAreaBarChart extends Component {
                 <CardRenderer
                     {...this.props}
                     chartType={this.getChartType()}
+                    series={series}
                     settings={settings}
                     className="flex-full"
                     renderer={lineAreaBarRenderer}
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/src/metabase/visualizations/lib/LineAreaBarRenderer.js b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
index 69449dd9b25d8bc11c20d94f86e4f4bb247dc7f0..d36b1a32cfeea1cb885a39b41bc2521f58869918 100644
--- a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
+++ b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
@@ -503,15 +503,18 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender,
     // HACK: This ensures each group is sorted by the same order as xValues,
     // otherwise we can end up with line charts with x-axis labels in the correct order
     // but the points in the wrong order. There may be a more efficient way to do this.
-    let sortMap = new Map()
-    for (const [index, key] of xValues.entries()) {
-        sortMap.set(key, index);
-    }
-    for (const group of groups) {
-        group.forEach(g => {
-            const sorted = g.top(Infinity).sort((a, b) => sortMap.get(a.key) - sortMap.get(b.key));
-            g.all = () => sorted;
-        });
+    // Don't apply to linear or timeseries X-axis since the points are always plotted in order
+    if (!isTimeseries && !isLinear) {
+        let sortMap = new Map()
+        for (const [index, key] of xValues.entries()) {
+            sortMap.set(key, index);
+        }
+        for (const group of groups) {
+            group.forEach(g => {
+                const sorted = g.top(Infinity).sort((a, b) => sortMap.get(a.key) - sortMap.get(b.key));
+                g.all = () => sorted;
+            });
+        }
     }
 
     let parent;
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/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/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"