diff --git a/docs/developers-guide-osx.md b/docs/developers-guide-osx.md
index 25e0d7408e1862cbd323c87138b53c44b3209a55..1defb97c6d9995e015fc532e00f856426d7a606b 100644
--- a/docs/developers-guide-osx.md
+++ b/docs/developers-guide-osx.md
@@ -10,43 +10,43 @@ NOTE: These instructions are only for packaging a built Metabase uberjar into `M
 
 3.  Update Perl. I'm not sure these steps are actually needed, so feel free to try skipping it and come back to it if it fails:
   
-   ```bash
-   # Upgrade Perl
-   brew install perl
-   
-   # Add new version of perl to your $PATH
-   # (replace "5.24.0_1" below with whatever version you installed)
-   echo 'export PATH="/usr/local/Cellar/perl/5.24.0_1/bin:$PATH"' >> ~/.bash_profile
-   source ~/.bash_profile
-   
-   # Double-check that we're using the newer version of CPAN
-   # (If this is your first time running CPAN, use the default config settings when prompted)
-   cpan --version # You should see a line like "running under Perl version 5.24.0."
-   ```
+    ```bash
+      # Upgrade Perl
+      brew install perl
+      
+      # Add new version of perl to your $PATH
+      # (replace "5.24.0_1" below with whatever version you installed)
+      echo 'export PATH="/usr/local/Cellar/perl/5.24.0_1/bin:$PATH"' >> ~/.bash_profile
+      source ~/.bash_profile
+      
+      # Double-check that we're using the newer version of CPAN
+      # (If this is your first time running CPAN, use the default config settings when prompted)
+      cpan --version # You should see a line like "running under Perl version 5.24.0."
+    ```
 
 4.  Next, you'll need to run the following commands before building the app:
 
     ```bash
-   # Fetch and initialize git submodule
-   git submodule update --init
-   
-   # Install libcurl (needed by WWW::Curl::Simple (I think))
-   brew install curl && brew link curl --force
-   
-   # The new version of LLVM is snippy so have CPAN pass compiler flags to fix errors
-   # (Make sure this file exists first. If you didn't upgrade Perl in the step above, 
-   # it might be in a different location; perhaps called "Config.pm". 
-   # You may need to run "cpan" (no arguments) to generate an appropriate initial config. 
-   # As above, you can go with the defaults).
-   sed -i '' -e "s/'make_arg' => q\[\]/'make_arg' => q\[CCFLAGS=\"-Wno-return-type\"\]/" ~/.cpan/CPAN/MyConfig.pm
-
-   # Install Perl modules used by ./bin/osx-setup and ./bin/osx-release
-   # You may have to run this as sudo if you didn't upgrade perl as described in step above
-   cpan install File::Copy::Recursive JSON Readonly String::Util Text::Caml WWW::Curl::Simple
-   
-   # Copy JRE and uberjar
-   ./bin/osx-setup
-   ```
+      # Fetch and initialize git submodule
+      git submodule update --init
+      
+      # Install libcurl (needed by WWW::Curl::Simple (I think))
+      brew install curl && brew link curl --force
+      
+      # The new version of LLVM is snippy so have CPAN pass compiler flags to fix errors
+      # (Make sure this file exists first. If you didn't upgrade Perl in the step above, 
+      # it might be in a different location; perhaps called "Config.pm". 
+      # You may need to run "cpan" (no arguments) to generate an appropriate initial config. 
+      # As above, you can go with the defaults).
+      sed -i '' -e "s/'make_arg' => q\[\]/'make_arg' => q\[CCFLAGS=\"-Wno-return-type\"\]/" ~/.cpan/CPAN/MyConfig.pm
+
+      # Install Perl modules used by ./bin/osx-setup and ./bin/osx-release
+      # You may have to run this as sudo if you didn't upgrade perl as described in step above
+      cpan install File::Copy::Recursive JSON Readonly String::Util Text::Caml WWW::Curl::Simple
+      
+      # Copy JRE and uberjar
+      ./bin/osx-setup
+    ```
 
 `./bin/osx-setup` will build run commands to build the uberjar for you if needed.
 Run `./bin/osx-setup` again at any time in the future to copy the latest version of the uberjar into the project.
diff --git a/frontend/src/metabase/admin/datamodel/metadata.js b/frontend/src/metabase/admin/datamodel/metadata.js
index ff6be7afe0b9139f544b1a6f4a6c96d20f005163..86858875c13db2b43193f2ba31e9ab5c482ac99d 100644
--- a/frontend/src/metabase/admin/datamodel/metadata.js
+++ b/frontend/src/metabase/admin/datamodel/metadata.js
@@ -6,6 +6,7 @@ import { push } from "react-router-redux";
 import MetabaseAnalytics from "metabase/lib/analytics";
 import { augmentTable } from "metabase/lib/table";
 import { loadTableAndForeignKeys } from "metabase/lib/table";
+import { isFK } from "metabase/lib/types";
 
 
 // resource wrappers
@@ -159,7 +160,7 @@ export const updateFieldSpecialType = createThunkAction("UPDATE_FIELD_SPECIAL_TY
     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") {
+        if (field.target && field.target.id != null && isFK(field.special_type)) {
             // we have something that used to be an FK and is now not an FK
             // clean up after ourselves
             field.target = null;
diff --git a/frontend/src/metabase/admin/settings/components/SettingsCustomMaps.jsx b/frontend/src/metabase/admin/settings/components/SettingsCustomMaps.jsx
index 3f11edc282a6333a6b4ae02862d64a7d1436c6e9..012a832c6198e201a7ee84856c73ab9e67144a6a 100644
--- a/frontend/src/metabase/admin/settings/components/SettingsCustomMaps.jsx
+++ b/frontend/src/metabase/admin/settings/components/SettingsCustomMaps.jsx
@@ -17,7 +17,9 @@ export default class SettingsCustomMaps extends Component {
         this.state = {
             map: null,
             originalMap: null,
-            geoJson: null
+            geoJson: null,
+            geoJsonLoading: false,
+            geoJsonError: null,
         };
     }
 
@@ -69,14 +71,26 @@ export default class SettingsCustomMaps extends Component {
     _loadGeoJson = async () => {
         try {
             const { map } = this.state;
-            this.setState({ geoJson: null });
+            this.setState({
+                geoJson: null,
+                geoJsonLoading: true,
+                geoJsonError: null,
+            });
             await this._saveMap(map.id, map);
             let geoJsonResponse = await fetch("/api/geojson/" + map.id, {
                 credentials: "same-origin"
             });
-            this.setState({ geoJson: await geoJsonResponse.json() });
+            this.setState({
+                geoJson: await geoJsonResponse.json(),
+                geoJsonLoading: false,
+                geoJsonError: null,
+            });
         } catch (e) {
-            this.setState({ geoJsonError: e });
+            this.setState({
+                geoJson: null,
+                geoJsonLoading: false,
+                geoJsonError: e,
+            });
             console.warn("map fetch failed", e)
         }
     }
@@ -91,6 +105,8 @@ export default class SettingsCustomMaps extends Component {
                     originalMap={this.state.originalMap}
                     onMapChange={(map) => this.setState({ map })}
                     geoJson={this.state.geoJson}
+                    geoJsonLoading={this.state.geoJsonLoading}
+                    geoJsonError={this.state.geoJsonError}
                     onLoadGeoJson={this._loadGeoJson}
                     onCancel={this._cancel}
                     onSave={this._save}
@@ -106,7 +122,9 @@ export default class SettingsCustomMaps extends Component {
                         ...map
                     },
                     originalMap: map,
-                    geoJson: null
+                    geoJson: null,
+                    geoJsonLoading: false,
+                    geoJsonError: null,
                 }, this._loadGeoJson)}
                 onAddMap={() => this.setState({
                     map: {
@@ -117,7 +135,9 @@ export default class SettingsCustomMaps extends Component {
                         region_name: null
                     },
                     originalMap: null,
-                    geoJson: null
+                    geoJson: null,
+                    geoJsonLoading: false,
+                    geoJsonError: null,
                 })}
                 onDeleteMap={this._delete}
             />
@@ -171,7 +191,6 @@ const GeoJsonPropertySelect = ({ value, onChange, geoJson }) => {
             options[property].push(feature.properties[property]);
         }
     }
-    console.log(options)
 
     return (
         <Select
@@ -193,7 +212,7 @@ const GeoJsonPropertySelect = ({ value, onChange, geoJson }) => {
     )
 }
 
-const EditMap = ({ map, onMapChange, originalMap, geoJson, geoJsonError, onLoadGeoJson, onCancel, onSave }) =>
+const EditMap = ({ map, onMapChange, originalMap, geoJson, geoJsonLoading, geoJsonError, onLoadGeoJson, onCancel, onSave }) =>
     <div>
         <h2>{ !originalMap ? "Add a new map" : "Edit map" }</h2>
         <div className="m2 mb4">
@@ -221,8 +240,8 @@ const EditMap = ({ map, onMapChange, originalMap, geoJson, geoJsonError, onLoadG
                 <button className={cx("Button ml1", { "Button--primary" : !geoJson })} onClick={onLoadGeoJson}>{geoJson ? "Refresh" : "Load"}</button>
             </div>
         </div>
-        { geoJson !== undefined &&
-            <LoadingAndErrorWrapper loading={geoJson === null} error={geoJsonError}>
+        { (geoJson || geoJsonLoading || geoJsonError) &&
+            <LoadingAndErrorWrapper loading={geoJsonLoading} error={geoJsonError}>
             { () =>
                 <div>
                     <div className="m2 mb4">
diff --git a/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx b/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx
index f48411276672255ef39755d3da93e0c1f2d71d73..81791838e133d9466010afbf377d33ed4db4fea1 100644
--- a/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx
+++ b/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx
@@ -179,7 +179,7 @@ export default class SettingsEditorApp extends Component {
                 <SettingsHeader ref="header" />
                 <div className="MetadataEditor-main flex flex-row flex-full mt2">
                     {this.renderSettingsSections()}
-                    <div className="px2">
+                    <div className="px2 flex-full">
                         {this.renderSettingsPane()}
                     </div>
                 </div>
diff --git a/frontend/src/metabase/auth/components/AuthScene.jsx b/frontend/src/metabase/auth/components/AuthScene.jsx
index c67987f8b8c99f8d5a364c6977c3f5329aa29e82..21f84fb783316a65c43091650b8b189574f48c33 100644
--- a/frontend/src/metabase/auth/components/AuthScene.jsx
+++ b/frontend/src/metabase/auth/components/AuthScene.jsx
@@ -28,7 +28,7 @@ export default class AuthScene extends Component {
                             <path fill="#fff" d="M1.5,91 L78,73.5 L87,119.5 L41.5,149 L1.5,91 Z" id="Path-Copy" stroke="#B6CCE5" ></path>
                             <path fill="#fff" d="M77.5000001,74.5 L143,44 L174,46 L86.0000001,119.5 L77.5000001,74.5 Z" id="Path-Copy-7" stroke="#B6CCE5" ></path>
                             <path fill="#fff" d="M142.5,45 L205,25.5 L229,39.5 L173.5,47.5 L142.5,45 Z" id="Path-Copy-9" stroke="#B6CCE5" ></path>
-                            <path fill="#fff" d="M158.499999,99 L225.499999,80.5 L270.999999,87.5 L226.999999,125 L158.499999,99 Z" id="Path-Copy-2" stroke="#B6CCE5" ></path>
+                            <path fill="#fff" d="M158.499999,99 L225.499999,80.5 L270.999999,87.5 L226.999999,125 L158.499999,99 Z" id="Path-Copy-3" stroke="#B6CCE5" ></path>
                             <path fill="#fff" d="M156.499999,101.5 L172.999999,47 L226.499999,39 L226.499999,81 L156.499999,101.5 Z" id="Path-Copy-11" stroke="#B6CCE5" ></path>
                             <path fill="#fff" d="M243.000001,88.5 L225.5,43.5 L288,39 L288,81.5 L243.000001,88.5 Z" id="Path-Copy-12" stroke="#B6CCE5"  transform="translate(256.750000, 63.750000) scale(-1, 1) translate(-256.750000, -63.750000) "></path>
                             <path fill="#fff" d="M286.5,44.5 L342.5,64 L319.5,110.5 L270,86.5 L286.5,44.5 Z" id="Path-Copy-4" stroke="#B6CCE5" ></path>
@@ -109,7 +109,8 @@ export default class AuthScene extends Component {
                         </svg>
                     </div>
                 </div>
-                <div className="bg-brand block py3 absolute bottom left right"></div>
+                { /*  09-12-2016 */ }
+                <div id="caspian" className="bg-brand block py3 absolute bottom left right"></div>
             </section>
         );
     }
diff --git a/frontend/src/metabase/css/dashboard.css b/frontend/src/metabase/css/dashboard.css
index 6d82033ac9b350ed428fa45447e257e52ae984ce..89ab20de025711b47127d7b91c719151e2871fcc 100644
--- a/frontend/src/metabase/css/dashboard.css
+++ b/frontend/src/metabase/css/dashboard.css
@@ -334,6 +334,12 @@
   stroke-opacity: 1 !important;
 }
 
+.dc-chart circle.bubble {
+    fill-opacity: 0.80;
+    stroke-width: 1;
+    stroke: white;
+}
+
 .enable-dots .dc-tooltip circle.dot:hover,
 .enable-dots .dc-tooltip circle.dot.hover {
   fill: currentColor;
@@ -401,7 +407,13 @@
 .mute-2 .sub._2 .dot,
 .mute-3 .sub._3 .dot,
 .mute-4 .sub._4 .dot,
-.mute-5 .sub._5 .dot { opacity: 0.25; }
+.mute-5 .sub._5 .dot,
+.mute-0 .sub._0 .bubble,
+.mute-1 .sub._1 .bubble,
+.mute-2 .sub._2 .bubble,
+.mute-3 .sub._3 .bubble,
+.mute-4 .sub._4 .bubble,
+.mute-5 .sub._5 .bubble { opacity: 0.25; }
 
 
 .mute-yl .dc-chart .axis.y,
diff --git a/frontend/src/metabase/lib/core.js b/frontend/src/metabase/lib/core.js
index 06cedb96b4c76f49b4a5c5bddf54d26f8f976523..6c614249e3490d851856dcd6df0f7568c4379841 100644
--- a/frontend/src/metabase/lib/core.js
+++ b/frontend/src/metabase/lib/core.js
@@ -1,3 +1,5 @@
+import { TYPE } from "metabase/lib/types";
+
 export const user_roles = [{
     'id': 'user',
     'name': 'User',
@@ -9,78 +11,78 @@ export const user_roles = [{
 }];
 
 export const field_special_types = [{
-    'id': 'id',
+    'id': TYPE.PK,
     'name': 'Entity Key',
     'section': 'Overall Row',
     'description': 'The primary key for this table.'
 }, {
-    'id': 'name',
+    'id': TYPE.Name,
     'name': 'Entity Name',
     'section': 'Overall Row',
     'description': 'The "name" of each record. Usually a column called "name", "title", etc.'
 }, {
-    'id': 'fk',
+    'id': TYPE.FK,
     'name': 'Foreign Key',
     'section': 'Overall Row',
     'description': 'Points to another table to make a connection.'
 }, {
-    'id': 'avatar',
+    'id': TYPE.AvatarURL,
     'name': 'Avatar Image URL',
     'section': 'Common'
 }, {
-    'id': 'category',
+    'id': TYPE.Category,
     'name': 'Category',
     'section': 'Common'
 }, {
-    'id': 'city',
+    'id': TYPE.City,
     'name': 'City',
     'section': 'Common'
 }, {
-    'id': 'country',
+    'id': TYPE.Country,
     'name': 'Country',
     'section': 'Common'
 }, {
-    'id': 'desc',
+    'id': TYPE.Description,
     'name': 'Description',
     'section': 'Common'
 }, {
-    'id': 'image',
+    'id': TYPE.ImageURL,
     'name': 'Image URL',
     'section': 'Common'
 }, {
-    'id': 'json',
+    'id': TYPE.SerializedJSON,
     'name': 'Field containing JSON',
     'section': 'Common'
 }, {
-    'id': 'latitude',
+    'id': TYPE.Latitude,
     'name': 'Latitude',
     'section': 'Common'
 }, {
-    'id': 'longitude',
+    'id': TYPE.Longitude,
     'name': 'Longitude',
     'section': 'Common'
 }, {
-    'id': 'number',
+    'id': TYPE.Number,
     'name': 'Number',
     'section': 'Common'
 }, {
-    'id': 'state',
+    'id': TYPE.State,
     'name': 'State',
     'section': 'Common'
 }, {
-    id: 'timestamp_seconds',
+    id: TYPE.UNIXTimestampSeconds,
     name: 'UNIX Timestamp (Seconds)',
     'section': 'Common'
 }, {
-    id: 'timestamp_milliseconds',
+    id: TYPE.UNIXTimestampMilliseconds,
     name: 'UNIX Timestamp (Milliseconds)',
     'section': 'Common'
 }, {
-    'id': 'url',
+    'id': TYPE.URL,
     'name': 'URL',
     'section': 'Common'
 }, {
-    'id': 'zip_code',
+    'id': TYPE.ZipCode,
     'name': 'Zip Code',
     'section': 'Common'
 }];
diff --git a/frontend/src/metabase/lib/formatting.js b/frontend/src/metabase/lib/formatting.js
index 3f0e5e66a2384183e4baf2e489fcfcba3a912cfb..346193d782b9f080913dc1bf284d5fd497a97de6 100644
--- a/frontend/src/metabase/lib/formatting.js
+++ b/frontend/src/metabase/lib/formatting.js
@@ -49,7 +49,7 @@ function formatMajorMinor(major, minor, options = {}) {
 }
 
 function formatTimeWithUnit(value, unit, options = {}) {
-    let m = parseTimestamp(value);
+    let m = parseTimestamp(value, unit);
     if (!m.isValid()) {
         return String(value);
     }
@@ -67,7 +67,7 @@ function formatTimeWithUnit(value, unit, options = {}) {
                 <div><span className="text-bold">{m.format("MMMM")}</span> {m.format("YYYY")}</div> :
                 m.format("MMMM") + " " + m.format("YYYY");
         case "year": // 2015
-            return String(value);
+            return m.format("YYYY");
         case "quarter": // Q1 - 2015
             return formatMajorMinor(m.format("[Q]Q"), m.format("YYYY"), { ...options, majorWidth: 0 });
         case "hour-of-day": // 12 AM
@@ -97,7 +97,7 @@ export function formatValue(value, options = {}) {
     } else if (column && column.unit != null) {
         return formatTimeWithUnit(value, column.unit, options);
     } else if (isDate(column) || moment.isDate(value) || moment.isMoment(value) || moment(value, ["YYYY-MM-DD'T'HH:mm:ss.SSSZ"], true).isValid()) {
-        return parseTimestamp(value).format("LLLL");
+        return parseTimestamp(value, column && column.unit).format("LLLL");
     } else if (typeof value === "string") {
         return value;
     } else if (typeof value === "number") {
diff --git a/frontend/src/metabase/lib/query.js b/frontend/src/metabase/lib/query.js
index 7e4ed6eb86cee0848b37bfc48519383695c76842..cff87c107910d3aa5c8148a210a7006f19826faf 100644
--- a/frontend/src/metabase/lib/query.js
+++ b/frontend/src/metabase/lib/query.js
@@ -5,6 +5,7 @@ import _ from "underscore";
 
 import { getOperators } from "metabase/lib/schema_metadata";
 import { createLookupByProperty } from "metabase/lib/table";
+import { isFK, TYPE } from "metabase/lib/types";
 
 
 export const NEW_QUERY_TEMPLATES = {
@@ -517,7 +518,7 @@ var Query = {
                 display_name: field[1],
                 name: field[1],
                 // TODO: we need to do something better here because filtering depends on knowing a sensible type for the field
-                base_type: "IntegerField",
+                base_type: TYPE.Integer,
                 operators_lookup: {},
                 valid_operators: [],
                 active: true,
@@ -549,17 +550,17 @@ var Query = {
         }
     },
 
-    getFieldOptions(fields, includeJoins = false, filterFn = (fields) => fields, usedFields = {}) {
+    getFieldOptions(fields, includeJoins = false, filterFn = _.identity, usedFields = {}) {
         var results = {
             count: 0,
             fields: null,
             fks: []
         };
         // filter based on filterFn, then remove fks if they'll be duplicated in the joins fields
-        results.fields = filterFn(fields).filter((f) => !usedFields[f.id] && (f.special_type !== "fk" || !includeJoins));
+        results.fields = filterFn(fields).filter((f) => !usedFields[f.id] && (!isFK(f.special_type) || !includeJoins));
         results.count += results.fields.length;
         if (includeJoins) {
-            results.fks = fields.filter((f) => f.special_type === "fk" && f.target).map((joinField) => {
+            results.fks = fields.filter((f) => isFK(f.special_type) && f.target).map((joinField) => {
                 var targetFields = filterFn(joinField.target.table.fields).filter(f => (!Array.isArray(f.id) || f.id[0] !== "aggregation") && !usedFields[f.id]);
                 results.count += targetFields.length;
                 return {
@@ -717,14 +718,14 @@ var Query = {
     },
 
     getQueryColumns(tableMetadata, query) {
-        let columns = Query.getBreakouts(query).map(b => Query.getQueryColumn(tableMetadata, b))
+        let columns = Query.getBreakouts(query).map(b => Query.getQueryColumn(tableMetadata, b));
         if (Query.getAggregationType(query) === "rows") {
             if (columns.length === 0) {
                 return null;
             }
         } else {
-            // NOTE: incomplete (missing name etc), count/distinct are actually IntegerField, but close enough for now
-            columns.push({ base_type: "FloatField", special_type: "number" });
+            // NOTE: incomplete (missing name etc), count/distinct are actually TYPE.Integer, but close enough for now
+            columns.push({ base_type: TYPE.Float, special_type: TYPE.Number });
         }
         return columns;
     }
diff --git a/frontend/src/metabase/lib/schema_metadata.js b/frontend/src/metabase/lib/schema_metadata.js
index 2a848a7057abf197a005fba2d793f18f047d6749..f8345611f2ba8edf7c1acb3b0c4bab202550ee98 100644
--- a/frontend/src/metabase/lib/schema_metadata.js
+++ b/frontend/src/metabase/lib/schema_metadata.js
@@ -1,8 +1,11 @@
 import _ from "underscore";
 
+import { isa, isFK, TYPE } from "metabase/lib/types";
+
 // primary field types used for picking operators, etc
 export const NUMBER = "NUMBER";
 export const STRING = "STRING";
+export const STRING_LIKE = "STRING_LIKE";
 export const BOOLEAN = "BOOLEAN";
 export const DATE_TIME = "DATE_TIME";
 export const LOCATION = "LOCATION";
@@ -20,82 +23,78 @@ export const UNKNOWN = "UNKNOWN";
 // NOTE: be sure not to create cycles using the "other" types
 const TYPES = {
     [DATE_TIME]: {
-        base: ["DateTimeField", "DateField", "TimeField"],
-        special: ["timestamp_milliseconds", "timestamp_seconds"]
+        base: [TYPE.DateTime],
+        special: [TYPE.DateTime]
     },
     [NUMBER]: {
-        base: ["IntegerField", "DecimalField", "FloatField", "BigIntegerField"],
-        special: ["number"]
+        base: [TYPE.Number],
+        special: [TYPE.Number]
     },
     [STRING]: {
-        base: ["CharField", "TextField"],
-        special: ["name"]
+        base: [TYPE.Text],
+        special: [TYPE.Text]
+    },
+    [STRING_LIKE]: {
+        base: [TYPE.TextLike]
     },
     [BOOLEAN]: {
-        base: ["BooleanField"]
+        base: [TYPE.Boolean]
     },
     [COORDINATE]: {
-        special: ["latitude", "longitude"]
+        special: [TYPE.Coordinate]
     },
     [LOCATION]: {
-        special: ["city", "country", "state", "zip_code"]
+        special: [TYPE.Address]
     },
     [ENTITY]: {
-        special: ["fk", "id", "name"]
+        special: [TYPE.FK, TYPE.PK, TYPE.Name]
     },
     [SUMMABLE]: {
         include: [NUMBER],
         exclude: [ENTITY, LOCATION, DATE_TIME]
     },
     [CATEGORY]: {
-        base: ["BooleanField"],
-        special: ["category"],
+        base: [TYPE.Boolean],
+        special: [TYPE.Category],
         include: [LOCATION]
     },
     // NOTE: this is defunct right now.  see definition of isDimension below.
     [DIMENSION]: {
-        field: ["dimension"],
         include: [DATE_TIME, CATEGORY, ENTITY]
     }
 };
 
 export function isFieldType(type, field) {
-    if (!field) {
-        return false;
-    }
+    if (!field) return false;
 
-    let def = TYPES[type];
+    const typeDefinition = TYPES[type];
     // check to see if it belongs to any of the field types:
-    for (let prop of ["field", "base", "special"]) {
-        if (def[prop] && _.contains(def[prop], field[prop+"_type"])) {
-            return true;
+    for (const prop of ["base", "special"]) {
+        const allowedTypes = typeDefinition[prop];
+        if (!allowedTypes) continue;
+
+        const fieldType = field[prop + "_type"];
+        for (const allowedType of allowedTypes) {
+            if (isa(fieldType, allowedType)) return true;
         }
     }
+
     // recursively check to see if it's NOT another field type:
-    if (def.exclude) {
-        for (let excludeType of def.exclude) {
-            if (isFieldType(excludeType, field)) {
-                return false;
-            }
-        }
+    for (const excludedType of (typeDefinition.exclude || [])) {
+        if (isFieldType(excludedType, field)) return false;
     }
+
     // recursively check to see if it's another field type:
-    if (def.include) {
-        for (let includeType of def.include) {
-            if (isFieldType(includeType, field)) {
-                return true;
-            }
-        }
+    for (const includedType of (typeDefinition.include || [])) {
+        if (isFieldType(includedType, field)) return true;
     }
     return false;
 }
 
 export function getFieldType(field) {
     // try more specific types first, then more generic types
-    for (let type of [DATE_TIME, LOCATION, COORDINATE, NUMBER, STRING, BOOLEAN]) {
-        if (isFieldType(type, field)) {
-            return type;
-        }
+    for (const type of [DATE_TIME, LOCATION, COORDINATE, NUMBER, STRING, STRING_LIKE, BOOLEAN]) {
+        if (isFieldType(type, field)) return type;
     }
 }
 
@@ -109,8 +108,7 @@ export const isCategory = isFieldType.bind(null, CATEGORY);
 export const isDimension = (col) => (col && col.source !== "aggregation");
 export const isMetric    = (col) => (col && col.source !== "breakout") && isSummable(col);
 
-export const isNumericBaseType = (field) => TYPES[NUMBER].base
-    .some(type => type === field.base_type);
+export const isNumericBaseType = (field) => isa(field && field.base_type, TYPE.Number);
 
 // operator argument constructors:
 
@@ -195,7 +193,7 @@ function longitudeFieldSelectArgument(field, table) {
     return {
         type: "select",
         values: table.fields
-            .filter(field => field.special_type === "longitude")
+            .filter(field => isa(field.special_type, TYPE.Longitude))
             .map(field => ({
                 key: field.id,
                 name: field.display_name
@@ -274,6 +272,12 @@ const OPERATORS_BY_TYPE_ORDERED = {
         { name: "STARTS_WITH",      verboseName: "Starts with", advanced: true},
         { name: "ENDS_WITH",        verboseName: "Ends with", advanced: true}
     ],
+    [STRING_LIKE]: [
+        { name: "=",                verboseName: "Is" },
+        { name: "!=",               verboseName: "Is not" },
+        { name: "IS_NULL",          verboseName: "Is empty", advanced: true },
+        { name: "NOT_NULL",         verboseName: "Not empty", advanced: true }
+    ],
     [DATE_TIME]: [
         { name: "=",                verboseName: "Is" },
         { name: "<",                verboseName: "Before" },
@@ -319,10 +323,10 @@ const MORE_VERBOSE_NAMES = {
 }
 
 export function getOperators(field, table) {
-    let type = getFieldType(field) || UNKNOWN;
+    const type = getFieldType(field) || UNKNOWN;
     return OPERATORS_BY_TYPE_ORDERED[type].map(operatorForType => {
-        let operator = OPERATORS[operatorForType.name];
-        let verboseNameLower = operatorForType.verboseName.toLowerCase();
+        const operator = OPERATORS[operatorForType.name];
+        const verboseNameLower = operatorForType.verboseName.toLowerCase();
         return {
             ...operator,
             ...operatorForType,
@@ -432,11 +436,7 @@ function populateFields(aggregator, fields) {
 // TODO: unit test
 export function getAggregators(table) {
     const supportedAggregations = Aggregators.filter(function (agg) {
-        if (agg.requiredDriverFeature && table.db && !_.contains(table.db.features, agg.requiredDriverFeature)) {
-            return false;
-        } else {
-            return true;
-        }
+        return !(agg.requiredDriverFeature && table.db && !_.contains(table.db.features, agg.requiredDriverFeature));
     });
     return _.map(supportedAggregations, function(aggregator) {
         return populateFields(aggregator, table.fields);
@@ -473,11 +473,11 @@ export function addValidOperatorsToFields(table) {
 export function hasLatitudeAndLongitudeColumns(columnDefs) {
     let hasLatitude = false;
     let hasLongitude = false;
-    for (let col of columnDefs) {
-        if (col.special_type === "latitude") {
+    for (const col of columnDefs) {
+        if (isa(col.special_type, TYPE.Latitude)) {
             hasLatitude = true;
         }
-        if (col.special_type === "longitude") {
+        if (isa(col.special_type, TYPE.Longitude)) {
             hasLongitude = true;
         }
     }
@@ -507,6 +507,7 @@ export const ICON_MAPPING = {
     [LOCATION]: 'location',
     [COORDINATE]: 'location',
     [STRING]: 'string',
+    [STRING_LIKE]: 'string',
     [NUMBER]: 'int',
     [BOOLEAN]: 'io'
 };
@@ -528,7 +529,7 @@ export function computeMetadataStrength(table) {
         table.fields.forEach(function(field) {
             score(field.description);
             score(field.special_type);
-            if (field.special_type === "fk") {
+            if (isFK(field.special_type)) {
                 score(field.target);
             }
         });
diff --git a/frontend/src/metabase/lib/time.js b/frontend/src/metabase/lib/time.js
index 532a19c1919d4ee1c25d7cdbae0431010722197f..dc544909fc12a1a32a6e8e63df7652e5d41628d7 100644
--- a/frontend/src/metabase/lib/time.js
+++ b/frontend/src/metabase/lib/time.js
@@ -2,11 +2,14 @@ import moment from "moment";
 
 // only attempt to parse the timezone if we're sure we have one (either Z or ±hh:mm)
 // moment normally interprets the DD in YYYY-MM-DD as an offset :-/
-export function parseTimestamp(value) {
+export function parseTimestamp(value, unit) {
     if (moment.isMoment(value)) {
         return value;
     } else if (typeof value === "string" && /(Z|[+-]\d\d:\d\d)$/.test(value)) {
         return moment.parseZone(value);
+    } else if (unit === "year") {
+        // workaround for https://github.com/metabase/metabase/issues/1992
+        return moment().year(value).startOf("year");
     } else {
         return moment.utc(value);
     }
diff --git a/frontend/src/metabase/lib/types.js b/frontend/src/metabase/lib/types.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e0a83bbe37ab231216c5c658a247608608c2ea6
--- /dev/null
+++ b/frontend/src/metabase/lib/types.js
@@ -0,0 +1,48 @@
+import _ from "underscore";
+
+import MetabaseSettings from "metabase/lib/settings";
+
+const PARENTS = MetabaseSettings.get("types");
+
+/// Basically exactly the same as Clojure's isa?
+/// Recurses through the type hierarchy until it can give you an anser.
+/// isa(TYPE.BigInteger, TYPE.Number) -> true
+/// isa(TYPE.Text, TYPE.Boolean) -> false
+export function isa(child, ancestor) {
+    if (!child || !ancestor) return false;
+
+    if (child === ancestor) return true;
+
+    const parents = PARENTS[child];
+    if (!parents) {
+        if (child !== "type/*") console.error("Invalid type:", child); // the base type is the only type with no parents, so anything else that gets here is invalid
+        return false;
+    }
+
+    for (const parent of parents) {
+        if (isa(parent, ancestor)) return true;
+    }
+
+    return false;
+}
+
+// build a pretty sweet dictionary of top-level types, so people can do TYPE.Latitude instead of "type/Latitude" and get error messages / etc.
+// this should also make it easier to keep track of things when we tweak the type hierarchy
+export let TYPE = {};
+for (const type of _.keys(PARENTS)) {
+    const key = type.substring(5); // strip off "type/"
+    TYPE[key] = type;
+}
+
+
+// convenience functions since these operations are super-common
+// this will also make it easier to tweak how these checks work in the future,
+// e.g. when we add an `is_pk` column and eliminate the PK special type we can just look for places that use isPK
+
+export function isPK(type) {
+    return isa(type, TYPE.PK);
+}
+
+export function isFK(type) {
+    return isa(type, TYPE.FK);
+}
diff --git a/frontend/src/metabase/lib/visualization_settings.js b/frontend/src/metabase/lib/visualization_settings.js
index c15074815f3d4b7fa5a656f5fc6d5afc2934f242..5e0d892074c5316f89a28dcb76e7253e8347d48e 100644
--- a/frontend/src/metabase/lib/visualization_settings.js
+++ b/frontend/src/metabase/lib/visualization_settings.js
@@ -12,14 +12,20 @@ import {
 
 import { isNumeric, isDate, isMetric, isDimension, hasLatitudeAndLongitudeColumns } from "metabase/lib/schema_metadata";
 import Query from "metabase/lib/query";
+import { capitalize } from "metabase/lib/formatting";
 
 import { getCardColors, getFriendlyName } from "metabase/visualizations/lib/utils";
 
+import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries";
+import { dimensionIsNumeric } from "metabase/visualizations/lib/numeric";
+
 import ChartSettingInput from "metabase/visualizations/components/settings/ChartSettingInput.jsx";
 import ChartSettingInputNumeric from "metabase/visualizations/components/settings/ChartSettingInputNumeric.jsx";
 import ChartSettingSelect from "metabase/visualizations/components/settings/ChartSettingSelect.jsx";
 import ChartSettingToggle from "metabase/visualizations/components/settings/ChartSettingToggle.jsx";
+import ChartSettingFieldPicker from "metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx";
 import ChartSettingFieldsPicker from "metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx";
+import ChartSettingColorPicker from "metabase/visualizations/components/settings/ChartSettingColorPicker.jsx";
 import ChartSettingColorsPicker from "metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx";
 import ChartSettingOrderedFields from "metabase/visualizations/components/settings/ChartSettingOrderedFields.jsx";
 
@@ -52,7 +58,24 @@ function getSeriesTitles([{ data: { rows, cols } }], vizSettings) {
     }
 }
 
-function getDefaultDimensionsAndMetrics([{ data: { cols, rows } }]) {
+function getDefaultColumns(series) {
+    if (series[0].card.display === "scatter") {
+        return getDefaultScatterColumns(series);
+    } else {
+        return getDefaultLineAreaBarColumns(series);
+    }
+}
+
+function getDefaultScatterColumns([{ data: { cols, rows } }]) {
+    // TODO
+    return {
+        dimensions: [null],
+        metrics: [null],
+        bubble: null
+    };
+}
+
+function getDefaultLineAreaBarColumns([{ data: { cols, rows } }]) {
     let type = getChartTypeFromData(cols, rows, false);
     switch (type) {
         case DIMENSION_DIMENSION_METRIC:
@@ -110,24 +133,36 @@ function getOptionFromColumn(col) {
 
 // const CURRENCIES = ["afn", "ars", "awg", "aud", "azn", "bsd", "bbd", "byr", "bzd", "bmd", "bob", "bam", "bwp", "bgn", "brl", "bnd", "khr", "cad", "kyd", "clp", "cny", "cop", "crc", "hrk", "cup", "czk", "dkk", "dop", "xcd", "egp", "svc", "eek", "eur", "fkp", "fjd", "ghc", "gip", "gtq", "ggp", "gyd", "hnl", "hkd", "huf", "isk", "inr", "idr", "irr", "imp", "ils", "jmd", "jpy", "jep", "kes", "kzt", "kpw", "krw", "kgs", "lak", "lvl", "lbp", "lrd", "ltl", "mkd", "myr", "mur", "mxn", "mnt", "mzn", "nad", "npr", "ang", "nzd", "nio", "ngn", "nok", "omr", "pkr", "pab", "pyg", "pen", "php", "pln", "qar", "ron", "rub", "shp", "sar", "rsd", "scr", "sgd", "sbd", "sos", "zar", "lkr", "sek", "chf", "srd", "syp", "tzs", "twd", "thb", "ttd", "try", "trl", "tvd", "ugx", "uah", "gbp", "usd", "uyu", "uzs", "vef", "vnd", "yer", "zwd"];
 
+import { normal } from "metabase/lib/colors";
+
+const isAnyField = () => true;
+
 const SETTINGS = {
+    "graph._dimension_filter": {
+        getDefault: ([{ card }]) => card.display === "scatter" ? isAnyField : isDimension
+    },
+    "graph._metric_filter": {
+        getDefault: ([{ card }]) => card.display === "scatter" ? isNumeric : isMetric
+    },
     "graph.dimensions": {
         section: "Data",
         title: "X-axis",
         widget: ChartSettingFieldsPicker,
         isValid: ([{ card, data }], vizSettings) =>
-            columnsAreValid(card.visualization_settings["graph.dimensions"], data, isDimension) &&
-            columnsAreValid(card.visualization_settings["graph.metrics"], data, isMetric),
+            columnsAreValid(card.visualization_settings["graph.dimensions"], data, vizSettings["graph._dimension_filter"]) &&
+            columnsAreValid(card.visualization_settings["graph.metrics"], data, vizSettings["graph._metric_filter"]),
         getDefault: (series, vizSettings) =>
-            getDefaultDimensionsAndMetrics(series).dimensions,
+            getDefaultColumns(series).dimensions,
         getProps: ([{ card, data }], vizSettings) => {
             const value = vizSettings["graph.dimensions"];
-            const options = data.cols.filter(isDimension).map(getOptionFromColumn);
+            const options = data.cols.filter(vizSettings["graph._dimension_filter"]).map(getOptionFromColumn);
             return {
                 options,
-                addAnother: (options.length > value.length && value.length < 2) ? "Add a series breakout..." : null
+                addAnother: (options.length > value.length && value.length < 2 && vizSettings["graph.metrics"].length < 2) ?
+                    "Add a series breakout..." : null
             };
         },
+        readDependencies: ["graph._dimension_filter", "graph._metric_filter"],
         writeDependencies: ["graph.metrics"]
     },
     "graph.metrics": {
@@ -135,16 +170,35 @@ const SETTINGS = {
         title: "Y-axis",
         widget: ChartSettingFieldsPicker,
         isValid: ([{ card, data }], vizSettings) =>
-            columnsAreValid(card.visualization_settings["graph.dimensions"], data, isDimension) &&
-            columnsAreValid(card.visualization_settings["graph.metrics"], data, isMetric),
+            columnsAreValid(card.visualization_settings["graph.dimensions"], data, vizSettings["graph._dimension_filter"]) &&
+            columnsAreValid(card.visualization_settings["graph.metrics"], data, vizSettings["graph._metric_filter"]),
         getDefault: (series, vizSettings) =>
-            getDefaultDimensionsAndMetrics(series).metrics,
+            getDefaultColumns(series).metrics,
         getProps: ([{ card, data }], vizSettings) => {
             const value = vizSettings["graph.dimensions"];
-            const options = data.cols.filter(isMetric).map(getOptionFromColumn);
+            const options = data.cols.filter(vizSettings["graph._metric_filter"]).map(getOptionFromColumn);
+            return {
+                options,
+                addAnother: options.length > value.length && vizSettings["graph.dimensions"].length < 2 ?
+                    "Add another series..." : null
+            };
+        },
+        readDependencies: ["graph._dimension_filter", "graph._metric_filter"],
+        writeDependencies: ["graph.dimensions"]
+    },
+    "scatter.bubble": {
+        section: "Data",
+        title: "Bubble size",
+        widget: ChartSettingFieldPicker,
+        isValid: ([{ card, data }], vizSettings) =>
+            columnsAreValid([card.visualization_settings["scatter.bubble"]], data, isNumeric),
+        getDefault: (series) =>
+            getDefaultColumns(series).bubble,
+        getProps: ([{ card, data }], vizSettings, onChange) => {
+            const options = data.cols.filter(isNumeric).map(getOptionFromColumn);
             return {
                 options,
-                addAnother: options.length > value.length ? "Add another series..." : null
+                onRemove: vizSettings["scatter.bubble"] ? () => onChange(null) : null
             };
         },
         writeDependencies: ["graph.dimensions"]
@@ -179,8 +233,84 @@ const SETTINGS = {
             (card.display === "area" && vizSettings["graph.metrics"].length > 1)
         )
     },
+    "graph.show_goal": {
+        section: "Display",
+        title: "Show goal",
+        widget: ChartSettingToggle,
+        default: false
+    },
+    "graph.goal_value": {
+        section: "Display",
+        title: "Goal value",
+        widget: ChartSettingInputNumeric,
+        default: 0,
+        getHidden: (series, vizSettings) => vizSettings["graph.show_goal"] !== true,
+        readDependencies: ["graph.show_goal"]
+    },
+    "line.missing": {
+        section: "Display",
+        title: "Replace missing values with",
+        widget: ChartSettingSelect,
+        default: "interpolate",
+        getProps: (series, vizSettings) => ({
+            options: [
+                { name: "Zero", value: "zero" },
+                { name: "Nothing", value: "none" },
+                { name: "Linear Interpolated", value: "interpolate" },
+            ]
+        })
+    },
+    "graph.x_axis._is_timeseries": {
+        readDependencies: ["graph.dimensions"],
+        getDefault: ([{ data }], vizSettings) =>
+            dimensionIsTimeseries(data, _.findIndex(data.cols, (c) => c.name === vizSettings["graph.dimensions"].filter(d => d)[0]))
+    },
+    "graph.x_axis._is_numeric": {
+        readDependencies: ["graph.dimensions"],
+        getDefault: ([{ data }], vizSettings) =>
+            dimensionIsNumeric(data, _.findIndex(data.cols, (c) => c.name === vizSettings["graph.dimensions"].filter(d => d)[0]))
+    },
+    "graph.x_axis.scale": {
+        section: "Axes",
+        title: "X-axis scale",
+        widget: ChartSettingSelect,
+        default: "ordinal",
+        readDependencies: ["graph.x_axis._is_timeseries", "graph.x_axis._is_numeric"],
+        getDefault: (series, vizSettings) =>
+            vizSettings["graph.x_axis._is_timeseries"] ? "timeseries" :
+            vizSettings["graph.x_axis._is_numeric"] ? "linear" :
+            "ordinal",
+        getProps: (series, vizSettings) => {
+            const options = [];
+            if (vizSettings["graph.x_axis._is_timeseries"]) {
+                options.push({ name: "Timeseries", value: "timeseries" });
+            }
+            if (vizSettings["graph.x_axis._is_numeric"]) {
+                options.push({ name: "Linear", value: "linear" });
+                options.push({ name: "Power", value: "pow" });
+                options.push({ name: "Log", value: "log" });
+            }
+            options.push({ name: "Ordinal", value: "ordinal" });
+            return { options };
+        }
+    },
+    "graph.y_axis.scale": {
+        section: "Axes",
+        title: "Y-axis scale",
+        widget: ChartSettingSelect,
+        default: "linear",
+        getProps: (series, vizSettings) => ({
+            options: [
+                { name: "Linear", value: "linear" },
+                { name: "Power", value: "pow" },
+                { name: "Log", value: "log" }
+            ]
+        })
+    },
     "graph.colors": {
         section: "Display",
+        getTitle: ([{ card: { display } }]) =>
+            capitalize(display === "scatter" ? "bubble" : display) + " Colors",
         widget: ChartSettingColorsPicker,
         readDependencies: ["graph.dimensions", "graph.metrics"],
         getDefault: ([{ card, data }], vizSettings) => {
@@ -299,16 +429,21 @@ const SETTINGS = {
         }),
     },
     "pie.show_legend": {
-        section: "Legend",
+        section: "Display",
         title: "Show legend",
         widget: ChartSettingToggle
     },
     "pie.show_legend_perecent": {
-        section: "Legend",
+        section: "Display",
         title: "Show percentages in legend",
         widget: ChartSettingToggle,
         default: true
     },
+    "pie.slice_threshold": {
+        section: "Display",
+        title: "Minimum slice percentage",
+        widget: ChartSettingInputNumeric
+    },
     "scalar.locale": {
         title: "Separator style",
         widget: ChartSettingSelect,
@@ -349,6 +484,18 @@ const SETTINGS = {
         title: "Multiply by a number",
         widget: ChartSettingInputNumeric
     },
+    "progress.goal": {
+        section: "Display",
+        title: "Goal",
+        widget: ChartSettingInputNumeric,
+        default: 0
+    },
+    "progress.color": {
+        section: "Display",
+        title: "Color",
+        widget: ChartSettingColorPicker,
+        default: normal.green
+    },
     "table.pivot": {
         title: "Pivot the table",
         widget: ChartSettingToggle,
@@ -480,10 +627,12 @@ const SETTINGS_PREFIXES_BY_CHART_TYPE = {
     line: ["graph.", "line."],
     area: ["graph.", "line.", "stackable."],
     bar: ["graph.", "stackable."],
+    scatter: ["graph.", "scatter."],
     pie: ["pie."],
     scalar: ["scalar."],
     table: ["table."],
-    map: ["map."]
+    map: ["map."],
+    progress: ["progress."],
 }
 
 // alias legacy map types
@@ -544,23 +693,25 @@ export function getSettings(series) {
 function getSettingWidget(id, vizSettings, series, onChangeSettings) {
     const settingDef = SETTINGS[id];
     const value = vizSettings[id];
+    const onChange = (value) => {
+        const newSettings = { [id]: value };
+        for (const id of (settingDef.writeDependencies || [])) {
+            newSettings[id] = vizSettings[id];
+        }
+        onChangeSettings(newSettings)
+    }
     return {
         ...settingDef,
         id: id,
         value: value,
+        title: settingDef.getTitle ? settingDef.getTitle(series, vizSettings) : settingDef.title,
         hidden: settingDef.getHidden ? settingDef.getHidden(series, vizSettings) : false,
         disabled: settingDef.getDisabled ? settingDef.getDisabled(series, vizSettings) : false,
         props: {
             ...(settingDef.props ? settingDef.props : {}),
-            ...(settingDef.getProps ? settingDef.getProps(series, vizSettings) : {})
+            ...(settingDef.getProps ? settingDef.getProps(series, vizSettings, onChange) : {})
         },
-        onChange: (value) => {
-            const newSettings = { [id]: value };
-            for (const id of (settingDef.writeDependencies || [])) {
-                newSettings[id] = vizSettings[id];
-            }
-            onChangeSettings(newSettings)
-        }
+        onChange
     };
 }
 
@@ -568,5 +719,5 @@ export function getSettingsWidgets(series, onChangeSettings) {
     const vizSettings = getSettings(series);
     return getSettingIdsForSeries(series).map(id =>
         getSettingWidget(id, vizSettings, series, onChangeSettings)
-    );
+    ).filter(widget => widget.widget && !widget.hidden);
 }
diff --git a/frontend/src/metabase/meta/metadata/Field.js b/frontend/src/metabase/meta/metadata/Field.js
index 3e58d199c86476b7da89d3ac3c711250625e8e8d..81c48ec05e7d8eb58395336b46d25364cbdb0bdb 100644
--- a/frontend/src/metabase/meta/metadata/Field.js
+++ b/frontend/src/metabase/meta/metadata/Field.js
@@ -4,6 +4,7 @@ import Base from "./Base";
 import Table from "./Table";
 
 import { isDate, isNumeric, isBoolean, isString, isSummable, isCategory, isDimension, isMetric, getIconForField } from "metabase/lib/schema_metadata";
+import { isPK } from "metabase/lib/types";
 
 export default class Field extends Base {
     static type = "fields";
@@ -35,7 +36,7 @@ export default class Field extends Base {
     isCategory()  { return isCategory(this._object); }
     isMetric()    { return isMetric(this._object); }
     isDimension() { return isDimension(this._object); }
-    isID()        { return this.special_type === "id"; }
+    isID()        { return isPK(this.special_type); }
 
     values() {
         return (this._object.values && this._object.values.length > 0 && this._object.values[0].values) || []
diff --git a/frontend/src/metabase/query_builder/QueryVisualizationObjectDetailTable.jsx b/frontend/src/metabase/query_builder/QueryVisualizationObjectDetailTable.jsx
index e1b24bd9ac753e4e07a171fc92c090eade0fec8b..5c3cd9260c70767deba576c07aa2087c7ff7452d 100644
--- a/frontend/src/metabase/query_builder/QueryVisualizationObjectDetailTable.jsx
+++ b/frontend/src/metabase/query_builder/QueryVisualizationObjectDetailTable.jsx
@@ -5,6 +5,7 @@ import Icon from 'metabase/components/Icon.jsx';
 import IconBorder from 'metabase/components/IconBorder.jsx';
 import LoadingSpinner from 'metabase/components/LoadingSpinner.jsx';
 import { foreignKeyCountsByOriginTable } from 'metabase/lib/schema_metadata';
+import { isPK } from "metabase/lib/types";
 import { singularize, inflect } from 'inflection';
 
 import cx from "classnames";
@@ -37,7 +38,7 @@ export default class QueryVisualizationObjectDetailTable extends Component {
 
         for (var i=0; i < this.props.data.cols.length; i++) {
             var coldef = this.props.data.cols[i];
-            if (coldef.special_type === "id") {
+            if (isPK(coldef.special_type)) {
                 return this.props.data.rows[0][i];
             }
         }
diff --git a/frontend/src/metabase/query_builder/actions.js b/frontend/src/metabase/query_builder/actions.js
index 965bc60135a0d797284a978acb889ec56404f08c..506c04473332d0861a9b476121d86b44a8c0d82e 100644
--- a/frontend/src/metabase/query_builder/actions.js
+++ b/frontend/src/metabase/query_builder/actions.js
@@ -14,6 +14,7 @@ import { formatSQL, humanize } from "metabase/lib/formatting";
 import Query from "metabase/lib/query";
 import { createQuery } from "metabase/lib/query";
 import { loadTableAndForeignKeys } from "metabase/lib/table";
+import { isPK, isFK } from "metabase/lib/types";
 import Utils from "metabase/lib/utils";
 import { applyParameters } from "metabase/meta/Card";
 
@@ -789,14 +790,16 @@ export const queryCompleted = createThunkAction(QUERY_COMPLETED, (card, queryRes
         let cardDisplay = card.display;
 
         // try a little logic to pick a smart display for the data
-        if (card.display !== "scalar" &&
+        // TODO: less hard-coded rules for picking chart type
+        const isScalarVisualization = card.display === "scalar" || card.display === "progress";
+        if (!isScalarVisualization &&
                 queryResult.data.rows &&
                 queryResult.data.rows.length === 1 &&
                 queryResult.data.columns.length === 1) {
             // if we have a 1x1 data result then this should always be viewed as a scalar
             cardDisplay = "scalar";
 
-        } else if (card.display === "scalar" &&
+        } else if (isScalarVisualization &&
                     queryResult.data.rows &&
                     (queryResult.data.rows.length > 1 || queryResult.data.columns.length > 1)) {
             // any time we were a scalar and now have more than 1x1 data switch to table view
@@ -852,7 +855,7 @@ export const cellClicked = createThunkAction(CELL_CLICKED, (rowIndex, columnInde
             isForeignColumn = coldef.table_id && coldef.table_id !== sourceTableID && coldef.fk_field_id,
             fieldRefForm    = isForeignColumn ? ['fk->', coldef.fk_field_id, coldef.id] : ['field-id', coldef.id];
 
-        if (coldef.special_type === "id") {
+        if (isPK(coldef.special_type)) {
             // action is on a PK column
             let newCard = startNewCard("query", card.dataset_query.database);
 
@@ -864,7 +867,7 @@ export const cellClicked = createThunkAction(CELL_CLICKED, (rowIndex, columnInde
             dispatch(setCardAndRun(newCard));
 
             MetabaseAnalytics.trackEvent("QueryBuilder", "Table Cell Click", "PK");
-        } else if (coldef.special_type === "fk") {
+        } else if (isFK(coldef.special_type)) {
             // action is on an FK column
             let newCard = startNewCard("query", card.dataset_query.database);
 
@@ -917,7 +920,7 @@ export const followForeignKey = createThunkAction(FOLLOW_FOREIGN_KEY, (fk) => {
         // extract the value we will use to filter our new query
         var originValue;
         for (var i=0; i < queryResult.data.cols.length; i++) {
-            if (queryResult.data.cols[i].special_type === "id") {
+            if (isPK(queryResult.data.cols[i].special_type)) {
                 originValue = queryResult.data.rows[0][i];
             }
         }
@@ -943,7 +946,7 @@ export const loadObjectDetailFKReferences = createThunkAction(LOAD_OBJECT_DETAIL
         function getObjectDetailIdValue(data) {
             for (var i=0; i < data.cols.length; i++) {
                 var coldef = data.cols[i];
-                if (coldef.special_type === "id") {
+                if (isPK(coldef.special_type)) {
                     return data.rows[0][i];
                 }
             }
diff --git a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
index 4a02444e047f6b9a64ae214565ea77357bd96be4..45cea1a8f1eb6c51de397b8b36bb77ff1146dabe 100644
--- a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
+++ b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
@@ -1,10 +1,12 @@
 import React, { Component, PropTypes } from "react";
+import ReactDOM from "react-dom";
 import { connect } from "react-redux";
 import cx from "classnames";
 import _ from "underscore";
 
 import { AngularResourceProxy } from "metabase/lib/redux";
 import { loadTableAndForeignKeys } from "metabase/lib/table";
+import { isPK, isFK } from "metabase/lib/types";
 
 import NotFound from "metabase/components/NotFound.jsx";
 import QueryHeader from "../QueryHeader.jsx";
@@ -53,11 +55,7 @@ function cellIsClickable(queryResult, rowIndex, columnIndex) {
 
     if (!coldef || !coldef.special_type) return false;
 
-    if (coldef.table_id != null && coldef.special_type === 'id' || (coldef.special_type === 'fk' && coldef.target)) {
-        return true;
-    } else {
-        return false;
-    }
+    return (coldef.table_id != null && (isPK(coldef.special_type) || (isFK(coldef.special_type) && coldef.target)));
 }
 
 function autocompleteResults(card, prefix) {
@@ -153,6 +151,13 @@ export default class QueryBuilder extends Component {
         }
     }
 
+    componentDidUpdate() {
+        let viz = ReactDOM.findDOMNode(this.refs.viz);
+        if (viz) {
+            viz.style.opacity = 1.0;
+        }
+    }
+
     componentWillUnmount() {
         window.removeEventListener('resize', this.handleResize);
     }
@@ -161,6 +166,10 @@ export default class QueryBuilder extends Component {
     // Debounce the function to improve resizing performance.
     handleResize(e) {
         this.forceUpdateDebounced();
+        let viz = ReactDOM.findDOMNode(this.refs.viz);
+        if (viz) {
+            viz.style.opacity = 0.2;
+        }
     }
 
     render() {
@@ -199,7 +208,7 @@ export default class QueryBuilder extends Component {
                         }
                     </div>
 
-                    <div id="react_qb_viz" className="flex z1">
+                    <div ref="viz" id="react_qb_viz" className="flex z1" style={{ "transition": "opacity 0.25s ease-in-out" }}>
                         <QueryVisualization {...this.props}/>
                     </div>
                 </div>
diff --git a/frontend/src/metabase/query_builder/selectors.js b/frontend/src/metabase/query_builder/selectors.js
index ef680b204a96cb47e53cdcc7253425f9fa0b4113..089db30368f1aab6bf1e77e8fbb6d5da9cc1ba58 100644
--- a/frontend/src/metabase/query_builder/selectors.js
+++ b/frontend/src/metabase/query_builder/selectors.js
@@ -8,6 +8,7 @@ import { isCardDirty } from "metabase/lib/card";
 import * as DataGrid from "metabase/lib/data_grid";
 import Query from "metabase/lib/query";
 import { parseFieldTarget } from "metabase/lib/query_time";
+import { isPK } from "metabase/lib/types";
 import { applyParameters } from "metabase/meta/Card";
 
 export const uiControls                = state => state.qb.uiControls;
@@ -90,8 +91,7 @@ export const isObjectDetail = createSelector(
 	        let pkField;
 	        for (var i=0; i < data.cols.length; i++) {
 	            let coldef = data.cols[i];
-	            if (coldef.table_id === dataset_query.query.source_table &&
-	                    coldef.special_type === "id") {
+	            if (coldef.table_id === dataset_query.query.source_table && isPK(coldef.special_type)) {
 	                pkField = coldef.id;
 	            }
 	        }
diff --git a/frontend/src/metabase/reference/components/Field.jsx b/frontend/src/metabase/reference/components/Field.jsx
index 366c548acd0d02440723dadecbb6030ca1df48a5..b65dbc1dc0a5093f26c83ef8032ab3b8832510b7 100644
--- a/frontend/src/metabase/reference/components/Field.jsx
+++ b/frontend/src/metabase/reference/components/Field.jsx
@@ -4,6 +4,7 @@ import { Link } from "react-router";
 
 import * as MetabaseCore from "metabase/lib/core";
 import { isNumericBaseType } from "metabase/lib/schema_metadata";
+import { isa, isFK, TYPE } from "metabase/lib/types";
 
 import i from 'icepick';
 
@@ -23,7 +24,7 @@ const Field = ({
     icon,
     isEditing,
     formField
-}) => 
+}) =>
     <div className={cx(S.item)}>
         <div className={S.leftIcons}>
             { icon && <Icon className={S.chartIcon} name={icon} size={20} /> }
@@ -58,9 +59,8 @@ const Field = ({
                                         'name': 'No field type',
                                         'section': 'Other'
                                     })
-                                    .filter(type => !isNumericBaseType(field) ?
-                                        !(type.id && type.id.startsWith("timestamp_")) :
-                                        true
+                                    .filter(type =>
+                                        isNumericBaseType(field) || !isa(type && type.id, TYPE.UNIXTimestamp)
                                     )
                             }
                             onChange={(type) => formField.special_type.onChange(type.id)}
@@ -84,8 +84,8 @@ const Field = ({
                 </div>
                 <div className={F.fieldForeignKey}>
                     { isEditing ?
-                        (formField.special_type.value === 'fk' ||
-                        (field.special_type === 'fk' && formField.special_type.value === undefined)) &&
+                        (isFK(formField.special_type.value) ||
+                        (isFK(field.special_type) && formField.special_type.value === undefined)) &&
                         <Select
                             triggerClasses={F.fieldSelect}
                             placeholder="Select a field type"
@@ -98,7 +98,7 @@ const Field = ({
                             onChange={(foreignKey) => formField.fk_target_field_id.onChange(foreignKey.id)}
                             optionNameFn={(foreignKey) => foreignKey.name}
                         /> :
-                        field.special_type === 'fk' &&
+                        isFK(field.special_type) &&
                         <span>
                             {i.getIn(foreignKeys, [field.fk_target_field_id, "name"])}
                         </span>
diff --git a/frontend/src/metabase/reference/components/FieldTypeDetail.jsx b/frontend/src/metabase/reference/components/FieldTypeDetail.jsx
index 737f218e3e7815c593749036d15fbc0bdcf87569..cf454dffcfeee48e42617ba0307d78ceb2da2d90 100644
--- a/frontend/src/metabase/reference/components/FieldTypeDetail.jsx
+++ b/frontend/src/metabase/reference/components/FieldTypeDetail.jsx
@@ -5,6 +5,7 @@ import pure from "recompose/pure";
 
 import * as MetabaseCore from "metabase/lib/core";
 import { isNumericBaseType } from "metabase/lib/schema_metadata";
+import { isFK } from "metabase/lib/types";
 
 import Select from "metabase/components/Select.jsx";
 
@@ -57,8 +58,8 @@ const FieldTypeDetail = ({
                 </span>
                 <span className="ml4">
                     { isEditing ?
-                        (fieldTypeFormField.value === 'fk' ||
-                        (field.special_type === 'fk' && fieldTypeFormField.value === undefined)) &&
+                        (isFK(fieldTypeFormField.value) ||
+                        (isFK(field.special_type) && fieldTypeFormField.value === undefined)) &&
                         <Select
                             triggerClasses="rounded bordered p1 inline-block"
                             placeholder="Select a field type"
@@ -71,7 +72,7 @@ const FieldTypeDetail = ({
                             onChange={(foreignKey) => foreignKeyFormField.onChange(foreignKey.id)}
                             optionNameFn={(foreignKey) => foreignKey.name}
                         /> :
-                        field.special_type === 'fk' &&
+                        isFK(field.special_type) &&
                         <span>
                             {i.getIn(foreignKeys, [field.fk_target_field_id, "name"])}
                         </span>
diff --git a/frontend/src/metabase/reference/utils.js b/frontend/src/metabase/reference/utils.js
index 5e89dd9dbabf5ac2a926feafc2343de08614a3fe..9039aeea0fbe5ef40be88ef91acf6ed568dc7cba 100644
--- a/frontend/src/metabase/reference/utils.js
+++ b/frontend/src/metabase/reference/utils.js
@@ -2,6 +2,7 @@ import i from "icepick";
 
 import { titleize, humanize } from "metabase/lib/formatting";
 import { startNewCard, serializeCardForUrl } from "metabase/lib/card";
+import { isPK } from "metabase/lib/types";
 
 export const idsToObjectMap = (ids, objects) => ids
     .map(id => objects[id])
@@ -128,12 +129,12 @@ export const databaseToForeignKeys = (database) => database && database.tables_l
         // ignore tables without primary key
         .filter(table => table && table.fields_lookup &&
             Object.values(table.fields_lookup)
-                .find(field => field.special_type === 'id')
+                .find(field => isPK(field.special_type))
         )
         .map(table => ({
             table: table,
             field: table && table.fields_lookup && Object.values(table.fields_lookup)
-                .find(field => field.special_type === 'id')
+                .find(field => isPK(field.special_type))
         }))
         .map(({ table, field }) => ({
             id: field.id,
diff --git a/frontend/src/metabase/visualizations/PieChart.jsx b/frontend/src/metabase/visualizations/PieChart.jsx
index e22d243dedd59cb25d4d735aec420b7a3f3d977b..7bb16fb948334c2bd86a86df2010138b4a774349 100644
--- a/frontend/src/metabase/visualizations/PieChart.jsx
+++ b/frontend/src/metabase/visualizations/PieChart.jsx
@@ -24,6 +24,8 @@ const PAD_ANGLE = (Math.PI / 180) * 1; // 1 degree in radians
 const SLICE_THRESHOLD = 1 / 360; // 1 degree in percentage
 const OTHER_SLICE_MIN_PERCENTAGE = 0.003;
 
+const PERCENT_REGEX = /percent/i;
+
 export default class PieChart extends Component {
     static displayName = "Pie";
     static identifier = "pie";
@@ -62,10 +64,13 @@ export default class PieChart extends Component {
         const formatMetric    =    (metric, jsx = true) => formatValue(metric, { column: cols[metricIndex], jsx, majorWidth: 0 })
         const formatPercent   =               (percent) => (100 * percent).toFixed(2) + "%"
 
+        const showPercentInTooltip = !PERCENT_REGEX.test(cols[metricIndex].name) && !PERCENT_REGEX.test(cols[metricIndex].display_name);
+
         let total = rows.reduce((sum, row) => sum + row[metricIndex], 0);
 
         // use standard colors for up to 5 values otherwise use color harmony to help differentiate slices
         let sliceColors = Object.values(rows.length > 5 ? colors.harmony : colors.normal);
+        let sliceThreshold = typeof settings["pie.slice_threshold"] === "number" ? settings["pie.slice_threshold"] / 100 : SLICE_THRESHOLD;
 
         let [slices, others] = _.chain(rows)
             .map((row, index) => ({
@@ -74,7 +79,7 @@ export default class PieChart extends Component {
                 percentage: row[metricIndex] / total,
                 color: sliceColors[index % sliceColors.length]
             }))
-            .partition((d) => d.percentage > SLICE_THRESHOLD)
+            .partition((d) => d.percentage > sliceThreshold)
             .value();
 
         let otherTotal = others.reduce((acc, o) => acc + o.value, 0);
@@ -119,8 +124,7 @@ export default class PieChart extends Component {
             : [
                 { key: getFriendlyName(cols[dimensionIndex]), value: formatDimension(slices[index].key) },
                 { key: getFriendlyName(cols[metricIndex]), value: formatMetric(slices[index].value) },
-                { key: "Percentage", value: formatPercent(slices[index].percentage) }
-            ]
+            ].concat(showPercentInTooltip ? [{ key: "Percentage", value: formatPercent(slices[index].percentage) }] : [])
         });
 
         let value, title;
diff --git a/frontend/src/metabase/visualizations/Progress.jsx b/frontend/src/metabase/visualizations/Progress.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..9c6a7e766a6193dbd4b5634ab9c571b2bddf6082
--- /dev/null
+++ b/frontend/src/metabase/visualizations/Progress.jsx
@@ -0,0 +1,156 @@
+import React, { Component, PropTypes } from "react";
+import ReactDOM from "react-dom";
+
+import { formatValue } from "metabase/lib/formatting";
+import Icon from "metabase/components/Icon.jsx";
+import IconBorder from "metabase/components/IconBorder.jsx";
+
+import Color from "color";
+
+const BORDER_RADIUS = 5;
+
+export default class Progress extends Component {
+    static displayName = "Progress";
+    static identifier = "progress";
+    static iconName = "number";
+
+    static minSize = { width: 3, height: 3 };
+
+    static isSensible(cols, rows) {
+        return rows.length === 1 && cols.length === 1;
+    }
+
+    static checkRenderable(cols, rows) {
+    }
+
+    componentDidMount() {
+        this.componentDidUpdate();
+    }
+
+    componentDidUpdate() {
+        const pointer = ReactDOM.findDOMNode(this.refs.pointer);
+        const label = ReactDOM.findDOMNode(this.refs.label);
+        const container = ReactDOM.findDOMNode(this.refs.container);
+
+        if (this.props.gridSize && this.props.gridSize.height < 4) {
+            pointer.parentNode.style.display = "none";
+            label.parentNode.style.display = "none";
+            // no need to do the rest of the repositioning
+            return;
+        } else {
+            pointer.parentNode.style.display = null;
+            label.parentNode.style.display = null;
+        }
+
+        // reset the pointer transform for these computations
+        pointer.style.transform = null;
+
+        // position the label
+        const containerWidth = container.offsetWidth;
+        const labelWidth = label.offsetWidth;
+        const pointerWidth = pointer.offsetWidth;
+        const pointerCenter = pointer.offsetLeft + pointerWidth / 2;
+        const minOffset = (-pointerWidth / 2) + BORDER_RADIUS
+        if (pointerCenter - labelWidth / 2 < minOffset) {
+            label.style.left = minOffset + "px";
+            label.style.right = null
+        } else if (pointerCenter + labelWidth / 2 > containerWidth - minOffset) {
+            label.style.left = null
+            label.style.right = minOffset + "px";
+        } else {
+            label.style.left = (pointerCenter - labelWidth / 2) + "px";
+            label.style.right = null;
+        }
+
+        // shift pointer at ends inward to line up with border radius
+        if (pointerCenter < BORDER_RADIUS) {
+            pointer.style.transform = "translate(" + BORDER_RADIUS + "px,0)";
+        } else if (pointerCenter > containerWidth - 5) {
+            pointer.style.transform = "translate(-" + BORDER_RADIUS + "px,0)";
+        }
+    }
+
+    render() {
+        const { series: [{ data: { rows } }], settings } = this.props;
+        const value = rows[0][0];
+        const goal = settings["progress.goal"] || 0;
+
+        const mainColor = settings["progress.color"];
+        const lightColor = Color(mainColor).lighten(0.25).rgbString();
+        const darkColor = Color(mainColor).darken(0.30).rgbString();
+
+        const progressColor = mainColor;
+        const restColor = value > goal ? darkColor : lightColor;
+        const arrowColor = value > goal ? darkColor : mainColor;
+
+        const barPercent = Math.max(0, value < goal ? value / goal : goal / value);
+        const arrowPercent = Math.max(0, value < goal ? value / goal : 1);
+
+        let barMessage;
+        if (value === goal) {
+            barMessage = "Goal met";
+        } else if (value > goal) {
+            barMessage = "Goal exceeded";
+        }
+
+        return (
+            <div className="full-height flex layout-centered">
+                <div className="flex-full full-height flex flex-column justify-center" style={{ padding: 10, paddingTop: 0 }}>
+                    <div
+                        ref="container"
+                        className="relative text-bold text-grey-4"
+                        style={{ height: 20 }}
+                    >
+                        <div
+                            ref="label"
+                            style={{ position: "absolute" }}
+                        >
+                            {formatValue(value, { comma: true })}
+                        </div>
+                    </div>
+                    <div className="relative" style={{ height: 10, marginBottom: 5 }}>
+                        <div
+                            ref="pointer"
+                            style={{
+                                width: 0,
+                                height: 0,
+                                position: "absolute",
+                                left: (arrowPercent * 100) + "%",
+                                marginLeft: -10,
+                                borderLeft: "10px solid transparent",
+                                borderRight: "10px solid transparent",
+                                borderTop: "10px solid " + arrowColor
+                            }}
+                        />
+                    </div>
+                    <div className="relative" style={{
+                        backgroundColor: restColor,
+                        borderRadius: BORDER_RADIUS,
+                        height: "25%",
+                        maxHeight: 65,
+                        overflow: "hidden"
+                    }}>
+                        <div style={{
+                                backgroundColor: progressColor,
+                                width: (barPercent * 100) + "%",
+                                height: "100%"
+                            }}
+                        />
+                        { barMessage &&
+                            <div className="flex align-center absolute spread text-white text-bold px2">
+                                <IconBorder borderWidth={2}>
+                                    <Icon name="check" size={14} />
+                                </IconBorder>
+                                <div className="pl2">{barMessage}</div>
+                            </div>
+                        }
+                    </div>
+                    <div className="mt1">
+                        <span className="float-left">0</span>
+                        <span className="float-right">Goal {formatValue(goal, { comma: true })}</span>
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/frontend/src/metabase/visualizations/Scalar.jsx b/frontend/src/metabase/visualizations/Scalar.jsx
index 87e8e0e799d5aa2b757f8f455249389239ee8033..e17300876d97b1c6af0c930ab7f6fb98b0998b85 100644
--- a/frontend/src/metabase/visualizations/Scalar.jsx
+++ b/frontend/src/metabase/visualizations/Scalar.jsx
@@ -7,6 +7,7 @@ import BarChart from "./BarChart.jsx";
 
 import Urls from "metabase/lib/urls";
 import { formatValue } from "metabase/lib/formatting";
+import { TYPE } from "metabase/lib/types";
 import { isSameSeries } from "metabase/visualizations/lib/utils";
 import { getSettings } from "metabase/lib/visualization_settings";
 
@@ -66,7 +67,7 @@ export default class Scalar extends Component {
                 card: { ...s.card, display: "bar" },
                 data: {
                     cols: [
-                        { base_type: "TextField", display_name: "Name", name: "dimension" },
+                        { base_type: TYPE.Text, display_name: "Name", name: "dimension" },
                         { ...s.data.cols[0], display_name: "Value", name: "metric" }],
                     rows: [
                         [s.card.name, s.data.rows[0][0]]
diff --git a/frontend/src/metabase/visualizations/ScatterPlot.jsx b/frontend/src/metabase/visualizations/ScatterPlot.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..76de5e1c6f2bb980b84979f500160a9f8274a222
--- /dev/null
+++ b/frontend/src/metabase/visualizations/ScatterPlot.jsx
@@ -0,0 +1,10 @@
+import React, { Component, PropTypes } from "react";
+
+import LineAreaBarChart from "./components/LineAreaBarChart.jsx";
+
+export default class ScatterPlot extends LineAreaBarChart {
+    static displayName = "Scatter";
+    static identifier = "scatter";
+    static iconName = "line";
+    static noun = "scatter plot";
+}
diff --git a/frontend/src/metabase/visualizations/components/ChartSettings.jsx b/frontend/src/metabase/visualizations/components/ChartSettings.jsx
index a54020fcbfbd8dfeea9c5090e6d78aaf1744f345..10374c314c2bcb995a6a51cf1928b994bea71879 100644
--- a/frontend/src/metabase/visualizations/components/ChartSettings.jsx
+++ b/frontend/src/metabase/visualizations/components/ChartSettings.jsx
@@ -27,7 +27,7 @@ const ChartSettingsTabs = ({ tabs, selectTab, activeTab}) =>
 const Widget = ({ title, hidden, disabled, widget, value, onChange, props }) => {
     const W = widget;
     return (
-        <div className={cx("mb3", { hide: hidden, disable: disabled })}>
+        <div className={cx("mb2", { hide: hidden, disable: disabled })}>
             { title && <h4 className="mb1">{title}</h4> }
             { W && <W value={value} onChange={onChange} {...props}/> }
         </div>
diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip.jsx b/frontend/src/metabase/visualizations/components/ChartTooltip.jsx
index 45203999085f2c950d3457ceaa49bfc869916385..09d9aac7eb1af4626a128d6c962038fe66181990 100644
--- a/frontend/src/metabase/visualizations/components/ChartTooltip.jsx
+++ b/frontend/src/metabase/visualizations/components/ChartTooltip.jsx
@@ -18,6 +18,12 @@ export default class ChartTooltip extends Component {
     static defaultProps = {
     };
 
+    componentWillReceiveProps({ hovered }) {
+        if (hovered && !Array.isArray(hovered.data)) {
+            console.warn("hovered.data should be an array of { key, value, col }", hovered.data);
+        }
+    }
+
     render() {
         const { series, hovered } = this.props;
         if (!(hovered && hovered.data && ((hovered.element && document.contains(hovered.element)) || hovered.event))) {
@@ -33,10 +39,16 @@ export default class ChartTooltip extends Component {
                 <table className="py1 px2">
                     <tbody>
                         { Array.isArray(hovered.data)  ?
-                            hovered.data.map(({ key, value }, index) =>
+                            hovered.data.map(({ key, value, col }, index) =>
                                 <tr key={index}>
                                     <td className="text-light text-right">{key}:</td>
-                                    <td className="pl1 text-bold text-left">{value}</td>
+                                    <td className="pl1 text-bold text-left">
+                                        { col ?
+                                            formatValue(value, { column: col, jsx: true, majorWidth: 0 })
+                                        :
+                                            value
+                                        }
+                                    </td>
                                 </tr>
                             )
                         :
diff --git a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx
index 1664d4664fc61c196292d47979b3cf3b2cb7c499..5e9e6fe99c5c555d1c22f7bbceee837bba2ec799 100644
--- a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx
+++ b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx
@@ -99,12 +99,14 @@ export default class LineAreaBarChart extends Component {
                 _.findIndex(cols, (col) => col.name === metricName)
             );
 
+            const bubbleIndex = settings["scatter.bubble"] && _.findIndex(cols, (col) => col.name === settings["scatter.bubble"]);
+            const extraIndexes = bubbleIndex && bubbleIndex >= 0 ? [bubbleIndex] : [];
+
             if (dimensions.length > 1) {
                 const dataset = crossfilter(rows);
                 const [dimensionIndex, seriesIndex] = dimensionIndexes;
-                const rowIndexes = [dimensionIndex].concat(metricIndexes);
+                const rowIndexes = [dimensionIndex].concat(metricIndexes, extraIndexes);
                 const seriesGroup = dataset.dimension(d => d[seriesIndex]).group()
-
                 nextState.series = seriesGroup.reduce(
                     (p, v) => p.concat([rowIndexes.map(i => v[i])]),
                     (p, v) => null, () => []
@@ -124,6 +126,7 @@ export default class LineAreaBarChart extends Component {
 
                 nextState.series = metricIndexes.map(metricIndex => {
                     const col = cols[metricIndex];
+                    const rowIndexes = [dimensionIndex].concat(metricIndex, extraIndexes);
                     return {
                         card: {
                             ...s.card,
@@ -131,8 +134,10 @@ export default class LineAreaBarChart extends Component {
                             name: getFriendlyName(col)
                         },
                         data: {
-                            rows: rows.map(row => [row[dimensionIndex], row[metricIndex]]),
-                            cols: [cols[dimensionIndex], s.data.cols[metricIndex]]
+                            rows: rows.map(row =>
+                                rowIndexes.map(i => row[i])
+                            ),
+                            cols: rowIndexes.map(i => s.data.cols[i])
                         }
                     };
                 });
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..631b8506451958f3f902ab703e9374d4aaa307f8
--- /dev/null
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker.jsx
@@ -0,0 +1,47 @@
+import React, { Component, PropTypes } from "react";
+
+import { normal } from 'metabase/lib/colors'
+const DEFAULT_COLOR_HARMONY = Object.values(normal);
+
+import PopoverWithTrigger from "metabase/components/PopoverWithTrigger.jsx";
+
+export default class ChartSettingColorPicker extends Component {
+    render() {
+        const { value, onChange, title } = this.props;
+        return (
+            <div className="flex align-center">
+                <PopoverWithTrigger
+                    ref="colorPopover"
+                    hasArrow={false}
+                    tetherOptions={{
+                        attachment: 'middle left',
+                        targetAttachment: 'middle right',
+                        targetOffset: '0 0',
+                        constraints: [{ to: 'window', attachment: 'together', pin: ['left', 'right']}]
+                    }}
+                    triggerElement={
+                        <span className="ml1 mr2 bordered inline-block cursor-pointer" style={{ padding: 4, borderRadius: 3 }}>
+                            <div style={{ width: 15, height: 15, backgroundColor: value }} />
+                        </span>
+                    }
+                >
+                    <ol className="p1">
+                        {DEFAULT_COLOR_HARMONY.map((color, colorIndex) =>
+                            <li
+                                key={colorIndex}
+                                className="CardSettings-colorBlock"
+                                style={{ backgroundColor: color }}
+                                onClick={() => {
+                                    onChange(color);
+                                    this.refs.colorPopover.close();
+                                }}
+                            ></li>
+                        )}
+                    </ol>
+                </PopoverWithTrigger>
+
+                <span className="text-bold">{title}</span>
+            </div>
+        );
+    }
+}
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx
index f5fd68c742d05f470afced27bb26c7936b50753a..9ca6cae19b3b9397fc44162c89f360e0990e87a2 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx
@@ -1,9 +1,6 @@
 import React, { Component, PropTypes } from "react";
 
-import { normal } from 'metabase/lib/colors'
-const DEFAULT_COLOR_HARMONY = Object.values(normal);
-
-import PopoverWithTrigger from "metabase/components/PopoverWithTrigger.jsx";
+import ChartSettingColorPicker from "./ChartSettingColorPicker.jsx";
 
 export default class ChartSettingColorsPicker extends Component {
     render() {
@@ -11,39 +8,12 @@ export default class ChartSettingColorsPicker extends Component {
         return (
             <div>
                 { seriesTitles.map((title, index) =>
-                    <div key={index} className="flex align-center">
-                        <PopoverWithTrigger
-                            ref="colorPopover"
-                            hasArrow={false}
-                            tetherOptions={{
-                                attachment: 'middle left',
-                                targetAttachment: 'middle right',
-                                targetOffset: '0 0',
-                                constraints: [{ to: 'window', attachment: 'together', pin: ['left', 'right']}]
-                            }}
-                            triggerElement={
-                                <span className="ml1 mr2 bordered inline-block cursor-pointer" style={{ padding: 4, borderRadius: 3 }}>
-                                    <div style={{ width: 15, height: 15, backgroundColor: value[index] }} />
-                                </span>
-                            }
-                        >
-                            <ol className="p1">
-                                {DEFAULT_COLOR_HARMONY.map((color, colorIndex) =>
-                                    <li
-                                        key={colorIndex}
-                                        className="CardSettings-colorBlock"
-                                        style={{ backgroundColor: color }}
-                                        onClick={() => {
-                                            onChange([...value.slice(0, index), color, ...value.slice(index + 1)]);
-                                            this.refs.colorPopover.close();
-                                        }}
-                                    ></li>
-                                )}
-                            </ol>
-                        </PopoverWithTrigger>
-
-                        <span className="text-bold">{title}</span>
-                    </div>
+                    <ChartSettingColorPicker
+                        key={index}
+                        value={value[index]}
+                        onChange={(color) => onChange([...value.slice(0, index), color, ...value.slice(index + 1)])}
+                        title={title}
+                    />
                 )}
             </div>
         );
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..2c7e9896d4e543749099ae6338367e71e13db6a1
--- /dev/null
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
@@ -0,0 +1,29 @@
+import React, { Component, PropTypes } from "react";
+
+import Icon from "metabase/components/Icon";
+import cx from "classnames";
+
+import ChartSettingSelect from "./ChartSettingSelect.jsx";
+
+const ChartSettingFieldPicker = ({ value, options, onChange, onRemove }) =>
+    <div className="flex align-center">
+        <ChartSettingSelect
+            value={value}
+            options={options}
+            onChange={onChange}
+            placeholder="Select a field"
+            placeholderNoOptions="No valid fields"
+            isInitiallyOpen={value === undefined}
+        />
+        <Icon
+            name="close"
+            className={cx("ml1 text-grey-4 text-brand-hover cursor-pointer", {
+                "disabled hidden": !onRemove
+            })}
+            width={12} height={12}
+            onClick={onRemove}
+        />
+    </div>
+
+
+export default ChartSettingFieldPicker;
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx
index 45c9e18e99b815456373caab3d762f96a606019d..7e6ea5cc982dc8d9d68ae9788636d9212a71a23a 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx
@@ -1,39 +1,30 @@
 import React, { Component, PropTypes } from "react";
 
-import Icon from "metabase/components/Icon";
-import cx from "classnames";
+import ChartSettingFieldPicker from "./ChartSettingFieldPicker.jsx";
 
-import ChartSettingSelect from "./ChartSettingSelect.jsx";
-
-const ChartSettingFieldsPicker = ({ value = [], onChange, options, addAnother }) =>
+const ChartSettingFieldsPicker = ({ value = [], options, onChange, addAnother }) =>
     <div>
         { Array.isArray(value) ? value.map((v, index) =>
-            <div key={index} className="flex align-center">
-                <ChartSettingSelect
-                    value={v}
-                    options={options}
-                    onChange={(v) => {
-                        let newValue = [...value];
-                        // this swaps the position of the existing value
-                        let existingIndex = value.indexOf(v);
-                        if (existingIndex >= 0) {
-                            newValue.splice(existingIndex, 1, value[index]);
-                        }
-                        // replace with the new value
-                        newValue.splice(index, 1, v);
-                        onChange(newValue);
-                    }}
-                    isInitiallyOpen={v === undefined}
-                />
-                <Icon
-                    name="close"
-                    className={cx("ml1 text-grey-4 text-brand-hover cursor-pointer", {
-                        "disabled hidden": value.filter(v => v != null).length < 2
-                    })}
-                    width={12} height={12}
-                    onClick={() => onChange([...value.slice(0, index), ...value.slice(index + 1)])}
-                />
-            </div>
+            <ChartSettingFieldPicker
+                key={index}
+                value={v}
+                options={options}
+                onChange={(v) => {
+                    let newValue = [...value];
+                    // this swaps the position of the existing value
+                    let existingIndex = value.indexOf(v);
+                    if (existingIndex >= 0) {
+                        newValue.splice(existingIndex, 1, value[index]);
+                    }
+                    // replace with the new value
+                    newValue.splice(index, 1, v);
+                    onChange(newValue);
+                }}
+                onRemove={value.filter(v => v != null).length > 1 || (value.length > 1 && v == null) ?
+                    () => onChange([...value.slice(0, index), ...value.slice(index + 1)]) :
+                    null
+                }
+            />
         ) : <span className="text-error">error</span>}
         { addAnother &&
             <div className="mt1">
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingSelect.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingSelect.jsx
index c2828825ffd6e941c5d70a8f37ccc0cae1d914b3..b8a2875d4fcf9d591e1caf2860f7cb5fad5d1378 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingSelect.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingSelect.jsx
@@ -3,15 +3,17 @@ import React, { Component, PropTypes } from "react";
 import Select from "metabase/components/Select.jsx";
 
 import _ from "underscore";
+import cx from "classnames";
 
-const ChartSettingSelect = ({ value, onChange, options = [], isInitiallyOpen }) =>
+const ChartSettingSelect = ({ value, onChange, options = [], isInitiallyOpen, className, placeholder, placeholderNoOptions }) =>
     <Select
-        className="block flex-full"
+        className={cx(className, "block flex-full", { disabled: options.length === 0 || (options.length === 1 && options[0].value === value) })}
         value={_.findWhere(options, { value })}
         options={options}
         optionNameFn={(o) => o.name}
         optionValueFn={(o) => o.value}
         onChange={onChange}
+        placeholder={options.length === 0 ? placeholderNoOptions : placeholder}
         isInitiallyOpen={isInitiallyOpen}
     />
 
diff --git a/frontend/src/metabase/visualizations/index.js b/frontend/src/metabase/visualizations/index.js
index f0912c8a1c6eeea9c661a3592c451dad0609b8b5..e0fa06a869645327747f0e89f9c60c52702a382f 100644
--- a/frontend/src/metabase/visualizations/index.js
+++ b/frontend/src/metabase/visualizations/index.js
@@ -1,11 +1,13 @@
 
 import Scalar     from "./Scalar.jsx";
+import Progress   from "./Progress.jsx";
 import Table      from "./Table.jsx";
 import LineChart  from "./LineChart.jsx";
 import BarChart   from "./BarChart.jsx";
 import PieChart   from "./PieChart.jsx";
 import AreaChart  from "./AreaChart.jsx";
 import MapViz     from "./Map.jsx";
+import ScatterPlot from "./ScatterPlot.jsx";
 
 const visualizations = new Map();
 const aliases = new Map();
@@ -28,14 +30,15 @@ export function registerVisualization(visualization) {
 }
 
 registerVisualization(Scalar);
+registerVisualization(Progress);
 registerVisualization(Table);
 registerVisualization(LineChart);
 registerVisualization(BarChart);
-registerVisualization(PieChart);
 registerVisualization(AreaChart);
+registerVisualization(ScatterPlot);
+registerVisualization(PieChart);
 registerVisualization(MapViz);
 
-
 import { enableVisualizationEasterEgg } from "./lib/utils";
 import XKCDChart from "./XKCDChart.jsx";
 import LineAreaBarChart from "./components/LineAreaBarChart.jsx";
diff --git a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
index d36b1a32cfeea1cb885a39b41bc2521f58869918..49c40f3565a9980716bcbd024d957e86d1f42d87 100644
--- a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
+++ b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
@@ -2,6 +2,7 @@ import crossfilter from "crossfilter";
 import d3 from "d3";
 import dc from "dc";
 import moment from "moment";
+import _ from "underscore";
 
 import {
     getAvailableCanvasWidth,
@@ -13,11 +14,14 @@ import {
 
 import {
     minTimeseriesUnit,
-    dimensionIsTimeseries,
     computeTimeseriesDataInverval,
     computeTimeseriesTicksInterval
 } from "./timeseries";
 
+import {
+    computeNumericDataInverval
+} from "./numeric";
+
 import { determineSeriesIndexFromElement } from "./tooltip";
 
 import { colorShades } from "./utils";
@@ -51,43 +55,26 @@ function getDcjsChartType(cardType) {
     switch (cardType) {
         case "line": return "lineChart";
         case "area": return "lineChart";
-        case "bar":  return "barChart";
+        case "bar":     return "barChart";
+        case "scatter": return "bubbleChart";
         default:     return "barChart";
     }
 }
 
-function initializeChart(card, element, chartType = getDcjsChartType(card.display)) {
-    // create the chart
-    let chart = dc[chartType](element);
-
-    // set width and height
-    chart = applyChartBoundary(chart, element);
-
-    // disable animations
-    chart.transitionDuration(0);
-
-    return chart;
-}
-
 function applyChartBoundary(chart, element) {
     return chart
         .width(getAvailableCanvasWidth(element))
         .height(getAvailableCanvasHeight(element));
 }
 
-function applyChartTimeseriesXAxis(chart, settings, series, xValues) {
+function applyChartTimeseriesXAxis(chart, settings, series, xValues, xDomain, xInterval) {
     // setup an x-axis where the dimension is a timeseries
     let dimensionColumn = series[0].data.cols[0];
 
-    let unit = minTimeseriesUnit(series.map(s => s.data.cols[0].unit));
-
     // compute the data interval
-    let dataInterval = computeTimeseriesDataInverval(xValues, unit);
+    let dataInterval = xInterval;
     let tickInterval = dataInterval;
 
-    // compute the domain
-    let xDomain = d3.extent(xValues);
-
     if (settings["graph.x_axis.labels_enabled"]) {
         chart.xAxisLabel(settings["graph.x_axis.title_text"] || getFriendlyName(dimensionColumn));
     }
@@ -99,21 +86,21 @@ function applyChartTimeseriesXAxis(chart, settings, series, xValues) {
         }
 
         chart.xAxis().tickFormat(timestamp => {
-            // these dates are in the browser's timezone, change to UTC
+            // HACK: these dates are in the browser's timezone, change to UTC
             let timestampUTC = moment(timestamp).format().replace(/[+-]\d+:\d+$/, "Z");
             return formatValue(timestampUTC, { column: dimensionColumn })
         });
 
         // Compute a sane interval to display based on the data granularity, domain, and chart width
-        tickInterval = computeTimeseriesTicksInterval(xValues, unit, chart.width(), MIN_PIXELS_PER_TICK.x);
+        tickInterval = computeTimeseriesTicksInterval(xDomain, dataInterval, chart.width(), MIN_PIXELS_PER_TICK.x, );
         chart.xAxis().ticks(d3.time[tickInterval.interval], tickInterval.count);
     } else {
         chart.xAxis().ticks(0);
     }
 
     // pad the domain slightly to prevent clipping
-    xDomain[0] = moment(xDomain[0]).subtract(dataInterval.count * 0.75, dataInterval.interval);
-    xDomain[1] = moment(xDomain[1]).add(dataInterval.count * 0.75, dataInterval.interval);
+    xDomain[0] = moment(xDomain[0]).subtract(dataInterval.count * 0.75, dataInterval.interval).toDate();
+    xDomain[1] = moment(xDomain[1]).add(dataInterval.count * 0.75, dataInterval.interval).toDate();
 
     // set the x scale
     chart.x(d3.time.scale.utc().domain(xDomain));//.nice(d3.time[dataInterval.interval]));
@@ -122,6 +109,44 @@ function applyChartTimeseriesXAxis(chart, settings, series, xValues) {
     chart.xUnits((start, stop) => Math.ceil(1 + moment(stop).diff(start, dataInterval.interval) / dataInterval.count));
 }
 
+function applyChartQuantitativeXAxis(chart, settings, series, xValues, xDomain, xInterval) {
+    const dimensionColumn = series[0].data.cols[0];
+
+    if (settings["graph.x_axis.labels_enabled"]) {
+        chart.xAxisLabel(settings["graph.x_axis.title_text"] || getFriendlyName(dimensionColumn));
+    }
+    if (settings["graph.x_axis.axis_enabled"]) {
+        chart.renderVerticalGridLines(settings["graph.x_axis.gridLine_enabled"]);
+        adjustTicksIfNeeded(chart.xAxis(), chart.width(), MIN_PIXELS_PER_TICK.x);
+
+        chart.xAxis().tickFormat(d => formatValue(d, { column: dimensionColumn }));
+    } else {
+        chart.xAxis().ticks(0);
+        chart.xAxis().tickFormat('');
+    }
+
+    let scale;
+    if (settings["graph.x_axis.scale"] === "pow") {
+        scale = d3.scale.pow().exponent(0.5);
+    } else if (settings["graph.x_axis.scale"] === "log") {
+        scale = d3.scale.log().base(Math.E);
+        if (!((xDomain[0] < 0 && xDomain[1] < 0) || (xDomain[0] > 0 && xDomain[1] > 0))) {
+            throw "X-axis must not cross 0 when using log scale.";
+        }
+    } else {
+        scale = d3.scale.linear();
+    }
+
+    // pad the domain slightly to prevent clipping
+    xDomain = [
+        xDomain[0] - xInterval * 0.75,
+        xDomain[1] + xInterval * 0.75
+    ];
+
+    chart.x(scale.domain(xDomain))
+        .xUnits(dc.units.fp.precision(xInterval));
+}
+
 function applyChartOrdinalXAxis(chart, settings, series, xValues) {
     const dimensionColumn = series[0].data.cols[0];
 
@@ -154,51 +179,99 @@ function applyChartOrdinalXAxis(chart, settings, series, xValues) {
         .xUnits(dc.units.ordinal);
 }
 
-function applyChartYAxis(chart, settings, series, yAxisSplit) {
-
-    if (settings["graph.y_axis.labels_enabled"]) {
+function applyChartYAxis(chart, settings, series, yExtent, axisName) {
+    let axis;
+    if (axisName === "left") {
+        axis = {
+            scale:   (...args) => chart.y(...args),
+            axis:    (...args) => chart.yAxis(...args),
+            label:   (...args) => chart.yAxisLabel(...args),
+            setting: (name) => settings["graph.y_axis." + name]
+        };
+    } else if (axisName === "right") {
+        axis = {
+            scale:   (...args) => chart.rightY(...args),
+            axis:    (...args) => chart.rightYAxis(...args),
+            label:   (...args) => chart.rightYAxisLabel(...args),
+            setting: (name) => settings["graph.y_axis." + name] // TODO: right axis settings
+        };
+    }
+
+    if (axis.setting("labels_enabled")) {
         // left
-        if (settings["graph.y_axis.title_text"]) {
-            chart.yAxisLabel(settings["graph.y_axis.title_text"]);
-        } else if (yAxisSplit[0].length === 1) {
-            chart.yAxisLabel(getFriendlyName(series[yAxisSplit[0][0]].data.cols[1]));
-        }
-        // right
-        if (yAxisSplit.length > 1 && yAxisSplit[1].length === 1) {
-            chart.rightYAxisLabel(getFriendlyName(series[yAxisSplit[1][0]].data.cols[1]));
+        if (axis.setting("title_text")) {
+            axis.label(axis.setting("title_text"));
+        } else {
+            // only use the column name if all in the series are the same
+            const labels = _.uniq(series.map(s => getFriendlyName(s.data.cols[1])));
+            if (labels.length === 1) {
+                axis.label(labels[0]);
+            }
         }
     }
 
-    if (settings["graph.y_axis.axis_enabled"]) {
+    if (axis.setting("axis_enabled")) {
         chart.renderHorizontalGridLines(true);
+        adjustTicksIfNeeded(axis.axis(), chart.height(), MIN_PIXELS_PER_TICK.y);
+    } else {
+        axis.axis().ticks(0);
+    }
 
-        adjustTicksIfNeeded(chart.yAxis(), chart.height(), MIN_PIXELS_PER_TICK.y);
-        if (yAxisSplit.length > 1 && chart.rightYAxis) {
-            adjustTicksIfNeeded(chart.rightYAxis(), chart.height(), MIN_PIXELS_PER_TICK.y);
-        }
+    let scale;
+    if (axis.setting("scale") === "pow") {
+        scale = d3.scale.pow().exponent(0.5);
+    } else if (axis.setting("scale") === "log") {
+        scale = d3.scale.log().base(Math.E);
+        // axis.axis().tickFormat((d) => scale.tickFormat(4,d3.format(",d"))(d));
     } else {
-        chart.yAxis().ticks(0);
-        if (chart.rightYAxis) {
-            chart.rightYAxis().ticks(0);
-        }
+        scale = d3.scale.linear();
     }
 
-    if (settings["graph.y_axis.auto_range"]) {
-        chart.elasticY(true);
+    if (axis.setting("auto_range")) {
+        // elasticY not compatible with log scale
+        if (axis.setting("scale") !== "log") {
+            // TODO: right axis?
+            chart.elasticY(true);
+        } else {
+            if (!((yExtent[0] < 0 && yExtent[1] < 0) || (yExtent[0] > 0 && yExtent[1] > 0))) {
+                throw "Y-axis must not cross 0 when using log scale.";
+            }
+            scale.domain(yExtent);
+        }
+        axis.scale(scale);
     } else {
-        chart.y(d3.scale.linear().domain([settings["graph.y_axis.min"], settings["graph.y_axis.max"]]))
+        if (axis.setting("scale") === "log" && !(
+            (axis.setting("min") < 0 && axis.setting("max") < 0) ||
+            (axis.setting("min") > 0 && axis.setting("max") > 0)
+        )) {
+            throw "Y-axis must not cross 0 when using log scale.";
+        }
+        axis.scale(scale.domain([axis.setting("min"), axis.setting("max")]))
     }
 }
 
-function applyChartTooltips(chart, onHoverChange) {
+function applyChartTooltips(chart, series, onHoverChange) {
+    let [{ data: { cols } }] = series;
     chart.on("renderlet.tooltips", function(chart) {
-        chart.selectAll(".bar, .dot, .area, .line, g.pie-slice, g.features")
+        chart.selectAll(".bar, .dot, .area, .line, .bubble, g.pie-slice, g.features")
             .on("mousemove", function(d, i) {
+                let data;
+                if (Array.isArray(d.key)) { // scatter
+                    data = d.key.map((value, index) => (
+                        { key: getFriendlyName(cols[index]), value: value, col: cols[index] }
+                    ));
+                } else if (d.data) { // line, area, bar
+                    data = [
+                        { key: getFriendlyName(cols[0]), value: d.data.key, col: cols[0] },
+                        { key: getFriendlyName(cols[1]), value: d.data.value, col: cols[1] }
+                    ];
+                }
+
                 onHoverChange && onHoverChange({
                     index: determineSeriesIndexFromElement(this),
                     element: this,
                     d: d,
-                    data: d.data
+                    data: data && _.uniq(data, (d) => d.col)
                 });
             })
             .on("mouseleave", function() {
@@ -209,7 +282,7 @@ function applyChartTooltips(chart, onHoverChange) {
     });
 }
 
-function applyChartLineBarSettings(chart, settings, chartType, isLinear, isTimeseries) {
+function applyChartLineBarSettings(chart, settings, chartType) {
     // if the chart supports 'brushing' (brush-based range filter), disable this since it intercepts mouse hovers which means we can't see tooltips
     if (chart.brushOn) {
         chart.brushOn(false);
@@ -234,11 +307,11 @@ function applyChartLineBarSettings(chart, settings, chartType, isLinear, isTimes
     if (chart.barPadding) {
         chart
             .barPadding(BAR_PADDING_RATIO)
-            .centerBar(isLinear || isTimeseries);
+            .centerBar(settings["graph.x_axis.scale"] !== "ordinal");
     }
 }
 
-function lineAndBarOnRender(chart, settings) {
+function lineAndBarOnRender(chart, settings, onGoalHover, isSplitAxis) {
     // once chart has rendered and we can access the SVG, do customizations to axis labels / etc that you can't do through dc.js
 
     function removeClipPath() {
@@ -294,7 +367,7 @@ function lineAndBarOnRender(chart, settings) {
 
     function voronoiHover() {
         const parent = chart.svg().select("svg > g");
-        const dots = chart.svg().selectAll(".dc-tooltip .dot")[0];
+        const dots = chart.svg().selectAll(".sub .dc-tooltip .dot")[0];
 
         if (dots.length === 0 || dots.length > VORONOI_MAX_POINTS) {
             return;
@@ -403,6 +476,47 @@ function lineAndBarOnRender(chart, settings) {
             });
     }
 
+    function fixStackZIndex() {
+        // reverse the order of .stack-list and .dc-tooltip-list children so 0 points in stacked
+        // charts don't appear on top of non-zero points
+        for (const list of chart.selectAll(".stack-list, .dc-tooltip-list")[0]) {
+            for (const child of list.childNodes) {
+                list.insertBefore(list.firstChild, child);
+            }
+        }
+    }
+
+    function cleanupGoal() {
+        // remove dots
+        chart.selectAll(".goal .dot").remove();
+
+        // move to end of the parent node so it's on top
+        chart.selectAll(".goal").each(function() { this.parentNode.appendChild(this); });
+        chart.selectAll(".goal .line").attr({
+            "stroke": "rgba(157,160,164, 0.7)",
+            "stroke-dasharray": "5,5"
+        });
+
+        // add the label
+        let goalLine = chart.selectAll(".goal .line")[0][0];
+        if (goalLine) {
+            let { x, y, width } = goalLine.getBBox();
+            const labelOnRight = !isSplitAxis;
+            chart.selectAll(".goal .stack._0")
+                .append("text")
+                .text("Goal")
+                .attr({
+                    x: labelOnRight ? x + width : x,
+                    y: y - 5,
+                    "text-anchor": labelOnRight ? "end" : "start",
+                    "font-weight": "bold",
+                    fill: "rgb(157,160,164)",
+                })
+                .on("mouseenter", function() { onGoalHover(this); })
+                .on("mouseleave", function() { onGoalHover(null); })
+        }
+    }
+
     // run these first so the rest of the margin computations take it into account
     hideDisabledLabels();
     hideDisabledAxis();
@@ -431,34 +545,141 @@ function lineAndBarOnRender(chart, settings) {
         hideDisabledAxis();
         hideBadAxis();
         disableClickFiltering();
+        fixStackZIndex();
+        cleanupGoal();
     });
 
     chart.render();
 }
 
+function reduceGroup(group, key) {
+    return group.reduce(
+        (acc, d) => (acc == null && d[key] == null) ? null : (acc || 0) + (d[key] || 0),
+        (acc, d) => (acc == null && d[key] == null) ? null : (acc || 0) - (d[key] || 0),
+        () => null
+    );
+}
+
+function fillMissingValues(datas, xValues, fillValue, getKey = (v) => v) {
+    try {
+        return datas.map(rows => {
+            const fillValues = rows[0].slice(1).map(d => fillValue);
+
+            let map = new Map();
+            for (const row of rows) {
+                map.set(getKey(row[0]), row);
+            }
+            let newRows = xValues.map(value => {
+                const key = getKey(value);
+                const row = map.get(key);
+                if (row) {
+                    map.delete(key);
+                    return [value, ...row.slice(1)];
+                } else {
+                    return [value, ...fillValues];
+                }
+            });
+            if (map.size > 0) {
+                console.warn("xValues missing!", map, newRows)
+            }
+            return newRows;
+        });
+    } catch (e) {
+        console.warn(e);
+        return datas;
+    }
+}
+
 export default function lineAreaBar(element, { series, onHoverChange, onRender, chartType, isScalarSeries, settings }) {
     const colors = settings["graph.colors"];
 
-    const isTimeseries = dimensionIsTimeseries(series[0].data);
-    const isLinear = false;
+    const isTimeseries = settings["graph.x_axis.scale"] === "timeseries";
+    const isQuantitative = ["linear", "log", "pow"].indexOf(settings["graph.x_axis.scale"]) >= 0;
 
-    // validation.  we require at least 2 rows for line charting
     if (series[0].data.cols.length < 2) {
-        return;
+        throw "This chart type requires at least 2 columns";
+    }
+
+    if (series.length > 20) {
+        throw "This chart type doesn't support more than 20 series";
     }
 
     let datas = series.map((s, index) =>
         s.data.rows.map(row => [
-            (isTimeseries) ? parseTimestamp(row[0]) : String(row[0]),
-            ...row.slice(1)
+            // don't parse as timestamp if we're going to display as a quantitative scale, e.x. years and Unix timestamps
+            (settings["graph.x_axis._is_timeseries"] && !isQuantitative) ?
+                parseTimestamp(row[0], s.data.cols[0].unit).toDate()
+            : settings["graph.x_axis._is_numeric"] ?
+                row[0]
+            :
+                String(row[0])
+            , ...row.slice(1)
         ])
     );
 
+    // compute the x-values
     let xValues = getXValues(datas, chartType);
 
+    // compute the domain
+    let xDomain = d3.extent(xValues);
+
+    let xInterval;
+    if (isTimeseries) {
+        // compute the interval
+        let unit = minTimeseriesUnit(series.map(s => s.data.cols[0].unit));
+        xInterval = computeTimeseriesDataInverval(xValues, unit);
+    } else if (isQuantitative) {
+        xInterval = computeNumericDataInverval(xValues);
+    }
+
+    if (settings["line.missing"] === "zero" || settings["line.missing"] === "none") {
+        if (isTimeseries) {
+            // replace xValues with
+            xValues = d3.time[xInterval.interval]
+                .range(xDomain[0], moment(xDomain[1]).add(1, "ms").toDate(), xInterval.count);
+            datas = fillMissingValues(
+                datas,
+                xValues,
+                settings["line.missing"] === "zero" ? 0 : null,
+                (m) => d3.round(m.getTime(), -1) // sometimes rounds up 1ms?
+            );
+        } if (isQuantitative) {
+            xValues = d3.range(xDomain[0], xDomain[1] + xInterval, xInterval);
+            datas = fillMissingValues(
+                datas,
+                xValues,
+                settings["line.missing"] === "zero" ? 0 : null,
+            );
+        } else {
+            datas = fillMissingValues(
+                datas,
+                xValues,
+                settings["line.missing"] === "zero" ? 0 : null
+            );
+        }
+    }
+
+    if (isScalarSeries) {
+        xValues = datas.map(data => data[0][0]);
+    }
+
     let dimension, groups, yAxisSplit;
 
-    if (settings["stackable.stacked"] && datas.length > 1) {
+    const isScatter = chartType === "scatter";
+    const isStacked = settings["stackable.stacked"] && datas.length > 1
+
+    if (isScatter) {
+        let dataset = crossfilter();
+        datas.map(data => dataset.add(data));
+
+        dimension = dataset.dimension(d => [d[0], d[1]]);
+        groups = datas.map(data => {
+            let dim = crossfilter(data).dimension(d => d);
+            return [
+                dim.group().reduceSum((d) => d[2] || 1)
+            ]
+        });
+    } else if (isStacked) {
         let dataset = crossfilter();
         datas.map((data, i) =>
             dataset.add(data.map(d => ({
@@ -470,11 +691,9 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender,
         dimension = dataset.dimension(d => d[0]);
         groups = [
             datas.map((data, i) =>
-                dimension.group().reduceSum(d => (d[i + 1] || 0))
+                reduceGroup(dimension.group(), i + 1)
             )
         ];
-
-        yAxisSplit = [series.map((s,i) => i)];
     } else {
         let dataset = crossfilter();
         datas.map(data => dataset.add(data));
@@ -483,28 +702,25 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender,
         groups = datas.map(data => {
             let dim = crossfilter(data).dimension(d => d[0]);
             return data[0].slice(1).map((_, i) =>
-                dim.group().reduceSum(d => (d[i + 1] || 0))
-            )
+                reduceGroup(dim.group(), i + 1)
+            );
         });
-
-        let yExtents = groups.map(group => d3.extent(group[0].all(), d => d.value));
-
-        if (!isScalarSeries && settings["graph.y_axis.auto_split"] !== false) {
-            yAxisSplit = computeSplit(yExtents);
-        } else {
-            yAxisSplit = [series.map((s,i) => i)];
-        }
     }
 
-    if (isScalarSeries) {
-        xValues = datas.map(data => data[0][0]);
+    let yExtents = groups.map(group => d3.extent(group[0].all(), d => d.value));
+    let yExtent = d3.extent([].concat(...yExtents));
+
+    if (!isScalarSeries && !isScatter && !isStacked && settings["graph.y_axis.auto_split"] !== false) {
+        yAxisSplit = computeSplit(yExtents);
+    } else {
+        yAxisSplit = [series.map((s,i) => i)];
     }
 
     // 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.
     // Don't apply to linear or timeseries X-axis since the points are always plotted in order
-    if (!isTimeseries && !isLinear) {
+    if (!isTimeseries && !isQuantitative) {
         let sortMap = new Map()
         for (const [index, key] of xValues.entries()) {
             sortMap.set(key, index);
@@ -517,24 +733,55 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender,
         }
     }
 
-    let parent;
-    if (groups.length > 1) {
-        parent = initializeChart(series[0].card, element, "compositeChart")
-    } else {
-        parent = element;
-    }
+    let parent = dc.compositeChart(element);
+    applyChartBoundary(parent, element);
+    parent.transitionDuration(0);
 
     let charts = groups.map((group, index) => {
         let chart = dc[getDcjsChartType(chartType)](parent);
 
+        // disable clicks
+        chart.onClick = () => {};
+
         chart
             .dimension(dimension)
             .group(group[0])
             .transitionDuration(0)
-            .useRightYAxis(yAxisSplit.length > 1 && yAxisSplit[1].includes(index))
+            .useRightYAxis(yAxisSplit.length > 1 && yAxisSplit[1].includes(index));
+
+        if (isScatter) {
+            chart
+                .keyAccessor((d) => d.key[0])
+                .valueAccessor((d) => d.key[1])
+
+            if (chart.radiusValueAccessor) {
+                const isBubble = datas[index][0].length > 2;
+                if (isBubble) {
+                    const BUBBLE_SCALE_FACTOR_MAX = 64;
+                    chart
+                        .radiusValueAccessor((d) => d.value)
+                        .r(d3.scale.sqrt()
+                            .domain([0, yExtent[1] * BUBBLE_SCALE_FACTOR_MAX])
+                            .range([0, 1])
+                        );
+                } else {
+                    chart.radiusValueAccessor((d) => 1)
+                    chart.MIN_RADIUS = 3
+                }
+                chart.minRadiusWithLabel(Infinity);
+            }
+        }
+
+        if (chart.defined) {
+            chart.defined(
+                settings["line.missing"] === "none" ?
+                    (d) => d.y != null :
+                    (d) => true
+            );
+        }
 
         // multiple series
-        if (groups.length > 1) {
+        if (groups.length > 1 || isScatter) {
             // multiple stacks
             if (group.length > 1) {
                 // compute shades of the assigned color
@@ -550,62 +797,90 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender,
             chart.stack(group[i])
         }
 
-        applyChartLineBarSettings(chart, settings, chartType, isLinear, isTimeseries);
+        applyChartLineBarSettings(chart, settings, chartType);
 
         return chart;
     });
 
-    let chart;
-    if (charts.length > 1) {
-        chart = parent.compose(charts);
-
-        if (!isScalarSeries) {
-            chart.on("renderlet.grouped-bar", function (chart) {
-                // HACK: dc.js doesn't support grouped bar charts so we need to manually resize/reposition them
-                // https://github.com/dc-js/dc.js/issues/558
-                let barCharts = chart.selectAll(".sub rect:first-child")[0].map(node => node.parentNode.parentNode.parentNode);
-                if (barCharts.length > 0) {
-                    let oldBarWidth = parseFloat(barCharts[0].querySelector("rect").getAttribute("width"));
-                    let newBarWidthTotal = oldBarWidth / barCharts.length;
-                    let seriesPadding =
-                        newBarWidthTotal < 4 ? 0 :
-                        newBarWidthTotal < 8 ? 1 :
-                                               2;
-                    let newBarWidth = Math.max(1, newBarWidthTotal - seriesPadding);
-
-                    chart.selectAll("g.sub rect").attr("width", newBarWidth);
-                    barCharts.forEach((barChart, index) => {
-                        barChart.setAttribute("transform", "translate(" + ((newBarWidth + seriesPadding) * index) + ", 0)");
-                    });
-                }
-            })
-        }
+    let onGoalHover = () => {};
+    if (settings["graph.show_goal"]) {
+        const goalData = [[xDomain[0], settings["graph.goal_value"]], [xDomain[1], settings["graph.goal_value"]]];
+        const goalDimension = crossfilter(goalData).dimension(d => d[0]);
+        const goalGroup = goalDimension.group().reduceSum(d => d[1]);
+        const goalIndex = charts.length;
+        let goalChart = dc.lineChart(parent)
+            .dimension(goalDimension)
+            .group(goalGroup)
+            .on('renderlet', function (chart) {
+                // remove "sub" class so the goal is not used in voronoi computation
+                chart.select(".sub._"+goalIndex)
+                    .classed("sub", false)
+                    .classed("goal", true);
+            });
+        charts.push(goalChart);
 
-        // HACK: compositeChart + ordinal X axis shenanigans
-        if (chartType === "bar") {
-            chart._rangeBandPadding(BAR_PADDING_RATIO) // https://github.com/dc-js/dc.js/issues/678
-        } else {
-            chart._rangeBandPadding(1) // https://github.com/dc-js/dc.js/issues/662
+        onGoalHover = (element) => {
+            onHoverChange(element && {
+                element: element,
+                data: [{ key: "Goal", value: settings["graph.goal"] }]
+            });
         }
+    }
+
+    let chart = parent.compose(charts);
+
+    if (groups.length > 1 && !isScalarSeries) {
+        chart.on("renderlet.grouped-bar", function (chart) {
+            // HACK: dc.js doesn't support grouped bar charts so we need to manually resize/reposition them
+            // https://github.com/dc-js/dc.js/issues/558
+            let barCharts = chart.selectAll(".sub rect:first-child")[0].map(node => node.parentNode.parentNode.parentNode);
+            if (barCharts.length > 0) {
+                let oldBarWidth = parseFloat(barCharts[0].querySelector("rect").getAttribute("width"));
+                let newBarWidthTotal = oldBarWidth / barCharts.length;
+                let seriesPadding =
+                    newBarWidthTotal < 4 ? 0 :
+                    newBarWidthTotal < 8 ? 1 :
+                                           2;
+                let newBarWidth = Math.max(1, newBarWidthTotal - seriesPadding);
+
+                chart.selectAll("g.sub rect").attr("width", newBarWidth);
+                barCharts.forEach((barChart, index) => {
+                    barChart.setAttribute("transform", "translate(" + ((newBarWidth + seriesPadding) * index) + ", 0)");
+                });
+            }
+        })
+    }
+
+    // HACK: compositeChart + ordinal X axis shenanigans
+    if (chartType === "bar") {
+        chart._rangeBandPadding(BAR_PADDING_RATIO) // https://github.com/dc-js/dc.js/issues/678
     } else {
-        chart = charts[0];
-        chart.transitionDuration(0)
-        applyChartBoundary(chart, element);
+        chart._rangeBandPadding(1) // https://github.com/dc-js/dc.js/issues/662
     }
 
     // x-axis settings
-    // TODO: we should support a linear (numeric) x-axis option
     if (isTimeseries) {
-        applyChartTimeseriesXAxis(chart, settings, series, xValues);
+        applyChartTimeseriesXAxis(chart, settings, series, xValues, xDomain, xInterval);
+    } else if (isQuantitative) {
+        applyChartQuantitativeXAxis(chart, settings, series, xValues, xDomain, xInterval);
     } else {
         applyChartOrdinalXAxis(chart, settings, series, xValues);
     }
 
     // y-axis settings
-    // TODO: if we are multi-series this could be split axis
-    applyChartYAxis(chart, settings, series, yAxisSplit);
+    let [left, right] = yAxisSplit.map(indexes => ({
+        series: indexes.map(index => series[index]),
+        extent: d3.extent([].concat(...indexes.map(index => yExtents[index])))
+    }));
+    if (left && left.series.length > 0) {
+        applyChartYAxis(chart, settings, left.series, left.extent, "left");
+    }
+    if (right && right.series.length > 0) {
+        applyChartYAxis(chart, settings, right.series, right.extent, "right");
+    }
+    const isSplitAxis = (right && right.series.length) && (left && left.series.length > 0);
 
-    applyChartTooltips(chart, (hovered) => {
+    applyChartTooltips(chart, series, (hovered) => {
         if (onHoverChange) {
             // disable tooltips on lines
             if (hovered && hovered.element && hovered.element.classList.contains("line")) {
@@ -624,7 +899,7 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender,
     chart.render();
 
     // apply any on-rendering functions
-    lineAndBarOnRender(chart, settings);
+    lineAndBarOnRender(chart, settings, onGoalHover, isSplitAxis);
 
     onRender && onRender({ yAxisSplit });
 
diff --git a/frontend/src/metabase/visualizations/lib/numeric.js b/frontend/src/metabase/visualizations/lib/numeric.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb671b949330e95de50d8b354b3ea793776874af
--- /dev/null
+++ b/frontend/src/metabase/visualizations/lib/numeric.js
@@ -0,0 +1,41 @@
+import { isNumeric } from "metabase/lib/schema_metadata";
+
+export function dimensionIsNumeric({ cols, rows }, i = 0) {
+    return isNumeric(cols[i]) || typeof (rows[0] && rows[0][i]) === "number";
+}
+
+export function precision(a) {
+    if (!isFinite(a)) {
+        return 0;
+    }
+    if (!a) {
+        return 0;
+    }
+    var e = 1;
+    while (Math.round(a / e) !== (a / e)) {
+        e /= 10;
+    }
+    while (Math.round(a / Math.pow(10, e)) === (a / Math.pow(10, e))) {
+        e *= 10;
+    }
+    return e;
+}
+
+export function computeNumericDataInverval(xValues) {
+    let bestPrecision = Infinity;
+    for (const value of xValues) {
+        let p = precision(value) || 1;
+        if (p < bestPrecision) {
+            bestPrecision = p;
+        }
+    }
+    return bestPrecision;
+}
+
+// logTickFormat(chart.xAxis())
+export function logTickFormat(axis) {
+    let superscript = "⁰¹²³⁴⁵⁶⁷⁸⁹";
+    let formatPower = (d) => (d + "").split("").map((c) => superscript[c]).join("");
+    let formatTick = (d) =>  10 + formatPower(Math.round(Math.log(d) / Math.LN10));
+    axis.tickFormat(formatTick);
+}
diff --git a/frontend/src/metabase/visualizations/lib/timeseries.js b/frontend/src/metabase/visualizations/lib/timeseries.js
index 7c4ee28a4d7312bb66f06e2e5e85b580c57acaf0..e76c13ae91e8b1989157c01b5674b33d4838d5fd 100644
--- a/frontend/src/metabase/visualizations/lib/timeseries.js
+++ b/frontend/src/metabase/visualizations/lib/timeseries.js
@@ -1,4 +1,3 @@
-import d3 from "d3";
 import moment from "moment";
 
 import { isDate } from "metabase/lib/schema_metadata";
@@ -10,15 +9,15 @@ const TIMESERIES_UNITS = new Set([
     "day",
     "week",
     "month",
-    "quarter"
-    // "year" // https://github.com/metabase/metabase/issues/1992
+    "quarter",
+    "year" // https://github.com/metabase/metabase/issues/1992
 ]);
 
 // investigate the response from a dataset query and determine if the dimension is a timeseries
-export function dimensionIsTimeseries({ cols, rows }) {
+export function dimensionIsTimeseries({ cols, rows }, i = 0) {
     return (
-        (isDate(cols[0]) && (cols[0].unit == null || TIMESERIES_UNITS.has(cols[0].unit))) ||
-        moment(rows[0] && rows[0][0], moment.ISO_8601).isValid()
+        (isDate(cols[i]) && (cols[i].unit == null || TIMESERIES_UNITS.has(cols[i].unit))) ||
+        moment(rows[0] && rows[0][i], moment.ISO_8601).isValid()
     );
 }
 
@@ -96,12 +95,11 @@ export function computeTimeseriesDataInverval(xValues, unit) {
     return TIMESERIES_INTERVALS[computeTimeseriesDataInvervalIndex(xValues, unit)];
 }
 
-export function computeTimeseriesTicksInterval(xValues, unit, chartWidth, minPixels) {
+export function computeTimeseriesTicksInterval(xDomain, xInterval, chartWidth, minPixels) {
     // If the interval that matches the data granularity results in too many ticks reduce the granularity until it doesn't.
     // TODO: compute this directly instead of iteratively
     let maxTickCount = Math.round(chartWidth / minPixels);
-    let xDomain = d3.extent(xValues);
-    let index = computeTimeseriesDataInvervalIndex(xValues, unit);
+    let index = TIMESERIES_INTERVALS.indexOf(xInterval);
     while (index < TIMESERIES_INTERVALS.length - 1) {
         let interval = TIMESERIES_INTERVALS[index];
         let intervalMs = moment(0).add(interval.count, interval.interval).valueOf();
diff --git a/frontend/test/metabase-bootstrap.js b/frontend/test/metabase-bootstrap.js
index 8e284485462c1a014a998bfdd19f8a691e4e1aab..39f62bab8b764e32eae36d08b4fbcd9aff69c9a7 100644
--- a/frontend/test/metabase-bootstrap.js
+++ b/frontend/test/metabase-bootstrap.js
@@ -1,16 +1,56 @@
 import "metabase/vendor";
 
 window.MetabaseBootstrap = {
-  "timezones": [
-    "GMT",
-    "UTC",
-    "US\/Alaska",
-    "US\/Arizona",
-    "US\/Central",
-    "US\/Eastern",
-    "US\/Hawaii",
-    "US\/Mountain",
-    "US\/Pacific",
-    "America\/Costa_Rica"
-  ]
+    timezones: [
+        "GMT",
+        "UTC",
+        "US\/Alaska",
+        "US\/Arizona",
+        "US\/Central",
+        "US\/Eastern",
+        "US\/Hawaii",
+        "US\/Mountain",
+        "US\/Pacific",
+        "America\/Costa_Rica"
+    ],
+    types: {
+        "type/Address":                   ["type/*"],
+        "type/Array":                     ["type/Collection"],
+        "type/AvatarURL":                 ["type/URL"],
+        "type/BigInteger":                ["type/Integer"],
+        "type/Boolean":                   ["type/*"],
+        "type/Category":                  ["type/Special"],
+        "type/City":                      ["type/Category", "type/Address", "type/Text"],
+        "type/Collection":                ["type/*"],
+        "type/Coordinate":                ["type/Float"],
+        "type/Country":                   ["type/Category", "type/Address", "type/Text"],
+        "type/Date":                      ["type/DateTime"],
+        "type/DateTime":                  ["type/*"],
+        "type/Decimal":                   ["type/Float"],
+        "type/Description":               ["type/Text"],
+        "type/Dictionary":                ["type/Collection"],
+        "type/FK":                        ["type/Special"],
+        "type/Float":                     ["type/Number"],
+        "type/IPAddress":                 ["type/TextLike"],
+        "type/ImageURL":                  ["type/URL"],
+        "type/Integer":                   ["type/Number"],
+        "type/Latitude":                  ["type/Coordinate"],
+        "type/Longitude":                 ["type/Coordinate"],
+        "type/Name":                      ["type/Category", "type/Address", "type/Text"],
+        "type/Number":                    ["type/*"],
+        "type/PK":                        ["type/Special"],
+        "type/SerializedJSON":            ["type/Text", "type/Collection"],
+        "type/Special":                   ["type/*"],
+        "type/State":                     ["type/Category", "type/Address", "type/Text"],
+        "type/Text":                      ["type/*"],
+        "type/TextLike":                  ["type/*"],
+        "type/Time":                      ["type/DateTime"],
+        "type/UNIXTimestamp":             ["type/Integer", "type/DateTime"],
+        "type/UNIXTimestampMilliseconds": ["type/UNIXTimestamp"],
+        "type/UNIXTimestampSeconds":      ["type/UNIXTimestamp"],
+        "type/URL":                       ["type/Text"],
+        "type/UUID":                      ["type/Text"],
+        "type/Zip":                       ["type/Address"],
+        "type/ZipCode":                   ["type/Integer"]
+    }
 };
diff --git a/frontend/test/unit/lib/data_grid.spec.js b/frontend/test/unit/lib/data_grid.spec.js
index fb9eb61b46e0686e93f253411a19fc5bc0db9452..0ad32a2f31dc007c9a42bff4f61553939db19abb 100644
--- a/frontend/test/unit/lib/data_grid.spec.js
+++ b/frontend/test/unit/lib/data_grid.spec.js
@@ -1,14 +1,16 @@
 import { pivot } from "metabase/lib/data_grid";
 
+import { TYPE } from "metabase/lib/types";
+
 function makeData(rows) {
     return {
         rows: rows,
         cols: [
-            { name: "D1", display_name: "Dimension 1", base_type: "TextField" },
-            { name: "D2", display_name: "Dimension 2", base_type: "TextField" },
-            { name: "M",  display_name: "Metric",      base_type: "IntegerField" }
+            { name: "D1", display_name: "Dimension 1", base_type: TYPE.Text },
+            { name: "D2", display_name: "Dimension 2", base_type: TYPE.Text },
+            { name: "M",  display_name: "Metric",      base_type: TYPE.Integer }
         ]
-    }
+    };
 }
 
 describe("data_grid", () => {
diff --git a/frontend/test/unit/lib/schema_metadata.spec.js b/frontend/test/unit/lib/schema_metadata.spec.js
index 2ce6be510ab212d1776d78ccafd08413a0d1647e..940d92980e8510291987c4c680dcaee93c1004ef 100644
--- a/frontend/test/unit/lib/schema_metadata.spec.js
+++ b/frontend/test/unit/lib/schema_metadata.spec.js
@@ -2,6 +2,7 @@ import {
     getFieldType,
     DATE_TIME,
     STRING,
+    STRING_LIKE,
     NUMBER,
     BOOLEAN,
     LOCATION,
@@ -9,35 +10,40 @@ import {
     foreignKeyCountsByOriginTable
 } from 'metabase/lib/schema_metadata';
 
+import { TYPE } from "metabase/lib/types";
+
 describe('schema_metadata', () => {
     describe('getFieldType', () => {
         it('should know a date', () => {
-            expect(getFieldType({ base_type: 'DateField' })).toEqual(DATE_TIME)
-            expect(getFieldType({ base_type: 'DateTimeField' })).toEqual(DATE_TIME)
-            expect(getFieldType({ base_type: 'TimeField' })).toEqual(DATE_TIME)
-            expect(getFieldType({ special_type: 'timestamp_seconds' })).toEqual(DATE_TIME)
-            expect(getFieldType({ special_type: 'timestamp_milliseconds' })).toEqual(DATE_TIME)
+            expect(getFieldType({ base_type: TYPE.Date })).toEqual(DATE_TIME)
+            expect(getFieldType({ base_type: TYPE.DateTime })).toEqual(DATE_TIME)
+            expect(getFieldType({ base_type: TYPE.Time })).toEqual(DATE_TIME)
+            expect(getFieldType({ special_type: TYPE.UNIXTimestampSeconds })).toEqual(DATE_TIME)
+            expect(getFieldType({ special_type: TYPE.UNIXTimestampMilliseconds })).toEqual(DATE_TIME)
         });
         it('should know a number', () => {
-            expect(getFieldType({ base_type: 'BigIntegerField' })).toEqual(NUMBER)
-            expect(getFieldType({ base_type: 'IntegerField' })).toEqual(NUMBER)
-            expect(getFieldType({ base_type: 'FloatField' })).toEqual(NUMBER)
-            expect(getFieldType({ base_type: 'DecimalField' })).toEqual(NUMBER)
+            expect(getFieldType({ base_type: TYPE.BigInteger })).toEqual(NUMBER)
+            expect(getFieldType({ base_type: TYPE.Integer })).toEqual(NUMBER)
+            expect(getFieldType({ base_type: TYPE.Float })).toEqual(NUMBER)
+            expect(getFieldType({ base_type: TYPE.Decimal })).toEqual(NUMBER)
         });
         it('should know a string', () => {
-            expect(getFieldType({ base_type: 'CharField' })).toEqual(STRING)
-            expect(getFieldType({ base_type: 'TextField' })).toEqual(STRING)
+            expect(getFieldType({ base_type: TYPE.Text })).toEqual(STRING)
         });
         it('should know a bool', () => {
-            expect(getFieldType({ base_type: 'BooleanField' })).toEqual(BOOLEAN)
+            expect(getFieldType({ base_type: TYPE.Boolean })).toEqual(BOOLEAN)
         });
         it('should know a location', () => {
-            expect(getFieldType({ special_type: 'city' })).toEqual(LOCATION)
-            expect(getFieldType({ special_type: 'country' })).toEqual(LOCATION)
+            expect(getFieldType({ special_type: TYPE.City })).toEqual(LOCATION)
+            expect(getFieldType({ special_type: TYPE.Country })).toEqual(LOCATION)
         });
         it('should know a coordinate', () => {
-            expect(getFieldType({ special_type: 'latitude' })).toEqual(COORDINATE)
-            expect(getFieldType({ special_type: 'longitude' })).toEqual(COORDINATE)
+            expect(getFieldType({ special_type: TYPE.Latitude })).toEqual(COORDINATE)
+            expect(getFieldType({ special_type: TYPE.Longitude })).toEqual(COORDINATE)
+        });
+        it('should know something that is string-like', () => {
+            expect(getFieldType({ base_type: TYPE.TextLike })).toEqual(STRING_LIKE);
+            expect(getFieldType({ base_type: TYPE.IPAddress })).toEqual(STRING_LIKE);
         });
         it('should know what it doesn\'t know', () => {
             expect(getFieldType({ base_type: 'DERP DERP DERP' })).toEqual(undefined)
diff --git a/frontend/test/unit/reference/utils.spec.js b/frontend/test/unit/reference/utils.spec.js
index 13cc7ae20c279f2c6bc0b8154d7c6de90e345b6f..f3a849f0218973b34f4f6dbd72e797bdd37e4fde 100644
--- a/frontend/test/unit/reference/utils.spec.js
+++ b/frontend/test/unit/reference/utils.spec.js
@@ -8,6 +8,8 @@ import {
     getQuestion
 } from 'metabase/reference/utils';
 
+import { TYPE } from "metabase/lib/types";
+
 describe("Reference utils.js", () => {
     const getProps = ({
         section = {
@@ -153,7 +155,7 @@ describe("Reference utils.js", () => {
                         fields_lookup: {
                             1: {
                                 id: 1,
-                                special_type: 'id',
+                                special_type: TYPE.PK,
                                 display_name: 'bar',
                                 description: 'foobar'
                             }
@@ -166,7 +168,7 @@ describe("Reference utils.js", () => {
                         fields_lookup: {
                             2: {
                                 id: 2,
-                                special_type: 'id',
+                                special_type: TYPE.PK,
                                 display_name: 'foo',
                                 description: 'barfoo'
                             }
diff --git a/frontend/test/unit/visualizations/lib/numeric.spec.js b/frontend/test/unit/visualizations/lib/numeric.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c37e860835c733a4271676c7da2ed026bd5f77d
--- /dev/null
+++ b/frontend/test/unit/visualizations/lib/numeric.spec.js
@@ -0,0 +1,47 @@
+import {
+    precision,
+    computeNumericDataInverval
+} from 'metabase/visualizations/lib/numeric';
+
+describe('visualization.lib.numeric', () => {
+    describe('precision', () => {
+        const CASES = [
+            [0,     0],
+            [10,    10],
+            [-10,   10],
+            [1,     1],
+            [-1,    1],
+            [0.1,   0.1],
+            [-0.1,  0.1],
+            [0.01,  0.01],
+            [-0.01, 0.01],
+            [1.1,   0.1],
+            [-1.1,  0.1],
+            [0.5,   0.1],
+            [0.9,   0.1],
+            [-0.5,  0.1],
+            [-0.9,  0.1],
+        ];
+        for (const c of CASES) {
+            it("precision of " + c[0] + " should be " + c[1], () => {
+                expect(precision(c[0])).toEqual(c[1]);
+            });
+        }
+    });
+    describe('computeNumericDataInverval', () => {
+        const CASES = [
+            [[0],       1],
+            [[1],       1],
+            [[0, 1],       1],
+            [[0.1, 1],  0.1],
+            [[0.1, 10], 0.1],
+            [[10, 1],   1],
+            [[0, null, 1], 1]
+        ];
+        for (const c of CASES) {
+            it("precision of " + c[0] + " should be " + c[1], () => {
+                expect(computeNumericDataInverval(c[0])).toEqual(c[1]);
+            });
+        }
+    });
+});
diff --git a/frontend/test/unit/visualizations/lib/timeseries.spec.js b/frontend/test/unit/visualizations/lib/timeseries.spec.js
index 852b4c2ff84ecc13e9121b00cbd2367830d9555a..b83323b42694a0ec81220a88473f17a195f4b0f9 100644
--- a/frontend/test/unit/visualizations/lib/timeseries.spec.js
+++ b/frontend/test/unit/visualizations/lib/timeseries.spec.js
@@ -3,6 +3,8 @@ import {
     computeTimeseriesDataInverval
 } from 'metabase/visualizations/lib/timeseries';
 
+import { TYPE } from "metabase/lib/types";
+
 describe('visualization.lib.timeseries', () => {
     describe('dimensionIsTimeseries', () => {
         // examples from https://en.wikipedia.org/wiki/ISO_8601
@@ -22,23 +24,23 @@ describe('visualization.lib.timeseries', () => {
             "scanner 005"
         ];
 
-        it("should detect DateField column as timeseries", () => {
-            expect(dimensionIsTimeseries({ cols: [{ base_type: "DateField" }]})).toBe(true);
+        it("should detect Date column as timeseries", () => {
+            expect(dimensionIsTimeseries({ cols: [{ base_type: TYPE.Date }]})).toBe(true);
         });
-        it("should detect TimeField column as timeseries", () => {
-            expect(dimensionIsTimeseries({ cols: [{ base_type: "TimeField" }]})).toBe(true);
+        it("should detect Time column as timeseries", () => {
+            expect(dimensionIsTimeseries({ cols: [{ base_type: TYPE.Time }]})).toBe(true);
         });
-        it("should detect DateTimeField column as timeseries", () => {
-            expect(dimensionIsTimeseries({ cols: [{ base_type: "DateTimeField" }]})).toBe(true);
+        it("should detect DateTime column as timeseries", () => {
+            expect(dimensionIsTimeseries({ cols: [{ base_type: TYPE.DateTime }]})).toBe(true);
         });
         ISO_8601_DATES.forEach(isoDate => {
             it("should detect values with ISO 8601 formatted string '" + isoDate + "' as timeseries", () => {
-                expect(dimensionIsTimeseries({ cols: [{ base_type: "TextField" }], rows: [[isoDate]]})).toBe(true);
+                expect(dimensionIsTimeseries({ cols: [{ base_type: TYPE.Text }], rows: [[isoDate]]})).toBe(true);
             })
         });
         NOT_DATES.forEach(notDate => {
             it("should not detect value '" + notDate + "' as timeseries", () => {
-                expect(dimensionIsTimeseries({ cols: [{ base_type: "TextField" }], rows: [[notDate]]})).toBe(false);
+                expect(dimensionIsTimeseries({ cols: [{ base_type: TYPE.Text }], rows: [[notDate]]})).toBe(false);
             });
         });
     });
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 2611d859ee995ed6452c52245c5c1c6db9855731..dcc9d1b481088afaa7bf3861347d939bb9aae8c6 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -3,10 +3,10 @@
   "version": "0.0.0",
   "dependencies": {
     "@kadira/storybook": {
-      "version": "1.36.0",
+      "version": "1.41.0",
       "dependencies": {
         "@kadira/storybook-ui": {
-          "version": "2.3.0",
+          "version": "2.6.1",
           "dependencies": {
             "@kadira/react-split-pane": {
               "version": "1.4.7"
@@ -18,24 +18,16 @@
               "version": "1.0.3"
             },
             "keycode": {
-              "version": "2.1.2"
+              "version": "2.1.6"
             },
             "lodash.pick": {
-              "version": "4.2.1",
-              "dependencies": {
-                "lodash._baseflatten": {
-                  "version": "4.2.1"
-                },
-                "lodash.rest": {
-                  "version": "4.0.3"
-                }
-              }
+              "version": "4.4.0"
             },
             "mantra-core": {
               "version": "1.7.0",
               "dependencies": {
                 "react-komposer": {
-                  "version": "1.12.0",
+                  "version": "1.13.1",
                   "dependencies": {
                     "hoist-non-react-statics": {
                       "version": "1.2.0"
@@ -53,6 +45,9 @@
                         }
                       }
                     },
+                    "mobx": {
+                      "version": "2.5.1"
+                    },
                     "shallowequal": {
                       "version": "0.2.2",
                       "dependencies": {
@@ -63,7 +58,7 @@
                               "version": "3.9.1"
                             },
                             "lodash.isarguments": {
-                              "version": "3.0.8"
+                              "version": "3.1.0"
                             },
                             "lodash.isarray": {
                               "version": "3.0.4"
@@ -85,10 +80,18 @@
               }
             },
             "react-fuzzy": {
-              "version": "0.2.2",
+              "version": "0.2.3",
               "dependencies": {
                 "fuse.js": {
-                  "version": "2.2.0"
+                  "version": "2.5.0"
+                }
+              }
+            },
+            "react-inspector": {
+              "version": "1.1.0",
+              "dependencies": {
+                "is-dom": {
+                  "version": "1.0.5"
                 }
               }
             },
@@ -133,7 +136,7 @@
                           "version": "3.9.1"
                         },
                         "lodash.isarguments": {
-                          "version": "3.0.8"
+                          "version": "3.1.0"
                         },
                         "lodash.isarray": {
                           "version": "3.0.4"
@@ -147,7 +150,7 @@
           }
         },
         "airbnb-js-shims": {
-          "version": "1.0.0",
+          "version": "1.0.1",
           "dependencies": {
             "array-includes": {
               "version": "3.0.2",
@@ -164,7 +167,7 @@
                   }
                 },
                 "es-abstract": {
-                  "version": "1.5.1",
+                  "version": "1.6.1",
                   "dependencies": {
                     "es-to-primitive": {
                       "version": "1.1.1",
@@ -208,7 +211,7 @@
                   }
                 },
                 "es-abstract": {
-                  "version": "1.5.1",
+                  "version": "1.6.1",
                   "dependencies": {
                     "es-to-primitive": {
                       "version": "1.1.1",
@@ -238,7 +241,7 @@
               }
             },
             "object.getownpropertydescriptors": {
-              "version": "2.0.2",
+              "version": "2.0.3",
               "dependencies": {
                 "define-properties": {
                   "version": "1.1.2",
@@ -252,7 +255,7 @@
                   }
                 },
                 "es-abstract": {
-                  "version": "1.5.1",
+                  "version": "1.6.1",
                   "dependencies": {
                     "es-to-primitive": {
                       "version": "1.1.1",
@@ -293,7 +296,7 @@
                   }
                 },
                 "es-abstract": {
-                  "version": "1.5.1",
+                  "version": "1.6.1",
                   "dependencies": {
                     "es-to-primitive": {
                       "version": "1.1.1",
@@ -337,7 +340,7 @@
                   }
                 },
                 "es-abstract": {
-                  "version": "1.5.1",
+                  "version": "1.6.1",
                   "dependencies": {
                     "es-to-primitive": {
                       "version": "1.1.1",
@@ -378,7 +381,7 @@
                   }
                 },
                 "es-abstract": {
-                  "version": "1.5.1",
+                  "version": "1.6.1",
                   "dependencies": {
                     "es-to-primitive": {
                       "version": "1.1.1",
@@ -406,11 +409,221 @@
             }
           }
         },
+        "babel-core": {
+          "version": "6.14.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"
+                        }
+                      }
+                    },
+                    "supports-color": {
+                      "version": "2.0.0"
+                    }
+                  }
+                },
+                "esutils": {
+                  "version": "2.0.2"
+                },
+                "js-tokens": {
+                  "version": "2.0.0"
+                }
+              }
+            },
+            "babel-generator": {
+              "version": "6.14.0",
+              "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-register": {
+              "version": "6.14.0",
+              "dependencies": {
+                "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"
+                    }
+                  }
+                },
+                "mkdirp": {
+                  "version": "0.5.1",
+                  "dependencies": {
+                    "minimist": {
+                      "version": "0.0.8"
+                    }
+                  }
+                },
+                "source-map-support": {
+                  "version": "0.2.10",
+                  "dependencies": {
+                    "source-map": {
+                      "version": "0.1.32",
+                      "dependencies": {
+                        "amdefine": {
+                          "version": "1.0.0"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "babel-template": {
+              "version": "6.15.0"
+            },
+            "babel-traverse": {
+              "version": "6.15.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.15.0",
+              "dependencies": {
+                "esutils": {
+                  "version": "2.0.2"
+                },
+                "to-fast-properties": {
+                  "version": "1.0.2"
+                }
+              }
+            },
+            "babylon": {
+              "version": "6.9.2"
+            },
+            "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.15.0"
+            },
+            "minimatch": {
+              "version": "3.0.3",
+              "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"
+            },
+            "private": {
+              "version": "0.1.6"
+            },
+            "shebang-regex": {
+              "version": "1.0.0"
+            },
+            "slash": {
+              "version": "1.0.0"
+            },
+            "source-map": {
+              "version": "0.5.6"
+            }
+          }
+        },
         "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"
@@ -540,6 +753,9 @@
                 }
               }
             },
+            "qs": {
+              "version": "6.2.0"
+            },
             "range-parser": {
               "version": "1.2.0"
             },
@@ -605,15 +821,15 @@
           "version": "3.0.1",
           "dependencies": {
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             }
           }
         },
         "qs": {
-          "version": "6.2.0"
+          "version": "6.2.1"
         },
         "redbox-react": {
-          "version": "1.2.10",
+          "version": "1.3.0",
           "dependencies": {
             "error-stack-parser": {
               "version": "1.3.6",
@@ -629,13 +845,13 @@
           }
         },
         "shelljs": {
-          "version": "0.6.0"
+          "version": "0.6.1"
         },
         "uuid": {
           "version": "2.0.2"
         },
         "webpack-dev-middleware": {
-          "version": "1.6.1",
+          "version": "1.7.0",
           "dependencies": {
             "memory-fs": {
               "version": "0.3.0",
@@ -649,7 +865,7 @@
                   }
                 },
                 "readable-stream": {
-                  "version": "2.1.4",
+                  "version": "2.1.5",
                   "dependencies": {
                     "buffer-shims": {
                       "version": "1.0.0"
@@ -658,7 +874,7 @@
                       "version": "1.0.2"
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "isarray": {
                       "version": "1.0.0"
@@ -687,16 +903,16 @@
       }
     },
     "ace-builds": {
-      "version": "1.2.2"
+      "version": "1.2.5"
     },
     "angular": {
-      "version": "1.2.30"
+      "version": "1.5.8"
     },
     "angular-cookie": {
       "version": "4.1.0"
     },
     "angular-cookies": {
-      "version": "1.2.30"
+      "version": "1.5.8"
     },
     "angular-http-auth": {
       "version": "1.2.1"
@@ -705,13 +921,13 @@
       "version": "1.2.28"
     },
     "angular-resource": {
-      "version": "1.2.30"
+      "version": "1.5.8"
     },
     "angular-route": {
-      "version": "1.2.30"
+      "version": "1.5.8"
     },
     "babel-core": {
-      "version": "6.10.4",
+      "version": "6.14.0",
       "dependencies": {
         "babel-code-frame": {
           "version": "6.11.0",
@@ -755,7 +971,7 @@
           }
         },
         "babel-generator": {
-          "version": "6.11.0",
+          "version": "6.14.0",
           "dependencies": {
             "detect-indent": {
               "version": "3.0.1",
@@ -790,10 +1006,10 @@
           "version": "6.8.0"
         },
         "babel-register": {
-          "version": "6.9.0",
+          "version": "6.14.0",
           "dependencies": {
             "core-js": {
-              "version": "2.4.0"
+              "version": "2.4.1"
             },
             "home-or-tmp": {
               "version": "1.0.0",
@@ -830,10 +1046,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"
@@ -841,10 +1057,10 @@
           }
         },
         "babel-template": {
-          "version": "6.9.0"
+          "version": "6.15.0"
         },
         "babel-traverse": {
-          "version": "6.10.4",
+          "version": "6.15.0",
           "dependencies": {
             "globals": {
               "version": "8.18.0"
@@ -865,7 +1081,7 @@
           }
         },
         "babel-types": {
-          "version": "6.11.1",
+          "version": "6.15.0",
           "dependencies": {
             "esutils": {
               "version": "2.0.2"
@@ -876,10 +1092,10 @@
           }
         },
         "babylon": {
-          "version": "6.8.3"
+          "version": "6.9.2"
         },
         "convert-source-map": {
-          "version": "1.2.0"
+          "version": "1.3.0"
         },
         "debug": {
           "version": "2.2.0",
@@ -893,16 +1109,16 @@
           "version": "0.4.0"
         },
         "lodash": {
-          "version": "4.13.1"
+          "version": "4.15.0"
         },
         "minimatch": {
-          "version": "3.0.2",
+          "version": "3.0.3",
           "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"
@@ -932,10 +1148,10 @@
       }
     },
     "babel-eslint": {
-      "version": "6.1.0",
+      "version": "6.1.2",
       "dependencies": {
         "babel-traverse": {
-          "version": "6.10.4",
+          "version": "6.15.0",
           "dependencies": {
             "babel-code-frame": {
               "version": "6.11.0",
@@ -982,10 +1198,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"
@@ -1017,18 +1233,18 @@
               }
             },
             "lodash": {
-              "version": "4.13.1"
+              "version": "4.15.0"
             }
           }
         },
         "babel-types": {
-          "version": "6.11.1",
+          "version": "6.15.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"
@@ -1039,7 +1255,7 @@
               "version": "2.0.2"
             },
             "lodash": {
-              "version": "4.13.1"
+              "version": "4.15.0"
             },
             "to-fast-properties": {
               "version": "1.0.2"
@@ -1047,63 +1263,24 @@
           }
         },
         "babylon": {
-          "version": "6.8.3",
-          "dependencies": {
-            "babel-runtime": {
-              "version": "6.9.2",
-              "dependencies": {
-                "core-js": {
-                  "version": "2.4.0"
-                },
-                "regenerator-runtime": {
-                  "version": "0.9.5"
-                }
-              }
-            }
-          }
+          "version": "6.9.2"
         },
         "lodash.assign": {
-          "version": "4.0.9",
+          "version": "4.2.0"
+        },
+        "lodash.pickby": {
+          "version": "4.6.0"
+        }
+      }
+    },
+    "babel-loader": {
+      "version": "6.2.5",
+      "dependencies": {
+        "mkdirp": {
+          "version": "0.5.1",
           "dependencies": {
-            "lodash.keys": {
-              "version": "4.0.7"
-            },
-            "lodash.rest": {
-              "version": "4.0.3"
-            }
-          }
-        },
-        "lodash.pickby": {
-          "version": "4.4.0",
-          "dependencies": {
-            "lodash._baseiteratee": {
-              "version": "4.7.0",
-              "dependencies": {
-                "lodash._stringtopath": {
-                  "version": "4.8.0",
-                  "dependencies": {
-                    "lodash._basetostring": {
-                      "version": "4.12.0"
-                    }
-                  }
-                }
-              }
-            },
-            "lodash.keysin": {
-              "version": "4.1.4"
-            }
-          }
-        }
-      }
-    },
-    "babel-loader": {
-      "version": "6.2.4",
-      "dependencies": {
-        "mkdirp": {
-          "version": "0.5.1",
-          "dependencies": {
-            "minimist": {
-              "version": "0.0.8"
+            "minimist": {
+              "version": "0.0.8"
             }
           }
         },
@@ -1130,10 +1307,10 @@
           }
         },
         "babel-template": {
-          "version": "6.9.0",
+          "version": "6.15.0",
           "dependencies": {
             "babel-traverse": {
-              "version": "6.13.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -1206,7 +1383,7 @@
               }
             },
             "babel-types": {
-              "version": "6.13.0",
+              "version": "6.15.0",
               "dependencies": {
                 "esutils": {
                   "version": "2.0.2"
@@ -1217,17 +1394,17 @@
               }
             },
             "babylon": {
-              "version": "6.8.4"
+              "version": "6.9.2"
             },
             "lodash": {
-              "version": "4.14.2"
+              "version": "4.15.0"
             }
           }
         }
       }
     },
     "babel-plugin-transform-flow-strip-types": {
-      "version": "6.8.0",
+      "version": "6.14.0",
       "dependencies": {
         "babel-plugin-syntax-flow": {
           "version": "6.13.0"
@@ -1246,7 +1423,7 @@
       }
     },
     "babel-polyfill": {
-      "version": "6.9.1",
+      "version": "6.13.0",
       "dependencies": {
         "babel-runtime": {
           "version": "6.11.6"
@@ -1260,7 +1437,7 @@
       }
     },
     "babel-preset-es2015": {
-      "version": "6.9.0",
+      "version": "6.14.0",
       "dependencies": {
         "babel-plugin-check-es2015-constants": {
           "version": "6.8.0",
@@ -1311,7 +1488,7 @@
           }
         },
         "babel-plugin-transform-es2015-block-scoping": {
-          "version": "6.10.1",
+          "version": "6.15.0",
           "dependencies": {
             "babel-runtime": {
               "version": "6.11.6",
@@ -1325,15 +1502,15 @@
               }
             },
             "babel-template": {
-              "version": "6.9.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 }
               }
             },
             "babel-traverse": {
-              "version": "6.12.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -1380,7 +1557,7 @@
                   "version": "6.8.0"
                 },
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "debug": {
                   "version": "2.2.0",
@@ -1409,7 +1586,7 @@
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
                 "esutils": {
                   "version": "2.0.2"
@@ -1420,18 +1597,18 @@
               }
             },
             "lodash": {
-              "version": "4.14.1"
+              "version": "4.15.0"
             }
           }
         },
         "babel-plugin-transform-es2015-classes": {
-          "version": "6.9.0",
+          "version": "6.14.0",
           "dependencies": {
             "babel-helper-define-map": {
               "version": "6.9.0",
               "dependencies": {
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
@@ -1447,7 +1624,7 @@
               "version": "6.8.0"
             },
             "babel-helper-replace-supers": {
-              "version": "6.8.0"
+              "version": "6.14.0"
             },
             "babel-messages": {
               "version": "6.8.0"
@@ -1464,18 +1641,18 @@
               }
             },
             "babel-template": {
-              "version": "6.9.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
             "babel-traverse": {
-              "version": "6.12.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -1519,7 +1696,7 @@
                   }
                 },
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "debug": {
                   "version": "2.2.0",
@@ -1546,18 +1723,18 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
                 "esutils": {
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -1579,7 +1756,7 @@
                       "version": "6.8.0"
                     },
                     "babel-traverse": {
-                      "version": "6.12.0",
+                      "version": "6.15.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -1626,7 +1803,7 @@
                           "version": "6.8.0"
                         },
                         "babylon": {
-                          "version": "6.8.4"
+                          "version": "6.9.2"
                         },
                         "debug": {
                           "version": "2.2.0",
@@ -1657,81 +1834,8 @@
                   }
                 },
                 "babel-types": {
-                  "version": "6.11.1",
+                  "version": "6.15.0",
                   "dependencies": {
-                    "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"
-                                    }
-                                  }
-                                },
-                                "supports-color": {
-                                  "version": "2.0.0"
-                                }
-                              }
-                            },
-                            "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"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
                     "esutils": {
                       "version": "2.0.2"
                     },
@@ -1741,7 +1845,7 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
@@ -1757,10 +1861,10 @@
               }
             },
             "babel-template": {
-              "version": "6.9.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.12.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -1833,7 +1937,7 @@
                   }
                 },
                 "babel-types": {
-                  "version": "6.11.1",
+                  "version": "6.15.0",
                   "dependencies": {
                     "esutils": {
                       "version": "2.0.2"
@@ -1844,10 +1948,10 @@
                   }
                 },
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             }
@@ -1884,86 +1988,13 @@
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
-                "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"
-                                }
-                              }
-                            },
-                            "supports-color": {
-                              "version": "2.0.0"
-                            }
-                          }
-                        },
-                        "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"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
                 "esutils": {
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -1998,18 +2029,18 @@
                   "version": "6.8.0"
                 },
                 "babel-template": {
-                  "version": "6.9.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babylon": {
-                      "version": "6.8.4"
+                      "version": "6.9.2"
                     },
                     "lodash": {
-                      "version": "4.14.1"
+                      "version": "4.15.0"
                     }
                   }
                 },
                 "babel-traverse": {
-                  "version": "6.12.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2056,7 +2087,7 @@
                       "version": "6.8.0"
                     },
                     "babylon": {
-                      "version": "6.8.4"
+                      "version": "6.9.2"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2083,7 +2114,7 @@
                       }
                     },
                     "lodash": {
-                      "version": "4.14.1"
+                      "version": "4.15.0"
                     }
                   }
                 }
@@ -2101,10 +2132,56 @@
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
+              "dependencies": {
+                "esutils": {
+                  "version": "2.0.2"
+                },
+                "lodash": {
+                  "version": "4.15.0"
+                },
+                "to-fast-properties": {
+                  "version": "1.0.2"
+                }
+              }
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-literals": {
+          "version": "6.8.0",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "6.11.6",
+              "dependencies": {
+                "core-js": {
+                  "version": "2.4.1"
+                },
+                "regenerator-runtime": {
+                  "version": "0.9.5"
+                }
+              }
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-modules-amd": {
+          "version": "6.8.0",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "6.11.6",
+              "dependencies": {
+                "core-js": {
+                  "version": "2.4.1"
+                },
+                "regenerator-runtime": {
+                  "version": "0.9.5"
+                }
+              }
+            },
+            "babel-template": {
+              "version": "6.15.0",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.12.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2139,6 +2216,9 @@
                             }
                           }
                         },
+                        "esutils": {
+                          "version": "2.0.2"
+                        },
                         "js-tokens": {
                           "version": "2.0.0"
                         }
@@ -2147,9 +2227,6 @@
                     "babel-messages": {
                       "version": "6.8.0"
                     },
-                    "babylon": {
-                      "version": "6.8.4"
-                    },
                     "debug": {
                       "version": "2.2.0",
                       "dependencies": {
@@ -2176,37 +2253,29 @@
                     }
                   }
                 },
-                "esutils": {
-                  "version": "2.0.2"
-                },
-                "lodash": {
-                  "version": "4.14.1"
+                "babel-types": {
+                  "version": "6.15.0",
+                  "dependencies": {
+                    "esutils": {
+                      "version": "2.0.2"
+                    },
+                    "to-fast-properties": {
+                      "version": "1.0.2"
+                    }
+                  }
                 },
-                "to-fast-properties": {
-                  "version": "1.0.2"
-                }
-              }
-            }
-          }
-        },
-        "babel-plugin-transform-es2015-literals": {
-          "version": "6.8.0",
-          "dependencies": {
-            "babel-runtime": {
-              "version": "6.11.6",
-              "dependencies": {
-                "core-js": {
-                  "version": "2.4.1"
+                "babylon": {
+                  "version": "6.9.2"
                 },
-                "regenerator-runtime": {
-                  "version": "0.9.5"
+                "lodash": {
+                  "version": "4.15.0"
                 }
               }
             }
           }
         },
         "babel-plugin-transform-es2015-modules-commonjs": {
-          "version": "6.11.5",
+          "version": "6.14.0",
           "dependencies": {
             "babel-plugin-transform-strict-mode": {
               "version": "6.11.3"
@@ -2223,10 +2292,10 @@
               }
             },
             "babel-template": {
-              "version": "6.9.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-traverse": {
-                  "version": "6.12.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2299,18 +2368,67 @@
                   }
                 },
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
-                "babel-traverse": {
-                  "version": "6.12.0",
+                "esutils": {
+                  "version": "2.0.2"
+                },
+                "lodash": {
+                  "version": "4.15.0"
+                },
+                "to-fast-properties": {
+                  "version": "1.0.2"
+                }
+              }
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-modules-systemjs": {
+          "version": "6.14.0",
+          "dependencies": {
+            "babel-helper-hoist-variables": {
+              "version": "6.8.0",
+              "dependencies": {
+                "babel-types": {
+                  "version": "6.15.0",
+                  "dependencies": {
+                    "esutils": {
+                      "version": "2.0.2"
+                    },
+                    "lodash": {
+                      "version": "4.15.0"
+                    },
+                    "to-fast-properties": {
+                      "version": "1.0.2"
+                    }
+                  }
+                }
+              }
+            },
+            "babel-runtime": {
+              "version": "6.11.6",
+              "dependencies": {
+                "core-js": {
+                  "version": "2.4.1"
+                },
+                "regenerator-runtime": {
+                  "version": "0.9.5"
+                }
+              }
+            },
+            "babel-template": {
+              "version": "6.15.0",
+              "dependencies": {
+                "babel-traverse": {
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2345,6 +2463,9 @@
                             }
                           }
                         },
+                        "esutils": {
+                          "version": "2.0.2"
+                        },
                         "js-tokens": {
                           "version": "2.0.0"
                         }
@@ -2353,9 +2474,6 @@
                     "babel-messages": {
                       "version": "6.8.0"
                     },
-                    "babylon": {
-                      "version": "6.8.4"
-                    },
                     "debug": {
                       "version": "2.2.0",
                       "dependencies": {
@@ -2382,14 +2500,133 @@
                     }
                   }
                 },
-                "esutils": {
-                  "version": "2.0.2"
+                "babel-types": {
+                  "version": "6.15.0",
+                  "dependencies": {
+                    "esutils": {
+                      "version": "2.0.2"
+                    },
+                    "to-fast-properties": {
+                      "version": "1.0.2"
+                    }
+                  }
+                },
+                "babylon": {
+                  "version": "6.9.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
+                }
+              }
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-modules-umd": {
+          "version": "6.12.0",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "6.11.6",
+              "dependencies": {
+                "core-js": {
+                  "version": "2.4.1"
                 },
-                "to-fast-properties": {
-                  "version": "1.0.2"
+                "regenerator-runtime": {
+                  "version": "0.9.5"
+                }
+              }
+            },
+            "babel-template": {
+              "version": "6.15.0",
+              "dependencies": {
+                "babel-traverse": {
+                  "version": "6.15.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"
+                                }
+                              }
+                            },
+                            "supports-color": {
+                              "version": "2.0.0"
+                            }
+                          }
+                        },
+                        "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.15.0",
+                  "dependencies": {
+                    "esutils": {
+                      "version": "2.0.2"
+                    },
+                    "to-fast-properties": {
+                      "version": "1.0.2"
+                    }
+                  }
+                },
+                "babylon": {
+                  "version": "6.9.2"
+                },
+                "lodash": {
+                  "version": "4.15.0"
                 }
               }
             }
@@ -2399,7 +2636,7 @@
           "version": "6.8.0",
           "dependencies": {
             "babel-helper-replace-supers": {
-              "version": "6.8.0",
+              "version": "6.14.0",
               "dependencies": {
                 "babel-helper-optimise-call-expression": {
                   "version": "6.8.0"
@@ -2408,18 +2645,18 @@
                   "version": "6.8.0"
                 },
                 "babel-template": {
-                  "version": "6.9.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babylon": {
-                      "version": "6.8.4"
+                      "version": "6.9.2"
                     },
                     "lodash": {
-                      "version": "4.14.1"
+                      "version": "4.15.0"
                     }
                   }
                 },
                 "babel-traverse": {
-                  "version": "6.12.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-code-frame": {
                       "version": "6.11.0",
@@ -2463,7 +2700,7 @@
                       }
                     },
                     "babylon": {
-                      "version": "6.8.4"
+                      "version": "6.9.2"
                     },
                     "debug": {
                       "version": "2.2.0",
@@ -2490,18 +2727,18 @@
                       }
                     },
                     "lodash": {
-                      "version": "4.14.1"
+                      "version": "4.15.0"
                     }
                   }
                 },
                 "babel-types": {
-                  "version": "6.11.1",
+                  "version": "6.15.0",
                   "dependencies": {
                     "esutils": {
                       "version": "2.0.2"
                     },
                     "lodash": {
-                      "version": "4.14.1"
+                      "version": "4.15.0"
                     },
                     "to-fast-properties": {
                       "version": "1.0.2"
@@ -2549,18 +2786,18 @@
               }
             },
             "babel-template": {
-              "version": "6.9.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
             "babel-traverse": {
-              "version": "6.12.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -2607,7 +2844,7 @@
                   "version": "6.8.0"
                 },
                 "babylon": {
-                  "version": "6.8.4"
+                  "version": "6.9.2"
                 },
                 "debug": {
                   "version": "2.2.0",
@@ -2634,18 +2871,18 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
                 "esutils": {
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2669,86 +2906,13 @@
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
-                "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"
-                                }
-                              }
-                            },
-                            "supports-color": {
-                              "version": "2.0.0"
-                            }
-                          }
-                        },
-                        "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"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
                 "esutils": {
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2780,7 +2944,7 @@
               "version": "6.9.0",
               "dependencies": {
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
@@ -2796,86 +2960,13 @@
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
-                "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"
-                                }
-                              }
-                            },
-                            "supports-color": {
-                              "version": "2.0.0"
-                            }
-                          }
-                        },
-                        "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"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
                 "esutils": {
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -2923,81 +3014,8 @@
               "version": "6.9.0",
               "dependencies": {
                 "babel-types": {
-                  "version": "6.11.1",
+                  "version": "6.15.0",
                   "dependencies": {
-                    "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"
-                                    }
-                                  }
-                                },
-                                "supports-color": {
-                                  "version": "2.0.0"
-                                }
-                              }
-                            },
-                            "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"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
                     "esutils": {
                       "version": "2.0.2"
                     },
@@ -3007,7 +3025,7 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
@@ -3044,10 +3062,10 @@
           }
         },
         "babel-plugin-transform-regenerator": {
-          "version": "6.11.4",
+          "version": "6.14.0",
           "dependencies": {
             "babel-core": {
-              "version": "6.11.4",
+              "version": "6.14.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -3091,7 +3109,7 @@
                   }
                 },
                 "babel-generator": {
-                  "version": "6.11.4",
+                  "version": "6.14.0",
                   "dependencies": {
                     "detect-indent": {
                       "version": "3.0.1",
@@ -3105,13 +3123,59 @@
                         "repeating": {
                           "version": "1.1.3",
                           "dependencies": {
-                            "is-finite": {
-                              "version": "1.0.1",
-                              "dependencies": {
-                                "number-is-nan": {
-                                  "version": "1.0.0"
-                                }
-                              }
+                            "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-register": {
+                  "version": "6.14.0",
+                  "dependencies": {
+                    "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"
+                        }
+                      }
+                    },
+                    "mkdirp": {
+                      "version": "0.5.1",
+                      "dependencies": {
+                        "minimist": {
+                          "version": "0.0.8"
+                        }
+                      }
+                    },
+                    "source-map-support": {
+                      "version": "0.2.10",
+                      "dependencies": {
+                        "source-map": {
+                          "version": "0.1.32",
+                          "dependencies": {
+                            "amdefine": {
+                              "version": "1.0.0"
                             }
                           }
                         }
@@ -3119,14 +3183,8 @@
                     }
                   }
                 },
-                "babel-helpers": {
-                  "version": "6.8.0"
-                },
-                "babel-messages": {
-                  "version": "6.8.0"
-                },
                 "babel-template": {
-                  "version": "6.9.0"
+                  "version": "6.15.0"
                 },
                 "convert-source-map": {
                   "version": "1.3.0"
@@ -3143,10 +3201,10 @@
                   "version": "0.4.0"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "minimatch": {
-                  "version": "3.0.2",
+                  "version": "3.0.3",
                   "dependencies": {
                     "brace-expansion": {
                       "version": "1.1.6",
@@ -3179,7 +3237,7 @@
               }
             },
             "babel-plugin-syntax-async-functions": {
-              "version": "6.8.0"
+              "version": "6.13.0"
             },
             "babel-runtime": {
               "version": "6.11.6",
@@ -3193,7 +3251,7 @@
               }
             },
             "babel-traverse": {
-              "version": "6.12.0",
+              "version": "6.15.0",
               "dependencies": {
                 "babel-code-frame": {
                   "version": "6.11.0",
@@ -3264,18 +3322,18 @@
                   }
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 }
               }
             },
             "babel-types": {
-              "version": "6.11.1",
+              "version": "6.15.0",
               "dependencies": {
                 "esutils": {
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.1"
+                  "version": "4.15.0"
                 },
                 "to-fast-properties": {
                   "version": "1.0.2"
@@ -3283,7 +3341,7 @@
               }
             },
             "babylon": {
-              "version": "6.8.4"
+              "version": "6.9.2"
             },
             "private": {
               "version": "0.1.6"
@@ -3324,81 +3382,8 @@
               "version": "6.9.0",
               "dependencies": {
                 "babel-types": {
-                  "version": "6.13.0",
+                  "version": "6.15.0",
                   "dependencies": {
-                    "babel-traverse": {
-                      "version": "6.13.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"
-                                    }
-                                  }
-                                },
-                                "supports-color": {
-                                  "version": "2.0.0"
-                                }
-                              }
-                            },
-                            "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"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
                     "to-fast-properties": {
                       "version": "1.0.2"
                     }
@@ -3408,7 +3393,7 @@
                   "version": "2.0.2"
                 },
                 "lodash": {
-                  "version": "4.14.2"
+                  "version": "4.15.0"
                 }
               }
             },
@@ -3521,10 +3506,10 @@
                   }
                 },
                 "babel-template": {
-                  "version": "6.9.0",
+                  "version": "6.15.0",
                   "dependencies": {
                     "babel-traverse": {
-                      "version": "6.13.0",
+                      "version": "6.15.0",
                       "dependencies": {
                         "babel-code-frame": {
                           "version": "6.11.0",
@@ -3597,7 +3582,7 @@
                       }
                     },
                     "babel-types": {
-                      "version": "6.13.0",
+                      "version": "6.15.0",
                       "dependencies": {
                         "esutils": {
                           "version": "2.0.2"
@@ -3608,10 +3593,10 @@
                       }
                     },
                     "babylon": {
-                      "version": "6.8.4"
+                      "version": "6.9.2"
                     },
                     "lodash": {
-                      "version": "4.14.2"
+                      "version": "4.15.0"
                     }
                   }
                 }
@@ -3649,18 +3634,18 @@
                           "version": "6.8.0"
                         },
                         "babel-template": {
-                          "version": "6.9.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "babylon": {
-                              "version": "6.8.4"
+                              "version": "6.9.2"
                             },
                             "lodash": {
-                              "version": "4.14.2"
+                              "version": "4.15.0"
                             }
                           }
                         },
                         "babel-traverse": {
-                          "version": "6.13.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "babel-code-frame": {
                               "version": "6.11.0",
@@ -3707,7 +3692,7 @@
                               "version": "6.8.0"
                             },
                             "babylon": {
-                              "version": "6.8.4"
+                              "version": "6.9.2"
                             },
                             "debug": {
                               "version": "2.2.0",
@@ -3734,18 +3719,18 @@
                               }
                             },
                             "lodash": {
-                              "version": "4.14.2"
+                              "version": "4.15.0"
                             }
                           }
                         },
                         "babel-types": {
-                          "version": "6.13.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "esutils": {
                               "version": "2.0.2"
                             },
                             "lodash": {
-                              "version": "4.14.2"
+                              "version": "4.15.0"
                             },
                             "to-fast-properties": {
                               "version": "1.0.2"
@@ -3783,7 +3768,7 @@
                               "version": "6.8.0"
                             },
                             "babel-traverse": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "babel-code-frame": {
                                   "version": "6.11.0",
@@ -3830,7 +3815,7 @@
                                   "version": "6.8.0"
                                 },
                                 "babylon": {
-                                  "version": "6.8.4"
+                                  "version": "6.9.2"
                                 },
                                 "debug": {
                                   "version": "2.2.0",
@@ -3861,7 +3846,7 @@
                           }
                         },
                         "lodash": {
-                          "version": "4.14.2"
+                          "version": "4.15.0"
                         }
                       }
                     },
@@ -3872,7 +3857,7 @@
                           "version": "6.8.0"
                         },
                         "babel-traverse": {
-                          "version": "6.13.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "babel-code-frame": {
                               "version": "6.11.0",
@@ -3919,7 +3904,7 @@
                               "version": "6.8.0"
                             },
                             "babylon": {
-                              "version": "6.8.4"
+                              "version": "6.9.2"
                             },
                             "debug": {
                               "version": "2.2.0",
@@ -3946,7 +3931,7 @@
                               }
                             },
                             "lodash": {
-                              "version": "4.14.2"
+                              "version": "4.15.0"
                             }
                           }
                         }
@@ -3967,10 +3952,10 @@
                       }
                     },
                     "babel-template": {
-                      "version": "6.9.0",
+                      "version": "6.15.0",
                       "dependencies": {
                         "babel-traverse": {
-                          "version": "6.13.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "babel-code-frame": {
                               "version": "6.11.0",
@@ -4043,94 +4028,21 @@
                           }
                         },
                         "babylon": {
-                          "version": "6.8.4"
+                          "version": "6.9.2"
                         },
                         "lodash": {
-                          "version": "4.14.2"
+                          "version": "4.15.0"
                         }
                       }
                     },
                     "babel-types": {
-                      "version": "6.13.0",
+                      "version": "6.15.0",
                       "dependencies": {
-                        "babel-traverse": {
-                          "version": "6.13.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"
-                                        }
-                                      }
-                                    },
-                                    "supports-color": {
-                                      "version": "2.0.0"
-                                    }
-                                  }
-                                },
-                                "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"
-                                    }
-                                  }
-                                }
-                              }
-                            }
-                          }
-                        },
                         "esutils": {
                           "version": "2.0.2"
                         },
                         "lodash": {
-                          "version": "4.14.2"
+                          "version": "4.15.0"
                         },
                         "to-fast-properties": {
                           "version": "1.0.2"
@@ -4179,18 +4091,18 @@
                               }
                             },
                             "babel-template": {
-                              "version": "6.9.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "babylon": {
-                                  "version": "6.8.4"
+                                  "version": "6.9.2"
                                 },
                                 "lodash": {
-                                  "version": "4.14.2"
+                                  "version": "4.15.0"
                                 }
                               }
                             },
                             "babel-traverse": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "babel-code-frame": {
                                   "version": "6.11.0",
@@ -4237,7 +4149,7 @@
                                   "version": "6.8.0"
                                 },
                                 "babylon": {
-                                  "version": "6.8.4"
+                                  "version": "6.9.2"
                                 },
                                 "debug": {
                                   "version": "2.2.0",
@@ -4264,18 +4176,18 @@
                                   }
                                 },
                                 "lodash": {
-                                  "version": "4.14.2"
+                                  "version": "4.15.0"
                                 }
                               }
                             },
                             "babel-types": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "esutils": {
                                   "version": "2.0.2"
                                 },
                                 "lodash": {
-                                  "version": "4.14.2"
+                                  "version": "4.15.0"
                                 },
                                 "to-fast-properties": {
                                   "version": "1.0.2"
@@ -4300,101 +4212,17 @@
                         }
                       }
                     },
-                    "babel-plugin-transform-exponentiation-operator": {
-                      "version": "6.8.0",
-                      "dependencies": {
-                        "babel-helper-builder-binary-assignment-operator-visitor": {
-                          "version": "6.8.0",
-                          "dependencies": {
-                            "babel-helper-explode-assignable-expression": {
-                              "version": "6.8.0",
-                              "dependencies": {
-                                "babel-traverse": {
-                                  "version": "6.13.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"
-                                                }
-                                              }
-                                            },
-                                            "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.2"
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "babel-types": {
-                              "version": "6.13.0",
+                    "babel-plugin-transform-exponentiation-operator": {
+                      "version": "6.8.0",
+                      "dependencies": {
+                        "babel-helper-builder-binary-assignment-operator-visitor": {
+                          "version": "6.15.0",
+                          "dependencies": {
+                            "babel-helper-explode-assignable-expression": {
+                              "version": "6.8.0",
                               "dependencies": {
                                 "babel-traverse": {
-                                  "version": "6.13.0",
+                                  "version": "6.15.0",
                                   "dependencies": {
                                     "babel-code-frame": {
                                       "version": "6.11.0",
@@ -4429,6 +4257,9 @@
                                             }
                                           }
                                         },
+                                        "esutils": {
+                                          "version": "2.0.2"
+                                        },
                                         "js-tokens": {
                                           "version": "2.0.0"
                                         }
@@ -4438,7 +4269,7 @@
                                       "version": "6.8.0"
                                     },
                                     "babylon": {
-                                      "version": "6.8.4"
+                                      "version": "6.9.2"
                                     },
                                     "debug": {
                                       "version": "2.2.0",
@@ -4463,14 +4294,22 @@
                                           }
                                         }
                                       }
+                                    },
+                                    "lodash": {
+                                      "version": "4.15.0"
                                     }
                                   }
-                                },
+                                }
+                              }
+                            },
+                            "babel-types": {
+                              "version": "6.15.0",
+                              "dependencies": {
                                 "esutils": {
                                   "version": "2.0.2"
                                 },
                                 "lodash": {
-                                  "version": "4.14.2"
+                                  "version": "4.15.0"
                                 },
                                 "to-fast-properties": {
                                   "version": "1.0.2"
@@ -4503,60 +4342,6 @@
         }
       }
     },
-    "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.2"
-        },
-        "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"
     },
@@ -4567,7 +4352,7 @@
           "version": "1.0.2"
         },
         "color-convert": {
-          "version": "1.3.1"
+          "version": "1.5.0"
         },
         "color-string": {
           "version": "0.3.0",
@@ -4597,16 +4382,16 @@
           }
         },
         "cssnano": {
-          "version": "3.7.3",
+          "version": "3.7.4",
           "dependencies": {
             "autoprefixer": {
-              "version": "6.4.0",
+              "version": "6.4.1",
               "dependencies": {
                 "browserslist": {
-                  "version": "1.3.5"
+                  "version": "1.3.6"
                 },
                 "caniuse-db": {
-                  "version": "1.0.30000519"
+                  "version": "1.0.30000530"
                 },
                 "normalize-range": {
                   "version": "0.1.2"
@@ -4622,23 +4407,41 @@
             "defined": {
               "version": "1.0.0"
             },
-            "indexes-of": {
-              "version": "1.0.1"
+            "has": {
+              "version": "1.0.1",
+              "dependencies": {
+                "function-bind": {
+                  "version": "1.1.0"
+                }
+              }
             },
             "postcss-calc": {
-              "version": "5.3.0",
+              "version": "5.3.1",
               "dependencies": {
                 "postcss-message-helpers": {
                   "version": "2.0.0"
                 },
                 "reduce-css-calc": {
-                  "version": "1.2.4",
+                  "version": "1.3.0",
                   "dependencies": {
                     "balanced-match": {
-                      "version": "0.1.0"
+                      "version": "0.4.2"
+                    },
+                    "math-expression-evaluator": {
+                      "version": "1.2.14",
+                      "dependencies": {
+                        "lodash.indexof": {
+                          "version": "4.0.5"
+                        }
+                      }
                     },
                     "reduce-function-call": {
-                      "version": "1.0.1"
+                      "version": "1.0.1",
+                      "dependencies": {
+                        "balanced-match": {
+                          "version": "0.1.0"
+                        }
+                      }
                     }
                   }
                 }
@@ -4648,7 +4451,7 @@
               "version": "2.2.0",
               "dependencies": {
                 "colormin": {
-                  "version": "1.1.1",
+                  "version": "1.1.2",
                   "dependencies": {
                     "css-color-names": {
                       "version": "0.0.4"
@@ -4697,12 +4500,7 @@
               }
             },
             "postcss-merge-idents": {
-              "version": "2.1.6",
-              "dependencies": {
-                "has-own": {
-                  "version": "1.0.0"
-                }
-              }
+              "version": "2.1.7"
             },
             "postcss-merge-longhand": {
               "version": "2.0.1"
@@ -4711,7 +4509,7 @@
               "version": "2.0.10",
               "dependencies": {
                 "vendors": {
-                  "version": "1.0.0"
+                  "version": "1.0.1"
                 }
               }
             },
@@ -4722,7 +4520,7 @@
               "version": "1.0.3"
             },
             "postcss-minify-params": {
-              "version": "1.0.4",
+              "version": "1.0.5",
               "dependencies": {
                 "alphanum-sort": {
                   "version": "1.0.2"
@@ -4739,11 +4537,14 @@
                   "version": "1.0.2"
                 },
                 "postcss-selector-parser": {
-                  "version": "2.2.0",
+                  "version": "2.2.1",
                   "dependencies": {
                     "flatten": {
                       "version": "1.0.2"
                     },
+                    "indexes-of": {
+                      "version": "1.0.1"
+                    },
                     "uniq": {
                       "version": "1.0.1"
                     }
@@ -4761,13 +4562,13 @@
                   "version": "2.0.0"
                 },
                 "normalize-url": {
-                  "version": "1.6.0",
+                  "version": "1.6.1",
                   "dependencies": {
                     "prepend-http": {
                       "version": "1.0.4"
                     },
                     "query-string": {
-                      "version": "4.2.2",
+                      "version": "4.2.3",
                       "dependencies": {
                         "strict-uri-encode": {
                           "version": "1.1.0"
@@ -4787,7 +4588,7 @@
               }
             },
             "postcss-ordered-values": {
-              "version": "2.2.1"
+              "version": "2.2.2"
             },
             "postcss-reduce-idents": {
               "version": "2.3.0"
@@ -4878,7 +4679,7 @@
                           }
                         },
                         "esprima": {
-                          "version": "2.7.2"
+                          "version": "2.7.3"
                         }
                       }
                     },
@@ -4954,7 +4755,7 @@
           "version": "4.1.0"
         },
         "postcss": {
-          "version": "5.1.2",
+          "version": "5.2.0",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -5046,7 +4847,7 @@
           }
         },
         "postcss-modules-values": {
-          "version": "1.1.3",
+          "version": "1.2.2",
           "dependencies": {
             "icss-replace-symbols": {
               "version": "1.0.2"
@@ -5062,7 +4863,7 @@
       "version": "3.5.17"
     },
     "dc": {
-      "version": "2.0.0-beta.31",
+      "version": "2.0.0-beta.32",
       "dependencies": {
         "crossfilter2": {
           "version": "1.3.14"
@@ -5106,10 +4907,10 @@
           }
         },
         "concat-stream": {
-          "version": "1.5.1",
+          "version": "1.5.2",
           "dependencies": {
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "readable-stream": {
               "version": "2.0.6",
@@ -5145,11 +4946,8 @@
           }
         },
         "doctrine": {
-          "version": "1.2.2",
+          "version": "1.4.0",
           "dependencies": {
-            "esutils": {
-              "version": "1.1.6"
-            },
             "isarray": {
               "version": "1.0.0"
             }
@@ -5212,13 +5010,18 @@
           }
         },
         "espree": {
-          "version": "3.1.7",
+          "version": "3.2.0",
           "dependencies": {
             "acorn": {
-              "version": "3.3.0"
+              "version": "4.0.3"
             },
             "acorn-jsx": {
-              "version": "3.0.1"
+              "version": "3.0.1",
+              "dependencies": {
+                "acorn": {
+                  "version": "3.3.0"
+                }
+              }
             }
           }
         },
@@ -5238,7 +5041,7 @@
                   "version": "0.3.1"
                 },
                 "del": {
-                  "version": "2.2.1",
+                  "version": "2.2.2",
                   "dependencies": {
                     "globby": {
                       "version": "5.0.0",
@@ -5284,7 +5087,7 @@
                   }
                 },
                 "graceful-fs": {
-                  "version": "4.1.5"
+                  "version": "4.1.6"
                 },
                 "write": {
                   "version": "0.2.1"
@@ -5297,7 +5100,7 @@
           }
         },
         "glob": {
-          "version": "7.0.5",
+          "version": "7.0.6",
           "dependencies": {
             "fs.realpath": {
               "version": "1.0.0"
@@ -5311,7 +5114,7 @@
               }
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "minimatch": {
               "version": "3.0.3",
@@ -5330,7 +5133,7 @@
               }
             },
             "once": {
-              "version": "1.3.3",
+              "version": "1.4.0",
               "dependencies": {
                 "wrappy": {
                   "version": "1.0.2"
@@ -5340,10 +5143,10 @@
           }
         },
         "globals": {
-          "version": "9.9.0"
+          "version": "9.10.0"
         },
         "ignore": {
-          "version": "3.1.3"
+          "version": "3.1.5"
         },
         "imurmurhash": {
           "version": "0.1.4"
@@ -5415,7 +5218,7 @@
               "version": "0.1.0",
               "dependencies": {
                 "once": {
-                  "version": "1.3.3",
+                  "version": "1.4.0",
                   "dependencies": {
                     "wrappy": {
                       "version": "1.0.2"
@@ -5428,7 +5231,7 @@
               "version": "3.1.2"
             },
             "string-width": {
-              "version": "1.0.1",
+              "version": "1.0.2",
               "dependencies": {
                 "code-point-at": {
                   "version": "1.0.0",
@@ -5498,7 +5301,7 @@
               }
             },
             "esprima": {
-              "version": "2.7.2"
+              "version": "2.7.3"
             }
           }
         },
@@ -5522,7 +5325,7 @@
           }
         },
         "lodash": {
-          "version": "4.14.2"
+          "version": "4.15.0"
         },
         "mkdirp": {
           "version": "0.5.1",
@@ -5556,7 +5359,7 @@
           "version": "1.0.0"
         },
         "path-is-inside": {
-          "version": "1.0.1"
+          "version": "1.0.2"
         },
         "pluralize": {
           "version": "1.2.1"
@@ -5587,16 +5390,13 @@
           "version": "1.0.4"
         },
         "table": {
-          "version": "3.7.8",
+          "version": "3.7.9",
           "dependencies": {
-            "bluebird": {
-              "version": "3.4.1"
-            },
             "slice-ansi": {
               "version": "0.0.4"
             },
             "string-width": {
-              "version": "1.0.1",
+              "version": "1.0.2",
               "dependencies": {
                 "code-point-at": {
                   "version": "1.0.0",
@@ -5613,22 +5413,19 @@
                       "version": "1.0.0"
                     }
                   }
-                }
-              }
-            },
-            "strip-ansi": {
-              "version": "3.0.1",
-              "dependencies": {
-                "ansi-regex": {
-                  "version": "2.0.0"
+                },
+                "strip-ansi": {
+                  "version": "3.0.1",
+                  "dependencies": {
+                    "ansi-regex": {
+                      "version": "2.0.0"
+                    }
+                  }
                 }
               }
             },
             "tv4": {
               "version": "1.2.7"
-            },
-            "xregexp": {
-              "version": "3.1.1"
             }
           }
         },
@@ -5646,8 +5443,45 @@
       }
     },
     "eslint-loader": {
-      "version": "1.4.0",
+      "version": "1.5.0",
       "dependencies": {
+        "find-cache-dir": {
+          "version": "0.1.1",
+          "dependencies": {
+            "commondir": {
+              "version": "1.0.1"
+            },
+            "mkdirp": {
+              "version": "0.5.1",
+              "dependencies": {
+                "minimist": {
+                  "version": "0.0.8"
+                }
+              }
+            },
+            "pkg-dir": {
+              "version": "1.0.0",
+              "dependencies": {
+                "find-up": {
+                  "version": "1.1.2",
+                  "dependencies": {
+                    "path-exists": {
+                      "version": "2.1.0"
+                    },
+                    "pinkie-promise": {
+                      "version": "2.0.1",
+                      "dependencies": {
+                        "pinkie": {
+                          "version": "2.0.4"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        },
         "object-assign": {
           "version": "4.1.0"
         }
@@ -5695,7 +5529,7 @@
       "version": "0.8.5"
     },
     "fixed-data-table": {
-      "version": "0.6.1"
+      "version": "0.6.3"
     },
     "flow-bin": {
       "version": "0.24.2",
@@ -5735,7 +5569,7 @@
                               }
                             },
                             "signal-exit": {
-                              "version": "3.0.0"
+                              "version": "3.0.1"
                             }
                           }
                         },
@@ -5774,15 +5608,7 @@
                                   }
                                 },
                                 "spdx-expression-parse": {
-                                  "version": "1.0.2",
-                                  "dependencies": {
-                                    "spdx-exceptions": {
-                                      "version": "1.0.5"
-                                    },
-                                    "spdx-license-ids": {
-                                      "version": "1.2.2"
-                                    }
-                                  }
+                                  "version": "1.0.3"
                                 }
                               }
                             }
@@ -5817,7 +5643,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.5"
+                                      "version": "4.1.6"
                                     },
                                     "parse-json": {
                                       "version": "2.2.0",
@@ -5857,7 +5683,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.5"
+                                      "version": "4.1.6"
                                     },
                                     "pify": {
                                       "version": "2.3.0"
@@ -5957,7 +5783,7 @@
                                   }
                                 },
                                 "signal-exit": {
-                                  "version": "3.0.0"
+                                  "version": "3.0.1"
                                 }
                               }
                             },
@@ -5990,15 +5816,7 @@
                                       }
                                     },
                                     "spdx-expression-parse": {
-                                      "version": "1.0.2",
-                                      "dependencies": {
-                                        "spdx-exceptions": {
-                                          "version": "1.0.5"
-                                        },
-                                        "spdx-license-ids": {
-                                          "version": "1.2.2"
-                                        }
-                                      }
+                                      "version": "1.0.3"
                                     }
                                   }
                                 }
@@ -6033,7 +5851,7 @@
                                       "version": "1.1.0",
                                       "dependencies": {
                                         "graceful-fs": {
-                                          "version": "4.1.5"
+                                          "version": "4.1.6"
                                         },
                                         "parse-json": {
                                           "version": "2.2.0",
@@ -6073,7 +5891,7 @@
                                       "version": "1.1.0",
                                       "dependencies": {
                                         "graceful-fs": {
-                                          "version": "4.1.5"
+                                          "version": "4.1.6"
                                         },
                                         "pify": {
                                           "version": "2.3.0"
@@ -6186,10 +6004,10 @@
                   }
                 },
                 "concat-stream": {
-                  "version": "1.5.1",
+                  "version": "1.5.2",
                   "dependencies": {
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "readable-stream": {
                       "version": "2.0.6",
@@ -6297,7 +6115,7 @@
                       "version": "2.0.0"
                     },
                     "unzip-response": {
-                      "version": "1.0.0"
+                      "version": "1.0.1"
                     },
                     "url-parse-lax": {
                       "version": "1.0.0",
@@ -6411,7 +6229,7 @@
                                           "version": "1.0.2"
                                         },
                                         "inherits": {
-                                          "version": "2.0.1"
+                                          "version": "2.0.3"
                                         },
                                         "isarray": {
                                           "version": "1.0.0"
@@ -6457,7 +6275,7 @@
                                       "version": "1.0.2"
                                     },
                                     "inherits": {
-                                      "version": "2.0.1"
+                                      "version": "2.0.3"
                                     },
                                     "isarray": {
                                       "version": "0.0.1"
@@ -6575,7 +6393,7 @@
                                           "version": "1.0.2"
                                         },
                                         "inherits": {
-                                          "version": "2.0.1"
+                                          "version": "2.0.3"
                                         },
                                         "isarray": {
                                           "version": "1.0.0"
@@ -6621,7 +6439,7 @@
                                       "version": "1.0.2"
                                     },
                                     "inherits": {
-                                      "version": "2.0.1"
+                                      "version": "2.0.3"
                                     },
                                     "isarray": {
                                       "version": "0.0.1"
@@ -6726,7 +6544,7 @@
                                           "version": "1.0.2"
                                         },
                                         "inherits": {
-                                          "version": "2.0.1"
+                                          "version": "2.0.3"
                                         },
                                         "isarray": {
                                           "version": "1.0.0"
@@ -6772,7 +6590,7 @@
                                       "version": "1.0.2"
                                     },
                                     "inherits": {
-                                      "version": "2.0.1"
+                                      "version": "2.0.3"
                                     },
                                     "isarray": {
                                       "version": "0.0.1"
@@ -6807,7 +6625,7 @@
                               "version": "1.0.0"
                             },
                             "stat-mode": {
-                              "version": "0.2.1"
+                              "version": "0.2.2"
                             },
                             "strip-dirs": {
                               "version": "1.1.1",
@@ -6874,7 +6692,7 @@
                                       "version": "1.0.2"
                                     },
                                     "inherits": {
-                                      "version": "2.0.1"
+                                      "version": "2.0.3"
                                     },
                                     "isarray": {
                                       "version": "1.0.0"
@@ -6992,7 +6810,7 @@
                                       }
                                     },
                                     "signal-exit": {
-                                      "version": "3.0.0"
+                                      "version": "3.0.1"
                                     }
                                   }
                                 },
@@ -7028,15 +6846,7 @@
                                           }
                                         },
                                         "spdx-expression-parse": {
-                                          "version": "1.0.2",
-                                          "dependencies": {
-                                            "spdx-exceptions": {
-                                              "version": "1.0.5"
-                                            },
-                                            "spdx-license-ids": {
-                                              "version": "1.2.2"
-                                            }
-                                          }
+                                          "version": "1.0.3"
                                         }
                                       }
                                     }
@@ -7071,7 +6881,7 @@
                                           "version": "1.1.0",
                                           "dependencies": {
                                             "graceful-fs": {
-                                              "version": "4.1.5"
+                                              "version": "4.1.6"
                                             },
                                             "parse-json": {
                                               "version": "2.2.0",
@@ -7111,7 +6921,7 @@
                                           "version": "1.1.0",
                                           "dependencies": {
                                             "graceful-fs": {
-                                              "version": "4.1.5"
+                                              "version": "4.1.6"
                                             },
                                             "pify": {
                                               "version": "2.3.0"
@@ -7231,7 +7041,7 @@
                                   "version": "3.9.1"
                                 },
                                 "lodash.isarguments": {
-                                  "version": "3.0.9"
+                                  "version": "3.1.0"
                                 },
                                 "lodash.isarray": {
                                   "version": "3.0.4"
@@ -7262,7 +7072,7 @@
                                       "version": "1.0.2"
                                     },
                                     "inherits": {
-                                      "version": "2.0.1"
+                                      "version": "2.0.3"
                                     },
                                     "isarray": {
                                       "version": "0.0.1"
@@ -7292,7 +7102,7 @@
                                   "version": "1.0.2"
                                 },
                                 "inherits": {
-                                  "version": "2.0.1"
+                                  "version": "2.0.3"
                                 },
                                 "isarray": {
                                   "version": "1.0.0"
@@ -7351,7 +7161,7 @@
                   }
                 },
                 "readable-stream": {
-                  "version": "2.1.4",
+                  "version": "2.1.5",
                   "dependencies": {
                     "buffer-shims": {
                       "version": "1.0.0"
@@ -7360,7 +7170,7 @@
                       "version": "1.0.2"
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "isarray": {
                       "version": "1.0.0"
@@ -7418,7 +7228,7 @@
                           }
                         },
                         "inherits": {
-                          "version": "2.0.1"
+                          "version": "2.0.3"
                         },
                         "stream-shift": {
                           "version": "1.0.0"
@@ -7426,19 +7236,19 @@
                       }
                     },
                     "glob-stream": {
-                      "version": "5.3.2",
+                      "version": "5.3.5",
                       "dependencies": {
                         "extend": {
                           "version": "3.0.0"
                         },
                         "glob-parent": {
-                          "version": "2.0.0",
+                          "version": "3.0.0",
                           "dependencies": {
                             "is-glob": {
-                              "version": "2.0.1",
+                              "version": "3.0.0",
                               "dependencies": {
                                 "is-extglob": {
-                                  "version": "1.0.0"
+                                  "version": "2.0.0"
                                 }
                               }
                             }
@@ -7534,7 +7344,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "for-in": {
-                                      "version": "0.1.5"
+                                      "version": "0.1.6"
                                     }
                                   }
                                 },
@@ -7547,7 +7357,12 @@
                               "version": "3.0.4",
                               "dependencies": {
                                 "glob-base": {
-                                  "version": "0.3.0"
+                                  "version": "0.3.0",
+                                  "dependencies": {
+                                    "glob-parent": {
+                                      "version": "2.0.0"
+                                    }
+                                  }
                                 },
                                 "is-dotfile": {
                                   "version": "1.0.2"
@@ -7585,7 +7400,7 @@
                                   "version": "1.0.2"
                                 },
                                 "inherits": {
-                                  "version": "2.0.1"
+                                  "version": "2.0.3"
                                 },
                                 "isarray": {
                                   "version": "0.0.1"
@@ -7629,7 +7444,7 @@
                       }
                     },
                     "graceful-fs": {
-                      "version": "4.1.5"
+                      "version": "4.1.6"
                     },
                     "gulp-sourcemaps": {
                       "version": "1.6.0",
@@ -7646,7 +7461,7 @@
                       "version": "1.0.0"
                     },
                     "lodash.isequal": {
-                      "version": "4.3.1"
+                      "version": "4.4.0"
                     },
                     "merge-stream": {
                       "version": "1.0.0"
@@ -7685,7 +7500,7 @@
                               "version": "1.0.2"
                             },
                             "inherits": {
-                              "version": "2.0.1"
+                              "version": "2.0.3"
                             },
                             "isarray": {
                               "version": "1.0.0"
@@ -7841,7 +7656,7 @@
                               }
                             },
                             "signal-exit": {
-                              "version": "3.0.0"
+                              "version": "3.0.1"
                             }
                           }
                         },
@@ -7880,15 +7695,7 @@
                                   }
                                 },
                                 "spdx-expression-parse": {
-                                  "version": "1.0.2",
-                                  "dependencies": {
-                                    "spdx-exceptions": {
-                                      "version": "1.0.5"
-                                    },
-                                    "spdx-license-ids": {
-                                      "version": "1.2.2"
-                                    }
-                                  }
+                                  "version": "1.0.3"
                                 }
                               }
                             }
@@ -7923,7 +7730,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.5"
+                                      "version": "4.1.6"
                                     },
                                     "parse-json": {
                                       "version": "2.2.0",
@@ -7963,7 +7770,7 @@
                                   "version": "1.1.0",
                                   "dependencies": {
                                     "graceful-fs": {
-                                      "version": "4.1.5"
+                                      "version": "4.1.6"
                                     },
                                     "pify": {
                                       "version": "2.3.0"
@@ -8022,11 +7829,8 @@
       }
     },
     "flow-status-webpack-plugin": {
-      "version": "0.1.5",
+      "version": "0.1.6",
       "dependencies": {
-        "colors": {
-          "version": "1.1.2"
-        },
         "shelljs": {
           "version": "0.6.1"
         }
@@ -8044,7 +7848,7 @@
           }
         },
         "inherits": {
-          "version": "2.0.1"
+          "version": "2.0.3"
         },
         "minimatch": {
           "version": "3.0.3",
@@ -8063,7 +7867,7 @@
           }
         },
         "once": {
-          "version": "1.3.3",
+          "version": "1.4.0",
           "dependencies": {
             "wrappy": {
               "version": "1.0.2"
@@ -8076,23 +7880,21 @@
       }
     },
     "history": {
-      "version": "3.0.0",
+      "version": "3.2.1",
       "dependencies": {
         "invariant": {
-          "version": "2.2.1",
-          "dependencies": {
-            "loose-envify": {
-              "version": "1.2.0",
-              "dependencies": {
-                "js-tokens": {
-                  "version": "1.0.3"
-                }
-              }
+          "version": "2.2.1"
+        },
+        "loose-envify": {
+          "version": "1.2.0",
+          "dependencies": {
+            "js-tokens": {
+              "version": "1.0.3"
             }
           }
         },
         "query-string": {
-          "version": "4.2.2",
+          "version": "4.2.3",
           "dependencies": {
             "object-assign": {
               "version": "4.1.0"
@@ -8103,17 +7905,7 @@
           }
         },
         "warning": {
-          "version": "2.1.0",
-          "dependencies": {
-            "loose-envify": {
-              "version": "1.2.0",
-              "dependencies": {
-                "js-tokens": {
-                  "version": "1.0.3"
-                }
-              }
-            }
-          }
+          "version": "3.0.0"
         }
       }
     },
@@ -8121,7 +7913,7 @@
       "version": "2.22.0",
       "dependencies": {
         "bluebird": {
-          "version": "3.4.1"
+          "version": "3.4.6"
         },
         "html-minifier": {
           "version": "2.1.7",
@@ -8318,7 +8110,7 @@
           }
         },
         "lodash": {
-          "version": "4.14.2"
+          "version": "4.15.0"
         },
         "pretty-error": {
           "version": "2.0.0",
@@ -8381,7 +8173,7 @@
                           "version": "1.0.2"
                         },
                         "inherits": {
-                          "version": "2.0.1"
+                          "version": "2.0.3"
                         },
                         "isarray": {
                           "version": "0.0.1"
@@ -8442,7 +8234,7 @@
       "version": "2.2.1",
       "dependencies": {
         "node-fetch": {
-          "version": "1.6.0",
+          "version": "1.6.1",
           "dependencies": {
             "encoding": {
               "version": "0.1.12",
@@ -8466,7 +8258,7 @@
       "version": "0.2.0",
       "dependencies": {
         "istanbul": {
-          "version": "0.4.4",
+          "version": "0.4.5",
           "dependencies": {
             "abbrev": {
               "version": "1.0.9"
@@ -8514,28 +8306,7 @@
               }
             },
             "esprima": {
-              "version": "2.7.2"
-            },
-            "fileset": {
-              "version": "0.2.1",
-              "dependencies": {
-                "minimatch": {
-                  "version": "2.0.10",
-                  "dependencies": {
-                    "brace-expansion": {
-                      "version": "1.1.6",
-                      "dependencies": {
-                        "balanced-match": {
-                          "version": "0.4.2"
-                        },
-                        "concat-map": {
-                          "version": "0.0.1"
-                        }
-                      }
-                    }
-                  }
-                }
-              }
+              "version": "2.7.3"
             },
             "handlebars": {
               "version": "4.0.5",
@@ -8560,7 +8331,7 @@
                   }
                 },
                 "uglify-js": {
-                  "version": "2.7.0",
+                  "version": "2.7.3",
                   "dependencies": {
                     "async": {
                       "version": "0.2.10"
@@ -8673,7 +8444,7 @@
               "version": "3.0.6"
             },
             "once": {
-              "version": "1.3.3",
+              "version": "1.4.0",
               "dependencies": {
                 "wrappy": {
                   "version": "1.0.2"
@@ -8692,7 +8463,7 @@
               }
             },
             "which": {
-              "version": "1.2.10",
+              "version": "1.2.11",
               "dependencies": {
                 "isexe": {
                   "version": "1.1.2"
@@ -8709,38 +8480,11 @@
         }
       }
     },
-    "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"
+      "version": "2.5.1"
     },
     "js-cookie": {
-      "version": "2.1.2"
+      "version": "2.1.3"
     },
     "json-loader": {
       "version": "0.5.4"
@@ -8752,7 +8496,7 @@
           "version": "0.5.3"
         },
         "bluebird": {
-          "version": "2.10.2"
+          "version": "2.11.0"
         },
         "body-parser": {
           "version": "1.15.2",
@@ -8924,7 +8668,7 @@
                           "version": "0.1.4",
                           "dependencies": {
                             "for-in": {
-                              "version": "0.1.5"
+                              "version": "0.1.6"
                             }
                           }
                         },
@@ -8960,7 +8704,7 @@
               }
             },
             "async-each": {
-              "version": "1.0.0"
+              "version": "1.0.1"
             },
             "fsevents": {
               "version": "1.0.14",
@@ -9338,13 +9082,13 @@
               "version": "2.0.0"
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "is-binary-path": {
               "version": "1.0.1",
               "dependencies": {
                 "binary-extensions": {
-                  "version": "1.5.0"
+                  "version": "1.6.0"
                 }
               }
             },
@@ -9363,7 +9107,7 @@
               "version": "2.1.0",
               "dependencies": {
                 "readable-stream": {
-                  "version": "2.1.4",
+                  "version": "2.1.5",
                   "dependencies": {
                     "buffer-shims": {
                       "version": "1.0.0"
@@ -9396,7 +9140,7 @@
           "version": "1.1.2"
         },
         "connect": {
-          "version": "3.4.1",
+          "version": "3.5.0",
           "dependencies": {
             "debug": {
               "version": "2.2.0",
@@ -9407,7 +9151,7 @@
               }
             },
             "finalhandler": {
-              "version": "0.4.1",
+              "version": "0.5.0",
               "dependencies": {
                 "escape-html": {
                   "version": "1.0.3"
@@ -9420,6 +9164,9 @@
                     }
                   }
                 },
+                "statuses": {
+                  "version": "1.3.0"
+                },
                 "unpipe": {
                   "version": "1.0.0"
                 }
@@ -9484,7 +9231,7 @@
           }
         },
         "glob": {
-          "version": "7.0.5",
+          "version": "7.0.6",
           "dependencies": {
             "fs.realpath": {
               "version": "1.0.0"
@@ -9498,10 +9245,10 @@
               }
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "once": {
-              "version": "1.3.3",
+              "version": "1.4.0",
               "dependencies": {
                 "wrappy": {
                   "version": "1.0.2"
@@ -9514,10 +9261,10 @@
           }
         },
         "graceful-fs": {
-          "version": "4.1.5"
+          "version": "4.1.6"
         },
         "http-proxy": {
-          "version": "1.14.0",
+          "version": "1.15.1",
           "dependencies": {
             "eventemitter3": {
               "version": "1.2.0"
@@ -9543,7 +9290,7 @@
                   "version": "1.0.2"
                 },
                 "inherits": {
-                  "version": "2.0.1"
+                  "version": "2.0.3"
                 },
                 "isarray": {
                   "version": "0.0.1"
@@ -9863,7 +9610,7 @@
           }
         },
         "which": {
-          "version": "1.2.10",
+          "version": "1.2.11",
           "dependencies": {
             "isexe": {
               "version": "1.1.2"
@@ -9907,7 +9654,7 @@
                       }
                     },
                     "signal-exit": {
-                      "version": "3.0.0"
+                      "version": "3.0.1"
                     }
                   }
                 },
@@ -9946,15 +9693,7 @@
                           }
                         },
                         "spdx-expression-parse": {
-                          "version": "1.0.2",
-                          "dependencies": {
-                            "spdx-exceptions": {
-                              "version": "1.0.5"
-                            },
-                            "spdx-license-ids": {
-                              "version": "1.2.2"
-                            }
-                          }
+                          "version": "1.0.3"
                         }
                       }
                     }
@@ -9989,7 +9728,7 @@
                           "version": "1.1.0",
                           "dependencies": {
                             "graceful-fs": {
-                              "version": "4.1.5"
+                              "version": "4.1.6"
                             },
                             "parse-json": {
                               "version": "2.2.0",
@@ -10029,7 +9768,7 @@
                           "version": "1.1.0",
                           "dependencies": {
                             "graceful-fs": {
-                              "version": "4.1.5"
+                              "version": "4.1.6"
                             },
                             "pify": {
                               "version": "2.3.0"
@@ -10082,7 +9821,7 @@
           }
         },
         "istanbul": {
-          "version": "0.4.4",
+          "version": "0.4.5",
           "dependencies": {
             "abbrev": {
               "version": "1.0.9"
@@ -10130,28 +9869,7 @@
               }
             },
             "esprima": {
-              "version": "2.7.2"
-            },
-            "fileset": {
-              "version": "0.2.1",
-              "dependencies": {
-                "minimatch": {
-                  "version": "2.0.10",
-                  "dependencies": {
-                    "brace-expansion": {
-                      "version": "1.1.6",
-                      "dependencies": {
-                        "balanced-match": {
-                          "version": "0.4.2"
-                        },
-                        "concat-map": {
-                          "version": "0.0.1"
-                        }
-                      }
-                    }
-                  }
-                }
-              }
+              "version": "2.7.3"
             },
             "handlebars": {
               "version": "4.0.5",
@@ -10176,7 +9894,7 @@
                   }
                 },
                 "uglify-js": {
-                  "version": "2.7.0",
+                  "version": "2.7.3",
                   "dependencies": {
                     "async": {
                       "version": "0.2.10"
@@ -10289,7 +10007,7 @@
               "version": "3.0.6"
             },
             "once": {
-              "version": "1.3.3",
+              "version": "1.4.0",
               "dependencies": {
                 "wrappy": {
                   "version": "1.0.2"
@@ -10308,7 +10026,7 @@
               }
             },
             "which": {
-              "version": "1.2.10",
+              "version": "1.2.11",
               "dependencies": {
                 "isexe": {
                   "version": "1.1.2"
@@ -10402,7 +10120,7 @@
       }
     },
     "karma-webpack": {
-      "version": "1.7.0",
+      "version": "1.8.0",
       "dependencies": {
         "async": {
           "version": "0.9.2"
@@ -10419,7 +10137,7 @@
           }
         },
         "webpack-dev-middleware": {
-          "version": "1.6.1",
+          "version": "1.7.0",
           "dependencies": {
             "memory-fs": {
               "version": "0.3.0",
@@ -10433,7 +10151,7 @@
                   }
                 },
                 "readable-stream": {
-                  "version": "2.1.4",
+                  "version": "2.1.5",
                   "dependencies": {
                     "buffer-shims": {
                       "version": "1.0.0"
@@ -10442,7 +10160,7 @@
                       "version": "1.0.2"
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "isarray": {
                       "version": "1.0.0"
@@ -10474,7 +10192,7 @@
       "version": "0.7.7"
     },
     "loader-utils": {
-      "version": "0.2.15",
+      "version": "0.2.16",
       "dependencies": {
         "big.js": {
           "version": "3.1.3"
@@ -10491,7 +10209,7 @@
       }
     },
     "moment": {
-      "version": "2.14.1"
+      "version": "2.15.0"
     },
     "node-libs-browser": {
       "version": "0.5.3",
@@ -10559,7 +10277,7 @@
               "version": "0.2.1"
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             }
           }
         },
@@ -10573,7 +10291,7 @@
           "version": "0.0.0"
         },
         "process": {
-          "version": "0.11.8"
+          "version": "0.11.9"
         },
         "punycode": {
           "version": "1.4.1"
@@ -10588,7 +10306,7 @@
               "version": "1.0.2"
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "isarray": {
               "version": "0.0.1"
@@ -10599,7 +10317,7 @@
           "version": "1.0.0",
           "dependencies": {
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             }
           }
         },
@@ -10642,10 +10360,10 @@
       }
     },
     "normalizr": {
-      "version": "2.1.0",
+      "version": "2.2.1",
       "dependencies": {
         "lodash": {
-          "version": "4.13.1"
+          "version": "4.15.0"
         }
       }
     },
@@ -10669,16 +10387,16 @@
       }
     },
     "postcss-cssnext": {
-      "version": "2.7.0",
+      "version": "2.8.0",
       "dependencies": {
         "autoprefixer": {
-          "version": "6.4.0",
+          "version": "6.4.1",
           "dependencies": {
             "browserslist": {
-              "version": "1.3.5"
+              "version": "1.3.6"
             },
             "caniuse-db": {
-              "version": "1.0.30000519"
+              "version": "1.0.30000530"
             },
             "normalize-range": {
               "version": "0.1.2"
@@ -10692,25 +10410,25 @@
           }
         },
         "caniuse-api": {
-          "version": "1.5.1",
+          "version": "1.5.2",
           "dependencies": {
             "browserslist": {
-              "version": "1.3.5"
+              "version": "1.3.6"
             },
             "caniuse-db": {
-              "version": "1.0.30000519"
+              "version": "1.0.30000530"
             },
             "lodash.memoize": {
-              "version": "4.1.1"
+              "version": "4.1.2"
             },
             "lodash.uniq": {
-              "version": "4.4.0"
+              "version": "4.5.0"
             },
             "shelljs": {
-              "version": "0.7.3",
+              "version": "0.7.4",
               "dependencies": {
                 "glob": {
-                  "version": "7.0.5",
+                  "version": "7.0.6",
                   "dependencies": {
                     "fs.realpath": {
                       "version": "1.0.0"
@@ -10724,7 +10442,7 @@
                       }
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "minimatch": {
                       "version": "3.0.3",
@@ -10743,7 +10461,7 @@
                       }
                     },
                     "once": {
-                      "version": "1.3.3",
+                      "version": "1.4.0",
                       "dependencies": {
                         "wrappy": {
                           "version": "1.0.2"
@@ -10801,24 +10519,37 @@
           }
         },
         "pixrem": {
-          "version": "3.0.1",
+          "version": "3.0.2",
           "dependencies": {
             "browserslist": {
-              "version": "1.3.5",
+              "version": "1.3.6",
               "dependencies": {
                 "caniuse-db": {
-                  "version": "1.0.30000519"
+                  "version": "1.0.30000530"
                 }
               }
             },
             "reduce-css-calc": {
-              "version": "1.2.4",
+              "version": "1.3.0",
               "dependencies": {
                 "balanced-match": {
-                  "version": "0.1.0"
+                  "version": "0.4.2"
+                },
+                "math-expression-evaluator": {
+                  "version": "1.2.14",
+                  "dependencies": {
+                    "lodash.indexof": {
+                      "version": "4.0.5"
+                    }
+                  }
                 },
                 "reduce-function-call": {
-                  "version": "1.0.1"
+                  "version": "1.0.1",
+                  "dependencies": {
+                    "balanced-match": {
+                      "version": "0.1.0"
+                    }
+                  }
                 }
               }
             }
@@ -10833,7 +10564,7 @@
           }
         },
         "postcss": {
-          "version": "5.1.2",
+          "version": "5.2.0",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -10859,20 +10590,52 @@
             }
           }
         },
+        "postcss-attribute-case-insensitive": {
+          "version": "1.0.1",
+          "dependencies": {
+            "postcss-selector-parser": {
+              "version": "2.2.1",
+              "dependencies": {
+                "flatten": {
+                  "version": "1.0.2"
+                },
+                "indexes-of": {
+                  "version": "1.0.1"
+                },
+                "uniq": {
+                  "version": "1.0.1"
+                }
+              }
+            }
+          }
+        },
         "postcss-calc": {
-          "version": "5.3.0",
+          "version": "5.3.1",
           "dependencies": {
             "postcss-message-helpers": {
               "version": "2.0.0"
             },
             "reduce-css-calc": {
-              "version": "1.2.4",
+              "version": "1.3.0",
               "dependencies": {
                 "balanced-match": {
-                  "version": "0.1.0"
+                  "version": "0.4.2"
+                },
+                "math-expression-evaluator": {
+                  "version": "1.2.14",
+                  "dependencies": {
+                    "lodash.indexof": {
+                      "version": "4.0.5"
+                    }
+                  }
                 },
                 "reduce-function-call": {
-                  "version": "1.0.1"
+                  "version": "1.0.1",
+                  "dependencies": {
+                    "balanced-match": {
+                      "version": "0.1.0"
+                    }
+                  }
                 }
               }
             }
@@ -11049,7 +10812,7 @@
           "version": "1.5.2",
           "dependencies": {
             "lodash.template": {
-              "version": "4.3.0",
+              "version": "4.4.0",
               "dependencies": {
                 "lodash._reinterpolate": {
                   "version": "3.0.0"
@@ -11093,10 +10856,10 @@
           "version": "1.0.0"
         },
         "postcss-selector-matches": {
-          "version": "2.0.1",
+          "version": "2.0.5",
           "dependencies": {
             "balanced-match": {
-              "version": "0.2.1"
+              "version": "0.4.2"
             }
           }
         },
@@ -11120,10 +10883,10 @@
           "version": "0.1.14",
           "dependencies": {
             "jspm": {
-              "version": "0.17.0-beta.25",
+              "version": "0.17.0-beta.28",
               "dependencies": {
                 "bluebird": {
-                  "version": "3.4.1"
+                  "version": "3.4.6"
                 },
                 "chalk": {
                   "version": "1.1.3",
@@ -11170,10 +10933,10 @@
                       }
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "once": {
-                      "version": "1.3.3",
+                      "version": "1.4.0",
                       "dependencies": {
                         "wrappy": {
                           "version": "1.0.2"
@@ -11186,10 +10949,10 @@
                   }
                 },
                 "graceful-fs": {
-                  "version": "4.1.5"
+                  "version": "4.1.6"
                 },
                 "jspm-github": {
-                  "version": "0.14.9",
+                  "version": "0.14.10",
                   "dependencies": {
                     "expand-tilde": {
                       "version": "1.2.2",
@@ -11218,7 +10981,7 @@
                                   "version": "1.0.2"
                                 },
                                 "inherits": {
-                                  "version": "2.0.1"
+                                  "version": "2.0.3"
                                 },
                                 "isarray": {
                                   "version": "0.0.1"
@@ -11331,53 +11094,145 @@
                                 }
                               }
                             },
-                            "inherits": {
-                              "version": "2.0.1"
-                            },
-                            "minimatch": {
-                              "version": "2.0.10",
+                            "inherits": {
+                              "version": "2.0.3"
+                            },
+                            "minimatch": {
+                              "version": "2.0.10",
+                              "dependencies": {
+                                "brace-expansion": {
+                                  "version": "1.1.6",
+                                  "dependencies": {
+                                    "balanced-match": {
+                                      "version": "0.4.2"
+                                    },
+                                    "concat-map": {
+                                      "version": "0.0.1"
+                                    }
+                                  }
+                                }
+                              }
+                            },
+                            "once": {
+                              "version": "1.4.0",
+                              "dependencies": {
+                                "wrappy": {
+                                  "version": "1.0.2"
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "tar-fs": {
+                      "version": "1.13.2",
+                      "dependencies": {
+                        "pump": {
+                          "version": "1.0.1",
+                          "dependencies": {
+                            "end-of-stream": {
+                              "version": "1.1.0",
+                              "dependencies": {
+                                "once": {
+                                  "version": "1.3.3",
+                                  "dependencies": {
+                                    "wrappy": {
+                                      "version": "1.0.2"
+                                    }
+                                  }
+                                }
+                              }
+                            },
+                            "once": {
+                              "version": "1.4.0",
+                              "dependencies": {
+                                "wrappy": {
+                                  "version": "1.0.2"
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "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.3"
+                                    },
+                                    "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": {
-                                "brace-expansion": {
-                                  "version": "1.1.6",
+                                "once": {
+                                  "version": "1.3.3",
                                   "dependencies": {
-                                    "balanced-match": {
-                                      "version": "0.4.2"
-                                    },
-                                    "concat-map": {
-                                      "version": "0.0.1"
+                                    "wrappy": {
+                                      "version": "1.0.2"
                                     }
                                   }
                                 }
                               }
                             },
-                            "once": {
-                              "version": "1.3.3",
+                            "readable-stream": {
+                              "version": "2.1.5",
                               "dependencies": {
-                                "wrappy": {
+                                "buffer-shims": {
+                                  "version": "1.0.0"
+                                },
+                                "core-util-is": {
+                                  "version": "1.0.2"
+                                },
+                                "inherits": {
+                                  "version": "2.0.3"
+                                },
+                                "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"
                             }
                           }
                         }
                       }
                     },
-                    "tar": {
-                      "version": "2.2.1",
-                      "dependencies": {
-                        "block-stream": {
-                          "version": "0.0.9"
-                        },
-                        "fstream": {
-                          "version": "1.0.10"
-                        },
-                        "inherits": {
-                          "version": "2.0.1"
-                        }
-                      }
-                    },
                     "which": {
-                      "version": "1.2.10",
+                      "version": "1.2.11",
                       "dependencies": {
                         "isexe": {
                           "version": "1.1.2"
@@ -11387,13 +11242,16 @@
                   }
                 },
                 "jspm-npm": {
-                  "version": "0.29.3",
+                  "version": "0.29.4",
                   "dependencies": {
+                    "buffer-peek-stream": {
+                      "version": "1.0.1"
+                    },
                     "readdirp": {
                       "version": "2.1.0",
                       "dependencies": {
                         "readable-stream": {
-                          "version": "2.1.4",
+                          "version": "2.1.5",
                           "dependencies": {
                             "buffer-shims": {
                               "version": "1.0.0"
@@ -11402,7 +11260,7 @@
                               "version": "1.0.2"
                             },
                             "inherits": {
-                              "version": "2.0.1"
+                              "version": "2.0.3"
                             },
                             "isarray": {
                               "version": "1.0.0"
@@ -11439,7 +11297,7 @@
                                   "version": "1.0.2"
                                 },
                                 "inherits": {
-                                  "version": "2.0.1"
+                                  "version": "2.0.3"
                                 },
                                 "isarray": {
                                   "version": "0.0.1"
@@ -11469,10 +11327,15 @@
                           "version": "0.6.1"
                         },
                         "form-data": {
-                          "version": "1.0.0-rc4",
+                          "version": "1.0.1",
                           "dependencies": {
                             "async": {
-                              "version": "1.5.2"
+                              "version": "2.0.1",
+                              "dependencies": {
+                                "lodash": {
+                                  "version": "4.15.0"
+                                }
+                              }
                             },
                             "mime-types": {
                               "version": "2.1.11",
@@ -11488,7 +11351,7 @@
                           "version": "1.8.0",
                           "dependencies": {
                             "bluebird": {
-                              "version": "2.10.2"
+                              "version": "2.11.0"
                             },
                             "commander": {
                               "version": "2.9.0",
@@ -11609,16 +11472,26 @@
                       }
                     },
                     "tar-fs": {
-                      "version": "1.13.0",
+                      "version": "1.13.2",
                       "dependencies": {
                         "pump": {
                           "version": "1.0.1",
                           "dependencies": {
                             "end-of-stream": {
-                              "version": "1.1.0"
+                              "version": "1.1.0",
+                              "dependencies": {
+                                "once": {
+                                  "version": "1.3.3",
+                                  "dependencies": {
+                                    "wrappy": {
+                                      "version": "1.0.2"
+                                    }
+                                  }
+                                }
+                              }
                             },
                             "once": {
-                              "version": "1.3.3",
+                              "version": "1.4.0",
                               "dependencies": {
                                 "wrappy": {
                                   "version": "1.0.2"
@@ -11640,7 +11513,7 @@
                                       "version": "1.0.2"
                                     },
                                     "inherits": {
-                                      "version": "2.0.1"
+                                      "version": "2.0.3"
                                     },
                                     "isarray": {
                                       "version": "1.0.0"
@@ -11672,7 +11545,7 @@
                               }
                             },
                             "readable-stream": {
-                              "version": "2.1.4",
+                              "version": "2.1.5",
                               "dependencies": {
                                 "buffer-shims": {
                                   "version": "1.0.0"
@@ -11681,7 +11554,7 @@
                                   "version": "1.0.2"
                                 },
                                 "inherits": {
-                                  "version": "2.0.1"
+                                  "version": "2.0.3"
                                 },
                                 "isarray": {
                                   "version": "1.0.0"
@@ -11705,7 +11578,7 @@
                       }
                     },
                     "which": {
-                      "version": "1.2.10",
+                      "version": "1.2.11",
                       "dependencies": {
                         "isexe": {
                           "version": "1.1.2"
@@ -11718,7 +11591,7 @@
                   "version": "0.4.1",
                   "dependencies": {
                     "rsvp": {
-                      "version": "3.2.1"
+                      "version": "3.3.1"
                     },
                     "semver": {
                       "version": "4.3.6"
@@ -11837,7 +11710,7 @@
                                   "version": "0.1.4",
                                   "dependencies": {
                                     "for-in": {
-                                      "version": "0.1.5"
+                                      "version": "0.1.6"
                                     }
                                   }
                                 },
@@ -11907,7 +11780,7 @@
                                       }
                                     },
                                     "which": {
-                                      "version": "1.2.10",
+                                      "version": "1.2.11",
                                       "dependencies": {
                                         "isexe": {
                                           "version": "1.1.2"
@@ -11937,16 +11810,16 @@
                           }
                         },
                         "lodash.assignwith": {
-                          "version": "4.1.0"
+                          "version": "4.2.0"
                         },
                         "lodash.isarray": {
                           "version": "4.0.0"
                         },
                         "lodash.isempty": {
-                          "version": "4.3.1"
+                          "version": "4.4.0"
                         },
                         "lodash.pick": {
-                          "version": "4.3.0"
+                          "version": "4.4.0"
                         },
                         "parse-filepath": {
                           "version": "1.0.1",
@@ -11991,13 +11864,13 @@
                       "version": "0.3.2"
                     },
                     "lodash.isplainobject": {
-                      "version": "4.0.5"
+                      "version": "4.0.6"
                     },
                     "lodash.isstring": {
                       "version": "4.0.1"
                     },
                     "lodash.mapvalues": {
-                      "version": "4.5.1"
+                      "version": "4.6.0"
                     },
                     "rechoir": {
                       "version": "0.6.2"
@@ -12032,7 +11905,7 @@
                   "version": "2.0.0"
                 },
                 "proper-lockfile": {
-                  "version": "1.1.2",
+                  "version": "1.2.0",
                   "dependencies": {
                     "err-code": {
                       "version": "1.1.1"
@@ -12041,7 +11914,7 @@
                       "version": "3.0.0"
                     },
                     "retry": {
-                      "version": "0.9.0"
+                      "version": "0.10.0"
                     }
                   }
                 },
@@ -12064,7 +11937,7 @@
                               "version": "1.0.2"
                             },
                             "inherits": {
-                              "version": "2.0.1"
+                              "version": "2.0.3"
                             },
                             "isarray": {
                               "version": "1.0.0"
@@ -12100,10 +11973,15 @@
                       "version": "0.6.1"
                     },
                     "form-data": {
-                      "version": "1.0.0-rc4",
+                      "version": "1.0.1",
                       "dependencies": {
                         "async": {
-                          "version": "1.5.2"
+                          "version": "2.0.1",
+                          "dependencies": {
+                            "lodash": {
+                              "version": "4.15.0"
+                            }
+                          }
                         }
                       }
                     },
@@ -12174,13 +12052,13 @@
                           "version": "0.2.0"
                         },
                         "jsprim": {
-                          "version": "1.3.0",
+                          "version": "1.3.1",
                           "dependencies": {
                             "extsprintf": {
                               "version": "1.0.2"
                             },
                             "json-schema": {
-                              "version": "0.2.2"
+                              "version": "0.2.3"
                             },
                             "verror": {
                               "version": "1.3.6"
@@ -12188,7 +12066,7 @@
                           }
                         },
                         "sshpk": {
-                          "version": "1.9.2",
+                          "version": "1.10.0",
                           "dependencies": {
                             "asn1": {
                               "version": "0.2.3"
@@ -12196,6 +12074,14 @@
                             "assert-plus": {
                               "version": "1.0.0"
                             },
+                            "bcrypt-pbkdf": {
+                              "version": "1.0.0",
+                              "dependencies": {
+                                "tweetnacl": {
+                                  "version": "0.14.3"
+                                }
+                              }
+                            },
                             "dashdash": {
                               "version": "1.14.0"
                             },
@@ -12259,153 +12145,358 @@
                   "version": "2.5.4",
                   "dependencies": {
                     "glob": {
-                      "version": "7.0.5",
+                      "version": "7.0.6",
                       "dependencies": {
                         "fs.realpath": {
                           "version": "1.0.0"
                         },
-                        "inflight": {
-                          "version": "1.0.5",
+                        "inflight": {
+                          "version": "1.0.5",
+                          "dependencies": {
+                            "wrappy": {
+                              "version": "1.0.2"
+                            }
+                          }
+                        },
+                        "inherits": {
+                          "version": "2.0.3"
+                        },
+                        "once": {
+                          "version": "1.4.0",
+                          "dependencies": {
+                            "wrappy": {
+                              "version": "1.0.2"
+                            }
+                          }
+                        },
+                        "path-is-absolute": {
+                          "version": "1.0.0"
+                        }
+                      }
+                    }
+                  }
+                },
+                "sane": {
+                  "version": "1.4.1",
+                  "dependencies": {
+                    "exec-sh": {
+                      "version": "0.2.0",
+                      "dependencies": {
+                        "merge": {
+                          "version": "1.2.0"
+                        }
+                      }
+                    },
+                    "fb-watchman": {
+                      "version": "1.9.0",
+                      "dependencies": {
+                        "bser": {
+                          "version": "1.0.2",
+                          "dependencies": {
+                            "node-int64": {
+                              "version": "0.4.0"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "minimist": {
+                      "version": "1.2.0"
+                    },
+                    "walker": {
+                      "version": "1.0.7",
+                      "dependencies": {
+                        "makeerror": {
+                          "version": "1.0.11",
+                          "dependencies": {
+                            "tmpl": {
+                              "version": "1.0.4"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "watch": {
+                      "version": "0.10.0"
+                    }
+                  }
+                },
+                "semver": {
+                  "version": "5.3.0"
+                },
+                "systemjs": {
+                  "version": "0.19.37",
+                  "dependencies": {
+                    "when": {
+                      "version": "3.7.7"
+                    }
+                  }
+                },
+                "systemjs-builder": {
+                  "version": "0.15.30",
+                  "dependencies": {
+                    "babel-core": {
+                      "version": "6.14.0",
+                      "dependencies": {
+                        "babel-code-frame": {
+                          "version": "6.11.0",
+                          "dependencies": {
+                            "esutils": {
+                              "version": "2.0.2"
+                            },
+                            "js-tokens": {
+                              "version": "2.0.0"
+                            }
+                          }
+                        },
+                        "babel-generator": {
+                          "version": "6.14.0",
+                          "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-register": {
+                          "version": "6.14.0",
+                          "dependencies": {
+                            "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"
+                                }
+                              }
+                            },
+                            "source-map-support": {
+                              "version": "0.2.10",
+                              "dependencies": {
+                                "source-map": {
+                                  "version": "0.1.32",
+                                  "dependencies": {
+                                    "amdefine": {
+                                      "version": "1.0.0"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "babel-runtime": {
+                          "version": "6.11.6",
+                          "dependencies": {
+                            "core-js": {
+                              "version": "2.4.1"
+                            },
+                            "regenerator-runtime": {
+                              "version": "0.9.5"
+                            }
+                          }
+                        },
+                        "babel-template": {
+                          "version": "6.15.0"
+                        },
+                        "babel-traverse": {
+                          "version": "6.15.0",
                           "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.2"
+                            "globals": {
+                              "version": "8.18.0"
+                            },
+                            "invariant": {
+                              "version": "2.2.1",
+                              "dependencies": {
+                                "loose-envify": {
+                                  "version": "1.2.0",
+                                  "dependencies": {
+                                    "js-tokens": {
+                                      "version": "1.0.3"
+                                    }
+                                  }
+                                }
+                              }
                             }
                           }
                         },
-                        "inherits": {
-                          "version": "2.0.1"
-                        },
-                        "once": {
-                          "version": "1.3.3",
+                        "babel-types": {
+                          "version": "6.15.0",
                           "dependencies": {
-                            "wrappy": {
+                            "esutils": {
+                              "version": "2.0.2"
+                            },
+                            "to-fast-properties": {
                               "version": "1.0.2"
                             }
                           }
                         },
-                        "path-is-absolute": {
-                          "version": "1.0.0"
-                        }
-                      }
-                    }
-                  }
-                },
-                "sane": {
-                  "version": "1.4.1",
-                  "dependencies": {
-                    "exec-sh": {
-                      "version": "0.2.0",
-                      "dependencies": {
-                        "merge": {
-                          "version": "1.2.0"
-                        }
-                      }
-                    },
-                    "fb-watchman": {
-                      "version": "1.9.0",
-                      "dependencies": {
-                        "bser": {
-                          "version": "1.0.2",
+                        "babylon": {
+                          "version": "6.9.2"
+                        },
+                        "convert-source-map": {
+                          "version": "1.3.0"
+                        },
+                        "debug": {
+                          "version": "2.2.0",
                           "dependencies": {
-                            "node-int64": {
-                              "version": "0.4.0"
+                            "ms": {
+                              "version": "0.7.1"
                             }
                           }
+                        },
+                        "json5": {
+                          "version": "0.4.0"
+                        },
+                        "lodash": {
+                          "version": "4.15.0"
+                        },
+                        "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"
                         }
                       }
                     },
-                    "minimist": {
-                      "version": "1.2.0"
-                    },
-                    "walker": {
-                      "version": "1.0.7",
+                    "babel-plugin-transform-cjs-system-wrapper": {
+                      "version": "0.2.1",
                       "dependencies": {
-                        "makeerror": {
-                          "version": "1.0.11",
+                        "babel-plugin-transform-cjs-system-require": {
+                          "version": "0.1.1"
+                        },
+                        "babel-template": {
+                          "version": "6.15.0",
                           "dependencies": {
-                            "tmpl": {
-                              "version": "1.0.4"
+                            "babel-runtime": {
+                              "version": "6.11.6",
+                              "dependencies": {
+                                "core-js": {
+                                  "version": "2.4.1"
+                                },
+                                "regenerator-runtime": {
+                                  "version": "0.9.5"
+                                }
+                              }
+                            },
+                            "babel-traverse": {
+                              "version": "6.15.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.15.0",
+                              "dependencies": {
+                                "esutils": {
+                                  "version": "2.0.2"
+                                },
+                                "to-fast-properties": {
+                                  "version": "1.0.2"
+                                }
+                              }
+                            },
+                            "babylon": {
+                              "version": "6.9.2"
+                            },
+                            "lodash": {
+                              "version": "4.15.0"
                             }
                           }
                         }
                       }
                     },
-                    "watch": {
-                      "version": "0.10.0"
-                    }
-                  }
-                },
-                "semver": {
-                  "version": "5.3.0"
-                },
-                "systemjs": {
-                  "version": "0.19.36",
-                  "dependencies": {
-                    "when": {
-                      "version": "3.7.7"
-                    }
-                  }
-                },
-                "systemjs-builder": {
-                  "version": "0.15.26",
-                  "dependencies": {
                     "babel-plugin-transform-es2015-modules-systemjs": {
-                      "version": "6.12.0",
+                      "version": "6.14.0",
                       "dependencies": {
                         "babel-helper-hoist-variables": {
                           "version": "6.8.0",
                           "dependencies": {
                             "babel-types": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
-                                "babel-traverse": {
-                                  "version": "6.13.0",
-                                  "dependencies": {
-                                    "babel-code-frame": {
-                                      "version": "6.11.0",
-                                      "dependencies": {
-                                        "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"
-                                            }
-                                          }
-                                        }
-                                      }
-                                    }
-                                  }
-                                },
                                 "esutils": {
                                   "version": "2.0.2"
                                 },
                                 "lodash": {
-                                  "version": "4.14.2"
+                                  "version": "4.15.0"
                                 },
                                 "to-fast-properties": {
                                   "version": "1.0.2"
@@ -12426,10 +12517,10 @@
                           }
                         },
                         "babel-template": {
-                          "version": "6.9.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "babel-traverse": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "babel-code-frame": {
                                   "version": "6.11.0",
@@ -12472,7 +12563,7 @@
                               }
                             },
                             "babel-types": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "esutils": {
                                   "version": "2.0.2"
@@ -12483,10 +12574,10 @@
                               }
                             },
                             "babylon": {
-                              "version": "6.8.4"
+                              "version": "6.9.2"
                             },
                             "lodash": {
-                              "version": "4.14.2"
+                              "version": "4.15.0"
                             }
                           }
                         }
@@ -12496,7 +12587,7 @@
                       "version": "0.0.1",
                       "dependencies": {
                         "babel-template": {
-                          "version": "6.9.0",
+                          "version": "6.15.0",
                           "dependencies": {
                             "babel-runtime": {
                               "version": "6.11.6",
@@ -12510,7 +12601,7 @@
                               }
                             },
                             "babel-traverse": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "babel-code-frame": {
                                   "version": "6.11.0",
@@ -12553,7 +12644,7 @@
                               }
                             },
                             "babel-types": {
-                              "version": "6.13.0",
+                              "version": "6.15.0",
                               "dependencies": {
                                 "esutils": {
                                   "version": "2.0.2"
@@ -12564,10 +12655,10 @@
                               }
                             },
                             "babylon": {
-                              "version": "6.8.4"
+                              "version": "6.9.2"
                             },
                             "lodash": {
-                              "version": "4.14.2"
+                              "version": "4.15.0"
                             }
                           }
                         }
@@ -12580,7 +12671,7 @@
                       "version": "0.0.4"
                     },
                     "es6-template-strings": {
-                      "version": "2.0.0",
+                      "version": "2.0.1",
                       "dependencies": {
                         "es5-ext": {
                           "version": "0.10.12",
@@ -12604,17 +12695,17 @@
                           }
                         },
                         "esniff": {
-                          "version": "1.0.0",
+                          "version": "1.1.0",
                           "dependencies": {
                             "d": {
-                              "version": "0.1.1"
+                              "version": "1.0.0"
                             }
                           }
                         }
                       }
                     },
                     "glob": {
-                      "version": "7.0.5",
+                      "version": "7.0.6",
                       "dependencies": {
                         "fs.realpath": {
                           "version": "1.0.0"
@@ -12628,10 +12719,10 @@
                           }
                         },
                         "inherits": {
-                          "version": "2.0.1"
+                          "version": "2.0.3"
                         },
                         "once": {
-                          "version": "1.3.3",
+                          "version": "1.4.0",
                           "dependencies": {
                             "wrappy": {
                               "version": "1.0.2"
@@ -12689,10 +12780,10 @@
                           }
                         },
                         "inherits": {
-                          "version": "2.0.1"
+                          "version": "2.0.3"
                         },
                         "once": {
-                          "version": "1.3.3",
+                          "version": "1.4.0",
                           "dependencies": {
                             "wrappy": {
                               "version": "1.0.2"
@@ -12705,7 +12796,7 @@
                       }
                     },
                     "rsvp": {
-                      "version": "3.2.1"
+                      "version": "3.3.1"
                     },
                     "semver": {
                       "version": "4.3.6"
@@ -12726,7 +12817,7 @@
                   }
                 },
                 "uglify-js": {
-                  "version": "2.7.0",
+                  "version": "2.7.3",
                   "dependencies": {
                     "async": {
                       "version": "0.2.10"
@@ -12817,7 +12908,7 @@
           }
         },
         "postcss": {
-          "version": "5.1.2",
+          "version": "5.2.0",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -12855,7 +12946,7 @@
       "version": "0.8.2",
       "dependencies": {
         "postcss": {
-          "version": "5.1.2",
+          "version": "5.2.0",
           "dependencies": {
             "js-base64": {
               "version": "2.1.9"
@@ -12885,16 +12976,16 @@
               "version": "0.23.1",
               "dependencies": {
                 "graceful-fs": {
-                  "version": "4.1.5"
+                  "version": "4.1.6"
                 },
                 "jsonfile": {
-                  "version": "2.3.1"
+                  "version": "2.4.0"
                 },
                 "rimraf": {
                   "version": "2.5.4",
                   "dependencies": {
                     "glob": {
-                      "version": "7.0.5",
+                      "version": "7.0.6",
                       "dependencies": {
                         "fs.realpath": {
                           "version": "1.0.0"
@@ -12908,10 +12999,10 @@
                           }
                         },
                         "inherits": {
-                          "version": "2.0.1"
+                          "version": "2.0.3"
                         },
                         "once": {
-                          "version": "1.3.3",
+                          "version": "1.4.0",
                           "dependencies": {
                             "wrappy": {
                               "version": "1.0.2"
@@ -12997,7 +13088,7 @@
           "version": "1.0.0"
         },
         "postcss": {
-          "version": "5.1.2",
+          "version": "5.2.0",
           "dependencies": {
             "source-map": {
               "version": "0.5.6"
@@ -13062,16 +13153,16 @@
               }
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "minimatch": {
-              "version": "3.0.2",
+              "version": "3.0.3",
               "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"
@@ -13081,7 +13172,7 @@
               }
             },
             "once": {
-              "version": "1.3.3",
+              "version": "1.4.0",
               "dependencies": {
                 "wrappy": {
                   "version": "1.0.2"
@@ -13093,6 +13184,36 @@
             }
           }
         },
+        "jasmine": {
+          "version": "2.4.1",
+          "dependencies": {
+            "exit": {
+              "version": "0.1.2"
+            },
+            "glob": {
+              "version": "3.2.11",
+              "dependencies": {
+                "inherits": {
+                  "version": "2.0.3"
+                },
+                "minimatch": {
+                  "version": "0.3.0",
+                  "dependencies": {
+                    "lru-cache": {
+                      "version": "2.7.3"
+                    },
+                    "sigmund": {
+                      "version": "1.0.1"
+                    }
+                  }
+                }
+              }
+            },
+            "jasmine-core": {
+              "version": "2.4.1"
+            }
+          }
+        },
         "jasminewd2": {
           "version": "0.0.9"
         },
@@ -13126,7 +13247,7 @@
                       "version": "1.0.2"
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "isarray": {
                       "version": "1.0.0"
@@ -13162,10 +13283,15 @@
               "version": "0.6.1"
             },
             "form-data": {
-              "version": "1.0.0-rc4",
+              "version": "1.0.1",
               "dependencies": {
                 "async": {
-                  "version": "1.5.2"
+                  "version": "2.0.1",
+                  "dependencies": {
+                    "lodash": {
+                      "version": "4.15.0"
+                    }
+                  }
                 }
               }
             },
@@ -13236,13 +13362,13 @@
                   "version": "0.2.0"
                 },
                 "jsprim": {
-                  "version": "1.3.0",
+                  "version": "1.3.1",
                   "dependencies": {
                     "extsprintf": {
                       "version": "1.0.2"
                     },
                     "json-schema": {
-                      "version": "0.2.2"
+                      "version": "0.2.3"
                     },
                     "verror": {
                       "version": "1.3.6"
@@ -13250,7 +13376,7 @@
                   }
                 },
                 "sshpk": {
-                  "version": "1.8.3",
+                  "version": "1.10.0",
                   "dependencies": {
                     "asn1": {
                       "version": "0.2.3"
@@ -13258,6 +13384,14 @@
                     "assert-plus": {
                       "version": "1.0.0"
                     },
+                    "bcrypt-pbkdf": {
+                      "version": "1.0.0",
+                      "dependencies": {
+                        "tweetnacl": {
+                          "version": "0.14.3"
+                        }
+                      }
+                    },
                     "dashdash": {
                       "version": "1.14.0"
                     },
@@ -13304,7 +13438,7 @@
               "version": "0.8.2"
             },
             "qs": {
-              "version": "5.2.0"
+              "version": "5.2.1"
             },
             "stringstream": {
               "version": "0.0.5"
@@ -13353,10 +13487,10 @@
               "version": "0.4.4"
             },
             "rimraf": {
-              "version": "2.5.3",
+              "version": "2.5.4",
               "dependencies": {
                 "glob": {
-                  "version": "7.0.5",
+                  "version": "7.0.6",
                   "dependencies": {
                     "fs.realpath": {
                       "version": "1.0.0"
@@ -13370,16 +13504,16 @@
                       }
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "minimatch": {
-                      "version": "3.0.2",
+                      "version": "3.0.3",
                       "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"
@@ -13389,7 +13523,7 @@
                       }
                     },
                     "once": {
-                      "version": "1.3.3",
+                      "version": "1.4.0",
                       "dependencies": {
                         "wrappy": {
                           "version": "1.0.2"
@@ -13431,7 +13565,7 @@
           }
         },
         "source-map-support": {
-          "version": "0.4.1",
+          "version": "0.4.2",
           "dependencies": {
             "source-map": {
               "version": "0.1.32",
@@ -13446,10 +13580,10 @@
       }
     },
     "react": {
-      "version": "15.2.1",
+      "version": "15.3.1",
       "dependencies": {
         "fbjs": {
-          "version": "0.8.3",
+          "version": "0.8.4",
           "dependencies": {
             "core-js": {
               "version": "1.2.7"
@@ -13484,13 +13618,13 @@
       }
     },
     "react-addons-css-transition-group": {
-      "version": "15.2.1"
+      "version": "15.3.1"
     },
     "react-addons-perf": {
-      "version": "15.2.1"
+      "version": "15.3.1"
     },
     "react-addons-shallow-compare": {
-      "version": "15.2.1"
+      "version": "15.3.1"
     },
     "react-ansi-style": {
       "version": "1.0.0",
@@ -13517,7 +13651,7 @@
       }
     },
     "react-dom": {
-      "version": "15.2.1"
+      "version": "15.3.1"
     },
     "react-draggable": {
       "version": "1.3.7"
@@ -13539,7 +13673,7 @@
       }
     },
     "react-leaflet": {
-      "version": "0.12.1",
+      "version": "0.12.2",
       "dependencies": {
         "lodash": {
           "version": "4.15.0"
@@ -13569,7 +13703,7 @@
           "version": "2.2.1"
         },
         "lodash": {
-          "version": "4.14.2"
+          "version": "4.15.0"
         },
         "loose-envify": {
           "version": "1.2.0",
@@ -13585,7 +13719,7 @@
       "version": "1.4.2",
       "dependencies": {
         "react-draggable": {
-          "version": "2.2.0"
+          "version": "2.2.2"
         }
       }
     },
@@ -13610,7 +13744,7 @@
       }
     },
     "react-router": {
-      "version": "2.6.1",
+      "version": "2.8.1",
       "dependencies": {
         "history": {
           "version": "2.1.2",
@@ -13654,7 +13788,7 @@
       "version": "4.0.5"
     },
     "react-sortable": {
-      "version": "1.0.1"
+      "version": "1.1.0"
     },
     "react-virtualized": {
       "version": "6.3.2",
@@ -13663,7 +13797,7 @@
           "version": "2.4.0"
         },
         "raf": {
-          "version": "3.2.0",
+          "version": "3.3.0",
           "dependencies": {
             "performance-now": {
               "version": "0.2.0"
@@ -13679,7 +13813,7 @@
           "version": "0.1.2"
         },
         "fbjs": {
-          "version": "0.8.3",
+          "version": "0.8.4",
           "dependencies": {
             "core-js": {
               "version": "1.2.7"
@@ -13720,13 +13854,13 @@
       }
     },
     "redux": {
-      "version": "3.5.2",
+      "version": "3.6.0",
       "dependencies": {
         "lodash": {
-          "version": "4.14.2"
+          "version": "4.15.0"
         },
         "lodash-es": {
-          "version": "4.14.2"
+          "version": "4.15.0"
         },
         "loose-envify": {
           "version": "1.2.0",
@@ -13737,7 +13871,7 @@
           }
         },
         "symbol-observable": {
-          "version": "0.2.4"
+          "version": "1.0.2"
         }
       }
     },
@@ -13754,7 +13888,7 @@
                   "version": "3.0.3"
                 },
                 "lodash.isarguments": {
-                  "version": "3.0.9"
+                  "version": "3.1.0"
                 },
                 "lodash.keysin": {
                   "version": "3.0.8",
@@ -13786,7 +13920,7 @@
               "version": "3.0.1"
             },
             "lodash.keys": {
-              "version": "4.0.8"
+              "version": "4.2.0"
             }
           }
         }
@@ -13825,7 +13959,7 @@
                   "version": "3.0.3"
                 },
                 "lodash.isarguments": {
-                  "version": "3.0.9"
+                  "version": "3.1.0"
                 },
                 "lodash.keysin": {
                   "version": "3.0.8",
@@ -13856,7 +13990,7 @@
       "version": "2.5.3"
     },
     "screenfull": {
-      "version": "3.0.0"
+      "version": "3.0.2"
     },
     "stack-source-map": {
       "version": "1.0.5",
@@ -13873,16 +14007,16 @@
       "version": "0.13.1"
     },
     "tether": {
-      "version": "1.3.2"
+      "version": "1.3.7"
     },
     "underscore": {
       "version": "1.8.3"
     },
     "unused-files-webpack-plugin": {
-      "version": "2.0.3",
+      "version": "2.0.4",
       "dependencies": {
         "glob": {
-          "version": "7.0.5",
+          "version": "7.0.6",
           "dependencies": {
             "fs.realpath": {
               "version": "1.0.0"
@@ -13896,16 +14030,16 @@
               }
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "minimatch": {
-              "version": "3.0.2",
+              "version": "3.0.3",
               "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"
@@ -13915,7 +14049,7 @@
               }
             },
             "once": {
-              "version": "1.3.3",
+              "version": "1.4.0",
               "dependencies": {
                 "wrappy": {
                   "version": "1.0.2"
@@ -13930,7 +14064,7 @@
       }
     },
     "webpack": {
-      "version": "1.13.1",
+      "version": "1.13.2",
       "dependencies": {
         "acorn": {
           "version": "3.3.0"
@@ -13945,7 +14079,7 @@
           "version": "0.9.1",
           "dependencies": {
             "graceful-fs": {
-              "version": "4.1.5"
+              "version": "4.1.6"
             },
             "memory-fs": {
               "version": "0.2.0"
@@ -13967,7 +14101,7 @@
               }
             },
             "readable-stream": {
-              "version": "2.1.4",
+              "version": "2.1.5",
               "dependencies": {
                 "buffer-shims": {
                   "version": "1.0.0"
@@ -13976,7 +14110,7 @@
                   "version": "1.0.2"
                 },
                 "inherits": {
-                  "version": "2.0.1"
+                  "version": "2.0.3"
                 },
                 "isarray": {
                   "version": "1.0.0"
@@ -14002,6 +14136,154 @@
             }
           }
         },
+        "node-libs-browser": {
+          "version": "0.6.0",
+          "dependencies": {
+            "assert": {
+              "version": "1.4.1"
+            },
+            "browserify-zlib": {
+              "version": "0.1.4",
+              "dependencies": {
+                "pako": {
+                  "version": "0.2.9"
+                }
+              }
+            },
+            "buffer": {
+              "version": "4.9.1",
+              "dependencies": {
+                "base64-js": {
+                  "version": "1.1.2"
+                },
+                "ieee754": {
+                  "version": "1.1.6"
+                },
+                "isarray": {
+                  "version": "1.0.0"
+                }
+              }
+            },
+            "console-browserify": {
+              "version": "1.1.0",
+              "dependencies": {
+                "date-now": {
+                  "version": "0.1.4"
+                }
+              }
+            },
+            "constants-browserify": {
+              "version": "0.0.1"
+            },
+            "crypto-browserify": {
+              "version": "3.2.8",
+              "dependencies": {
+                "pbkdf2-compat": {
+                  "version": "2.0.1"
+                },
+                "ripemd160": {
+                  "version": "0.2.0"
+                },
+                "sha.js": {
+                  "version": "2.2.6"
+                }
+              }
+            },
+            "domain-browser": {
+              "version": "1.1.7"
+            },
+            "events": {
+              "version": "1.1.1"
+            },
+            "http-browserify": {
+              "version": "1.7.0",
+              "dependencies": {
+                "Base64": {
+                  "version": "0.2.1"
+                },
+                "inherits": {
+                  "version": "2.0.3"
+                }
+              }
+            },
+            "https-browserify": {
+              "version": "0.0.0"
+            },
+            "os-browserify": {
+              "version": "0.1.2"
+            },
+            "path-browserify": {
+              "version": "0.0.0"
+            },
+            "process": {
+              "version": "0.11.9"
+            },
+            "punycode": {
+              "version": "1.4.1"
+            },
+            "querystring-es3": {
+              "version": "0.2.1"
+            },
+            "readable-stream": {
+              "version": "1.1.14",
+              "dependencies": {
+                "core-util-is": {
+                  "version": "1.0.2"
+                },
+                "inherits": {
+                  "version": "2.0.3"
+                },
+                "isarray": {
+                  "version": "0.0.1"
+                }
+              }
+            },
+            "stream-browserify": {
+              "version": "1.0.0",
+              "dependencies": {
+                "inherits": {
+                  "version": "2.0.3"
+                }
+              }
+            },
+            "string_decoder": {
+              "version": "0.10.31"
+            },
+            "timers-browserify": {
+              "version": "1.4.2"
+            },
+            "tty-browserify": {
+              "version": "0.0.0"
+            },
+            "url": {
+              "version": "0.10.3",
+              "dependencies": {
+                "punycode": {
+                  "version": "1.3.2"
+                },
+                "querystring": {
+                  "version": "0.2.0"
+                }
+              }
+            },
+            "util": {
+              "version": "0.10.3",
+              "dependencies": {
+                "inherits": {
+                  "version": "2.0.1"
+                }
+              }
+            },
+            "vm-browserify": {
+              "version": "0.0.4",
+              "dependencies": {
+                "indexof": {
+                  "version": "0.0.1"
+                }
+              }
+            }
+          }
+        },
         "optimist": {
           "version": "0.6.1",
           "dependencies": {
@@ -14213,7 +14495,7 @@
                               "version": "0.1.4",
                               "dependencies": {
                                 "for-in": {
-                                  "version": "0.1.5"
+                                  "version": "0.1.6"
                                 }
                               }
                             },
@@ -14249,7 +14531,7 @@
                   }
                 },
                 "async-each": {
-                  "version": "1.0.0"
+                  "version": "1.0.1"
                 },
                 "fsevents": {
                   "version": "1.0.14",
@@ -14627,13 +14909,13 @@
                   "version": "2.0.0"
                 },
                 "inherits": {
-                  "version": "2.0.1"
+                  "version": "2.0.3"
                 },
                 "is-binary-path": {
                   "version": "1.0.1",
                   "dependencies": {
                     "binary-extensions": {
-                      "version": "1.5.0"
+                      "version": "1.6.0"
                     }
                   }
                 },
@@ -14668,7 +14950,7 @@
                       }
                     },
                     "readable-stream": {
-                      "version": "2.1.4",
+                      "version": "2.1.5",
                       "dependencies": {
                         "buffer-shims": {
                           "version": "1.0.0"
@@ -14698,7 +14980,7 @@
               }
             },
             "graceful-fs": {
-              "version": "4.1.5"
+              "version": "4.1.6"
             }
           }
         },
@@ -14721,7 +15003,7 @@
       }
     },
     "webpack-dev-server": {
-      "version": "1.14.1",
+      "version": "1.15.2",
       "dependencies": {
         "compression": {
           "version": "1.6.2",
@@ -14770,7 +15052,7 @@
           }
         },
         "connect-history-api-fallback": {
-          "version": "1.1.0"
+          "version": "1.3.0"
         },
         "express": {
           "version": "4.14.0",
@@ -14932,17 +15214,161 @@
             }
           }
         },
-        "http-proxy": {
-          "version": "1.14.0",
+        "http-proxy-middleware": {
+          "version": "0.17.1",
           "dependencies": {
-            "eventemitter3": {
-              "version": "1.2.0"
+            "http-proxy": {
+              "version": "1.15.1",
+              "dependencies": {
+                "eventemitter3": {
+                  "version": "1.2.0"
+                },
+                "requires-port": {
+                  "version": "1.0.0"
+                }
+              }
             },
-            "requires-port": {
-              "version": "1.0.0"
+            "is-glob": {
+              "version": "2.0.1",
+              "dependencies": {
+                "is-extglob": {
+                  "version": "1.0.0"
+                }
+              }
+            },
+            "lodash": {
+              "version": "4.15.0"
+            },
+            "micromatch": {
+              "version": "2.3.11",
+              "dependencies": {
+                "arr-diff": {
+                  "version": "2.0.0",
+                  "dependencies": {
+                    "arr-flatten": {
+                      "version": "1.0.1"
+                    }
+                  }
+                },
+                "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.4"
+                    }
+                  }
+                },
+                "normalize-path": {
+                  "version": "2.0.1"
+                },
+                "object.omit": {
+                  "version": "2.0.0",
+                  "dependencies": {
+                    "for-own": {
+                      "version": "0.1.4",
+                      "dependencies": {
+                        "for-in": {
+                          "version": "0.1.6"
+                        }
+                      }
+                    },
+                    "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"
+                    }
+                  }
+                },
+                "regex-cache": {
+                  "version": "0.4.3",
+                  "dependencies": {
+                    "is-equal-shallow": {
+                      "version": "0.1.3"
+                    },
+                    "is-primitive": {
+                      "version": "2.0.0"
+                    }
+                  }
+                }
+              }
             }
           }
         },
+        "open": {
+          "version": "0.0.5"
+        },
         "optimist": {
           "version": "0.6.1",
           "dependencies": {
@@ -15048,7 +15474,7 @@
                       "version": "1.0.5",
                       "dependencies": {
                         "querystringify": {
-                          "version": "0.0.3"
+                          "version": "0.0.4"
                         },
                         "requires-port": {
                           "version": "1.0.0"
@@ -15073,16 +15499,16 @@
               }
             },
             "inherits": {
-              "version": "2.0.1"
+              "version": "2.0.3"
             },
             "json3": {
               "version": "3.3.2"
             },
             "url-parse": {
-              "version": "1.1.1",
+              "version": "1.1.3",
               "dependencies": {
                 "querystringify": {
-                  "version": "0.0.3"
+                  "version": "0.0.4"
                 },
                 "requires-port": {
                   "version": "1.0.0"
@@ -15111,7 +15537,7 @@
           }
         },
         "webpack-dev-middleware": {
-          "version": "1.6.1",
+          "version": "1.7.0",
           "dependencies": {
             "memory-fs": {
               "version": "0.3.0",
@@ -15125,7 +15551,7 @@
                   }
                 },
                 "readable-stream": {
-                  "version": "2.1.4",
+                  "version": "2.1.5",
                   "dependencies": {
                     "buffer-shims": {
                       "version": "1.0.0"
@@ -15134,7 +15560,7 @@
                       "version": "1.0.2"
                     },
                     "inherits": {
-                      "version": "2.0.1"
+                      "version": "2.0.3"
                     },
                     "isarray": {
                       "version": "1.0.0"
@@ -15163,7 +15589,7 @@
       }
     },
     "webpack-hot-middleware": {
-      "version": "2.12.1",
+      "version": "2.12.2",
       "dependencies": {
         "ansi-html": {
           "version": "0.0.5"
@@ -15185,7 +15611,7 @@
       }
     },
     "webpack-postcss-tools": {
-      "version": "1.1.1",
+      "version": "1.1.2",
       "dependencies": {
         "lodash": {
           "version": "3.10.1"
diff --git a/package.json b/package.json
index d0c0c22685a912dfbdbfcb466f2b62a9e05f7225..a61d2d52a5a9664c1423c952d12f360ac01cdcb5 100644
--- a/package.json
+++ b/package.json
@@ -21,8 +21,8 @@
     "classnames": "^2.1.3",
     "color": "^0.11.1",
     "crossfilter": "^1.3.12",
-    "d3": "^3.5.16",
-    "dc": "^2.0.0-beta.25",
+    "d3": "^3.5.17",
+    "dc": "^2.0.0-beta.32",
     "diff": "^2.2.1",
     "fixed-data-table": "^0.6.0",
     "history": "^3.0.0",
diff --git a/resources/sample-dataset.db.mv.db b/resources/sample-dataset.db.mv.db
index 4480ba88092d3f6df37b815b26fe8f9dda199bec..55eebd4a85a8f105d3f9312016676ad1eff6780b 100644
Binary files a/resources/sample-dataset.db.mv.db and b/resources/sample-dataset.db.mv.db differ
diff --git a/sample_dataset/metabase/sample_dataset/generate.clj b/sample_dataset/metabase/sample_dataset/generate.clj
index eb5614e7a6f459cf5499c5ebdb9156c1c0642c3f..93c6a95a8e7b53debd233bad857865c307278fa8 100644
--- a/sample_dataset/metabase/sample_dataset/generate.clj
+++ b/sample_dataset/metabase/sample_dataset/generate.clj
@@ -1,4 +1,6 @@
 (ns metabase.sample-dataset.generate
+  "Logic for generating the sample dataset.
+   Run this with `lein generate-sample-dataset`."
   (:require (clojure.java [io :as io]
                           [jdbc :as jdbc])
             [clojure.math.numeric-tower :as math]
@@ -316,7 +318,7 @@
     :field        "PRODUCT_ID"
     :dest-table   "PRODUCTS"}])
 
-(def ^:private ^:const annotations
+(def ^:private ^:const metabase-metadata
   {:orders   {:description "This is a confirmed order for a product from a user."
               :columns     {:created_at {:description "The date and time an order was submitted."}
                             :id         {:description "This is a unique ID for the product. It is also called the “Invoice number” or “Confirmation number” in customer facing emails and screens."}
@@ -341,7 +343,7 @@
                           :source     {:description "The channel through which we acquired this user. Valid values include: Affiliate, Facebook, Google, Organic and Twitter"}
                           :state      {:description "The state or province of the account’s billing address"}
                           :zip        {:description  "The postal code of the account’s billing address"
-                                       :special_type :zip_code}}}
+                                       :special_type "type/ZipCode"}}}
    :products {:description "This is our product catalog. It includes all products ever sold by the Sample Company."
               :columns      {:category   {:description "The type of product, valid values include: Doohicky, Gadget, Gizmo and Widget"}
                              :created_at {:description "The date the product was added to our catalog."}
@@ -353,7 +355,7 @@
                              :vendor     {:description "The source of the product."}}}
    :reviews  {:description "These are reviews our customers have left on products. Note that these are not tied to orders so it is possible people have reviewed products they did not purchase from us."
               :columns     {:body       {:description  "The review the user left. Limited to 2000 characters."
-                                         :special_type :desc}
+                                         :special_type "type/Description"}
                             :created_at {:description "The day and time a review was written by a user."}
                             :id         {:description "A unique internal identifier for the review. Should not be used externally."}
                             :product_id {:description "The product the review was for"}
@@ -396,12 +398,12 @@
      ;; Insert the _metabase_metadata table
      (println "Inserting _metabase_metadata...")
      (jdbc/execute! db ["CREATE TABLE \"_METABASE_METADATA\" (\"KEYPATH\" VARCHAR(255), \"VALUE\" VARCHAR(255), PRIMARY KEY (\"KEYPATH\"));"])
-     (jdbc/insert-multi! db "_METABASE_METADATA" (reduce concat (for [[table-name {table-description :description, columns :columns}] annotations]
+     (jdbc/insert-multi! db "_METABASE_METADATA" (reduce concat (for [[table-name {table-description :description, columns :columns}] metabase-metadata]
                                                                   (let [table-name (s/upper-case (name table-name))]
                                                                     (conj (for [[column-name kvs] columns
                                                                                 [k v]             kvs]
                                                                             {:keypath (format "%s.%s.%s" table-name (s/upper-case (name column-name)) (name k))
-                                                                             :value   (name v)})
+                                                                             :value   v})
                                                                           {:keypath (format "%s.description" table-name)
                                                                            :value table-description})))))
 
@@ -416,4 +418,5 @@
 (defn -main [& [filename]]
   (let [filename (or filename sample-dataset-filename)]
     (println (format "Writing sample dataset to %s..." filename))
-    (create-h2-db filename)))
+    (create-h2-db filename)
+    (System/exit 0)))
diff --git a/src/metabase/api/field.clj b/src/metabase/api/field.clj
index 39bc83084021478e6edc2f7f1d655f56a75710c5..c1389ea22dbb638c216c250da42dcf4fd29027cd 100644
--- a/src/metabase/api/field.clj
+++ b/src/metabase/api/field.clj
@@ -5,12 +5,14 @@
             [metabase.db.metadata-queries :as metadata]
             (metabase.models [hydrate :refer [hydrate]]
                              [field :refer [Field] :as field]
-                             [field-values :refer [FieldValues create-field-values-if-needed! field-should-have-field-values?]])))
+                             [field-values :refer [FieldValues create-field-values-if-needed! field-should-have-field-values?]])
+            metabase.types
+            [metabase.util :as u]))
 
-(defannotation FieldSpecialType
-  "Param must be a valid `Field` special type."
+(defannotation FieldType
+  "Param must be a valid `Field` type."
   [symb value :nillable]
-  (checkp-contains? field/special-types symb (keyword value)))
+  (checkp-with (u/rpartial isa? :type/*) symb (keyword value) (str "Invalid field type: " value)))
 
 (defannotation FieldVisibilityType
   "Param must be a valid `Field` visibility type."
@@ -34,22 +36,16 @@
    display_name       NonEmptyString
    fk_target_field_id Integer
    points_of_interest NonEmptyString
-   special_type       FieldSpecialType
+   special_type       FieldType
    visibility_type    FieldVisibilityType}
 
   (let-404 [field (Field id)]
     (write-check field)
     (let [special_type       (keyword (get body :special_type (:special_type field)))
           visibility_type    (or visibility_type (:visibility_type field))
-          ;; only let target field be set for :fk type fields, and if it's not in the payload then leave the current value
-          fk-target-field-id (when (= :fk special_type)
+          ;; only let target field be set for :type/FK type fields, and if it's not in the payload then leave the current value
+          fk-target-field-id (when (isa? special_type :type/FK)
                                (get body :fk_target_field_id (:fk_target_field_id field)))]
-      ;; make sure that the special type is allowed for the base type
-      (check (field/valid-special-type-for-base-type? special_type (:base_type field))
-        [400 (format "Special type %s cannot be used for fields with base type %s. Base type must be one of: %s"
-                     special_type
-                     (:base_type field)
-                     (field/special-type->valid-base-types special_type))])
       ;; validate that fk_target_field_id is a valid Field
       ;; TODO - we should also check that the Field is within the same database as our field
       (when fk-target-field-id
@@ -76,7 +72,7 @@
 
 
 (defendpoint GET "/:id/values"
-  "If `Field`'s special type is `category`/`city`/`state`/`country`, or its base type is `BooleanField`, return
+  "If `Field`'s special type derives from `type/Category`, or its base type is `type/Boolean`, return
    all distinct values of the field, and a map of human-readable values defined by the user."
   [id]
   (let-404 [field (Field id)]
@@ -88,13 +84,13 @@
 
 (defendpoint POST "/:id/value_map_update"
   "Update the human-readable values for a `Field` whose special type is `category`/`city`/`state`/`country`
-   or whose base type is `BooleanField`."
+   or whose base type is `type/Boolean`."
   [id :as {{:keys [values_map]} :body}]
   {values_map [Required Dict]}
   (let-404 [field (Field id)]
     (write-check field)
     (check (field-should-have-field-values? field)
-      [400 "You can only update the mapped values of a Field whose 'special_type' is 'category'/'city'/'state'/'country' or whose 'base_type' is 'BooleanField'."])
+      [400 "You can only update the mapped values of a Field whose 'special_type' is 'category'/'city'/'state'/'country' or whose 'base_type' is 'type/Boolean'."])
     (if-let [field-values-id (db/select-one-id FieldValues, :field_id id)]
       (check-500 (db/update! FieldValues field-values-id
                    :human_readable_values values_map))
diff --git a/src/metabase/config.clj b/src/metabase/config.clj
index 25f87ad1b1b391c6675ecc7503f7cac671eaa48d..93a8128e63d8ed1e3ed4027ad529cd92e4eb5e65 100644
--- a/src/metabase/config.clj
+++ b/src/metabase/config.clj
@@ -45,6 +45,8 @@
 
 
 ;; These are convenience functions for accessing config values that ensures a specific return type
+;; TODO - These names are bad. They should be something like  `int`, `boolean`, and `keyword`, respectively.
+;; See https://github.com/metabase/metabase/wiki/Metabase-Clojure-Style-Guide#dont-repeat-namespace-alias-in-function-names for discussion
 (defn ^Integer config-int  "Fetch a configuration key and parse it as an integer." [k] (some-> k config-str Integer/parseInt))
 (defn ^Boolean config-bool "Fetch a configuration key and parse it as a boolean."  [k] (some-> k config-str Boolean/parseBoolean))
 (defn ^Keyword config-kw   "Fetch a configuration key and parse it as a keyword."  [k] (some-> k config-str keyword))
diff --git a/src/metabase/db.clj b/src/metabase/db.clj
index 99b50a7ea65315dd9d5a07f4c42f79017cbc074b..81075c1f1873b58af3edbd378bdb3aee872c4656 100644
--- a/src/metabase/db.clj
+++ b/src/metabase/db.clj
@@ -860,3 +860,22 @@
   [[source-entity fk] [dest-entity pk]]
   {:left-join [(entity->table-name dest-entity) [:= (qualify source-entity fk)
                                                     (qualify dest-entity pk)]]})
+
+
+(defn isa
+  "Convenience for generating an HoneySQL `IN` clause for a keyword and all of its descendents.
+   Intended for use with the type hierarchy in `metabase.types`.
+
+     (db/select Field :special_type (db/isa :type/URL))
+      ->
+     (db/select Field :special_type [:in #{\"type/URL\" \"type/ImageURL\" \"type/AvatarURL\"}])
+
+   Also accepts optional EXPR for use directly in a HoneySQL `where`:
+
+     (db/select Field {:where (db/isa :special_type :type/URL)})
+     ->
+     (db/select Field {:where [:in :special_type #{\"type/URL\" \"type/ImageURL\" \"type/AvatarURL\"}]})"
+  ([type-keyword]
+   [:in (set (map u/keyword->qualified-name (cons type-keyword (descendants type-keyword))))])
+  ([expr type-keyword]
+   [:in expr (last (isa type-keyword))]))
diff --git a/src/metabase/db/metadata_queries.clj b/src/metabase/db/metadata_queries.clj
index 3262f6ae95db84780fa2a43655d3c2b7b154fea9..47b904a0cbf13d8a3e1867b97cec09a178c92f9e 100644
--- a/src/metabase/db/metadata_queries.clj
+++ b/src/metabase/db/metadata_queries.clj
@@ -29,7 +29,7 @@
 
 (defn field-distinct-values
   "Return the distinct values of FIELD.
-   This is used to create a `FieldValues` object for `:category` Fields."
+   This is used to create a `FieldValues` object for `:type/Category` Fields."
   ([field]
     (field-distinct-values field @(resolve 'metabase.sync-database.analyze/low-cardinality-threshold)))
   ([{field-id :id :as field} max-results]
diff --git a/src/metabase/db/migrations.clj b/src/metabase/db/migrations.clj
index 1272e2f1d8df9e08e94599efefa2fb10b31245a6..20af0ab32a08fb63280abca108150ef7718d6fc4 100644
--- a/src/metabase/db/migrations.clj
+++ b/src/metabase/db/migrations.clj
@@ -1,8 +1,10 @@
 (ns metabase.db.migrations
   "Clojure-land data migration definitions and fns for running them."
   (:require [clojure.tools.logging :as log]
-            (metabase [db :as db]
-                      [driver :as driver])
+            (metabase [config :as config]
+                      [db :as db]
+                      [driver :as driver]
+                      types)
             [metabase.events.activity-feed :refer [activity-feed-topics]]
             (metabase.models [activity :refer [Activity]]
                              [card :refer [Card]]
@@ -231,3 +233,58 @@
                                  :last_analyzed (u/new-sql-timestamp))
                                ;; add this column to the set we've processed already
                                (swap! processed-fields conj column-name)))))))))))))))))
+
+
+;;; New type system
+(def ^:private ^:const old-special-type->new-type
+  {"avatar"                 "type/AvatarURL"
+   "category"               "type/Category"
+   "city"                   "type/City"
+   "country"                "type/Country"
+   "desc"                   "type/Description"
+   "fk"                     "type/FK"
+   "id"                     "type/PK"
+   "image"                  "type/ImageURL"
+   "json"                   "type/SerializedJSON"
+   "latitude"               "type/Latitude"
+   "longitude"              "type/Longitude"
+   "name"                   "type/Name"
+   "number"                 "type/Number"
+   "state"                  "type/State"
+   "timestamp_milliseconds" "type/UNIXTimestampMilliseconds"
+   "timestamp_seconds"      "type/UNIXTimestampSeconds"
+   "url"                    "type/URL"
+   "zip_code"               "type/ZipCode"})
+
+;; make sure the new types are all valid
+(when-not config/is-prod?
+  (doseq [[_ t] old-special-type->new-type]
+    (assert (isa? (keyword t) :type/*))))
+
+(def ^:private ^:const old-base-type->new-type
+  {"ArrayField"      "type/Array"
+   "BigIntegerField" "type/BigInteger"
+   "BooleanField"    "type/Boolean"
+   "CharField"       "type/Text"
+   "DateField"       "type/Date"
+   "DateTimeField"   "type/DateTime"
+   "DecimalField"    "type/Decimal"
+   "DictionaryField" "type/Dictionary"
+   "FloatField"      "type/Float"
+   "IntegerField"    "type/Integer"
+   "TextField"       "type/Text"
+   "TimeField"       "type/Time"
+   "UUIDField"       "type/UUID"
+   "UnknownField"    "type/*"})
+
+(when-not config/is-prod?
+  (doseq [[_ t] old-base-type->new-type]
+    (assert (isa? (keyword t) :type/*))))
+
+(defmigration migrate-base-types
+  (doseq [[old-type new-type] old-special-type->new-type]
+    (db/update-where! 'Field {:special_type old-type}
+      :special_type new-type))
+  (doseq [[old-type new-type] old-base-type->new-type]
+    (db/update-where! 'Field {:base_type old-type}
+      :base_type new-type)))
diff --git a/src/metabase/driver.clj b/src/metabase/driver.clj
index 402d5e4ccbc65efe41b7c7a093ce74d3ac6d5d86..b1c403b12f5cab2240dd027735b93bcaf8c31c75 100644
--- a/src/metabase/driver.clj
+++ b/src/metabase/driver.clj
@@ -290,28 +290,28 @@
   "Return the `Field.base_type` that corresponds to a given class returned by the DB.
    This is used to infer the types of results that come back from native queries."
   [klass]
-  (or ({Boolean                         :BooleanField
-        Double                          :FloatField
-        Float                           :FloatField
-        Integer                         :IntegerField
-        Long                            :IntegerField
-        String                          :TextField
-        java.math.BigDecimal            :DecimalField
-        java.math.BigInteger            :BigIntegerField
-        java.sql.Date                   :DateField
-        java.sql.Timestamp              :DateTimeField
-        java.util.Date                  :DateTimeField
-        java.util.UUID                  :TextField
-        clojure.lang.PersistentArrayMap :DictionaryField
-        clojure.lang.PersistentHashMap  :DictionaryField
-        clojure.lang.PersistentVector   :ArrayField
-        org.postgresql.util.PGobject    :UnknownField} klass)
-      (condp isa? klass
-        clojure.lang.IPersistentMap     :DictionaryField
-        clojure.lang.IPersistentVector  :ArrayField
-        nil)
-      (do (log/warn (format "Don't know how to map class '%s' to a Field base_type, falling back to :UnknownField." klass))
-          :UnknownField)))
+  (or (some (fn [[mapped-class mapped-type]]
+              (when (isa? klass mapped-class)
+                mapped-type))
+            [[Boolean                        :type/Boolean]
+             [Double                         :type/Float]
+             [Float                          :type/Float]
+             [Integer                        :type/Integer]
+             [Long                           :type/Integer]
+             [java.math.BigDecimal           :type/Decimal]
+             [java.math.BigInteger           :type/BigInteger]
+             [Number                         :type/Number]
+             [String                         :type/Text]
+             [java.sql.Date                  :type/Date]
+             [java.sql.Timestamp             :type/DateTime]
+             [java.util.Date                 :type/DateTime]
+             [java.util.UUID                 :type/Text]       ; shouldn't this be :type/UUID ?
+             [clojure.lang.IPersistentMap    :type/Dictionary]
+             [clojure.lang.IPersistentVector :type/Array]
+             [org.bson.types.ObjectId        :type/MongoBSONID]
+             [org.postgresql.util.PGobject   :type/*]])
+      (log/warn (format "Don't know how to map class '%s' to a Field base_type, falling back to :type/*." klass))
+      :type/*))
 
 ;; ## Driver Lookup
 
diff --git a/src/metabase/driver/bigquery.clj b/src/metabase/driver/bigquery.clj
index af9bc2914a2c4f0ba23f4cccea402fbbe37364bb..0f2c3eccedff2f6d89dc27bf7471eb20c25287e9 100644
--- a/src/metabase/driver/bigquery.clj
+++ b/src/metabase/driver/bigquery.clj
@@ -143,12 +143,12 @@
    (execute (.get (.tables client) project-id dataset-id table-id))))
 
 (def ^:private ^:const  bigquery-type->base-type
-  {"BOOLEAN"   :BooleanField
-   "FLOAT"     :FloatField
-   "INTEGER"   :IntegerField
-   "RECORD"    :DictionaryField ; RECORD -> field has a nested schema
-   "STRING"    :TextField
-   "TIMESTAMP" :DateTimeField})
+  {"BOOLEAN"   :type/Boolean
+   "FLOAT"     :type/Float
+   "INTEGER"   :type/Integer
+   "RECORD"    :type/Dictionary ; RECORD -> field has a nested schema
+   "STRING"    :type/Text
+   "TIMESTAMP" :type/DateTime})
 
 (defn- table-schema->metabase-field-info [^TableSchema schema]
   (for [^TableFieldSchema field (.getFields schema)]
@@ -374,7 +374,7 @@
                          (and (seq schema-name) (seq field-name) (seq table-name))
                          (log/error "Don't know how to alias: " this))]}
   (cond
-    field (recur field) ; DateTimeField
+    field (recur field) ; type/DateTime
     index (name (let [{{{ag-type :aggregation-type} :aggregation} :query} sqlqp/*query*]
                   (if (= ag-type :distinct) :count
                       ag-type)))
diff --git a/src/metabase/driver/crate.clj b/src/metabase/driver/crate.clj
index 1f036cb644934a55bfb8a2239b2cb15107cffd3d..7ffad9abedbc368704f3412519372b5886785e3e 100644
--- a/src/metabase/driver/crate.clj
+++ b/src/metabase/driver/crate.clj
@@ -11,33 +11,33 @@
 (def ^:private ^:const column->base-type
   "Map of Crate column types -> Field base types
    Crate data types -> https://crate.io/docs/reference/sql/data_types.html"
-  {:integer         :IntegerField
-   :string          :TextField
-   :boolean         :BooleanField
-   :byte            :IntegerField
-   :short           :IntegerField
-   :long            :BigIntegerField
-   :float           :FloatField
-   :double          :FloatField
-   :ip              :UnknownField
-   :timestamp       :DateTimeField
-   :geo_shape       :DictionaryField
-   :geo_point       :ArrayField
-   :object          :DictionaryField
-   :array           :ArrayField
-   :object_array    :ArrayField
-   :string_array    :ArrayField
-   :integer_array   :ArrayField
-   :float_array     :ArrayField
-   :boolean_array   :ArrayField
-   :byte_array      :ArrayField
-   :timestamp_array :ArrayField
-   :short_array     :ArrayField
-   :long_array      :ArrayField
-   :double_array    :ArrayField
-   :ip_array        :ArrayField
-   :geo_shape_array :ArrayField
-   :geo_point_array :ArrayField})
+  {:integer         :type/Integer
+   :string          :type/Text
+   :boolean         :type/Boolean
+   :byte            :type/Integer
+   :short           :type/Integer
+   :long            :type/BigInteger
+   :float           :type/Float
+   :double          :type/Float
+   :ip              :type/*
+   :timestamp       :type/DateTime
+   :geo_shape       :type/Dictionary
+   :geo_point       :type/Array
+   :object          :type/Dictionary
+   :array           :type/Array
+   :object_array    :type/Array
+   :string_array    :type/Array
+   :integer_array   :type/Array
+   :float_array     :type/Array
+   :boolean_array   :type/Array
+   :byte_array      :type/Array
+   :timestamp_array :type/Array
+   :short_array     :type/Array
+   :long_array      :type/Array
+   :double_array    :type/Array
+   :ip_array        :type/Array
+   :geo_shape_array :type/Array
+   :geo_point_array :type/Array})
 
 
 (def ^:private ^:const now (hsql/call :current_timestamp 3))
diff --git a/src/metabase/driver/druid.clj b/src/metabase/driver/druid.clj
index 31a0589f14d2bf0a0701a349a32f91536aeeaa66..84b614f432b27c2a9c4d13bd06ac4f3e85c4486c 100644
--- a/src/metabase/driver/druid.clj
+++ b/src/metabase/driver/druid.clj
@@ -69,8 +69,8 @@
   ;; string-encoded booleans + dates are treated as strings (!)
   {:name      field-name
    :base-type (if (= :metric druid-field-type)
-                :FloatField
-                :TextField)})
+                :type/Float
+                :type/Text)})
 
 (defn- describe-table [database table]
   (let [details                      (:details database)
@@ -80,7 +80,7 @@
      :fields (set (concat
                     ;; every Druid table is an event stream w/ a timestamp field
                     [{:name       "timestamp"
-                      :base-type  :DateTimeField
+                      :base-type  :type/DateTime
                       :pk?        true}]
                     (map (partial describe-table-field :dimension) dimensions)
                     (map (partial describe-table-field :metric) metrics)))}))
diff --git a/src/metabase/driver/druid/query_processor.clj b/src/metabase/driver/druid/query_processor.clj
index 034adad237b93a9bf69a8319c9ddbbba010a1abc..1df740c1cdb8cbeb322250a5271f2fd64fb10ad2 100644
--- a/src/metabase/driver/druid/query_processor.clj
+++ b/src/metabase/driver/druid/query_processor.clj
@@ -59,11 +59,14 @@
    "Is this `Field`/`DateTimeField` a `:dimension` or `:metric`?"))
 
 (extend-protocol IDimensionOrMetric
-  Field         (dimension-or-metric? [this] (case (:base-type this)
-                                               :TextField    :dimension
-                                               :FloatField   :metric
-                                               :IntegerField :metric))
-  DateTimeField (dimension-or-metric? [this] (dimension-or-metric? (:field this))))
+  Field         (dimension-or-metric? [{:keys [base-type]}]
+                  (cond
+                    (isa? base-type :type/Text)    :dimension
+                    (isa? base-type :type/Float)   :metric
+                    (isa? base-type :type/Integer) :metric))
+
+  DateTimeField (dimension-or-metric? [this]
+                  (dimension-or-metric? (:field this))))
 
 
 (def ^:private ^:const query-type->default-query
diff --git a/src/metabase/driver/generic_sql.clj b/src/metabase/driver/generic_sql.clj
index 4f4aafcbefb490337c7ac4f924b3781e9f0715c2..05a983a3ab55afff4868fa0c7b2e4c5698c0daa9 100644
--- a/src/metabase/driver/generic_sql.clj
+++ b/src/metabase/driver/generic_sql.clj
@@ -46,7 +46,7 @@
 
   (column->special-type ^clojure.lang.Keyword [this, ^String column-name, ^Keyword column-type]
     "*OPTIONAL*. Attempt to determine the special-type of a field given the column name and native type.
-     For example, the Postgres driver can mark Postgres JSON type columns as `:json` special type.")
+     For example, the Postgres driver can mark Postgres JSON type columns as `:type/SerializedJSON` special type.")
 
   (connection-details->spec [this, ^Map details-map]
     "Given a `Database` DETAILS-MAP, return a JDBC connection spec.")
@@ -215,7 +215,7 @@
         pk-field       (field/Field (table/pk-field-id table))
         pk-field-k     (when pk-field
                          (qualify+escape table pk-field))
-        transform-fn   (if (contains? #{:TextField :CharField} (:base_type field))
+        transform-fn   (if (isa? (:base_type field) :type/Text)
                          u/jdbc-clob->str
                          identity)
         select*        {:select   [[field-k :field]]                ; if we don't specify an explicit ORDER BY some DBs like Redshift will return them in a (seemingly) random order
@@ -338,9 +338,11 @@
          (merge {:name      column_name
                  :custom    {:column-type type_name}
                  :base-type (or (column->base-type driver (keyword type_name))
-                                (do (log/warn (format "Don't know how to map column type '%s' to a Field base_type, falling back to :UnknownField." type_name))
-                                    :UnknownField))}
+                                (do (log/warn (format "Don't know how to map column type '%s' to a Field base_type, falling back to :type/*." type_name))
+                                    :type/*))}
                 (when calculated-special-type
+                  (assert (isa? calculated-special-type :type/*)
+                    (str "Invalid type: " calculated-special-type))
                   {:special-type calculated-special-type})))))
 
 (defn- add-table-pks
diff --git a/src/metabase/driver/generic_sql/query_processor.clj b/src/metabase/driver/generic_sql/query_processor.clj
index 4e84e8fc58bf16aa4b5bbab4ab73c85cb2724a05..3bc2113e9c15fa71b3298a73b2e010b098be47ce 100644
--- a/src/metabase/driver/generic_sql/query_processor.clj
+++ b/src/metabase/driver/generic_sql/query_processor.clj
@@ -76,10 +76,10 @@
   Field
   (formatted [{:keys [schema-name table-name special-type field-name]}]
     (let [field (keyword (hx/qualify-and-escape-dots schema-name table-name field-name))]
-      (case special-type
-        :timestamp_seconds      (sql/unix-timestamp->timestamp (driver) field :seconds)
-        :timestamp_milliseconds (sql/unix-timestamp->timestamp (driver) field :milliseconds)
-        field)))
+      (cond
+        (isa? special-type :type/UNIXTimestampSeconds)      (sql/unix-timestamp->timestamp (driver) field :seconds)
+        (isa? special-type :type/UNIXTimestampMilliseconds) (sql/unix-timestamp->timestamp (driver) field :milliseconds)
+        :else                                               field)))
 
   DateTimeField
   (formatted [{unit :unit, field :field}]
diff --git a/src/metabase/driver/h2.clj b/src/metabase/driver/h2.clj
index 9e710c69ce1d1f08bd45c034583ac39647e2f3a2..858e16154ddbe4e3d41e752d40254668f6933360 100644
--- a/src/metabase/driver/h2.clj
+++ b/src/metabase/driver/h2.clj
@@ -1,6 +1,7 @@
 (ns metabase.driver.h2
   ;; TODO - This namespace should be reworked to use `u/drop-first-arg` like newer drivers
-  (:require [clojure.string :as s]
+  (:require [clojure.java.jdbc :as jdbc]
+            [clojure.string :as s]
             [honeysql.core :as hsql]
             [metabase.db :as db]
             [metabase.db.spec :as dbspec]
@@ -9,69 +10,69 @@
             [metabase.util :as u]
             [metabase.util.honeysql-extensions :as hx]))
 
-(defn- column->base-type [_ column-type]
-  ({:ARRAY                       :UnknownField
-     :BIGINT                      :BigIntegerField
-     :BINARY                      :UnknownField
-     :BIT                         :BooleanField
-     :BLOB                        :UnknownField
-     :BOOL                        :BooleanField
-     :BOOLEAN                     :BooleanField
-     :BYTEA                       :UnknownField
-     :CHAR                        :CharField
-     :CHARACTER                   :CharField
-     :CLOB                        :TextField
-     :DATE                        :DateField
-     :DATETIME                    :DateTimeField
-     :DEC                         :DecimalField
-     :DECIMAL                     :DecimalField
-     :DOUBLE                      :FloatField
-     :FLOAT                       :FloatField
-     :FLOAT4                      :FloatField
-     :FLOAT8                      :FloatField
-     :GEOMETRY                    :UnknownField
-     :IDENTITY                    :IntegerField
-     :IMAGE                       :UnknownField
-     :INT                         :IntegerField
-     :INT2                        :IntegerField
-     :INT4                        :IntegerField
-     :INT8                        :BigIntegerField
-     :INTEGER                     :IntegerField
-     :LONGBLOB                    :UnknownField
-     :LONGTEXT                    :TextField
-     :LONGVARBINARY               :UnknownField
-     :LONGVARCHAR                 :TextField
-     :MEDIUMBLOB                  :UnknownField
-     :MEDIUMINT                   :IntegerField
-     :MEDIUMTEXT                  :TextField
-     :NCHAR                       :CharField
-     :NCLOB                       :TextField
-     :NTEXT                       :TextField
-     :NUMBER                      :DecimalField
-     :NUMERIC                     :DecimalField
-     :NVARCHAR                    :TextField
-     :NVARCHAR2                   :TextField
-     :OID                         :UnknownField
-     :OTHER                       :UnknownField
-     :RAW                         :UnknownField
-     :REAL                        :FloatField
-     :SIGNED                      :IntegerField
-     :SMALLDATETIME               :DateTimeField
-     :SMALLINT                    :IntegerField
-     :TEXT                        :TextField
-     :TIME                        :TimeField
-     :TIMESTAMP                   :DateTimeField
-     :TINYBLOB                    :UnknownField
-     :TINYINT                     :IntegerField
-     :TINYTEXT                    :TextField
-     :UUID                        :TextField
-     :VARBINARY                   :UnknownField
-     :VARCHAR                     :TextField
-     :VARCHAR2                    :TextField
-     :VARCHAR_CASESENSITIVE       :TextField
-     :VARCHAR_IGNORECASE          :TextField
-     :YEAR                        :IntegerField
-    (keyword "DOUBLE PRECISION") :FloatField} column-type))
+(def ^:private ^:const column->base-type
+  {:ARRAY                       :type/*
+   :BIGINT                      :type/BigInteger
+   :BINARY                      :type/*
+   :BIT                         :type/Boolean
+   :BLOB                        :type/*
+   :BOOL                        :type/Boolean
+   :BOOLEAN                     :type/Boolean
+   :BYTEA                       :type/*
+   :CHAR                        :type/Text
+   :CHARACTER                   :type/Text
+   :CLOB                        :type/Text
+   :DATE                        :type/Date
+   :DATETIME                    :type/DateTime
+   :DEC                         :type/Decimal
+   :DECIMAL                     :type/Decimal
+   :DOUBLE                      :type/Float
+   :FLOAT                       :type/Float
+   :FLOAT4                      :type/Float
+   :FLOAT8                      :type/Float
+   :GEOMETRY                    :type/*
+   :IDENTITY                    :type/Integer
+   :IMAGE                       :type/*
+   :INT                         :type/Integer
+   :INT2                        :type/Integer
+   :INT4                        :type/Integer
+   :INT8                        :type/BigInteger
+   :INTEGER                     :type/Integer
+   :LONGBLOB                    :type/*
+   :LONGTEXT                    :type/Text
+   :LONGVARBINARY               :type/*
+   :LONGVARCHAR                 :type/Text
+   :MEDIUMBLOB                  :type/*
+   :MEDIUMINT                   :type/Integer
+   :MEDIUMTEXT                  :type/Text
+   :NCHAR                       :type/Text
+   :NCLOB                       :type/Text
+   :NTEXT                       :type/Text
+   :NUMBER                      :type/Decimal
+   :NUMERIC                     :type/Decimal
+   :NVARCHAR                    :type/Text
+   :NVARCHAR2                   :type/Text
+   :OID                         :type/*
+   :OTHER                       :type/*
+   :RAW                         :type/*
+   :REAL                        :type/Float
+   :SIGNED                      :type/Integer
+   :SMALLDATETIME               :type/DateTime
+   :SMALLINT                    :type/Integer
+   :TEXT                        :type/Text
+   :TIME                        :type/Time
+   :TIMESTAMP                   :type/DateTime
+   :TINYBLOB                    :type/*
+   :TINYINT                     :type/Integer
+   :TINYTEXT                    :type/Text
+   :UUID                        :type/Text
+   :VARBINARY                   :type/*
+   :VARCHAR                     :type/Text
+   :VARCHAR2                    :type/Text
+   :VARCHAR_CASESENSITIVE       :type/Text
+   :VARCHAR_IGNORECASE          :type/Text
+   :YEAR                        :type/Integer
+   (keyword "DOUBLE PRECISION") :type/Float})
 
 
 ;; These functions for exploding / imploding the options in the connection strings are here so we can override shady options
@@ -118,9 +119,8 @@
              (hsql/raw "timestamp '1970-01-01T00:00:00Z'")))
 
 
-(defn- process-query-in-context [_ qp]
-  (fn [{query-type :type, :as query}]
-    {:pre [query-type]}
+(defn- check-native-query-not-using-default-user [{query-type :type, :as query}]
+  (u/prog1 query
     ;; For :native queries check to make sure the DB in question has a (non-default) NAME property specified in the connection string.
     ;; We don't allow SQL execution on H2 databases for the default admin account for security reasons
     (when (= (keyword query-type) :native)
@@ -129,9 +129,11 @@
             [_ options]    (connection-string->file+options db)
             {:strs [USER]} options]
         (when (or (s/blank? USER)
-                  (= USER "sa")) ; "sa" is the default USER
-          (throw (Exception. "Running SQL queries against H2 databases using the default (admin) database user is forbidden.")))))
-    (qp query)))
+                  (= USER "sa"))        ; "sa" is the default USER
+          (throw (Exception. "Running SQL queries against H2 databases using the default (admin) database user is forbidden.")))))))
+
+(defn- process-query-in-context [_ qp]
+  (comp qp check-native-query-not-using-default-user))
 
 
 ;; H2 doesn't have date_trunc() we fake it by formatting a date to an appropriate string
@@ -215,7 +217,7 @@
   sql/ISQLDriver
   (merge (sql/ISQLDriverDefaultsMixin)
          {:active-tables             sql/post-filtered-active-tables
-          :column->base-type         column->base-type
+          :column->base-type         (u/drop-first-arg column->base-type)
           :connection-details->spec  connection-details->spec
           :date                      date
           :string-length-fn          (u/drop-first-arg string-length-fn)
diff --git a/src/metabase/driver/mongo.clj b/src/metabase/driver/mongo.clj
index 9dccabc2dd56b89cfa88f95728fa9a906e1ba94e..d8a5a2eeda437e8507bb5295ca7f29e4baa76c10 100644
--- a/src/metabase/driver/mongo.clj
+++ b/src/metabase/driver/mongo.clj
@@ -59,14 +59,14 @@
   (cond
     ;; 1. url?
     (and (string? field-value)
-         (u/is-url? field-value)) :url
+         (u/is-url? field-value)) :type/URL
     ;; 2. json?
     (and (string? field-value)
          (or (.startsWith "{" field-value)
              (.startsWith "[" field-value))) (when-let [j (u/try-apply json/parse-string field-value)]
                                            (when (or (map? j)
                                                      (sequential? j))
-                                             :json))))
+                                             :type/SerializedJSON))))
 
 (defn- find-nested-fields [field-value nested-fields]
   (loop [[k & more-keys] (keys field-value)
@@ -91,7 +91,7 @@
                                  (update special-types st safe-inc)
                                  special-types)))
       (update :nested-fields (fn [nested-fields]
-                               (if (isa? (type field-value) clojure.lang.IPersistentMap)
+                               (if (map? field-value)
                                  (find-nested-fields field-value nested-fields)
                                  nested-fields)))))
 
diff --git a/src/metabase/driver/mongo/query_processor.clj b/src/metabase/driver/mongo/query_processor.clj
index bd9ea858bd25f4e5c83d9213ec527676f7ad3a19..a315c7c5ae3a20365ba025184be6d624a7002244 100644
--- a/src/metabase/driver/mongo/query_processor.clj
+++ b/src/metabase/driver/mongo/query_processor.clj
@@ -103,10 +103,10 @@
     (mongo-let [field (as-> field <>
                         (->initial-rvalue <>)
                         (cond
-                          (= special-type :timestamp_milliseconds)
+                          (isa? special-type :type/UNIXTimestampMilliseconds)
                           {$add [(java.util.Date. 0) <>]}
 
-                          (= special-type :timestamp_seconds)
+                          (isa? special-type :type/UNIXTimestampSeconds)
                           {$add [(java.util.Date. 0) {$multiply [<> 1000]}]}
 
                           :else <>))]
@@ -148,6 +148,7 @@
                                        3]})
           :year            {$year field})))))
 
+
 (extend-protocol IRValue
   nil (->rvalue [_] nil)
 
@@ -160,10 +161,9 @@
     (str \$ (->lvalue this)))
 
   Value
-  (->rvalue [{value :value, {:keys [field-name base-type]} :field}]
-    (if (and (= field-name "_id")
-             (= base-type  :UnknownField))
-      `(ObjectId. ~value)
+  (->rvalue [{value :value, {:keys [base-type]} :field}]
+    (if (isa? base-type :type/MongoBSONID)
+      (ObjectId. (str value))
       value))
 
   DateTimeValue
@@ -195,7 +195,7 @@
   RelativeDateTimeValue
   (->rvalue [{:keys [amount unit field]}]
     (->rvalue (map->DateTimeValue {:value (u/relative-date (or unit :day) amount)
-                                       :field field}))))
+                                   :field field}))))
 
 
 ;;; ## CLAUSE APPLICATION
diff --git a/src/metabase/driver/mongo/util.clj b/src/metabase/driver/mongo/util.clj
index 0c4efb106d9690db185fc3a60efc3b90cd52c0cf..b4dfcb5b5836c853c792124f7cf3bb303e8763d9 100644
--- a/src/metabase/driver/mongo/util.clj
+++ b/src/metabase/driver/mongo/util.clj
@@ -85,8 +85,9 @@
   [[binding database] & body]
   `(let [f# (fn [~binding]
               ~@body)]
-     (if *mongo-connection* (f# *mongo-connection*)
-         (-with-mongo-connection f# ~database))))
+     (if *mongo-connection*
+       (f# *mongo-connection*)
+       (-with-mongo-connection f# ~database))))
 
 ;; TODO - this isn't neccesarily Mongo-specific; consider moving
 (defn values->base-type
@@ -109,4 +110,4 @@
            last                     ; last result will be tuple with highest count
            first                    ; keep just the type
            driver/class->base-type) ; convert to Field base_type
-      :UnknownField))
+      :type/*))
diff --git a/src/metabase/driver/mysql.clj b/src/metabase/driver/mysql.clj
index 4a279c0b4292761259edb5c28bc1fb4af3fe4392..9b7745cd575395ae6d6508cf5c7986f1488dedd7 100644
--- a/src/metabase/driver/mysql.clj
+++ b/src/metabase/driver/mysql.clj
@@ -11,37 +11,37 @@
 ;;; # IMPLEMENTATION
 
 (defn- column->base-type [column-type]
-  ({:BIGINT     :BigIntegerField
-    :BINARY     :UnknownField
-    :BIT        :BooleanField
-    :BLOB       :UnknownField
-    :CHAR       :CharField
-    :DATE       :DateField
-    :DATETIME   :DateTimeField
-    :DECIMAL    :DecimalField
-    :DOUBLE     :FloatField
-    :ENUM       :UnknownField
-    :FLOAT      :FloatField
-    :INT        :IntegerField
-    :INTEGER    :IntegerField
-    :LONGBLOB   :UnknownField
-    :LONGTEXT   :TextField
-    :MEDIUMBLOB :UnknownField
-    :MEDIUMINT  :IntegerField
-    :MEDIUMTEXT :TextField
-    :NUMERIC    :DecimalField
-    :REAL       :FloatField
-    :SET        :UnknownField
-    :SMALLINT   :IntegerField
-    :TEXT       :TextField
-    :TIME       :TimeField
-    :TIMESTAMP  :DateTimeField
-    :TINYBLOB   :UnknownField
-    :TINYINT    :IntegerField
-    :TINYTEXT   :TextField
-    :VARBINARY  :UnknownField
-    :VARCHAR    :TextField
-    :YEAR       :IntegerField} (keyword (s/replace (name column-type) #"\sUNSIGNED$" "")))) ; strip off " UNSIGNED" from end if present
+  ({:BIGINT     :type/BigInteger
+    :BINARY     :type/*
+    :BIT        :type/Boolean
+    :BLOB       :type/*
+    :CHAR       :type/Text
+    :DATE       :type/Date
+    :DATETIME   :type/DateTime
+    :DECIMAL    :type/Decimal
+    :DOUBLE     :type/Float
+    :ENUM       :type/*
+    :FLOAT      :type/Float
+    :INT        :type/Integer
+    :INTEGER    :type/Integer
+    :LONGBLOB   :type/*
+    :LONGTEXT   :type/Text
+    :MEDIUMBLOB :type/*
+    :MEDIUMINT  :type/Integer
+    :MEDIUMTEXT :type/Text
+    :NUMERIC    :type/Decimal
+    :REAL       :type/Float
+    :SET        :type/*
+    :SMALLINT   :type/Integer
+    :TEXT       :type/Text
+    :TIME       :type/Time
+    :TIMESTAMP  :type/DateTime
+    :TINYBLOB   :type/*
+    :TINYINT    :type/Integer
+    :TINYTEXT   :type/Text
+    :VARBINARY  :type/*
+    :VARCHAR    :type/Text
+    :YEAR       :type/Integer} (keyword (s/replace (name column-type) #"\sUNSIGNED$" "")))) ; strip off " UNSIGNED" from end if present
 
 (def ^:private ^:const connection-args
   "Map of args for the MySQL JDBC connection string.
diff --git a/src/metabase/driver/oracle.clj b/src/metabase/driver/oracle.clj
index 7132ccc5a1f78133bc0485bf29a704915c97b279..76823e19bde4f1c78f491f0f1f15568b9826dc0f 100644
--- a/src/metabase/driver/oracle.clj
+++ b/src/metabase/driver/oracle.clj
@@ -14,31 +14,31 @@
 
 (def ^:private ^:const pattern->type
   [;; Any types -- see http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i107578
-   [#"ANYDATA"     :UnknownField]  ; Instance of a given type with data plus a description of the type (?)
-   [#"ANYTYPE"     :UnknownField]  ; Can be any named SQL type or an unnamed transient type
-   [#"ARRAY"       :UnknownField]
-   [#"BFILE"       :UnknownField]
-   [#"BLOB"        :UnknownField]
-   [#"RAW"         :UnknownField]
-   [#"CHAR"        :TextField]
-   [#"CLOB"        :TextField]
-   [#"DATE"        :DateField]
-   [#"DOUBLE"      :FloatField]
-   [#"^EXPRESSION" :UnknownField]  ; Expression filter type
-   [#"FLOAT"       :FloatField]
-   [#"INTERVAL"    :DateTimeField] ; Does this make sense?
-   [#"LONG RAW"    :UnknownField]
-   [#"LONG"        :TextField]
-   [#"^ORD"        :UnknownField]  ; Media types -- http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i121058
-   [#"NUMBER"      :DecimalField]
-   [#"REAL"        :FloatField]
-   [#"REF"         :UnknownField]
-   [#"ROWID"       :UnknownField]
-   [#"^SDO_"       :UnknownField]  ; Spatial types -- see http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i107588
-   [#"STRUCT"      :UnknownField]
-   [#"TIMESTAMP"   :DateTimeField]
-   [#"URI"         :TextField]
-   [#"XML"         :UnknownField]])
+   [#"ANYDATA"     :type/*]  ; Instance of a given type with data plus a description of the type (?)
+   [#"ANYTYPE"     :type/*]  ; Can be any named SQL type or an unnamed transient type
+   [#"ARRAY"       :type/*]
+   [#"BFILE"       :type/*]
+   [#"BLOB"        :type/*]
+   [#"RAW"         :type/*]
+   [#"CHAR"        :type/Text]
+   [#"CLOB"        :type/Text]
+   [#"DATE"        :type/Date]
+   [#"DOUBLE"      :type/Float]
+   [#"^EXPRESSION" :type/*]  ; Expression filter type
+   [#"FLOAT"       :type/Float]
+   [#"INTERVAL"    :type/DateTime] ; Does this make sense?
+   [#"LONG RAW"    :type/*]
+   [#"LONG"        :type/Text]
+   [#"^ORD"        :type/*]  ; Media types -- http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i121058
+   [#"NUMBER"      :type/Decimal]
+   [#"REAL"        :type/Float]
+   [#"REF"         :type/*]
+   [#"ROWID"       :type/*]
+   [#"^SDO_"       :type/*]  ; Spatial types -- see http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i107588
+   [#"STRUCT"      :type/*]
+   [#"TIMESTAMP"   :type/DateTime]
+   [#"URI"         :type/Text]
+   [#"XML"         :type/*]])
 
 (defn- connection-details->spec [{:keys [sid], :as details}]
   (update (dbspec/oracle details) :subname (u/rpartial str \: sid)))
diff --git a/src/metabase/driver/postgres.clj b/src/metabase/driver/postgres.clj
index 93eec8e807565268345a763233cc16c8636b59a6..0a015841f1af3f66690709f340a7253d9211b276 100644
--- a/src/metabase/driver/postgres.clj
+++ b/src/metabase/driver/postgres.clj
@@ -12,76 +12,79 @@
             [metabase.util.honeysql-extensions :as hx])
   ;; This is necessary for when NonValidatingFactory is passed in the sslfactory connection string argument,
   ;; e.x. when connecting to a Heroku Postgres database from outside of Heroku.
-  (:import org.postgresql.ssl.NonValidatingFactory))
+  (:import java.util.UUID
+           org.postgresql.ssl.NonValidatingFactory))
 
 (defn- column->base-type
   "Map of Postgres column types -> Field base types.
    Add more mappings here as you come across them."
   [column-type]
-  ({:bigint        :BigIntegerField
-    :bigserial     :BigIntegerField
-    :bit           :UnknownField
-    :bool          :BooleanField
-    :boolean       :BooleanField
-    :box           :UnknownField
-    :bpchar        :CharField       ; "blank-padded char" is the internal name of "character"
-    :bytea         :UnknownField    ; byte array
-    :cidr          :TextField       ; IPv4/IPv6 network address
-    :circle        :UnknownField
-    :date          :DateField
-    :decimal       :DecimalField
-    :float4        :FloatField
-    :float8        :FloatField
-    :geometry      :UnknownField
-    :inet          :TextField
-    :int           :IntegerField
-    :int2          :IntegerField
-    :int4          :IntegerField
-    :int8          :BigIntegerField
-    :interval      :UnknownField    ; time span
-    :json          :TextField
-    :jsonb         :TextField
-    :line          :UnknownField
-    :lseg          :UnknownField
-    :macaddr       :TextField
-    :money         :DecimalField
-    :numeric       :DecimalField
-    :path          :UnknownField
-    :pg_lsn        :IntegerField    ; PG Log Sequence #
-    :point         :UnknownField
-    :real          :FloatField
-    :serial        :IntegerField
-    :serial2       :IntegerField
-    :serial4       :IntegerField
-    :serial8       :BigIntegerField
-    :smallint      :IntegerField
-    :smallserial   :IntegerField
-    :text          :TextField
-    :time          :TimeField
-    :timetz        :TimeField
-    :timestamp     :DateTimeField
-    :timestamptz   :DateTimeField
-    :tsquery       :UnknownField
-    :tsvector      :UnknownField
-    :txid_snapshot :UnknownField
-    :uuid          :UUIDField
-    :varbit        :UnknownField
-    :varchar       :TextField
-    :xml           :TextField
-    (keyword "bit varying")                :UnknownField
-    (keyword "character varying")          :TextField
-    (keyword "double precision")           :FloatField
-    (keyword "time with time zone")        :TimeField
-    (keyword "time without time zone")     :TimeField
-    (keyword "timestamp with timezone")    :DateTimeField
-    (keyword "timestamp without timezone") :DateTimeField} column-type))
+  ({:bigint        :type/BigInteger
+    :bigserial     :type/BigInteger
+    :bit           :type/*
+    :bool          :type/Boolean
+    :boolean       :type/Boolean
+    :box           :type/*
+    :bpchar        :type/Text       ; "blank-padded char" is the internal name of "character"
+    :bytea         :type/*          ; byte array
+    :cidr          :type/Text       ; IPv4/IPv6 network address
+    :circle        :type/*
+    :date          :type/Date
+    :decimal       :type/Decimal
+    :float4        :type/Float
+    :float8        :type/Float
+    :geometry      :type/*
+    :inet          :type/IPAddress
+    :int           :type/Integer
+    :int2          :type/Integer
+    :int4          :type/Integer
+    :int8          :type/BigInteger
+    :interval      :type/*          ; time span
+    :json          :type/Text
+    :jsonb         :type/Text
+    :line          :type/*
+    :lseg          :type/*
+    :macaddr       :type/Text
+    :money         :type/Decimal
+    :numeric       :type/Decimal
+    :path          :type/*
+    :pg_lsn        :type/Integer    ; PG Log Sequence #
+    :point         :type/*
+    :real          :type/Float
+    :serial        :type/Integer
+    :serial2       :type/Integer
+    :serial4       :type/Integer
+    :serial8       :type/BigInteger
+    :smallint      :type/Integer
+    :smallserial   :type/Integer
+    :text          :type/Text
+    :time          :type/Time
+    :timetz        :type/Time
+    :timestamp     :type/DateTime
+    :timestamptz   :type/DateTime
+    :tsquery       :type/*
+    :tsvector      :type/*
+    :txid_snapshot :type/*
+    :uuid          :type/UUID
+    :varbit        :type/*
+    :varchar       :type/Text
+    :xml           :type/Text
+    (keyword "bit varying")                :type/*
+    (keyword "character varying")          :type/Text
+    (keyword "double precision")           :type/Float
+    (keyword "time with time zone")        :type/Time
+    (keyword "time without time zone")     :type/Time
+    (keyword "timestamp with timezone")    :type/DateTime
+    (keyword "timestamp without timezone") :type/DateTime} column-type))
 
 (defn- column->special-type
   "Attempt to determine the special-type of a Field given its name and Postgres column type."
   [column-name column-type]
-  ;; this is really, really simple right now.  if its postgres :json type then it's :json special-type
-  (when (= column-type :json)
-    :json))
+  ;; this is really, really simple right now.  if its postgres :json type then it's :type/SerializedJSON special-type
+  (case column-type
+    :json :type/SerializedJSON
+    :inet :type/IPAddress
+    nil))
 
 (def ^:const ssl-params
   "Params to include in the JDBC connection spec for an SSL connection."
@@ -167,10 +170,12 @@
     message))
 
 (defn- prepare-value [{value :value, {:keys [base-type]} :field}]
-  (if (and (= base-type :UUIDField)
-           value)
-    (java.util.UUID/fromString value)
-    value))
+  (if-not value
+    value
+    (cond
+      (isa? base-type :type/UUID)      (UUID/fromString value)
+      (isa? base-type :type/IPAddress) (hx/cast :inet value)
+      :else                            value)))
 
 
 (defn- materialized-views
diff --git a/src/metabase/driver/sqlite.clj b/src/metabase/driver/sqlite.clj
index d65bc4509ff525bd0a216d742c57bfbf8055f681..995aa22d5e68bd8e8eb5795cc317a5b434b1707e 100644
--- a/src/metabase/driver/sqlite.clj
+++ b/src/metabase/driver/sqlite.clj
@@ -14,21 +14,21 @@
 ;; because SQLite types can have optional lengths, e.g. NVARCHAR(100) or NUMERIC(10,5)
 ;; See also http://www.sqlite.org/datatype3.html
 (def ^:private ^:const pattern->type
-  [[#"BIGINT"   :BigIntegerField]
-   [#"BIG INT"  :BigIntegerField]
-   [#"INT"      :IntegerField]
-   [#"CHAR"     :TextField]
-   [#"TEXT"     :TextField]
-   [#"CLOB"     :TextField]
-   [#"BLOB"     :UnknownField]
-   [#"REAL"     :FloatField]
-   [#"DOUB"     :FloatField]
-   [#"FLOA"     :FloatField]
-   [#"NUMERIC"  :FloatField]
-   [#"DECIMAL"  :DecimalField]
-   [#"BOOLEAN"  :BooleanField]
-   [#"DATETIME" :DateTimeField]
-   [#"DATE"     :DateField]])
+  [[#"BIGINT"   :type/BigInteger]
+   [#"BIG INT"  :type/BigInteger]
+   [#"INT"      :type/Integer]
+   [#"CHAR"     :type/Text]
+   [#"TEXT"     :type/Text]
+   [#"CLOB"     :type/Text]
+   [#"BLOB"     :type/*]
+   [#"REAL"     :type/Float]
+   [#"DOUB"     :type/Float]
+   [#"FLOA"     :type/Float]
+   [#"NUMERIC"  :type/Float]
+   [#"DECIMAL"  :type/Decimal]
+   [#"BOOLEAN"  :type/Boolean]
+   [#"DATETIME" :type/DateTime]
+   [#"DATE"     :type/Date]])
 
 ;; register the SQLite concatnation operator `||` with HoneySQL as `sqlite-concat`
 ;; (hsql/format (hsql/call :sqlite-concat :a :b)) -> "(a || b)"
diff --git a/src/metabase/driver/sqlserver.clj b/src/metabase/driver/sqlserver.clj
index ace23e6cac805ca9ebbab67802cbacc0fb28ac8b..140691c758465b28ae3d38d97068452268dd4550 100644
--- a/src/metabase/driver/sqlserver.clj
+++ b/src/metabase/driver/sqlserver.clj
@@ -11,42 +11,42 @@
 (defn- column->base-type
   "See [this page](https://msdn.microsoft.com/en-us/library/ms187752.aspx) for details."
   [column-type]
-  ({:bigint           :BigIntegerField
-     :binary           :UnknownField
-     :bit              :BooleanField ; actually this is 1 / 0 instead of true / false ...
-     :char             :CharField
-     :cursor           :UnknownField
-     :date             :DateField
-     :datetime         :DateTimeField
-     :datetime2        :DateTimeField
-     :datetimeoffset   :DateTimeField
-     :decimal          :DecimalField
-     :float            :FloatField
-     :geography        :UnknownField
-     :geometry         :UnknownField
-     :hierarchyid      :UnknownField
-     :image            :UnknownField
-     :int              :IntegerField
-     :money            :DecimalField
-     :nchar            :CharField
-     :ntext            :TextField
-     :numeric          :DecimalField
-     :nvarchar         :TextField
-     :real             :FloatField
-     :smalldatetime    :DateTimeField
-     :smallint         :IntegerField
-     :smallmoney       :DecimalField
-     :sql_variant      :UnknownField
-     :table            :UnknownField
-     :text             :TextField
-     :time             :TimeField
-     :timestamp        :UnknownField ; not a standard SQL timestamp, see https://msdn.microsoft.com/en-us/library/ms182776.aspx
-     :tinyint          :IntegerField
-     :uniqueidentifier :UUIDField
-     :varbinary        :UnknownField
-     :varchar          :TextField
-     :xml              :UnknownField
-     (keyword "int identity") :IntegerField} column-type)) ; auto-incrementing integer (ie pk) field
+  ({:bigint           :type/BigInteger
+    :binary           :type/*
+    :bit              :type/Boolean ; actually this is 1 / 0 instead of true / false ...
+    :char             :type/Text
+    :cursor           :type/*
+    :date             :type/Date
+    :datetime         :type/DateTime
+    :datetime2        :type/DateTime
+    :datetimeoffset   :type/DateTime
+    :decimal          :type/Decimal
+    :float            :type/Float
+    :geography        :type/*
+    :geometry         :type/*
+    :hierarchyid      :type/*
+    :image            :type/*
+    :int              :type/Integer
+    :money            :type/Decimal
+    :nchar            :type/Text
+    :ntext            :type/Text
+    :numeric          :type/Decimal
+    :nvarchar         :type/Text
+    :real             :type/Float
+    :smalldatetime    :type/DateTime
+    :smallint         :type/Integer
+    :smallmoney       :type/Decimal
+    :sql_variant      :type/*
+    :table            :type/*
+    :text             :type/Text
+    :time             :type/Time
+    :timestamp        :type/* ; not a standard SQL timestamp, see https://msdn.microsoft.com/en-us/library/ms182776.aspx
+    :tinyint          :type/Integer
+    :uniqueidentifier :type/UUID
+    :varbinary        :type/*
+    :varchar          :type/Text
+    :xml              :type/*
+    (keyword "int identity") :type/Integer} column-type)) ; auto-incrementing integer (ie pk) field
 
 (defn- connection-details->spec [{:keys [domain instance ssl], :as details}]
   (-> ;; Having the `:ssl` key present, even if it is `false`, will make the driver attempt to connect with SSL
diff --git a/src/metabase/models/database.clj b/src/metabase/models/database.clj
index c962f307f0fd1c7bf743e3ef30fcc2aa8dff7e36..cc0a05b3a3b903be88c439f7ff3c51a1c7e47fa7 100644
--- a/src/metabase/models/database.clj
+++ b/src/metabase/models/database.clj
@@ -34,7 +34,7 @@
   [{:keys [id]}]
   (let [table-ids (db/select-ids 'Table, :db_id id, :active true)]
     (when (seq table-ids)
-      (db/select 'Field, :table_id [:in table-ids], :special_type "id"))))
+      (db/select 'Field, :table_id [:in table-ids], :special_type (db/isa :type/PK)))))
 
 
 (u/strict-extend (class Database)
diff --git a/src/metabase/models/field.clj b/src/metabase/models/field.clj
index 935c74a6746c9cc4df5f210c676fa7d2838434ba..454c342e57df70ec3d1d673d2391afc9043004cf 100644
--- a/src/metabase/models/field.clj
+++ b/src/metabase/models/field.clj
@@ -3,6 +3,7 @@
                      [string :as s])
             [metabase.config :as config]
             [metabase.db :as db]
+            metabase.types
             (metabase.models [field-values :refer [FieldValues]]
                              [humanization :as humanization]
                              [interface :as i])
@@ -11,44 +12,6 @@
 
 ;;; ------------------------------------------------------------ Type Mappings ------------------------------------------------------------
 
-(def ^:const special-types
-  "Possible values for `Field.special_type`."
-  #{:avatar
-    :category
-    :city
-    :country
-    :desc
-    :fk
-    :id
-    :image
-    :json
-    :latitude
-    :longitude
-    :name
-    :number
-    :state
-    :timestamp_milliseconds
-    :timestamp_seconds
-    :url
-    :zip_code})
-
-(def ^:const base-types
-  "Possible values for `Field.base_type`."
-  #{:ArrayField
-    :BigIntegerField
-    :BooleanField
-    :CharField
-    :DateField
-    :DateTimeField
-    :DecimalField
-    :DictionaryField
-    :FloatField
-    :IntegerField
-    :TextField
-    :TimeField
-    :UUIDField      ; e.g. a Postgres 'UUID' column
-    :UnknownField})
-
 (def ^:const visibility-types
   "Possible values for `Field.visibility_type`."
   #{:normal         ; Default setting.  field has no visibility restrictions.
@@ -58,21 +21,6 @@
     :retired})      ; For fields that no longer exist in the physical db.  automatically set by Metabase.  QP should error if encountered in a query.
 
 
-(def ^:const special-type->valid-base-types
-  "Map of special types to set of base types that are allowed to have that special type.
-   Special types not included in this map can be applied to any base type."
-  (let [numeric-base-types #{:BigIntegerField :DecimalField :FloatField :IntegerField}]
-    {:timestamp_seconds      numeric-base-types
-     :timestamp_milliseconds numeric-base-types}))
-
-(defn valid-special-type-for-base-type?
-  "Can SPECIAL-TYPE be used for this BASE-TYPE?"
-  ^Boolean [special-type base-type]
-  (let [valid-base-types (special-type->valid-base-types (keyword special-type))]
-    (or (not valid-base-types)
-        (contains? valid-base-types (keyword base-type)))))
-
-
 
 ;;; ------------------------------------------------------------ Entity & Lifecycle ------------------------------------------------------------
 
@@ -80,7 +28,7 @@
 
 (defn- assert-valid-special-type [{special-type :special_type}]
   (when special-type
-    (assert (contains? special-types (keyword special-type))
+    (assert (isa? (keyword special-type) :type/*)
       (str "Invalid special type: " special-type))))
 
 (defn- pre-insert [field]
@@ -118,7 +66,7 @@
 (defn target
   "Return the FK target `Field` that this `Field` points to."
   [{:keys [special_type fk_target_field_id]}]
-  (when (and (= :fk special_type)
+  (when (and (isa? special_type :type/FK)
              fk_target_field_id)
     (Field fk_target_field_id)))
 
@@ -142,7 +90,7 @@
   {:batched-hydrate :target}
   [fields]
   (let [target-field-ids (set (for [field fields
-                                    :when (and (= :fk (:special_type field))
+                                    :when (and (isa? (:special_type field) :type/FK)
                                                (:fk_target_field_id field))]
                                 (:fk_target_field_id field)))
         id->target-field (u/key-by :id (when (seq target-field-ids)
@@ -183,62 +131,62 @@
 
    *  Convert field name to lowercase before matching against a pattern
    *  Consider a nil set-of-valid-base-types to mean \"match any base type\""
-  (let [bool-or-int #{:BooleanField :BigIntegerField :IntegerField}
-        float       #{:DecimalField :FloatField}
-        int-or-text #{:BigIntegerField :IntegerField :CharField :TextField}
-        text        #{:CharField :TextField}]
-    [[#"^.*_lat$"       float       :latitude]
-     [#"^.*_lon$"       float       :longitude]
-     [#"^.*_lng$"       float       :longitude]
-     [#"^.*_long$"      float       :longitude]
-     [#"^.*_longitude$" float       :longitude]
-     [#"^.*_rating$"    int-or-text :category]
-     [#"^.*_type$"      int-or-text :category]
-     [#"^.*_url$"       text        :url]
-     [#"^_latitude$"    float       :latitude]
-     [#"^active$"       bool-or-int :category]
-     [#"^city$"         text        :city]
-     [#"^country$"      text        :country]
-     [#"^countryCode$"  text        :country]
-     [#"^currency$"     int-or-text :category]
-     [#"^first_name$"   text        :name]
-     [#"^full_name$"    text        :name]
-     [#"^gender$"       int-or-text :category]
-     [#"^last_name$"    text        :name]
-     [#"^lat$"          float       :latitude]
-     [#"^latitude$"     float       :latitude]
-     [#"^lon$"          float       :longitude]
-     [#"^lng$"          float       :longitude]
-     [#"^long$"         float       :longitude]
-     [#"^longitude$"    float       :longitude]
-     [#"^name$"         text        :name]
-     [#"^postalCode$"   int-or-text :zip_code]
-     [#"^postal_code$"  int-or-text :zip_code]
-     [#"^rating$"       int-or-text :category]
-     [#"^role$"         int-or-text :category]
-     [#"^sex$"          int-or-text :category]
-     [#"^state$"        text        :state]
-     [#"^status$"       int-or-text :category]
-     [#"^type$"         int-or-text :category]
-     [#"^url$"          text        :url]
-     [#"^zip_code$"     int-or-text :zip_code]
-     [#"^zipcode$"      int-or-text :zip_code]]))
+  (let [bool-or-int #{:type/Boolean :type/Integer}
+        float       #{:type/Float}
+        int-or-text #{:type/Integer :type/Text}
+        text        #{:type/Text}]
+    [[#"^.*_lat$"       float       :type/Latitude]
+     [#"^.*_lon$"       float       :type/Longitude]
+     [#"^.*_lng$"       float       :type/Longitude]
+     [#"^.*_long$"      float       :type/Longitude]
+     [#"^.*_longitude$" float       :type/Longitude]
+     [#"^.*_rating$"    int-or-text :type/Category]
+     [#"^.*_type$"      int-or-text :type/Category]
+     [#"^.*_url$"       text        :type/URL]
+     [#"^_latitude$"    float       :type/Latitude]
+     [#"^active$"       bool-or-int :type/Category]
+     [#"^city$"         text        :type/City]
+     [#"^country$"      text        :type/Country]
+     [#"^countryCode$"  text        :type/Country]
+     [#"^currency$"     int-or-text :type/Category]
+     [#"^first_name$"   text        :type/Name]
+     [#"^full_name$"    text        :type/Name]
+     [#"^gender$"       int-or-text :type/Category]
+     [#"^last_name$"    text        :type/Name]
+     [#"^lat$"          float       :type/Latitude]
+     [#"^latitude$"     float       :type/Latitude]
+     [#"^lon$"          float       :type/Longitude]
+     [#"^lng$"          float       :type/Longitude]
+     [#"^long$"         float       :type/Longitude]
+     [#"^longitude$"    float       :type/Longitude]
+     [#"^name$"         text        :type/Name]
+     [#"^postalCode$"   int-or-text :type/ZipCode]
+     [#"^postal_code$"  int-or-text :type/ZipCode]
+     [#"^rating$"       int-or-text :type/Category]
+     [#"^role$"         int-or-text :type/Category]
+     [#"^sex$"          int-or-text :type/Category]
+     [#"^state$"        text        :type/State]
+     [#"^status$"       int-or-text :type/Category]
+     [#"^type$"         int-or-text :type/Category]
+     [#"^url$"          text        :type/URL]
+     [#"^zip_code$"     int-or-text :type/ZipCode]
+     [#"^zipcode$"      int-or-text :type/ZipCode]]))
 
 ;; Check that all the pattern tuples are valid
 (when-not config/is-prod?
   (doseq [[name-pattern base-types special-type] pattern+base-types+special-type]
     (assert (instance? java.util.regex.Pattern name-pattern))
-    (assert (every? (partial contains? base-types) base-types))
-    (assert (contains? special-types special-type))))
+    (assert (every? (u/rpartial isa? :type/*) base-types))
+    (assert (isa? special-type :type/*))))
 
 (defn- infer-field-special-type
   "If `name` and `base-type` matches a known pattern, return the `special_type` we should assign to it."
   [field-name base-type]
   (when (and (string? field-name)
              (keyword? base-type))
-    (or (when (= "id" (s/lower-case field-name)) :id)
+    (or (when (= "id" (s/lower-case field-name)) :type/PK)
         (some (fn [[name-pattern valid-base-types special-type]]
-                (when (and (contains? valid-base-types base-type)
+                (when (and (some (partial isa? base-type) valid-base-types)
                            (re-matches name-pattern (s/lower-case field-name)))
                   special-type))
               pattern+base-types+special-type))))
@@ -255,7 +203,7 @@
                                (humanization/name->human-readable-name field-name))
              :special_type (or (:special_type existing-field)
                                special-type
-                               (when pk? :id)
+                               (when pk? :type/PK)
                                (infer-field-special-type field-name base-type))
 
              :parent_id    parent-id)
@@ -273,9 +221,9 @@
   [table-id {field-name :name, :keys [base-type special-type pk? parent-id raw-column-id]}]
   {:pre [(integer? table-id)
          (string? field-name)
-         (contains? base-types base-type)]}
+         (isa? base-type :type/*)]}
   (let [special-type (or special-type
-                       (when pk? :id)
+                       (when pk? :type/PK)
                        (infer-field-special-type field-name base-type))]
     (db/insert! Field
       :table_id      table-id
diff --git a/src/metabase/models/field_values.clj b/src/metabase/models/field_values.clj
index 6c843b0d5ef6ad2aab88ce895143192a221724e1..080fdf14a9b6be3a73e0c7d40b71dcf7ac3761e6 100644
--- a/src/metabase/models/field_values.clj
+++ b/src/metabase/models/field_values.clj
@@ -33,9 +33,9 @@
          (contains? field :base_type)
          (contains? field :special_type)]}
   (and (not (contains? #{:retired :sensitive :hidden :details-only} (keyword visibility_type)))
-       (not (contains? #{:DateField :DateTimeField :TimeField} (keyword base_type)))
-       (or (contains? #{:category :city :state :country :name} (keyword special_type))
-           (= (keyword base_type) :BooleanField))))
+       (not (isa? (keyword base_type) :type/DateTime))
+       (or (isa? (keyword base_type) :type/Boolean)
+           (isa? (keyword special_type) :type/Category))))
 
 (defn- create-field-values!
   "Create `FieldValues` for a `Field`."
diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj
index daeebbf7f2de9737d0e810a207baf27eb4996f97..f6246a3ee80c9da3cde9e5e6e5a718f1ad5be5ce 100644
--- a/src/metabase/models/interface.clj
+++ b/src/metabase/models/interface.clj
@@ -106,7 +106,7 @@
     "Return a map of keyword field names to their types for fields that should be serialized/deserialized in a special way. Valid types are `:json`, `:keyword`, or `:clob`.
 
      *  `:json` serializes objects as JSON strings before going into the DB, and parses JSON strings when coming out
-     *  `:keyword` calls `name` before going into the DB, and `keyword` when coming out
+     *  `:keyword` calls `u/keyword->qualified-name` before going into the DB, and `keyword` when coming out
      *  `:clob` converts clobs to Strings (via `metabase.util/jdbc-clob->str`) when coming out
 
        (types [_] {:cards :json}) ; encode `:cards` as JSON when stored in the DB"))
@@ -123,7 +123,7 @@
                       (if (string? s)
                         (json/parse-string s keyword)
                         obj)))}
-   :keyword {:in  name
+   :keyword {:in  u/keyword->qualified-name
              :out keyword}
    :clob    {:in  identity
              :out u/jdbc-clob->str}})
diff --git a/src/metabase/models/table.clj b/src/metabase/models/table.clj
index 96e8f3d7fe7cc1f9cd99191640f37fc7ac298ea8..ebe3499fc6814e6a627936e4c09a6ff15b32b82a 100644
--- a/src/metabase/models/table.clj
+++ b/src/metabase/models/table.clj
@@ -75,7 +75,7 @@
   "Return the ID of the primary key `Field` for TABLE."
   {:hydrate :pk_field, :arglists '([table])}
   [{:keys [id]}]
-  (db/select-one-id Field, :table_id id, :special_type "id", :visibility_type [:not-in ["sensitive" "retired"]]))
+  (db/select-one-id Field, :table_id id, :special_type (db/isa :type/PK), :visibility_type [:not-in ["sensitive" "retired"]]))
 
 
 (defn- with-objects [hydration-key fetch-objects-fn tables]
diff --git a/src/metabase/models/user.clj b/src/metabase/models/user.clj
index cdb44e3e5f1511decad500f527018ac309f99b89..631bad260348dcd40aac017db266e82636176b14 100644
--- a/src/metabase/models/user.clj
+++ b/src/metabase/models/user.clj
@@ -123,5 +123,5 @@
 
 (defn instance-created-at
   "The date this Metabase instance was created.  We use the `:date_joined` of the first `User` to determine this."
-  []
+  ^java.sql.Timestamp []
   (db/select-one-field :date_joined User, {:order-by [[:date_joined :asc]]}))
diff --git a/src/metabase/public_settings.clj b/src/metabase/public_settings.clj
index 891e0443ba3905c4bb2a462c3d04161430b02885..06324a824c6ff48aa5cf03607c063495087d1930 100644
--- a/src/metabase/public_settings.clj
+++ b/src/metabase/public_settings.clj
@@ -4,6 +4,7 @@
                       [db :as db])
             (metabase.models [common :as common]
                              [setting :refer [defsetting], :as setting])
+            [metabase.types :as types]
             [metabase.util.password :as password])
   (:import java.util.TimeZone))
 
@@ -81,4 +82,5 @@
    :has_sample_dataset    (db/exists? 'Database, :is_sample true)
    :google_auth_client_id (setting/get :google-auth-client-id)
    :google_maps_api_key   (google-maps-api-key)
-   :custom_geojson        (setting/get :custom-geojson)})
+   :custom_geojson        (setting/get :custom-geojson)
+   :types                 (types/types->parents)})
diff --git a/src/metabase/pulse/render.clj b/src/metabase/pulse/render.clj
index d11b61876eee29edd3d2a14e714410eb2c0efb5f..b70c2d0027904c86f5a7bf513877df68b6fe9a51 100644
--- a/src/metabase/pulse/render.clj
+++ b/src/metabase/pulse/render.clj
@@ -87,13 +87,13 @@
 
 (defn- datetime-field?
   [field]
-  (or (contains? #{:DateTimeField :TimeField :DateField} (:base_type field))
-      (contains? #{:timestamp_seconds :timestamp_milliseconds} (:special_type field))))
+  (or (isa? (:base_type field) :type/DateTime)
+      (isa? (:base_type field) :type/DateTime)))
 
 (defn- number-field?
   [field]
-  (or (contains? #{:IntegerField :DecimalField :FloatField :BigIntegerField} (:base_type field))
-      (contains? #{:number} (:special_type field))))
+  (or (isa? (:base_type field)    :type/Number)
+      (isa? (:special_type field) :type/Number)))
 
 
 ;;; # ------------------------------------------------------------ FORMATTING ------------------------------------------------------------
diff --git a/src/metabase/query_processor.clj b/src/metabase/query_processor.clj
index 4e64bd6712f8e4891f29a0085c1c663b1adacf4f..dde25c9d601f3ca90c83f5d1ab7589e71539890b 100644
--- a/src/metabase/query_processor.clj
+++ b/src/metabase/query_processor.clj
@@ -224,8 +224,8 @@
                 (seq fields)))))
 
 (defn- datetime-field? [{:keys [base-type special-type]}]
-  (or (contains? #{:DateField :DateTimeField} base-type)
-      (contains? #{:timestamp_seconds :timestamp_milliseconds} special-type)))
+  (or (isa? base-type :type/DateTime)
+      (isa? special-type :type/DateTime)))
 
 (defn- fields-for-source-table
   "Return the all fields for SOURCE-TABLE, for use as an implicit `:fields` clause."
diff --git a/src/metabase/query_processor/annotate.clj b/src/metabase/query_processor/annotate.clj
index a2818f67ac4ffe6b2d48df3d37ab656a86c7df9a..7844dc175a795b3a2a3c480ff4975aa6ef4c904c 100644
--- a/src/metabase/query_processor/annotate.clj
+++ b/src/metabase/query_processor/annotate.clj
@@ -1,11 +1,13 @@
 (ns metabase.query-processor.annotate
   (:require [clojure.set :as set]
+            [clojure.string :as str]
             [clojure.tools.logging :as log]
             [medley.core :as m]
             [metabase.db :as db]
             [metabase.models.field :refer [Field]]
             [metabase.query-processor.interface :as i]
-            [metabase.util :as u]))
+            [metabase.util :as u])
+  (:import metabase.query_processor.interface.ExpressionRef))
 
 ;; Fields should be returned in the following order:
 ;; 1.  Breakout Fields
@@ -80,10 +82,7 @@
    (This is for handling Mongo nested Fields, I think (?))"
   [field]
   {:post [(keyword? (:field-name %))]}
-  (assoc field :field-name (->> (rest (i/qualified-name-components field))
-                                (interpose ".")
-                                (apply str)
-                                keyword)))
+  (assoc field :field-name (keyword (str/join \. (rest (i/qualified-name-components field))))))
 
 (defn- ag-type->field-name
   "Return the (keyword) name that should be used for the column in the results. This is the same as the name of the aggregation,
@@ -108,14 +107,14 @@
                            :special-type       (:special-type ag-field)})
                         ;; Always treat count or distinct count as an integer even if the DB in question returns it as something wacky like a BigDecimal or Float
                         (when (contains? #{:count :distinct} ag-type)
-                          {:base-type    :IntegerField
-                           :special-type :number})
+                          {:base-type    :type/Integer
+                           :special-type :type/Number})
                         ;; For the time being every Expression is an arithmetic operator and returns a floating-point number, so hardcoding these types is fine;
                         ;; In the future when we extend Expressions to handle more functionality we'll want to introduce logic that associates a return type with a given expression.
                         ;; But this will work for the purposes of a patch release.
-                        (when (instance? metabase.query_processor.interface.ExpressionRef ag-field)
-                          {:base-type    :FloatField
-                           :special-type :number})))))
+                        (when (instance? ExpressionRef ag-field)
+                          {:base-type    :type/Float
+                           :special-type :type/Number})))))
 
 (defn- add-unknown-fields-if-needed
   "When create info maps for any fields we didn't expect to come back from the query.
@@ -130,7 +129,7 @@
       (log/warn (u/format-color 'yellow "There are fields we weren't expecting in the results: %s\nExpected: %s\nActual: %s"
                   missing-keys expected-keys actual-keys)))
     (concat fields (for [k missing-keys]
-                     {:base-type          :UnknownField
+                     {:base-type          :type/*
                       :preview-display    true
                       :special-type       nil
                       :field-name         k
@@ -157,10 +156,10 @@
   "Return a importance for FIELD based on the relative importance of its `:special-type`.
    i.e. a Field with special type `:id` should be sorted ahead of all other Fields in the results."
   [{:keys [special-type]}]
-  (condp = special-type
-    :id   :0-id
-    :name :1-name
-          :2-other))
+  (cond
+    (isa? special-type :type/PK)   :0-id
+    (isa? special-type :type/Name) :1-name
+    :else                          :2-other))
 
 (defn- field-importance-fn
   "Create a function to return an \"importance\" vector for use in sorting FIELD."
@@ -208,7 +207,7 @@
   "Fetch fk info and return a function that returns the destination Field of a given Field."
   ([fields]
    (or (fk-field->dest-fn fields (for [{:keys [special_type id]} fields
-                                       :when (= special_type :fk)]
+                                       :when (isa? special_type :type/FK)]
                                    id))
        (constantly nil)))
   ;; Fetch the foreign key fields whose origin is in the returned Fields, create a map of origin-field-id->destination-field-id
@@ -228,7 +227,7 @@
      (some-> id id->dest-id dest-id->field))))
 
 (defn- add-extra-info-to-fk-fields
-  "Add `:extra_info` about foreign keys to `Fields` whose `special_type` is `:fk`."
+  "Add `:extra_info` about foreign keys to `Fields` whose `special_type` is a `:type/FK`."
   [fields]
   (let [field->dest (fk-field->dest-fn fields)]
     (for [field fields]
@@ -236,7 +235,9 @@
         (assoc field
           :target     (when dest-field
                         (into {} dest-field))
-          :extra_info (if table_id {:target_table_id table_id} {}))))))
+          :extra_info (if table_id
+                        {:target_table_id table_id}
+                        {}))))))
 
 (defn- resolve-sort-and-format-columns
   "Collect the Fields referenced in QUERY, sort them according to the rules at the top
diff --git a/src/metabase/query_processor/interface.clj b/src/metabase/query_processor/interface.clj
index 77ae08e67539b414d4739a5a9d5184114d33ab52..f114f722aa08302610bc6e71551664ea6cd1825e 100644
--- a/src/metabase/query_processor/interface.clj
+++ b/src/metabase/query_processor/interface.clj
@@ -59,8 +59,8 @@
 (s/defrecord Field [field-id           :- su/IntGreaterThanZero
                     field-name         :- su/NonBlankString
                     field-display-name :- su/NonBlankString
-                    base-type          :- (apply s/enum field/base-types)
-                    special-type       :- (s/maybe (apply s/enum field/special-types))
+                    base-type          :- su/FieldType
+                    special-type       :- (s/maybe su/FieldType)
                     visibility-type    :- (apply s/enum field/visibility-types)
                     table-id           :- su/IntGreaterThanZero
                     schema-name        :- (s/maybe su/NonBlankString)
diff --git a/src/metabase/query_processor/resolve.clj b/src/metabase/query_processor/resolve.clj
index e9d2af3833b59eb975d19bc9673b0a3ceff4c10e..14fa7c1d422f8cabb95597054de9d378f7444f10 100644
--- a/src/metabase/query_processor/resolve.clj
+++ b/src/metabase/query_processor/resolve.clj
@@ -104,8 +104,8 @@
                                                                map->Field
                                                                (assoc :fk-field-id fk-field-id))]
     ;; try to resolve the Field with the ones available in field-id->field
-    (let [datetime-field? (or (contains? #{:DateField :DateTimeField} base-type)
-                              (contains? #{:timestamp_seconds :timestamp_milliseconds} special-type))]
+    (let [datetime-field? (or (isa? base-type :type/DateTime)
+                              (isa? special-type :type/DateTime))]
       (if-not datetime-field?
         field
         (map->DateTimeField {:field field
@@ -224,7 +224,7 @@
                            [:= :target-pk.table_id :target-table.id]]
                :where     [:and [:in :source-fk.id      (set fk-field-ids)]
                                 [:=  :source-fk.table_id     source-table-id]
-                                [:=  :source-fk.special_type "fk"]]})))
+                                (db/isa :source-fk.special_type :type/FK)]})))
 
 (defn- fk-field-ids->joined-tables
   "Fetch info for PK/FK `Fields` for the JOIN-TABLES referenced in a Query."
diff --git a/src/metabase/sync_database/analyze.clj b/src/metabase/sync_database/analyze.clj
index b888a2a0b8b85a6481e276c4be75209f681d3946..1116729ca90892cb1e615036abb17aafadb66484 100644
--- a/src/metabase/sync_database/analyze.clj
+++ b/src/metabase/sync_database/analyze.clj
@@ -15,12 +15,12 @@
             [metabase.util :as u]))
 
 (def ^:private ^:const percent-valid-url-threshold
-  "Fields that have at least this percent of values that are valid URLs should be marked as `special_type = :url`."
+  "Fields that have at least this percent of values that are valid URLs should be given a special type of `:type/URL`."
   0.95)
 
 
 (def ^:private ^:const low-cardinality-threshold
-  "Fields with less than this many distinct values should automatically be marked with `special_type = :category`."
+  "Fields with less than this many distinct values should automatically be given a special type of `:type/Category`."
   40)
 
 (def ^:private ^:const field-values-entry-max-length
@@ -45,16 +45,12 @@
 (defn test-for-cardinality?
   "Should FIELD should be tested for cardinality?"
   [field is-new?]
-  (let [not-field-values-elligible #{:ArrayField
-                                     :DateField
-                                     :DateTimeField
-                                     :DictionaryField
-                                     :TimeField
-                                     :UnknownField}]
-    (or (field-values/field-should-have-field-values? field)
-        (and (nil? (:special_type field))
-             is-new?
-             (not (contains? not-field-values-elligible (:base_type field)))))))
+  (or (field-values/field-should-have-field-values? field)
+      (and (nil? (:special_type field))
+           is-new?
+           (not (isa? (:base_type field) :type/DateTime))
+           (not (isa? (:base_type field) :type/Collection))
+           (not (= (:base_type field) :type/*)))))
 
 (defn test:cardinality-and-extract-field-values
   "Extract field-values for FIELD.  If number of values exceeds `low-cardinality-threshold` then we return an empty set of values."
@@ -71,13 +67,13 @@
     ;; TODO: eventually we can check for :nullable? based on the original values above
     (cond-> (assoc field-stats :values distinct-values)
       (and (nil? (:special_type field))
-           (pos? (count distinct-values))) (assoc :special-type :category))))
+           (pos? (count distinct-values))) (assoc :special-type :type/Category))))
 
 (defn- test:no-preview-display
   "If FIELD's is textual and its average length is too great, mark it so it isn't displayed in the UI."
   [driver field field-stats]
   (if-not (and (= :normal (:visibility_type field))
-               (contains? #{:CharField :TextField} (:base_type field)))
+               (isa? (:base_type field) :type/Text))
     ;; this field isn't suited for this test
     field-stats
     ;; test for avg length
@@ -89,10 +85,10 @@
           (assoc field-stats :preview-display false))))))
 
 (defn- test:url-special-type
-  "If FIELD is texual, doesn't have a `special_type`, and its non-nil values are primarily URLs, mark it as `special_type` `url`."
+  "If FIELD is texual, doesn't have a `special_type`, and its non-nil values are primarily URLs, mark it as `special_type` `:type/URL`."
   [driver field field-stats]
   (if-not (and (not (:special_type field))
-               (contains? #{:CharField :TextField} (:base_type field)))
+               (isa? (:base_type field) :type/Text))
     ;; this field isn't suited for this test
     field-stats
     ;; test for url values
@@ -129,15 +125,15 @@
    are valid serialized JSON dictionaries or arrays."
   [driver field field-stats]
   (if-not (and (not (:special_type field))
-               (contains? #{:CharField :TextField} (:base_type field)))
+               (not (isa? (:base_type field) :type/Text)))
     ;; this field isn't suited for this test
     field-stats
     ;; check for json values
     (if-not (values-are-valid-json? (take driver/max-sync-lazy-seq-results (driver/field-values-lazy-seq driver field)))
       field-stats
       (do
-        (log/debug (u/format-color 'green "Field '%s' looks like it contains valid JSON objects. Setting special_type to :json." (field/qualified-name field)))
-        (assoc field-stats :special-type :json, :preview-display false)))))
+        (log/debug (u/format-color 'green "Field '%s' looks like it contains valid JSON objects. Setting special_type to :type/JSON." (field/qualified-name field)))
+        (assoc field-stats :special-type :type/JSON, :preview-display false)))))
 
 (defn- test:new-field
   "Do the various tests that should only be done for a new `Field`.
diff --git a/src/metabase/sync_database/interface.clj b/src/metabase/sync_database/interface.clj
index 28c8b2491c3e2c81e7f819a6f62aff9580a3a85a..cdccf509ff960dcf440d0f32c6e75f64fef998bc 100644
--- a/src/metabase/sync_database/interface.clj
+++ b/src/metabase/sync_database/interface.clj
@@ -9,7 +9,7 @@
   "Schema for the expected output of `analyze-table`."
   {(s/optional-key :row_count) (s/maybe s/Int)
    (s/optional-key :fields)    [{:id                               su/IntGreaterThanZero
-                                 (s/optional-key :special-type)    (apply s/enum field/special-types)
+                                 (s/optional-key :special-type)    su/FieldType
                                  (s/optional-key :preview-display) s/Bool
                                  (s/optional-key :values)          [s/Any]}]})
 
@@ -21,8 +21,8 @@
 (def DescribeTableField
   "Schema for a given Field as provided in `describe-table` or `analyze-table`."
   {:name                           su/NonBlankString
-   :base-type                      (apply s/enum field/base-types)
-   (s/optional-key :special-type)  (apply s/enum field/special-types)
+   :base-type                      su/FieldType
+   (s/optional-key :special-type)  su/FieldType
    (s/optional-key :pk?)           s/Bool
    (s/optional-key :nested-fields) #{(s/recursive #'DescribeTableField)}
    (s/optional-key :custom)        {s/Any s/Any}})
diff --git a/src/metabase/sync_database/sync.clj b/src/metabase/sync_database/sync.clj
index 997f172bcfd9e453116bd03898731001c3e4b7e5..1e9849a408587e9f37e885af318e6f30da3af8e2 100644
--- a/src/metabase/sync_database/sync.clj
+++ b/src/metabase/sync_database/sync.clj
@@ -14,7 +14,7 @@
 
 (defn- save-fks!
   "Update all of the FK relationships present in DATABASE based on what's captured in the raw schema.
-   This will set :special_type :fk and :fk_target_field_id <field-id> for each found FK relationship.
+   This will set :special_type :type/FK and :fk_target_field_id <field-id> for each found FK relationship.
    NOTE: we currently overwrite any previously defined metadata when doing this."
   [fk-sources]
   {:pre [(coll? fk-sources)
@@ -24,7 +24,7 @@
     (when-let [source-field-id (db/select-one-id Field, :raw_column_id fk-source-id, :visibility_type [:not= "retired"])]
       (when-let [target-field-id (db/select-one-id Field, :raw_column_id fk-target-id, :visibility_type [:not= "retired"])]
         (db/update! Field source-field-id
-          :special_type       :fk
+          :special_type       :type/FK
           :fk_target_field_id target-field-id)))))
 
 
@@ -47,22 +47,24 @@
   (doseq [{:keys [keypath value]} (driver/table-rows-seq driver database metabase-metadata-table)]
     ;; TODO: this does not support schemas in dbs :(
     (let [[_ table-name field-name k] (re-matches #"^([^.]+)\.(?:([^.]+)\.)?([^.]+)$" keypath)]
-      (try (when-not (if field-name
-                       (when-let [table-id (db/select-one-id Table
-                                             ;; TODO: this needs to support schemas
-                                             ;; TODO: eventually limit this to "core" schema tables
-                                             :db_id  (:id database)
-                                             :name   table-name
-                                             :active true)]
-                         (db/update-where! Field {:name     field-name
-                                                  :table_id table-id}
+      ;; ignore legacy entries that try to set field_type since it's no longer part of Field
+      (when-not (= (keyword k) :field_type)
+        (try (when-not (if field-name
+                         (when-let [table-id (db/select-one-id Table
+                                               ;; TODO: this needs to support schemas
+                                               ;; TODO: eventually limit this to "core" schema tables
+                                               :db_id  (:id database)
+                                               :name   table-name
+                                               :active true)]
+                           (db/update-where! Field {:name     field-name
+                                                    :table_id table-id}
+                             (keyword k) value))
+                         (db/update-where! Table {:name  table-name
+                                                  :db_id (:id database)}
                            (keyword k) value))
-                       (db/update-where! Table {:name  table-name
-                                                :db_id (:id database)}
-                         (keyword k) value))
-             (log/error (u/format-color "Error syncing _metabase_metadata: no matching keypath: %s" keypath)))
-           (catch Throwable e
-             (log/error (u/format-color 'red "Error in _metabase_metadata: %s" (.getMessage e))))))))
+               (log/error (u/format-color "Error syncing _metabase_metadata: no matching keypath: %s" keypath)))
+             (catch Throwable e
+               (log/error (u/format-color 'red "Error in _metabase_metadata: %s" (.getMessage e)))))))))
 
 
 (defn- save-table-fields!
diff --git a/src/metabase/task/follow_up_emails.clj b/src/metabase/task/follow_up_emails.clj
index 7f5f33ffe212c1eed19c94dc207bb94ab52d0c63..e9eb7da8906e9db7ab607bb899f7ae21013c7e4f 100644
--- a/src/metabase/task/follow_up_emails.clj
+++ b/src/metabase/task/follow_up_emails.clj
@@ -9,10 +9,11 @@
             (metabase [db :as db]
                       [email :as email])
             [metabase.email.messages :as messages]
-            (metabase.models [activity :as activity]
+            (metabase.models [activity :refer [Activity]]
                              [setting :as setting]
-                             [user :as user]
-                             [view-log :as view-log])
+                             [user :as user, :refer [User]]
+                             [view-log :refer [ViewLog]])
+            [metabase.public-settings :as public-settings]
             [metabase.task :as task]))
 
 
@@ -23,8 +24,8 @@
 (defonce ^:private follow-up-emails-job (atom nil))
 (defonce ^:private follow-up-emails-trigger (atom nil))
 
-(setting/defsetting follow-up-email-sent
-  "have we sent a follow up email to the instance admin?"
+(setting/defsetting ^:private follow-up-email-sent
+  "Have we sent a follow up email to the instance admin?"
   :type      :boolean
   :default   false
   :internal? true)
@@ -35,41 +36,39 @@
 (defonce ^:private abandonment-emails-job (atom nil))
 (defonce ^:private abandonment-emails-trigger (atom nil))
 
-(setting/defsetting abandonment-email-sent
-  "have we sent an abandonment email to the instance admin?"
+(setting/defsetting ^:private abandonment-email-sent
+  "Have we sent an abandonment email to the instance admin?"
   :type      :boolean
   :default   false
   :internal? true)
 
 ;; 2 weeks of inactivity after 30 days of total install
-;;
 
 ;; this sends out a general 2 week email follow up email
 (jobs/defjob FollowUpEmail
              [ctx]
              ;; if we've already sent the follow-up email then we are done
-             (when-not (= "true" (follow-up-email-sent))
+             (when-not (follow-up-email-sent)
                ;; figure out when we consider the instance created
                (when-let [instance-created (user/instance-created-at)]
                  ;; we need to be 2+ weeks (14 days) from creation to send the follow up
                  (when (< (* 14 24 60 60 1000)
-                          (- (System/currentTimeMillis) (.getTime ^java.sql.Timestamp instance-created)))
+                          (- (System/currentTimeMillis) (.getTime instance-created)))
                    (send-follow-up-email!)))))
 
 ;; this sends out an email any time after 30 days if the instance has stopped being used for 14 days
 (jobs/defjob AbandonmentEmail
              [ctx]
              ;; if we've already sent the abandonment email then we are done
-             (when-not (= "true" (abandonment-email-sent))
+             (when-not (abandonment-email-sent)
                ;; figure out when we consider the instance created
                (when-let [instance-created (user/instance-created-at)]
                  ;; we need to be 4+ weeks (30 days) from creation to send the follow up
                  (when (< (* 30 24 60 60 1000)
-                          (- (System/currentTimeMillis) (.getTime ^java.sql.Timestamp instance-created)))
+                          (- (System/currentTimeMillis) (.getTime instance-created)))
                    ;; we need access to email AND the instance must be opted into anonymous tracking
                    (when (and (email/email-configured?)
-                              (let [tracking? (setting/get :anon-tracking-enabled)]
-                                (or (nil? tracking?) (= "true" tracking?))))
+                              (public-settings/anon-tracking-enabled))
                      (send-abandonment-email!))))))
 
 (defn task-init
@@ -108,26 +107,25 @@
   (try
     ;; we need access to email AND the instance must be opted into anonymous tracking
     (when (and (email/email-configured?)
-               (let [tracking? (setting/get :anon-tracking-enabled)]
-                 (or (nil? tracking?) (= "true" tracking?))))
+               (public-settings/anon-tracking-enabled))
       ;; grab the oldest admins email address, that's who we'll send to
-      (when-let [admin (user/User :is_superuser true, {:order-by [:date_joined]})]
+      (when-let [admin (User :is_superuser true, {:order-by [:date_joined]})]
         (messages/send-follow-up-email (:email admin) "follow-up")))
     (catch Throwable t
       (log/error "Problem sending follow-up email" t))
     (finally
-      (setting/set! :follow-up-email-sent true))))
+      (follow-up-email-sent true))))
 
 (defn- send-abandonment-email!
   "Send an email to the instance admin about why Metabase usage has died down."
   []
   ;; grab the oldest admins email address, that's who we'll send to
-  (when-let [admin (user/User :is_superuser true, {:order-by [:date_joined]})]
+  (when-let [admin (User :is_superuser true, {:order-by [:date_joined]})]
     ;; inactive = no users created, no activity created, no dash/card views (past 7 days)
-    (let [last-user      (c/from-sql-time (db/select-one-field :date_joined user/User,       {:order-by [[:date_joined :desc]]}))
-          last-activity  (c/from-sql-time (db/select-one-field :timestamp activity/Activity, {:order-by [[:timestamp :desc]]}))
-          last-view      (c/from-sql-time (db/select-one-field :timestamp view-log/ViewLog,  {:order-by [[:timestamp :desc]]}))
-          two-weeks-ago  (t/minus (t/now) (t/days 14))]
+    (let [last-user     (c/from-sql-time (db/select-one-field :date_joined User,   {:order-by [[:date_joined :desc]]}))
+          last-activity (c/from-sql-time (db/select-one-field :timestamp Activity, {:order-by [[:timestamp :desc]]}))
+          last-view     (c/from-sql-time (db/select-one-field :timestamp ViewLog,  {:order-by [[:timestamp :desc]]}))
+          two-weeks-ago (t/minus (t/now) (t/days 14))]
       (when (and (t/before? last-user two-weeks-ago)
                  (t/before? last-activity two-weeks-ago)
                  (t/before? last-view two-weeks-ago))
@@ -136,4 +134,4 @@
           (catch Throwable t
             (log/error "Problem sending abandonment email" t))
           (finally
-            (setting/set! :abandonment-email-sent "true")))))))
+            (abandonment-email-sent true)))))))
diff --git a/src/metabase/types.clj b/src/metabase/types.clj
new file mode 100644
index 0000000000000000000000000000000000000000..f940e69b691efb6b29a9144b7bdcc4b3284fb25e
--- /dev/null
+++ b/src/metabase/types.clj
@@ -0,0 +1,100 @@
+(ns metabase.types)
+
+(derive :type/Collection :type/*)
+
+(derive :type/Dictionary :type/Collection)
+(derive :type/Array :type/Collection)
+
+
+;;; Numeric Types
+
+(derive :type/Number :type/*)
+
+(derive :type/Integer :type/Number)
+(derive :type/BigInteger :type/Integer)
+(derive :type/ZipCode :type/Integer)
+
+(derive :type/Float :type/Number)
+(derive :type/Decimal :type/Float)
+
+(derive :type/Coordinate :type/Float)
+(derive :type/Latitude :type/Coordinate)
+(derive :type/Longitude :type/Coordinate)
+
+
+;;; Text Types
+
+(derive :type/Text :type/*)
+
+(derive :type/UUID :type/Text)
+
+(derive :type/URL :type/Text)
+(derive :type/AvatarURL :type/URL)
+(derive :type/ImageURL :type/URL)
+
+(derive :type/City :type/Text)
+(derive :type/State :type/Text)
+(derive :type/Country :type/Text)
+
+(derive :type/Name :type/Text)
+(derive :type/Description :type/Text)
+
+(derive :type/SerializedJSON :type/Text)
+(derive :type/SerializedJSON :type/Collection)
+
+;;; DateTime Types
+
+(derive :type/DateTime :type/*)
+
+(derive :type/Time :type/DateTime)
+(derive :type/Date :type/DateTime)
+
+(derive :type/UNIXTimestamp :type/DateTime)
+(derive :type/UNIXTimestamp :type/Integer)
+(derive :type/UNIXTimestampSeconds :type/UNIXTimestamp)
+(derive :type/UNIXTimestampMilliseconds :type/UNIXTimestamp)
+
+
+;;; Other
+
+(derive :type/Boolean :type/*)
+
+;;; Text-Like Types: Things that should be displayed as text for most purposes but that *shouldn't* support advanced filter options like starts with / contains
+
+(derive :type/TextLike :type/*)
+(derive :type/IPAddress :type/TextLike)
+(derive :type/MongoBSONID :type/TextLike)
+
+;;; "Virtual" Types
+
+(derive :type/Address :type/*)
+(derive :type/City :type/Address)
+(derive :type/State :type/Address)
+(derive :type/Country :type/Address)
+(derive :type/Name :type/Address)
+(derive :type/Zip :type/Address)
+
+
+;;; Legacy Special Types. These will hopefully be going away in the future when we add columns like `:is_pk` and `:cardinality`
+
+(derive :type/Special :type/*)
+
+(derive :type/FK :type/Special)
+(derive :type/PK :type/Special)
+
+(derive :type/Category :type/Special)
+
+(derive :type/City :type/Category)
+(derive :type/State :type/Category)
+(derive :type/Country :type/Category)
+(derive :type/Name :type/Category)
+
+
+;;; ------------------------------------------------------------ Util Fns ------------------------------------------------------------
+
+(defn types->parents
+  "Return a map of various types to their parent types.
+   This is intended for export to the frontend as part of `MetabaseBootstrap` so it can build its own implementation of `isa?`."
+  []
+  (into {} (for [t (descendants :type/*)]
+             {t (parents t)})))
diff --git a/src/metabase/util.clj b/src/metabase/util.clj
index 0731875687a9daf6373b58a5a0a9653d766b00db..c379ccea88256728981377ffbfc5eb667bc87ccd 100644
--- a/src/metabase/util.clj
+++ b/src/metabase/util.clj
@@ -662,3 +662,11 @@
   [f coll]
   (into {} (for [item coll]
              {(f item) item})))
+
+(defn keyword->qualified-name
+  "Return keyword K as a string, including its namespace, if any (unlike `name`).
+
+     (keyword->qualified-name :type/FK) ->  \"type/FK\""
+  [k]
+  (when k
+    (s/replace (str k) #"^:" "")))
diff --git a/src/metabase/util/schema.clj b/src/metabase/util/schema.clj
index f6b39d289a451dfc9589f4a1cacd17df2a759c17..43a844a1a97a79fd2864d3e677ced6e3a8501395 100644
--- a/src/metabase/util/schema.clj
+++ b/src/metabase/util/schema.clj
@@ -1,7 +1,9 @@
 (ns metabase.util.schema
   "Various schemas that are useful throughout the app."
   (:require [clojure.string :as str]
-            [schema.core :as s]))
+            [schema.core :as s]
+            metabase.types
+            [metabase.util :as u]))
 
 (def NonBlankString
   "Schema for a string that cannot be blank."
@@ -14,3 +16,7 @@
 (def KeywordOrString
   "Schema for something that can be either a `Keyword` or a `String`."
   (s/named (s/cond-pre s/Keyword s/Str) "Keyword or string"))
+
+(def FieldType
+  "Is this a valid Field type (does it derive from `:type/*`?"
+  (s/pred (u/rpartial isa? :type/*) "Valid type"))
diff --git a/test/metabase/api/database_test.clj b/test/metabase/api/database_test.clj
index affa2cb2da88c0f4d04ac20fa40ae5be78b1e095..e96e7e68855dd17b0f03199fc7974a83fc4c04ee 100644
--- a/test/metabase/api/database_test.clj
+++ b/test/metabase/api/database_test.clj
@@ -259,7 +259,7 @@
                                                        :table_id           (id :categories)
                                                        :caveats            nil
                                                        :points_of_interest nil
-                                                       :special_type       "id"
+                                                       :special_type       "type/PK"
                                                        :name               "ID"
                                                        :display_name       "ID"
                                                        :updated_at         $
@@ -271,7 +271,7 @@
                                                        :preview_display    true
                                                        :created_at         $
                                                        :last_analyzed      $
-                                                       :base_type          "BigIntegerField"
+                                                       :base_type          "type/BigInteger"
                                                        :visibility_type    "normal"
                                                        :fk_target_field_id $
                                                        :parent_id          nil
@@ -281,7 +281,7 @@
                                                        :table_id           (id :categories)
                                                        :caveats            nil
                                                        :points_of_interest nil
-                                                       :special_type       "name"
+                                                       :special_type       "type/Name"
                                                        :name               "NAME"
                                                        :display_name       "Name"
                                                        :updated_at         $
@@ -293,7 +293,7 @@
                                                        :preview_display    true
                                                        :created_at         $
                                                        :last_analyzed      $
-                                                       :base_type          "TextField"
+                                                       :base_type          "type/Text"
                                                        :visibility_type    "normal"
                                                        :fk_target_field_id $
                                                        :parent_id          nil
diff --git a/test/metabase/api/dataset_test.clj b/test/metabase/api/dataset_test.clj
index 5adc59629783c18a1e4b9b978680d5c0322b8aba..c5ff594d172165dc99d16660e6f491efc62d4d79 100644
--- a/test/metabase/api/dataset_test.clj
+++ b/test/metabase/api/dataset_test.clj
@@ -53,7 +53,7 @@
   ;; the second result is checking our QueryExection log to ensure it captured the right details
   [{:data         {:rows    [[1000]]
                    :columns ["count"]
-                   :cols    [{:base_type "IntegerField", :special_type "number", :name "count", :display_name "count", :id nil, :table_id nil,
+                   :cols    [{:base_type "type/Integer", :special_type "type/Number", :name "count", :display_name "count", :id nil, :table_id nil,
                               :description nil, :target nil, :extra_info {}, :source "aggregation"}]
                    :native_form true}
     :row_count    1
@@ -151,7 +151,7 @@
              :archived               false}
     :result {:data         {:rows    [[1000]]
                             :columns ["count"]
-                            :cols    [{:base_type "IntegerField", :special_type "number", :name "count", :display_name "count", :id nil, :table_id nil,
+                            :cols    [{:base_type "type/Integer", :special_type "type/Number", :name "count", :display_name "count", :id nil, :table_id nil,
                                        :description nil, :target nil, :extra_info {}, :source "aggregation"}]
                             :native_form true}
              :row_count    1
diff --git a/test/metabase/api/field_test.clj b/test/metabase/api/field_test.clj
index b73e12f0f62cb78104de71d9bdbe27e58269b196..5e40a253524f1688c4b627282b8f019452b20b0c 100644
--- a/test/metabase/api/field_test.clj
+++ b/test/metabase/api/field_test.clj
@@ -53,7 +53,7 @@
                             :show_in_getting_started false
                             :raw_table_id            $
                             :created_at              $})
-     :special_type       "name"
+     :special_type       "type/Name"
      :name               "NAME"
      :display_name       "Name"
      :caveats            nil
@@ -66,7 +66,7 @@
      :position           0
      :preview_display    true
      :created_at         $
-     :base_type          "TextField"
+     :base_type          "type/Text"
      :fk_target_field_id nil
      :parent_id          nil})
   ((user->client :rasta) :get 200 (format "field/%d" (id :users :name))))
@@ -93,7 +93,7 @@
    {:name            "Field Test"
     :display_name    "yay"
     :description     "foobar"
-    :special_type    :name
+    :special_type    :type/Name
     :visibility_type :sensitive}
    {:name            "Field Test"
     :display_name    "yay"
@@ -106,7 +106,7 @@
       ((user->client :crowberto) :put 200 (format "field/%d" field-id) {:name            "something else"
                                                                         :display_name    "yay"
                                                                         :description     "foobar"
-                                                                        :special_type    :name
+                                                                        :special_type    :type/Name
                                                                         :visibility_type :sensitive})
       (let [updated-val (simple-field-details (Field field-id))]
         ;; unset it
@@ -116,31 +116,24 @@
          updated-val
          (simple-field-details (Field field-id))]))))
 
-;; when we set the special-type from :fk to something else, make sure fk_target_field_id is set to nil
+;; when we set the special-type from :type/FK to something else, make sure fk_target_field_id is set to nil
 (expect
   [true
    nil]
   (tu/with-temp* [Field [{fk-field-id :id}]
-                  Field [{field-id :id}    {:special_type :fk, :fk_target_field_id fk-field-id}]]
+                  Field [{field-id :id}    {:special_type :type/FK, :fk_target_field_id fk-field-id}]]
     (let [original-val (boolean (db/select-one-field :fk_target_field_id Field, :id field-id))]
-      ;; unset the :fk special-type
-      ((user->client :crowberto) :put 200 (format "field/%d" field-id) {:special_type :name})
+      ;; unset the :type/FK special-type
+      ((user->client :crowberto) :put 200 (format "field/%d" field-id) {:special_type :type/Name})
       [original-val
        (db/select-one-field :fk_target_field_id Field, :id field-id)])))
 
-;; check that you can't set a field to :timestamp_seconds/:timestamp_milliseconds if it's not of a proper base_type
-(expect
-  ["Special type :timestamp_seconds cannot be used for fields with base type :TextField. Base type must be one of: #{:BigIntegerField :DecimalField :IntegerField :FloatField}"
-   nil]
-  (tu/with-temp* [Field [{field-id :id} {:base_type :TextField, :special_type nil}]]
-    [((user->client :crowberto) :put 400 (str "field/" field-id) {:special_type :timestamp_seconds})
-     (db/select-one-field :special_type Field, :id field-id)]))
 
 ;; check that you *can* set it if it *is* the proper base type
 (expect
-  :timestamp_seconds
-  (tu/with-temp* [Field [{field-id :id} {:base_type :IntegerField}]]
-    ((user->client :crowberto) :put 200 (str "field/" field-id) {:special_type :timestamp_seconds})
+  :type/UNIXTimestampSeconds
+  (tu/with-temp* [Field [{field-id :id} {:base_type :type/Integer}]]
+    ((user->client :crowberto) :put 200 (str "field/" field-id) {:special_type :type/UNIXTimestampSeconds})
     (db/select-one-field :special_type Field, :id field-id)))
 
 
@@ -153,7 +146,7 @@
   (:id (field->field-values table-key field-key)))
 
 ;; ## GET /api/field/:id/values
-;; Should return something useful for a field that has special_type :category
+;; Should return something useful for a field that has special_type :type/Category
 (expect
   {:field_id              (id :venues :price)
    :human_readable_values {}
@@ -167,7 +160,7 @@
     (-> ((user->client :rasta) :get 200 (format "field/%d/values" (id :venues :price)))
         (dissoc :created_at :updated_at))))
 
-;; Should return nothing for a field whose special_type is *not* :category
+;; Should return nothing for a field whose special_type is *not* :type/Category
 (expect
   {:values                {}
    :human_readable_values {}}
@@ -211,7 +204,7 @@
        (dissoc :created_at :updated_at))])
 
 ;; Check that we get an error if we call value_map_update on something that isn't a category
-(expect "You can only update the mapped values of a Field whose 'special_type' is 'category'/'city'/'state'/'country' or whose 'base_type' is 'BooleanField'."
+(expect "You can only update the mapped values of a Field whose 'special_type' is 'category'/'city'/'state'/'country' or whose 'base_type' is 'type/Boolean'."
   ((user->client :crowberto) :post 400 (format "field/%d/value_map_update" (id :venues :id))
    {:values_map {:1 "$"
                  :2 "$$"
diff --git a/test/metabase/api/notify_test.clj b/test/metabase/api/notify_test.clj
index 5068f4c639d24098126d60488cd63037843e1a8f..e363ee4607e65db93387cb4bf55e70659b9d94cc 100644
--- a/test/metabase/api/notify_test.clj
+++ b/test/metabase/api/notify_test.clj
@@ -17,11 +17,9 @@
 (expect
   {:status 404
    :body "Not found."}
-  (try (client/post ((resolve 'metabase.http-client/build-url) "notify/db/10000" {}) {:accept :json
-                                                                                      :headers {"X-METABASE-APIKEY" "test-api-key"}})
+  (try (client/post (http/build-url "notify/db/10000" {}) {:accept  :json
+                                                           :headers {"X-METABASE-APIKEY" "test-api-key"}})
        (catch clojure.lang.ExceptionInfo e
-         (-> (.getData ^clojure.lang.ExceptionInfo e)
-             (:object)
-             (select-keys [:status :body])))))
+         (select-keys (:object (ex-data e)) [:status :body]))))
 
 ;; TODO - how can we validate the normal scenario given that it just kicks off a background job?
diff --git a/test/metabase/api/table_test.clj b/test/metabase/api/table_test.clj
index 129e503b8013f075f2b4e9c45cf52061d2092554..a59b0567d6856822328932e007942ee27c4a081d 100644
--- a/test/metabase/api/table_test.clj
+++ b/test/metabase/api/table_test.clj
@@ -118,24 +118,24 @@
                      (assoc :table_id (id :categories))
                      (dissoc :target))]
     [(merge defaults (match-$ (Field (id :categories :id))
-                       {:special_type       "id"
+                       {:special_type       "type/PK"
                         :name               "ID"
                         :display_name       "ID"
                         :updated_at         $
                         :id                 (id :categories :id)
                         :created_at         $
-                        :base_type          "BigIntegerField"
+                        :base_type          "type/BigInteger"
                         :fk_target_field_id $
                         :raw_column_id      $
                         :last_analyzed      $}))
      (merge defaults (match-$ (Field (id :categories :name))
-                       {:special_type       "name"
+                       {:special_type       "type/Name"
                         :name               "NAME"
                         :display_name       "Name"
                         :updated_at         $
                         :id                 (id :categories :name)
                         :created_at         $
-                        :base_type          "TextField"
+                        :base_type          "type/Text"
                         :fk_target_field_id $
                         :raw_column_id      $
                         :last_analyzed      $}))])
@@ -150,26 +150,26 @@
             :display_name "Categories"
             :fields       (let [defaults (assoc field-defaults :table_id (id :categories))]
                             [(merge defaults (match-$ (Field (id :categories :id))
-                                               {:special_type       "id"
+                                               {:special_type       "type/PK"
                                                 :name               "ID"
                                                 :display_name       "ID"
                                                 :updated_at         $
                                                 :id                 $
                                                 :position           0
                                                 :created_at         $
-                                                :base_type          "BigIntegerField"
+                                                :base_type          "type/BigInteger"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))
                              (merge defaults (match-$ (Field (id :categories :name))
-                                               {:special_type       "name"
+                                               {:special_type       "type/Name"
                                                 :name               "NAME"
                                                 :display_name       "Name"
                                                 :updated_at         $
                                                 :id                 $
                                                 :position           0
                                                 :created_at         $
-                                                :base_type          "TextField"
+                                                :base_type          "type/Text"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))])
@@ -209,13 +209,13 @@
             :display_name "Users"
             :fields       (let [defaults (assoc field-defaults :table_id (id :users))]
                             [(merge defaults (match-$ (Field (id :users :id))
-                                               {:special_type       "id"
+                                               {:special_type       "type/PK"
                                                 :name               "ID"
                                                 :display_name       "ID"
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "BigIntegerField"
+                                                :base_type          "type/BigInteger"
                                                 :visibility_type    "normal"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
@@ -227,31 +227,31 @@
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "DateTimeField"
+                                                :base_type          "type/DateTime"
                                                 :visibility_type    "normal"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))
                              (merge defaults (match-$ (Field (id :users :name))
-                                               {:special_type       "name"
+                                               {:special_type       "type/Name"
                                                 :name               "NAME"
                                                 :display_name       "Name"
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "TextField"
+                                                :base_type          "type/Text"
                                                 :visibility_type    "normal"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))
                              (merge defaults (match-$ (Field :table_id (id :users), :name "PASSWORD")
-                                               {:special_type       "category"
+                                               {:special_type       "type/Category"
                                                 :name               "PASSWORD"
                                                 :display_name       "Password"
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "TextField"
+                                                :base_type          "type/Text"
                                                 :visibility_type    "sensitive"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
@@ -289,13 +289,13 @@
             :display_name "Users"
             :fields       (let [defaults (assoc field-defaults :table_id (id :users))]
                             [(merge defaults (match-$ (Field (id :users :id))
-                                               {:special_type       "id"
+                                               {:special_type       "type/PK"
                                                 :name               "ID"
                                                 :display_name       "ID"
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "BigIntegerField"
+                                                :base_type          "type/BigInteger"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))
@@ -306,18 +306,18 @@
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "DateTimeField"
+                                                :base_type          "type/DateTime"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))
                              (merge defaults (match-$ (Field (id :users :name))
-                                               {:special_type       "name"
+                                               {:special_type       "type/Name"
                                                 :name               "NAME"
                                                 :display_name       "Name"
                                                 :updated_at         $
                                                 :id                 $
                                                 :created_at         $
-                                                :base_type          "TextField"
+                                                :base_type          "type/Text"
                                                 :fk_target_field_id $
                                                 :raw_column_id      $
                                                 :last_analyzed      $}))])
@@ -385,10 +385,10 @@
                                 :raw_column_id      $
                                 :name               "USER_ID"
                                 :display_name       "User ID"
-                                :base_type          "IntegerField"
+                                :base_type          "type/Integer"
                                 :preview_display    $
                                 :position           $
-                                :special_type       "fk"
+                                :special_type       "type/FK"
                                 :fk_target_field_id $
                                 :created_at         $
                                 :updated_at         $
@@ -410,10 +410,10 @@
                                 :raw_column_id      $
                                 :name               "ID"
                                 :display_name       "ID"
-                                :base_type          "BigIntegerField"
+                                :base_type          "type/BigInteger"
                                 :preview_display    $
                                 :position           $
-                                :special_type       "id"
+                                :special_type       "type/PK"
                                 :fk_target_field_id $
                                 :created_at         $
                                 :updated_at         $
diff --git a/test/metabase/driver/bigquery_test.clj b/test/metabase/driver/bigquery_test.clj
index d98c0fe6aba170c44b4155aa11017d869d8dbbd7..395fd7a7f8f97b9b7793218f283cd1806f256519 100644
--- a/test/metabase/driver/bigquery_test.clj
+++ b/test/metabase/driver/bigquery_test.clj
@@ -9,57 +9,57 @@
 ;; Make sure that paging works correctly for the bigquery driver when fetching a list of tables
 ;; Default page size is 50 so if we have more than that number of tables make sure they all show up
 (def-database-definition ^:private fifty-one-different-tables
-  ["birds_1"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_2"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_3"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_4"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_5"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_6"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_7"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_8"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_9"  [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_10" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_11" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_12" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_13" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_14" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_15" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_16" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_17" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_18" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_19" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_20" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_21" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_22" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_23" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_24" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_25" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_26" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_27" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_28" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_29" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_30" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_31" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_32" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_33" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_34" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_35" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_36" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_37" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_38" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_39" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_40" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_41" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_42" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_43" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_44" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_45" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_46" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_47" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_48" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_49" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_50" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]]
-  ["birds_51" [{:field-name "name", :base-type :TextField}] [["Rasta"] ["Lucky"]]])
+  ["birds_1"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_2"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_3"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_4"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_5"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_6"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_7"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_8"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_9"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_10" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_11" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_12" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_13" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_14" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_15" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_16" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_17" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_18" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_19" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_20" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_21" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_22" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_23" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_24" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_25" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_26" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_27" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_28" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_29" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_30" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_31" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_32" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_33" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_34" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_35" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_36" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_37" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_38" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_39" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_40" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_41" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_42" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_43" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_44" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_45" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_46" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_47" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_48" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_49" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_50" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
+  ["birds_51" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]])
 
 ;; only run this test 1 out of every 5 times since it takes like 5-10 minutes just to sync the DB and we don't have all day
 (when (> (rand) 0.80)
@@ -82,9 +82,9 @@
 ;; make sure that BigQuery native queries maintain the column ordering specified in the SQL -- post-processing ordering shouldn't apply (Issue #2821)
 (expect-with-engine :bigquery
   {:columns ["venue_id" "user_id" "checkins_id"]
-   :cols    [{:name "venue_id",    :base_type :IntegerField}
-             {:name "user_id",     :base_type :IntegerField}
-             {:name "checkins_id", :base_type :IntegerField}]}
+   :cols    [{:name "venue_id",    :base_type :type/Integer}
+             {:name "user_id",     :base_type :type/Integer}
+             {:name "checkins_id", :base_type :type/Integer}]}
   (select-keys (:data (qp/process-query {:native   {:query "SELECT [test_data.checkins.venue_id] AS [venue_id], [test_data.checkins.user_id] AS [user_id], [test_data.checkins.id] AS [checkins_id]
                                                             FROM [test_data.checkins]
                                                             LIMIT 2"}
diff --git a/test/metabase/driver/druid_test.clj b/test/metabase/driver/druid_test.clj
index d338438ec60a98a84be1fdb5b87996a74545568a..5e89b527b20786c933644bacf8f5c0baa7418e92 100644
--- a/test/metabase/driver/druid_test.clj
+++ b/test/metabase/driver/druid_test.clj
@@ -27,12 +27,12 @@
                :rows        [["2013-01-03T08:00:00.000Z" "931" "Simcha Yan" "1" "Kinaree Thai Bistro"       1]
                              ["2013-01-10T08:00:00.000Z" "285" "Kfir Caj"   "2" "Ruen Pair Thai Restaurant" 1]]
                :annotate?   nil
-               :cols        [{:name "timestamp",   :base_type :TextField}
-                             {:name "id",          :base_type :TextField}
-                             {:name "user_name",   :base_type :TextField}
-                             {:name "venue_price", :base_type :TextField}
-                             {:name "venue_name",  :base_type :TextField}
-                             {:name "count",       :base_type :IntegerField}]
+               :cols        [{:name "timestamp",   :base_type :type/Text}
+                             {:name "id",          :base_type :type/Text}
+                             {:name "user_name",   :base_type :type/Text}
+                             {:name "venue_price", :base_type :type/Text}
+                             {:name "venue_name",  :base_type :type/Text}
+                             {:name "count",       :base_type :type/Integer}]
                :native_form {:query native-query}}}
   (metabase.test.data.datasets/with-engine :druid
     (timeseries-qp-test/with-flattened-dbdef
diff --git a/test/metabase/driver/generic_sql/native_test.clj b/test/metabase/driver/generic_sql/native_test.clj
index 27f4932d21ac1fb2f9132498df753c6541a58f65..91c9ec71b2b2f2f54a1e09a947d147cc880d8dee 100644
--- a/test/metabase/driver/generic_sql/native_test.clj
+++ b/test/metabase/driver/generic_sql/native_test.clj
@@ -11,7 +11,7 @@
          :data {:rows [[100]
                        [99]]
                 :columns ["ID"]
-                :cols [{:name "ID", :base_type :IntegerField}]
+                :cols [{:name "ID", :base_type :type/Integer}]
                 :native_form {:query "SELECT ID FROM VENUES ORDER BY ID DESC LIMIT 2;"}}}
   (qp/process-query {:native   {:query "SELECT ID FROM VENUES ORDER BY ID DESC LIMIT 2;"}
                      :type     :native
@@ -24,9 +24,9 @@
      :data {:rows [[100 "Mohawk Bend" 46]
                    [99 "Golden Road Brewing" 10]]
             :columns ["ID" "NAME" "CATEGORY_ID"]
-            :cols [{:name "ID", :base_type :IntegerField}
-                   {:name "NAME", :base_type :TextField}
-                   {:name "CATEGORY_ID", :base_type :IntegerField}]
+            :cols [{:name "ID", :base_type :type/Integer}
+                   {:name "NAME", :base_type :type/Text}
+                   {:name "CATEGORY_ID", :base_type :type/Integer}]
             :native_form {:query "SELECT ID, NAME, CATEGORY_ID FROM VENUES ORDER BY ID DESC LIMIT 2;"}}}
   (qp/process-query {:native   {:query "SELECT ID, NAME, CATEGORY_ID FROM VENUES ORDER BY ID DESC LIMIT 2;"}
                      :type     :native
diff --git a/test/metabase/driver/generic_sql_test.clj b/test/metabase/driver/generic_sql_test.clj
index ec784d7907ae0e4f2964b7547d657674db29947c..5254f3d5142826e0fb36d661e922cdd847a841c6 100644
--- a/test/metabase/driver/generic_sql_test.clj
+++ b/test/metabase/driver/generic_sql_test.clj
@@ -39,22 +39,22 @@
    :schema "PUBLIC"
    :fields #{{:name      "NAME",
               :custom    {:column-type "VARCHAR"}
-              :base-type :TextField}
+              :base-type :type/Text}
              {:name      "LATITUDE"
               :custom    {:column-type "DOUBLE"}
-              :base-type :FloatField}
+              :base-type :type/Float}
              {:name      "LONGITUDE"
               :custom    {:column-type "DOUBLE"}
-              :base-type :FloatField}
+              :base-type :type/Float}
              {:name      "PRICE"
               :custom    {:column-type "INTEGER"}
-              :base-type :IntegerField}
+              :base-type :type/Integer}
              {:name      "CATEGORY_ID"
               :custom    {:column-type "INTEGER"}
-              :base-type :IntegerField}
+              :base-type :type/Integer}
              {:name      "ID"
               :custom    {:column-type "BIGINT"}
-              :base-type :BigIntegerField
+              :base-type :type/BigInteger
               :pk?       true}}}
   (driver/describe-table (H2Driver.) (db) @venues-table))
 
diff --git a/test/metabase/driver/mongo_test.clj b/test/metabase/driver/mongo_test.clj
index 87ce9048af07dbbda2e8df29ea7db570bcc88bf5..f3475cbd35eb8e284df36d6ed05f8001a37007d7 100644
--- a/test/metabase/driver/mongo_test.clj
+++ b/test/metabase/driver/mongo_test.clj
@@ -7,9 +7,13 @@
                              [field :refer [Field]]
                              [table :refer [Table] :as table])
             [metabase.query-processor :as qp]
+            [metabase.query-processor.expand :as ql]
+            [metabase.query-processor-test :refer [rows]]
             [metabase.test.data :as data]
-            [metabase.test.data.datasets :as datasets])
-  (:import metabase.driver.mongo.MongoDriver))
+            [metabase.test.data.datasets :as datasets]
+            [metabase.test.data.interface :as i])
+  (:import org.bson.types.ObjectId
+           metabase.driver.mongo.MongoDriver))
 
 ;; ## Logic for selectively running mongo
 
@@ -79,7 +83,7 @@
    :data      {:rows        [[1]]
                :annotate?   nil
                :columns     ["count"]
-               :cols        [{:name "count", :base_type :IntegerField}]
+               :cols        [{:name "count", :base_type :type/Integer}]
                :native_form {:collection "venues"
                              :query      native-query}}}
   (qp/process-query {:native   {:query      native-query
@@ -102,17 +106,17 @@
   {:schema nil
    :name   "venues"
    :fields #{{:name "name",
-              :base-type :TextField}
+              :base-type :type/Text}
              {:name "latitude",
-              :base-type :FloatField}
+              :base-type :type/Float}
              {:name "longitude",
-              :base-type :FloatField}
+              :base-type :type/Float}
              {:name "price",
-              :base-type :IntegerField}
+              :base-type :type/Integer}
              {:name "category_id",
-              :base-type :IntegerField}
+              :base-type :type/Integer}
              {:name "_id",
-              :base-type :IntegerField,
+              :base-type :type/Integer,
               :pk? true}}}
   (driver/describe-table (MongoDriver.) (mongo-db) (table-name->table :venues)))
 
@@ -144,25 +148,41 @@
 
 ;; Test that Fields got synced correctly, and types are correct
 (expect-when-testing-mongo
-    [[{:special_type :id,        :base_type :IntegerField,  :name "_id"}
-      {:special_type :name,      :base_type :TextField,     :name "name"}]
-     [{:special_type :id,        :base_type :IntegerField,  :name "_id"}
-      {:special_type nil,        :base_type :DateTimeField, :name "date"}
-      {:special_type :category,  :base_type :IntegerField,  :name "user_id"}
-      {:special_type nil,        :base_type :IntegerField,  :name "venue_id"}]
-     [{:special_type :id,        :base_type :IntegerField,  :name "_id"}
-      {:special_type nil,        :base_type :DateTimeField, :name "last_login"}
-      {:special_type :name,      :base_type :TextField,     :name "name"}
-      {:special_type :category,  :base_type :TextField,     :name "password"}]
-     [{:special_type :id,        :base_type :IntegerField,  :name "_id"}
-      {:special_type :category,  :base_type :IntegerField,  :name "category_id"}
-      {:special_type :latitude,  :base_type :FloatField,    :name "latitude"}
-      {:special_type :longitude, :base_type :FloatField,    :name "longitude"}
-      {:special_type :name,      :base_type :TextField,     :name "name"}
-      {:special_type :category,  :base_type :IntegerField,  :name "price"}]]
+    [[{:special_type :type/PK,        :base_type :type/Integer,  :name "_id"}
+      {:special_type :type/Name,      :base_type :type/Text,     :name "name"}]
+     [{:special_type :type/PK,        :base_type :type/Integer,  :name "_id"}
+      {:special_type nil,             :base_type :type/DateTime, :name "date"}
+      {:special_type :type/Category,  :base_type :type/Integer,  :name "user_id"}
+      {:special_type nil,             :base_type :type/Integer,  :name "venue_id"}]
+     [{:special_type :type/PK,        :base_type :type/Integer,  :name "_id"}
+      {:special_type nil,             :base_type :type/DateTime, :name "last_login"}
+      {:special_type :type/Name,      :base_type :type/Text,     :name "name"}
+      {:special_type :type/Category,  :base_type :type/Text,     :name "password"}]
+     [{:special_type :type/PK,        :base_type :type/Integer,  :name "_id"}
+      {:special_type :type/Category,  :base_type :type/Integer,  :name "category_id"}
+      {:special_type :type/Latitude,  :base_type :type/Float,    :name "latitude"}
+      {:special_type :type/Longitude, :base_type :type/Float,    :name "longitude"}
+      {:special_type :type/Name,      :base_type :type/Text,     :name "name"}
+      {:special_type :type/Category,  :base_type :type/Integer,  :name "price"}]]
     (for [nm table-names]
       (for [field (db/select [Field :name :base_type :special_type]
                     :active   true
                     :table_id (:id (table-name->table nm))
                     {:order-by [:name]})]
         (into {} field))))
+
+
+;;; Check that we support Mongo BSON ID and can filter by it (#1367)
+
+(i/def-database-definition ^:private with-bson-ids
+  ["birds"
+   [{:field-name "name", :base-type :type/Text}
+    {:field-name "bird_id", :base-type :type/MongoBSONID}]
+   [["Rasta Toucan" (ObjectId. "012345678901234567890123")]
+    ["Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")]]])
+
+(datasets/expect-with-engine :mongo
+  [[2 "Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")]]
+  (rows (data/dataset metabase.driver.mongo-test/with-bson-ids
+          (data/run-query birds
+            (ql/filter (ql/= $bird_id "abcdefabcdefabcdefabcdef"))))))
diff --git a/test/metabase/driver/mysql_test.clj b/test/metabase/driver/mysql_test.clj
index 6969a9e0535f2df79d92b98ac6a6ef2d5e3b7079..a4376b99c8599e9dca5d6bae85bf903ddd9a4df5 100644
--- a/test/metabase/driver/mysql_test.clj
+++ b/test/metabase/driver/mysql_test.clj
@@ -7,7 +7,7 @@
 ;; MySQL allows 0000-00-00 dates, but JDBC does not; make sure that MySQL is converting them to NULL when returning them like we asked
 (def-database-definition ^:private ^:const all-zero-dates
   ["exciting-moments-in-history"
-   [{:field-name "moment", :base-type :DateTimeField}]
+   [{:field-name "moment", :base-type :type/DateTime}]
    [["0000-00-00"]]])
 
 (expect-with-engine :mysql
diff --git a/test/metabase/driver/postgres_test.clj b/test/metabase/driver/postgres_test.clj
index 776b4d795dd81a9de65c474a566737ba9e66b37e..5312ab42c325a2543929a3cb20e2633cb30f9dc8 100644
--- a/test/metabase/driver/postgres_test.clj
+++ b/test/metabase/driver/postgres_test.clj
@@ -51,7 +51,7 @@
 
 ;; Verify that we identify JSON columns and mark metadata properly during sync
 (expect-with-engine :postgres
-  :json
+  :type/SerializedJSON
   (data/with-temp-db
     [_
      (i/create-database-definition "Postgres with a JSON Field"
@@ -62,9 +62,9 @@
 
 
 ;;; # UUID Support
-(i/def-database-definition ^:const ^:private with-uuid
+(i/def-database-definition ^:private with-uuid
   ["users"
-   [{:field-name "user_id", :base-type :UUIDField}]
+   [{:field-name "user_id", :base-type :type/UUID}]
    [[#uuid "4f01dcfd-13f7-430c-8e6f-e505c0851027"]
     [#uuid "4652b2e7-d940-4d55-a971-7e484566663e"]
     [#uuid "da1d6ecc-e775-4008-b366-c38e7a2e8433"]
@@ -72,10 +72,10 @@
     [#uuid "84ed434e-80b4-41cf-9c88-e334427104ae"]]])
 
 
-;; Check that we can load a Postgres Database with a :UUIDField
+;; Check that we can load a Postgres Database with a :type/UUID
 (expect-with-engine :postgres
-  [{:name "id",      :base_type :IntegerField}
-   {:name "user_id", :base_type :UUIDField}]
+  [{:name "id",      :base_type :type/Integer}
+   {:name "user_id", :base_type :type/UUID}]
   (->> (data/dataset metabase.driver.postgres-test/with-uuid
          (data/run-query users))
        :data
@@ -99,9 +99,9 @@
 
 
 ;; Make sure that Tables / Fields with dots in their names get escaped properly
-(i/def-database-definition ^:const ^:private dots-in-names
+(i/def-database-definition ^:private dots-in-names
   ["objects.stuff"
-   [{:field-name "dotted.name", :base-type :TextField}]
+   [{:field-name "dotted.name", :base-type :type/Text}]
    [["toucan_cage"]
     ["four_loko"]
     ["ouija_board"]]])
@@ -117,14 +117,14 @@
 
 
 ;; Make sure that duplicate column names (e.g. caused by using a FK) still return both columns
-(i/def-database-definition ^:const ^:private duplicate-names
+(i/def-database-definition ^:private duplicate-names
   ["birds"
-   [{:field-name "name", :base-type :TextField}]
+   [{:field-name "name", :base-type :type/Text}]
    [["Rasta"]
     ["Lucky"]]]
   ["people"
-   [{:field-name "name", :base-type :TextField}
-    {:field-name "bird_id", :base-type :IntegerField, :fk :birds}]
+   [{:field-name "name", :base-type :type/Text}
+    {:field-name "bird_id", :base-type :type/Integer, :fk :birds}]
    [["Cam" 1]]])
 
 (expect-with-engine :postgres
@@ -136,6 +136,22 @@
       :data (dissoc :cols :native_form)))
 
 
+;;; Check support for `inet` columns
+(i/def-database-definition ^:private ip-addresses
+  ["addresses"
+   [{:field-name "ip", :base-type {:native "inet"}}]
+   [[(hsql/raw "'192.168.1.1'::inet")]
+    [(hsql/raw "'10.4.4.15'::inet")]]])
+
+;; Filtering by inet columns should add the appropriate SQL cast, e.g. `cast('192.168.1.1' AS inet)` (otherwise this wouldn't work)
+(expect-with-engine :postgres
+  [[1]]
+  (rows (data/dataset metabase.driver.postgres-test/ip-addresses
+          (data/run-query addresses
+            (ql/aggregation (ql/count))
+            (ql/filter (ql/= $ip "192.168.1.1"))))))
+
+
 ;; Check that we properly fetch materialized views.
 ;; As discussed in #2355 they don't come back from JDBC `DatabaseMetadata` so we have to fetch them manually.
 (expect-with-engine :postgres
diff --git a/test/metabase/http_client.clj b/test/metabase/http_client.clj
index 0cc9659dae644ab9c4330d0eaf02da7f17fbef9a..038345181f3decd365e2067174582fdb3c7c6993 100644
--- a/test/metabase/http_client.clj
+++ b/test/metabase/http_client.clj
@@ -14,11 +14,13 @@
   "Prefix to automatically prepend to the URL of calls made with `client`."
   (str "http://localhost:" (config/config-str :mb-jetty-port) "/api/"))
 
-(defn- build-url [url url-param-kwargs]
-  {:pre [(string? url)
-         (or (nil? url-param-kwargs)
-             (map? url-param-kwargs))]}
-  (str *url-prefix* url (when-not (empty? url-param-kwargs)
+(defn build-url
+  "Build an API URL for `localhost` and `MB_JETTY_PORT` with URL-PARAM-KWARGS.
+
+     (build-url \"db/1\" {:x true}) -> \"http://localhost:3000/api/db/1?x=true\""
+  [url url-param-kwargs]
+  {:pre [(string? url) (u/maybe? map? url-param-kwargs)]}
+  (str *url-prefix* url (when (seq url-param-kwargs)
                           (str "?" (s/join \& (for [[k v] url-param-kwargs]
                                                 (str (if (keyword? k) (name k) k)
                                                      \=
diff --git a/test/metabase/models/field_test.clj b/test/metabase/models/field_test.clj
index e0ad0474542e54699b7f957ac70d9c37f72c915a..4eb01a4087584cd6819773bbd94e14f15b989dae 100644
--- a/test/metabase/models/field_test.clj
+++ b/test/metabase/models/field_test.clj
@@ -6,78 +6,68 @@
             [metabase.test.util :as tu]))
 
 
-;; valid-special-type-for-base-type?
-(expect true  (valid-special-type-for-base-type? nil                     nil))
-(expect true  (valid-special-type-for-base-type? nil                     :foo))
-(expect true  (valid-special-type-for-base-type? nil                     :IntegerField))
-(expect true  (valid-special-type-for-base-type? :timestamp_seconds      :IntegerField))
-(expect true  (valid-special-type-for-base-type? :timestamp_milliseconds :IntegerField))
-(expect false (valid-special-type-for-base-type? :timestamp_seconds      :DateTimeField))
-(expect false (valid-special-type-for-base-type? :timestamp_milliseconds :DateTimeField))
-
-
 ;; field-should-have-field-values?
 
 ;; retired/sensitive/hidden/details-only fields should always be excluded
-(expect false (field-should-have-field-values? {:base_type       :BooleanField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/Boolean
+                                                :special_type    :type/Category
                                                 :visibility_type :retired}))
-(expect false (field-should-have-field-values? {:base_type       :BooleanField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/Boolean
+                                                :special_type    :type/Category
                                                 :visibility_type :sensitive}))
-(expect false (field-should-have-field-values? {:base_type       :BooleanField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/Boolean
+                                                :special_type    :type/Category
                                                 :visibility_type :hidden}))
-(expect false (field-should-have-field-values? {:base_type       :BooleanField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/Boolean
+                                                :special_type    :type/Category
                                                 :visibility_type :details-only}))
 ;; date/time based fields should always be excluded
-(expect false (field-should-have-field-values? {:base_type       :DateField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/Date
+                                                :special_type    :type/Category
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :DateTimeField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/DateTime
+                                                :special_type    :type/Category
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :TimeField
-                                                :special_type    :category
+(expect false (field-should-have-field-values? {:base_type       :type/Time
+                                                :special_type    :type/Category
                                                 :visibility_type :normal}))
 ;; most special types should be excluded
-(expect false (field-should-have-field-values? {:base_type    :CharField
-                                                :special_type :image
+(expect false (field-should-have-field-values? {:base_type       :type/Text
+                                                :special_type    :type/ImageURL
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :CharField
+(expect false (field-should-have-field-values? {:base_type       :type/Text
                                                 :special_type    :id
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :CharField
-                                                :special_type    :fk
+(expect false (field-should-have-field-values? {:base_type       :type/Text
+                                                :special_type    :type/FK
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :CharField
-                                                :special_type    :latitude
+(expect false (field-should-have-field-values? {:base_type       :type/Text
+                                                :special_type    :type/Latitude
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :CharField
-                                                :special_type    :number
+(expect false (field-should-have-field-values? {:base_type       :type/Text
+                                                :special_type    :type/Number
                                                 :visibility_type :normal}))
-(expect false (field-should-have-field-values? {:base_type       :CharField
-                                                :special_type    :timestamp_milliseconds
+(expect false (field-should-have-field-values? {:base_type       :type/Text
+                                                :special_type    :type/UNIXTimestampMilliseconds
                                                 :visibility_type :normal}))
 ;; boolean fields + category/city/state/country fields are g2g
-(expect true (field-should-have-field-values? {:base_type       :BooleanField
-                                               :special_type    :number
+(expect true (field-should-have-field-values? {:base_type       :type/Boolean
+                                               :special_type    :type/Number
                                                :visibility_type :normal}))
-(expect true (field-should-have-field-values? {:base_type       :CharField
-                                               :special_type    :category
+(expect true (field-should-have-field-values? {:base_type       :type/Text
+                                               :special_type    :type/Category
                                                :visibility_type :normal}))
-(expect true (field-should-have-field-values? {:base_type       :TextField
-                                               :special_type    :city
+(expect true (field-should-have-field-values? {:base_type       :type/Text
+                                               :special_type    :type/City
                                                :visibility_type :normal}))
-(expect true (field-should-have-field-values? {:base_type       :TextField
-                                               :special_type    :state
+(expect true (field-should-have-field-values? {:base_type       :type/Text
+                                               :special_type    :type/State
                                                :visibility_type :normal}))
-(expect true (field-should-have-field-values? {:base_type       :TextField
-                                               :special_type    :country
+(expect true (field-should-have-field-values? {:base_type       :type/Text
+                                               :special_type    :type/Country
                                                :visibility_type :normal}))
-(expect true (field-should-have-field-values? {:base_type       :TextField
-                                               :special_type    :name
+(expect true (field-should-have-field-values? {:base_type       :type/Text
+                                               :special_type    :type/Name
                                                :visibility_type :normal}))
 
 
@@ -85,16 +75,15 @@
 
 (tu/resolve-private-fns metabase.models.field infer-field-special-type)
 
-(expect nil (infer-field-special-type nil nil))
-(expect nil (infer-field-special-type "id" nil))
-(expect nil (infer-field-special-type nil :IntegerField))
-;; name of "id" should be :id
-(expect :id (infer-field-special-type "id" :IntegerField))
+(expect nil            (infer-field-special-type nil       nil))
+(expect nil            (infer-field-special-type "id"      nil))
+(expect nil            (infer-field-special-type nil       :type/Integer))
+(expect :type/PK       (infer-field-special-type "id"      :type/Integer))
 ;; other pattern matches based on type/regex (remember, base_type matters in matching!)
-(expect :category (infer-field-special-type "rating" :IntegerField))
-(expect nil (infer-field-special-type "rating" :BooleanField))
-(expect :country (infer-field-special-type "country" :TextField))
-(expect nil (infer-field-special-type "country" :IntegerField))
+(expect :type/Category (infer-field-special-type "rating"  :type/Integer))
+(expect nil            (infer-field-special-type "rating"  :type/Boolean))
+(expect :type/Country  (infer-field-special-type "country" :type/Text))
+(expect nil            (infer-field-special-type "country" :type/Integer))
 
 
 ;; TODO: update-field
diff --git a/test/metabase/models/field_values_test.clj b/test/metabase/models/field_values_test.clj
index ebcf37885cc567010d1fd90ca9359dfbd3cedc73..287a9eec11edf752f352333f65bdb292e164cee0 100644
--- a/test/metabase/models/field_values_test.clj
+++ b/test/metabase/models/field_values_test.clj
@@ -9,38 +9,33 @@
 
 ;; ## TESTS FOR FIELD-SHOULD-HAVE-FIELD-VALUES?
 
-(expect true
-  (field-should-have-field-values? {:special_type :category
-                                    :visibility_type :normal
-                                    :base_type :TextField}))
-
-(expect false
-  (field-should-have-field-values? {:special_type :category
-                                    :visibility_type :sensitive
-                                    :base_type :TextField}))
-(expect false
-  (field-should-have-field-values? {:special_type :category
-                                    :visibility_type :hidden
-                                    :base_type :TextField}))
-(expect false
-  (field-should-have-field-values? {:special_type :category
-                                    :visibility_type :details-only
-                                    :base_type :TextField}))
-
-(expect false
-  (field-should-have-field-values? {:special_type nil
-                                    :visibility_type :normal
-                                    :base_type :TextField}))
-
-(expect true
-  (field-should-have-field-values? {:special_type "country"
-                                    :visibility_type :normal
-                                    :base_type :TextField}))
-
-(expect true
-  (field-should-have-field-values? {:special_type nil
-                                    :visibility_type :normal
-                                    :base_type "BooleanField"}))
+(expect (field-should-have-field-values? {:special_type    :type/Category
+                                          :visibility_type :normal
+                                          :base_type       :type/Text}))
+
+(expect false (field-should-have-field-values? {:special_type    :type/Category
+                                                :visibility_type :sensitive
+                                                :base_type       :type/Text}))
+
+(expect false (field-should-have-field-values? {:special_type    :type/Category
+                                                :visibility_type :hidden
+                                                :base_type       :type/Text}))
+
+(expect false (field-should-have-field-values? {:special_type :type/Category
+                                                :visibility_type          :details-only
+                                                :base_type                :type/Text}))
+
+(expect false (field-should-have-field-values? {:special_type    nil
+                                                :visibility_type :normal
+                                                :base_type       :type/Text}))
+
+(expect (field-should-have-field-values? {:special_type    "type/Country"
+                                          :visibility_type :normal
+                                          :base_type       :type/Text}))
+
+(expect (field-should-have-field-values? {:special_type    nil
+                                          :visibility_type :normal
+                                          :base_type       "type/Boolean"}))
 
 
 (expect
diff --git a/test/metabase/query_processor/expand_resolve_test.clj b/test/metabase/query_processor/expand_resolve_test.clj
index 8d35fcc88090acf39578100d6b79b34b13657c7b..cb15f930eaf65048d4a91945b60f532e5268e715 100644
--- a/test/metabase/query_processor/expand_resolve_test.clj
+++ b/test/metabase/query_processor/expand_resolve_test.clj
@@ -45,8 +45,8 @@
                                                 :fk-field-id        nil
                                                 :field-name         "PRICE"
                                                 :field-display-name "Price"
-                                                :base-type          :IntegerField
-                                                :special-type       :category
+                                                :base-type          :type/Integer
+                                                :special-type       :type/Category
                                                 :visibility-type    :normal
                                                 :table-id           (id :venues)
                                                 :schema-name        "PUBLIC"
@@ -60,8 +60,8 @@
                                                         :fk-field-id        nil
                                                         :field-name         "PRICE"
                                                         :field-display-name "Price"
-                                                        :base-type          :IntegerField
-                                                        :special-type       :category
+                                                        :base-type          :type/Integer
+                                                        :special-type       :type/Category
                                                         :visibility-type    :normal
                                                         :table-id           (id :venues)
                                                         :schema-name        "PUBLIC"
@@ -104,8 +104,8 @@
                                                 :fk-field-id        (id :venues :category_id)
                                                 :field-name         "NAME"
                                                 :field-display-name "Name"
-                                                :base-type          :TextField
-                                                :special-type       :name
+                                                :base-type          :type/Text
+                                                :special-type       :type/Name
                                                 :visibility-type    :normal
                                                 :table-id           (id :categories)
                                                 :schema-name        nil
@@ -119,8 +119,8 @@
                                                         :fk-field-id        (id :venues :category_id)
                                                         :field-name         "NAME"
                                                         :field-display-name "Name"
-                                                        :base-type          :TextField
-                                                        :special-type       :name
+                                                        :base-type          :type/Text
+                                                        :special-type       :type/Name
                                                         :visibility-type    :normal
                                                         :table-id           (id :categories)
                                                         :schema-name        nil
@@ -171,7 +171,7 @@
                                                         :fk-field-id        (id :checkins :user_id)
                                                         :field-name         "LAST_LOGIN"
                                                         :field-display-name "Last Login"
-                                                        :base-type          :DateTimeField
+                                                        :base-type          :type/DateTime
                                                         :special-type       nil
                                                         :visibility-type    :normal
                                                         :table-id           (id :users)
@@ -187,7 +187,7 @@
                                                                 :fk-field-id        (id :checkins :user_id)
                                                                 :field-name         "LAST_LOGIN"
                                                                 :field-display-name "Last Login"
-                                                                :base-type          :DateTimeField
+                                                                :base-type          :type/DateTime
                                                                 :special-type       nil
                                                                 :visibility-type    :normal
                                                                 :table-id           (id :users)
@@ -236,10 +236,10 @@
                                   :id     (id :checkins)}
                    :aggregation  {:aggregation-type :sum
                                   :field            {:description        nil
-                                                     :base-type          :IntegerField
+                                                     :base-type          :type/Integer
                                                      :parent             nil
                                                      :table-id           (id :venues)
-                                                     :special-type       :category
+                                                     :special-type       :type/Category
                                                      :field-name         "PRICE"
                                                      :field-display-name "Price"
                                                      :parent-id          nil
@@ -250,7 +250,7 @@
                                                      :table-name         "VENUES__via__VENUE_ID"
                                                      :schema-name        nil}}
                    :breakout     [{:field {:description        nil
-                                           :base-type          :DateField
+                                           :base-type          :type/Date
                                            :parent             nil
                                            :table-id           (id :checkins)
                                            :special-type       nil
diff --git a/test/metabase/query_processor_test.clj b/test/metabase/query_processor_test.clj
index 88a5cad8697255813c1a5f141aecb538ef469132..0bd1f4b7df74cc7e2ad15d04c198e148572dc5f7 100644
--- a/test/metabase/query_processor_test.clj
+++ b/test/metabase/query_processor_test.clj
@@ -105,12 +105,12 @@
    {:table_id (id :categories)
     :id       (id :categories col)}
    (case col
-     :id   {:special_type :id
+     :id   {:special_type :type/PK
             :base_type    (id-field-type)
             :name         (format-name "id")
             :display_name "ID"}
-     :name {:special_type :name
-            :base_type    (expected-base-type->actual :TextField)
+     :name {:special_type :type/Name
+            :base_type    (expected-base-type->actual :type/Text)
             :name         (format-name "name")
             :display_name "Name"})))
 
@@ -123,16 +123,16 @@
    {:table_id (id :users)
     :id       (id :users col)}
    (case col
-     :id         {:special_type :id
+     :id         {:special_type :type/PK
                   :base_type    (id-field-type)
                   :name         (format-name "id")
                   :display_name "ID"}
-     :name       {:special_type :name
-                  :base_type    (expected-base-type->actual :TextField)
+     :name       {:special_type :type/Name
+                  :base_type    (expected-base-type->actual :type/Text)
                   :name         (format-name "name")
                   :display_name "Name"}
      :last_login {:special_type nil
-                  :base_type    (expected-base-type->actual :DateTimeField)
+                  :base_type    (expected-base-type->actual :type/DateTime)
                   :name         (format-name "last_login")
                   :display_name "Last Login"
                   :unit         :default})))
@@ -151,7 +151,7 @@
    {:table_id (id :venues)
     :id       (id :venues col)}
    (case col
-     :id          {:special_type :id
+     :id          {:special_type :type/PK
                    :base_type    (id-field-type)
                    :name         (format-name "id")
                    :display_name "ID"}
@@ -160,25 +160,25 @@
                                    {})
                    :target       (target-field (categories-col :id))
                    :special_type (if (fks-supported?)
-                                   :fk
-                                   :category)
-                   :base_type    (expected-base-type->actual :IntegerField)
+                                   :type/FK
+                                   :type/Category)
+                   :base_type    (expected-base-type->actual :type/Integer)
                    :name         (format-name "category_id")
                    :display_name "Category ID"}
-     :price       {:special_type :category
-                   :base_type    (expected-base-type->actual :IntegerField)
+     :price       {:special_type :type/Category
+                   :base_type    (expected-base-type->actual :type/Integer)
                    :name         (format-name "price")
                    :display_name "Price"}
-     :longitude   {:special_type :longitude,
-                   :base_type    (expected-base-type->actual :FloatField)
+     :longitude   {:special_type :type/Longitude
+                   :base_type    (expected-base-type->actual :type/Float)
                    :name         (format-name "longitude")
                    :display_name "Longitude"}
-     :latitude    {:special_type :latitude
-                   :base_type    (expected-base-type->actual :FloatField)
+     :latitude    {:special_type :type/Latitude
+                   :base_type    (expected-base-type->actual :type/Float)
                    :name         (format-name "latitude")
                    :display_name "Latitude"}
-     :name        {:special_type :name
-                   :base_type    (expected-base-type->actual :TextField)
+     :name        {:special_type :type/Name
+                   :base_type    (expected-base-type->actual :type/Text)
                    :name         (format-name "name")
                    :display_name "Name"})))
 
@@ -196,24 +196,26 @@
    {:table_id (id :checkins)
     :id       (id :checkins col)}
    (case col
-     :id       {:special_type :id
+     :id       {:special_type :type/PK
                 :base_type    (id-field-type)
                 :name         (format-name "id")
                 :display_name "ID"}
-     :venue_id {:extra_info   (if (fks-supported?) {:target_table_id (id :venues)}
-                                  {})
+     :venue_id {:extra_info   (if (fks-supported?)
+                                {:target_table_id (id :venues)}
+                                {})
                 :target       (target-field (venues-col :id))
                 :special_type (when (fks-supported?)
-                                :fk)
-                :base_type    (expected-base-type->actual :IntegerField)
+                                :type/FK)
+                :base_type    (expected-base-type->actual :type/Integer)
                 :name         (format-name "venue_id")
                 :display_name "Venue ID"}
      :user_id  {:extra_info   (if (fks-supported?) {:target_table_id (id :users)}
                                   {})
                 :target       (target-field (users-col :id))
-                :special_type (if (fks-supported?) :fk
-                                  :category)
-                :base_type    (expected-base-type->actual :IntegerField)
+                :special_type (if (fks-supported?)
+                                :type/FK
+                                :type/Category)
+                :base_type    (expected-base-type->actual :type/Integer)
                 :name         (format-name "user_id")
                 :display_name "User ID"})))
 
@@ -228,8 +230,8 @@
   {:arglists '([ag-col-kw] [ag-col-kw field])}
   ([ag-col-kw]
    (case ag-col-kw
-     :count  {:base_type    :IntegerField
-              :special_type :number
+     :count  {:base_type    :type/Integer
+              :special_type :type/Number
               :name         "count"
               :display_name "count"
               :id           nil
@@ -278,7 +280,10 @@
      :else        (vec (for [row rows]
                          (vec (for [[f v] (partition 2 (interleave format-fns row))]
                                 (when (or v format-nil-values?)
-                                  (f v)))))))))
+                                  (try (f v)
+                                       (catch Throwable e
+                                         (printf "(%s %s) failed: %s" f v (.getMessage e))
+                                         (throw e)))))))))))
 
 (def ^:private formatted-venues-rows (partial format-rows-by [int str int (partial u/round-to-decimals 4) (partial u/round-to-decimals 4) int]))
 
@@ -772,8 +777,8 @@
 
 (defn- cumulative-count-col [col-fn col-name]
   (assoc (aggregate-col :count (col-fn col-name))
-         :base_type    :IntegerField
-         :special_type :number))
+    :base_type    :type/Integer
+    :special_type :type/Number))
 
 ;;; cum_count w/o breakout should be treated the same as count
 (qp-expect-with-all-engines
@@ -1598,14 +1603,14 @@
 
 (expect-with-non-timeseries-dbs
   (if (i/has-questionable-timezone-support? *driver*)
-    [[1  6] [2 10] [3  4] [4  9] [5  9] [6  8] [7  8] [8  9] [9  7] [10  9]]
-    [[1  8] [2  9] [3  9] [4  4] [5 11] [6  8] [7  6] [8 10] [9  6] [10 10]])
+    [[1 6] [2 10] [3 4] [4 9] [5  9] [6 8] [7 8] [8  9] [9 7] [10  9]]
+    [[1 8] [2  9] [3 9] [4 4] [5 11] [6 8] [7 6] [8 10] [9 6] [10 10]])
   (sad-toucan-incidents-with-bucketing :day-of-month))
 
 (expect-with-non-timeseries-dbs
   (if (i/has-questionable-timezone-support? *driver*)
-    [[152  6] [153 10] [154  4] [155  9] [156  9] [157  8] [158  8] [159  9] [160  7] [161  9]]
-    [[152  8] [153  9] [154  9] [155  4] [156 11] [157  8] [158  6] [159 10] [160  6] [161 10]])
+    [[152 6] [153 10] [154 4] [155 9] [156  9] [157  8] [158 8] [159  9] [160 7] [161  9]]
+    [[152 8] [153  9] [154 9] [155 4] [156 11] [157  8] [158 6] [159 10] [160 6] [161 10]])
   (sad-toucan-incidents-with-bucketing :day-of-year))
 
 (expect-with-non-timeseries-dbs
@@ -1670,7 +1675,7 @@
   (create-database-definition (str "a-checkin-every-" interval-seconds "-seconds")
     ["checkins"
      [{:field-name "timestamp"
-       :base-type  :DateTimeField}]
+       :base-type  :type/DateTime}]
      (vec (for [i (range -15 15)]
             ;; Create timestamps using relative dates (e.g. `DATEADD(second, -195, GETUTCDATE())` instead of generating `java.sql.Timestamps` here so
             ;; they'll be in the DB's native timezone. Some DBs refuse to use the same timezone we're running the tests from *cough* SQL Server *cough*
diff --git a/test/metabase/sync_database/analyze_test.clj b/test/metabase/sync_database/analyze_test.clj
index 932bcd83b07d801418ed386c72d58c67da00204d..0ba6ea66eafb738d9186f4fec317267494fb3a7d 100644
--- a/test/metabase/sync_database/analyze_test.clj
+++ b/test/metabase/sync_database/analyze_test.clj
@@ -15,7 +15,7 @@
 
 (expect
   {:values       [1 2 3 4]
-   :special-type :category}
+   :special-type :type/Category}
   (with-redefs-fn {#'metadata-queries/field-distinct-values (constantly [1 2 3 4])}
     #(test:cardinality-and-extract-field-values {} {})))
 
diff --git a/test/metabase/sync_database/introspect_test.clj b/test/metabase/sync_database/introspect_test.clj
index 4fa464fb896c5f2c83c5d74c73f2ca14c3559623..3294051e3fe9cf90babb92fdc530bc276a39a0a1 100644
--- a/test/metabase/sync_database/introspect_test.clj
+++ b/test/metabase/sync_database/introspect_test.clj
@@ -79,26 +79,26 @@
    [(merge field-defaults
            {:name    "beak_size"
             :is_pk   true
-            :details {:inches 7, :special-type "category", :base-type "IntegerField"}})]
+            :details {:inches 7, :special-type "type/Category", :base-type "type/Integer"}})]
    [(merge field-defaults
            {:name    "beak_size"
-            :details {:inches 8, :base-type "IntegerField"}})
+            :details {:inches 8, :base-type "type/Integer"}})
     (merge field-defaults
            {:name    "num_feathers"
-            :details {:count 10000, :base-type "IntegerField"}})]
+            :details {:count 10000, :base-type "type/Integer"}})]
    [(merge field-defaults
            {:name    "beak_size"
-            :details {:inches 8, :base-type "IntegerField"}
+            :details {:inches 8, :base-type "type/Integer"}
             :active  false})
     (merge field-defaults
            {:name    "num_feathers"
-            :details {:count 12000, :base-type "IntegerField"}})]
+            :details {:count 12000, :base-type "type/Integer"}})]
    [(merge field-defaults
            {:name    "beak_size"
-            :details {:inches 8, :base-type "IntegerField"}})
+            :details {:inches 8, :base-type "type/Integer"}})
     (merge field-defaults
            {:name    "num_feathers"
-            :details {:count 12000, :base-type "IntegerField"}})]]
+            :details {:count 12000, :base-type "type/Integer"}})]]
   (tu/with-temp* [Database [{database-id :id}]
                   RawTable [{raw-table-id :id, :as table} {:database_id database-id}]]
     (let [get-columns #(->> (db/select RawColumn, :raw_table_id raw-table-id, {:order-by [:id]})
@@ -107,21 +107,21 @@
       [(get-columns)
        ;; now add a column
        (do
-         (save-all-table-columns! table [{:name "beak_size", :base-type :IntegerField, :details {:inches 7}, :pk? true, :special-type "category"}])
+         (save-all-table-columns! table [{:name "beak_size", :base-type :type/Integer, :details {:inches 7}, :pk? true, :special-type "type/Category"}])
          (get-columns))
        ;; now add another column and modify the first
        (do
-         (save-all-table-columns! table [{:name "beak_size", :base-type :IntegerField, :details {:inches 8}}
-                                         {:name "num_feathers", :base-type :IntegerField, :details {:count 10000}}])
+         (save-all-table-columns! table [{:name "beak_size", :base-type :type/Integer, :details {:inches 8}}
+                                         {:name "num_feathers", :base-type :type/Integer, :details {:count 10000}}])
          (get-columns))
        ;; now remove the first column
        (do
-         (save-all-table-columns! table [{:name "num_feathers", :base-type :IntegerField, :details {:count 12000}}])
+         (save-all-table-columns! table [{:name "num_feathers", :base-type :type/Integer, :details {:count 12000}}])
          (get-columns))
        ;; lastly, resurrect the first column (this ensures uniqueness by name)
        (do
-         (save-all-table-columns! table [{:name "beak_size", :base-type :IntegerField, :details {:inches 8}}
-                                         {:name "num_feathers", :base-type :IntegerField, :details {:count 12000}}])
+         (save-all-table-columns! table [{:name "beak_size", :base-type :type/Integer, :details {:inches 8}}
+                                         {:name "num_feathers", :base-type :type/Integer, :details {:count 12000}}])
          (get-columns))])))
 
 ;; create-raw-table
@@ -152,7 +152,7 @@
             :columns [(merge field-defaults
                              {:name    "beak_size"
                               :is_pk   true
-                              :details {:inches 7, :base-type "IntegerField"}})]})]]
+                              :details {:inches 7, :base-type "type/Integer"}})]})]]
   (tu/with-temp* [Database [{database-id :id, :as db}]]
     [(get-tables database-id)
      ;; now add a table
@@ -168,7 +168,7 @@
                                        :name    "toucanery"
                                        :details {:owner "Cam"}
                                        :fields  [{:name      "beak_size"
-                                                  :base-type :IntegerField
+                                                  :base-type :type/Integer
                                                   :pk?       true
                                                   :details   {:inches 7}}]})
        (get-tables database-id))]))
@@ -187,7 +187,7 @@
             :columns [(merge field-defaults
                              {:name    "beak_size"
                               :is_pk   true
-                              :details {:inches 7, :base-type "IntegerField"}})]})]]
+                              :details {:inches 7, :base-type "type/Integer"}})]})]]
   (tu/with-temp* [Database [{database-id :id, :as db}]
                   RawTable [table {:database_id database-id
                                    :schema      "aviary"
@@ -200,7 +200,7 @@
                                  :name    "toucanery"
                                  :details {:owner "Cam", :sqft 10000}
                                  :fields [{:name      "beak_size"
-                                           :base-type :IntegerField
+                                           :base-type :type/Integer
                                            :pk?       true
                                            :details   {:inches 7}}]})
        (get-tables database-id))]))
diff --git a/test/metabase/sync_database/sync_dynamic_test.clj b/test/metabase/sync_database/sync_dynamic_test.clj
index cca8638b84d0eaed6fb68d3d82961198fda92a97..309ed10a3477fbc5336ec4921f12e08a38d66d1b 100644
--- a/test/metabase/sync_database/sync_dynamic_test.clj
+++ b/test/metabase/sync_database/sync_dynamic_test.clj
@@ -37,69 +37,69 @@
 (expect
   [[]
    ;; initial sync
-   [(merge field-defaults {:base_type    :IntegerField
-                           :special_type :id
+   [(merge field-defaults {:base_type    :type/Integer
+                           :special_type :type/PK
                            :name         "First"
                            :display_name "First"})
-    (merge field-defaults {:base_type    :TextField
+    (merge field-defaults {:base_type    :type/Text
                            :name         "Second"
                            :display_name "Second"})
-    (merge field-defaults {:base_type    :BooleanField
+    (merge field-defaults {:base_type    :type/Boolean
                            :special_type nil
                            :name         "Third"
                            :display_name "Third"})]
    ;; add column, modify first column, add some nested fields
-   [(merge field-defaults {:base_type    :DecimalField
-                           :special_type :id
+   [(merge field-defaults {:base_type    :type/Decimal
+                           :special_type :type/PK
                            :name         "First"
                            :display_name "First"})
-    (merge field-defaults {:base_type    :TextField
+    (merge field-defaults {:base_type    :type/Text
                            :name         "Second"
                            :display_name "Second"})
-    (merge field-defaults {:base_type    :BooleanField
+    (merge field-defaults {:base_type    :type/Boolean
                            :name         "Third"
                            :display_name "Third"})
-    (merge field-defaults {:base_type    :IntegerField
-                           :special_type :category
+    (merge field-defaults {:base_type    :type/Integer
+                           :special_type :type/Category
                            :name         "rating"
                            :display_name "Rating"})
-    (merge field-defaults {:base_type    :TextField
-                           :special_type :city
+    (merge field-defaults {:base_type    :type/Text
+                           :special_type :type/City
                            :name         "city"
                            :display_name "City"
                            :parent_id    true})
-    (merge field-defaults {:base_type    :TextField
-                           :special_type :category
+    (merge field-defaults {:base_type    :type/Text
+                           :special_type :type/Category
                            :name         "type"
                            :display_name "Type"
                            :parent_id    true})]
    ;; first column retired, 3rd column now a pk, another nested field
-   [(merge field-defaults {:base_type    :DecimalField
-                           :special_type :id
+   [(merge field-defaults {:base_type    :type/Decimal
+                           :special_type :type/PK
                            :name         "First"
                            :display_name "First"})
-    (merge field-defaults {:base_type    :TextField
+    (merge field-defaults {:base_type    :type/Text
                            :name         "Second"
                            :display_name "Second"})
-    (merge field-defaults {:base_type    :BooleanField
-                           :special_type :id
+    (merge field-defaults {:base_type    :type/Boolean
+                           :special_type :type/PK
                            :name         "Third"
                            :display_name "Third"})
     (merge field-defaults {:name         "rating"
                            :display_name "Rating"
-                           :base_type    :IntegerField
-                           :special_type :category})
-    (merge field-defaults {:base_type    :TextField
-                           :special_type :city
+                           :base_type    :type/Integer
+                           :special_type :type/Category})
+    (merge field-defaults {:base_type    :type/Text
+                           :special_type :type/City
                            :name         "city"
                            :display_name "City"
                            :parent_id    true})
-    (merge field-defaults {:base_type    :TextField
-                           :special_type :category
+    (merge field-defaults {:base_type    :type/Text
+                           :special_type :type/Category
                            :name         "type"
                            :display_name "Type"
                            :parent_id    true})
-    (merge field-defaults {:base_type    :BooleanField
+    (merge field-defaults {:base_type    :type/Boolean
                            :name         "new"
                            :display_name "New"
                            :parent_id    true})]]
@@ -116,19 +116,19 @@
       ;; start with no fields
       [(get-fields)
        ;; first sync will add all the fields
-       (save-fields! {:name "First", :base-type :IntegerField, :pk? true}
-                     {:name "Second", :base-type :TextField}
-                     {:name "Third", :base-type :BooleanField})
+       (save-fields! {:name "First", :base-type :type/Integer, :pk? true}
+                     {:name "Second", :base-type :type/Text}
+                     {:name "Third", :base-type :type/Boolean})
        ;; now add another column (with nested-fields!) and modify the first
-       (save-fields! {:name "First", :base-type :DecimalField, :pk? false}
-                     {:name "Second", :base-type :TextField}
-                     {:name "Third", :base-type :BooleanField}
-                     {:name "rating", :base-type :IntegerField, :nested-fields [{:name "city", :base-type :TextField}
-                                                                                {:name "type", :base-type :TextField}]})
+       (save-fields! {:name "First", :base-type :type/Decimal, :pk? false}
+                     {:name "Second", :base-type :type/Text}
+                     {:name "Third", :base-type :type/Boolean}
+                     {:name "rating", :base-type :type/Integer, :nested-fields [{:name "city", :base-type :type/Text}
+                                                                                {:name "type", :base-type :type/Text}]})
        ;; now remove the first column (should have no effect), and make tweaks to the nested columns
-       (save-fields! {:name "Second", :base-type :TextField}
-                     {:name "Third", :base-type :BooleanField, :pk? true}
-                     {:name "rating", :base-type :IntegerField, :nested-fields [{:name "new", :base-type :BooleanField}]})])))
+       (save-fields! {:name "Second", :base-type :type/Text}
+                     {:name "Third", :base-type :type/Boolean, :pk? true}
+                     {:name "rating", :base-type :type/Integer, :nested-fields [{:name "new", :base-type :type/Boolean}]})])))
 
 
 ;; scan-table-and-update-data-model!
diff --git a/test/metabase/sync_database/sync_test.clj b/test/metabase/sync_database/sync_test.clj
index ea1ae9347f7c4bafb45810b0a4bf1f5b8d131a0c..0e0102a07325535202be7500fb1fbc1f65977a30 100644
--- a/test/metabase/sync_database/sync_test.clj
+++ b/test/metabase/sync_database/sync_test.clj
@@ -26,9 +26,9 @@
 ;; save-fks!
 (expect
   [[{:special_type nil, :name "fk1", :fk_target_field_id false}]
-   [{:special_type :fk, :name "fk1", :fk_target_field_id true}]
-   [{:special_type :fk, :name "fk1", :fk_target_field_id true}]
-   [{:special_type :fk, :name "fk1", :fk_target_field_id true}]]
+   [{:special_type :type/FK, :name "fk1", :fk_target_field_id true}]
+   [{:special_type :type/FK, :name "fk1", :fk_target_field_id true}]
+   [{:special_type :type/FK, :name "fk1", :fk_target_field_id true}]]
   (tu/with-temp* [Database  [{database-id :id}]
                   RawTable  [{raw-table-id1 :id, :as table}  {:database_id database-id, :name "fk_source"}]
                   RawColumn [{raw-fk1 :id}                   {:raw_table_id raw-table-id1, :name "fk1"}]
@@ -119,54 +119,54 @@
    ;; initial sync
    [(merge field-defaults {:name         "First"
                            :display_name "First"
-                           :base_type    :IntegerField
-                           :special_type :id})
+                           :base_type    :type/Integer
+                           :special_type :type/PK})
     (merge field-defaults {:name         "Second"
                            :display_name "Second"
-                           :base_type    :TextField})
+                           :base_type    :type/Text})
     (merge field-defaults {:name         "Third"
                            :display_name "Third"
-                           :base_type    :BooleanField
+                           :base_type    :type/Boolean
                            :special_type nil})]
    ;; add column, modify first column
    [(merge field-defaults {:name         "First"
                            :display_name "First"
-                           :base_type    :DecimalField
-                           :special_type :id}) ; existing special types are NOT modified
+                           :base_type    :type/Decimal
+                           :special_type :type/PK}) ; existing special types are NOT modified
     (merge field-defaults {:name         "Second"
                            :display_name "Second"
-                           :base_type    :TextField})
+                           :base_type    :type/Text})
     (merge field-defaults {:name         "Third"
                            :display_name "Third"
-                           :base_type    :BooleanField
+                           :base_type    :type/Boolean
                            :special_type nil})
     (merge field-defaults {:name         "rating"
                            :display_name "Rating"
-                           :base_type    :IntegerField
-                           :special_type :category})]
+                           :base_type    :type/Integer
+                           :special_type :type/Category})]
    ;; first column retired, 3rd column now a pk
    [(merge field-defaults {:name            "First"
                            :display_name    "First"
-                           :base_type       :DecimalField
+                           :base_type       :type/Decimal
                            :visibility_type :retired ; field retired when RawColumn disabled
-                           :special_type    :id})
+                           :special_type    :type/PK})
     (merge field-defaults {:name         "Second"
                            :display_name "Second"
-                           :base_type    :TextField})
+                           :base_type    :type/Text})
     (merge field-defaults {:name         "Third"
                            :display_name "Third"
-                           :base_type    :BooleanField
-                           :special_type :id}) ; special type can be set if it was nil before
+                           :base_type    :type/Boolean
+                           :special_type :type/PK}) ; special type can be set if it was nil before
     (merge field-defaults {:name         "rating"
                            :display_name "Rating"
-                           :base_type    :IntegerField
-                           :special_type :category})]]
+                           :base_type    :type/Integer
+                           :special_type :type/Category})]]
   (tu/with-temp* [Database  [{database-id :id}]
                   RawTable  [{raw-table-id :id, :as table} {:database_id database-id}]
-                  RawColumn [{raw-column-id1 :id} {:raw_table_id raw-table-id, :name "First", :is_pk true, :details {:base-type "IntegerField"}}]
-                  RawColumn [{raw-column-id2 :id} {:raw_table_id raw-table-id, :name "Second", :details {:base-type "TextField"}}]
-                  RawColumn [{raw-column-id3 :id} {:raw_table_id raw-table-id, :name "Third", :details {:base-type "BooleanField"}}]
-                  Table     [{table-id :id, :as tbl} {:db_id database-id, :raw_table_id raw-table-id}]]
+                  RawColumn [{raw-column-id1 :id}          {:raw_table_id raw-table-id, :name "First", :is_pk true, :details {:base-type "type/Integer"}}]
+                  RawColumn [{raw-column-id2 :id}          {:raw_table_id raw-table-id, :name "Second", :details {:base-type "type/Text"}}]
+                  RawColumn [{raw-column-id3 :id}          {:raw_table_id raw-table-id, :name "Third", :details {:base-type "type/Boolean"}}]
+                  Table     [{table-id :id, :as tbl}       {:db_id database-id, :raw_table_id raw-table-id}]]
     (let [get-fields #(->> (db/select Field, :table_id table-id, {:order-by [:id]})
                            (mapv tu/boolean-ids-and-timestamps)
                            (mapv (fn [m]
@@ -175,14 +175,14 @@
           first-sync     (do
                            (save-table-fields! tbl)
                            (get-fields))]
-      (tu/with-temp* [RawColumn [_ {:raw_table_id raw-table-id, :name "rating", :details {:base-type "IntegerField"}}]]
+      (tu/with-temp* [RawColumn [_ {:raw_table_id raw-table-id, :name "rating", :details {:base-type "type/Integer"}}]]
         ;; start with no fields
         [initial-fields
          ;; first sync will add all the fields
          first-sync
          ;; now add another column and modify the first
          (do
-           (db/update! RawColumn raw-column-id1, :is_pk false, :details {:base-type "DecimalField"})
+           (db/update! RawColumn raw-column-id1, :is_pk false, :details {:base-type "type/Decimal"})
            (save-table-fields! tbl)
            (get-fields))
          ;; now disable the first column
@@ -224,12 +224,13 @@
 
 ;; update-data-models-for-table!
 (expect
-  (let [disable-fks #(map (fn [field]
-                            (if (= :fk (:special_type field))
-                              (assoc field
-                                :special_type       nil
-                                :fk_target_field_id false)
-                              field)) %)]
+  (let [disable-fks (fn [fields]
+                      (for [field fields]
+                        (if (isa? (:special_type field) :type/FK)
+                          (assoc field
+                            :special_type       nil
+                            :fk_target_field_id false)
+                          field)))]
     [[(-> (last moviedb/moviedb-tables-and-fields)
           (update :fields disable-fks))]
      [(-> (last moviedb/moviedb-tables-and-fields)
@@ -244,25 +245,25 @@
 
       ;; stub out the Table we are going to sync for real below
       (let [raw-table-id (db/select-one-id RawTable, :database_id database-id, :name "roles")
-            tbl          (db/insert! Table
+            table        (db/insert! Table
                            :db_id        database-id
                            :raw_table_id raw-table-id
                            :name         "roles"
                            :active       true)]
-        [;; now lets run a sync and check what we got
+        [ ;; now lets run a sync and check what we got
          (do
-           (update-data-models-for-table! tbl)
+           (update-data-models-for-table! table)
            (get-tables database-id))
          ;; run the sync a second time to see how we respond to repeat syncing (should be same since nothing changed)
          (do
-           (update-data-models-for-table! tbl)
+           (update-data-models-for-table! table)
            (get-tables database-id))
          ;; one more time, but lets disable the table this time and ensure that's handled properly
          (do
            (db/update-where! RawTable {:database_id database-id
                                        :name        "roles"}
              :active false)
-           (update-data-models-for-table! tbl)
+           (update-data-models-for-table! table)
            (get-tables database-id))]))))
 
 
@@ -300,7 +301,7 @@
          (get-tables database-id))])))
 
 
-(defn resolve-fk-targets
+(defn- resolve-fk-targets
   "Convert :fk_target_[column|field]_id into more testable information with table/schema names."
   [m]
   (let [resolve-raw-column (fn [column-id]
@@ -353,15 +354,15 @@
 ;;; ------------------------------------------------------------ Make sure that "crufty" tables are marked as such ------------------------------------------------------------
 (i/def-database-definition ^:const ^:private db-with-some-cruft
   ["acquired_toucans"
-   [{:field-name "species",              :base-type :CharField}
-    {:field-name "cam_has_acquired_one", :base-type :BooleanField}]
+   [{:field-name "species",              :base-type :type/Text}
+    {:field-name "cam_has_acquired_one", :base-type :type/Boolean}]
    [["Toco"               false]
     ["Chestnut-Mandibled" true]
     ["Keel-billed"        false]
     ["Channel-billed"     false]]]
   ["south_migrationhistory"
-   [{:field-name "app_name",  :base-type :CharField}
-    {:field-name "migration", :base-type :CharField}]
+   [{:field-name "app_name",  :base-type :type/Text}
+    {:field-name "migration", :base-type :type/Text}]
    [["main" "0001_initial"]
     ["main" "0002_add_toucans"]]])
 
diff --git a/test/metabase/sync_database_test.clj b/test/metabase/sync_database_test.clj
index 4c925016c195a568e46b136bb4cc3476f1e10d7c..39f38f39beec4f42b96fa65e13e25fceb92275d0 100644
--- a/test/metabase/sync_database_test.clj
+++ b/test/metabase/sync_database_test.clj
@@ -16,18 +16,18 @@
   {"movie"  {:name "movie"
              :schema "default"
              :fields #{{:name      "id"
-                        :base-type :IntegerField}
+                        :base-type :type/Integer}
                        {:name      "title"
-                        :base-type :TextField}
+                        :base-type :type/Text}
                        {:name      "studio"
-                        :base-type :TextField}}}
+                        :base-type :type/Text}}}
    "studio" {:name "studio"
              :schema nil
              :fields #{{:name         "studio"
-                        :base-type    :TextField
-                        :special-type :id}
+                        :base-type    :type/Text
+                        :special-type :type/PK}
                        {:name      "name"
-                        :base-type :TextField}}}})
+                        :base-type :type/Text}}}})
 
 (defrecord SyncTestDriver []
   clojure.lang.Named
@@ -104,34 +104,34 @@
            :name         "movie"
            :display_name "Movie"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "studio"
                                   :display_name       "Studio"
-                                  :base_type          :TextField
+                                  :base_type          :type/Text
                                   :fk_target_field_id true})
                           (merge field-defaults
                                  {:special_type nil
                                   :name         "title"
                                   :display_name "Title"
-                                  :base_type    :TextField})]})
+                                  :base_type    :type/Text})]})
    (merge table-defaults
           {:name         "studio"
            :display_name "Studio"
            :fields       [(merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})
+                                  :base_type    :type/Text})
                           (merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "studio"
                                   :display_name "Studio"
-                                  :base_type    :TextField})]})]
+                                  :base_type    :type/Text})]})]
   (tu/with-temp Database [fake-db {:engine :sync-test}]
     (sync-database! fake-db)
     ;; we are purposely running the sync twice to test for possible logic issues which only manifest
@@ -148,20 +148,20 @@
           :name         "movie"
           :display_name "Movie"
           :fields       [(merge field-defaults
-                                {:special_type :id
+                                {:special_type :type/PK
                                  :name         "id"
                                  :display_name "ID"
-                                 :base_type    :IntegerField})
+                                 :base_type    :type/Integer})
                          (merge field-defaults
                                 {:special_type nil
                                  :name         "studio"
                                  :display_name "Studio"
-                                 :base_type    :TextField})
+                                 :base_type    :type/Text})
                          (merge field-defaults
                                 {:special_type nil
                                  :name         "title"
                                  :display_name "Title"
-                                 :base_type    :TextField})]})
+                                 :base_type    :type/Text})]})
   (tu/with-temp* [Database [fake-db {:engine :sync-test}]
                   RawTable [{raw-table-id :id} {:database_id (:id fake-db), :name "movie", :schema "default"}]
                   Table    [fake-table {:raw_table_id raw-table-id
@@ -229,11 +229,11 @@
 ;; ## Individual Helper Fns
 
 ;; ## TEST PK SYNCING
-(expect [:id
+(expect [:type/PK
          nil
-         :id
-         :latitude
-         :id]
+         :type/PK
+         :type/Latitude
+         :type/PK]
   (let [get-special-type (fn [] (db/select-one-field :special_type Field, :id (id :venues :id)))]
     [;; Special type should be :id to begin with
      (get-special-type)
@@ -244,7 +244,7 @@
      (do (sync-table! @venues-table)
          (get-special-type))
      ;; sync-table! should *not* change the special type of fields that are marked with a different type
-     (do (db/update! Field (id :venues :id), :special_type :latitude)
+     (do (db/update! Field (id :venues :id), :special_type :type/Latitude)
          (get-special-type))
      ;; Make sure that sync-table runs set-table-pks-if-needed!
      (do (db/update! Field (id :venues :id), :special_type nil)
@@ -265,9 +265,9 @@
   (db/select-one-field :fk_target_field_id Field, :id (id :venues :category_id)))
 
 ;; Check that sync-table! causes FKs to be set like we'd expect
-(expect [{:special_type :fk, :fk_target_field_id true}
+(expect [{:special_type :type/FK, :fk_target_field_id true}
          {:special_type nil, :fk_target_field_id false}
-         {:special_type :fk, :fk_target_field_id true}]
+         {:special_type :type/FK, :fk_target_field_id true}]
   (let [field-id (id :checkins :user_id)
         get-special-type-and-fk-exists? (fn []
                                           (into {} (-> (db/select-one [Field :special_type :fk_target_field_id], :id field-id)
diff --git a/test/metabase/test/data.clj b/test/metabase/test/data.clj
index 905218634bf9059f3e77c629389cb11712f29100..73947e45098cef3c4b21c71fdf1468274d2953b9 100644
--- a/test/metabase/test/data.clj
+++ b/test/metabase/test/data.clj
@@ -206,7 +206,7 @@
                        (db/update! Field (:id @field) :visibility_type (name visibility-type)))
                      (when special-type
                        (log/debug (format "SET SPECIAL TYPE %s.%s -> %s" table-name field-name special-type))
-                       (db/update! Field (:id @field) :special_type (name special-type)))))))
+                       (db/update! Field (:id @field) :special_type (u/keyword->qualified-name special-type)))))))
              db))))))
 
 (defn remove-database!
diff --git a/test/metabase/test/data/bigquery.clj b/test/metabase/test/data/bigquery.clj
index 82688d53f3fe7a895babccaca3ec035de4c0bd9c..970b8ac61315f7852c1689631b0c1e893866d722 100644
--- a/test/metabase/test/data/bigquery.clj
+++ b/test/metabase/test/data/bigquery.clj
@@ -119,17 +119,16 @@
 
 
 (def ^:private ^:const base-type->bigquery-type
-  {:BigIntegerField :INTEGER
-   :BooleanField    :BOOLEAN
-   :CharField       :STRING
-   :DateField       :TIMESTAMP
-   :DateTimeField   :TIMESTAMP
-   :DecimalField    :FLOAT
-   :DictionaryField :RECORD
-   :FloatField      :FLOAT
-   :IntegerField    :INTEGER
-   :TextField       :STRING
-   :TimeField       :TIMESTAMP})
+  {:type/BigInteger :INTEGER
+   :type/Boolean    :BOOLEAN
+   :type/Date       :TIMESTAMP
+   :type/DateTime   :TIMESTAMP
+   :type/Decimal    :FLOAT
+   :type/Dictionary :RECORD
+   :type/Float      :FLOAT
+   :type/Integer    :INTEGER
+   :type/Text       :STRING
+   :type/Time       :TIMESTAMP})
 
 (defn- fielddefs->field-name->base-type
   "Convert FIELD-DEFINITIONS to a format appropriate for passing to `create-table!`."
diff --git a/test/metabase/test/data/crate.clj b/test/metabase/test/data/crate.clj
index c98973d73a2c097ed1d235e1c732e76a614d020f..f231b0fa62eb5480d89346cd6d0328bc36b69a7d 100644
--- a/test/metabase/test/data/crate.clj
+++ b/test/metabase/test/data/crate.clj
@@ -9,16 +9,15 @@
   (:import metabase.driver.crate.CrateDriver))
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "long"
-   :BooleanField    "boolean"
-   :CharField       "string"
-   :DateField       "timestamp"
-   :DateTimeField   "timestamp"
-   :DecimalField    "integer"
-   :FloatField      "float"
-   :IntegerField    "integer"
-   :TextField       "string"
-   :TimeField       "timestamp"})
+  {:type/BigInteger "long"
+   :type/Boolean    "boolean"
+   :type/Date       "timestamp"
+   :type/DateTime   "timestamp"
+   :type/Decimal    "integer"
+   :type/Float      "float"
+   :type/Integer    "integer"
+   :type/Text       "string"
+   :type/Time       "timestamp"})
 
 
 (defn- timestamp->CrateDateTime
diff --git a/test/metabase/test/data/dataset_definitions/avian-singles.edn b/test/metabase/test/data/dataset_definitions/avian-singles.edn
index a6f30f60ac37961547b46d984b51964f93a71b20..f18e5eec2905cbde7c82739986f24d1a2f77c877 100644
--- a/test/metabase/test/data/dataset_definitions/avian-singles.edn
+++ b/test/metabase/test/data/dataset_definitions/avian-singles.edn
@@ -1,5 +1,5 @@
 [["users" [{:field-name "name"
-            :base-type  :CharField}]
+            :base-type  :type/Text}]
   [["Rasta Toucan"]
    ["Lucky Pigeon"]
    ["Peter Pelican"]
@@ -9,13 +9,13 @@
    ["Brenda Blackbird"]
    ["Annie Albatross"]]]
  ["messages" [{:field-name "sender_id"
-               :base-type  :IntegerField
+               :base-type  :type/Integer
                :fk         :users}
               {:field-name "reciever_id"
-               :base-type  :IntegerField
+               :base-type  :type/Integer
                :fk         :users}
               {:field-name "text"
-               :base-type  :CharField}]
+               :base-type  :type/Text}]
   [[8 7 "Coo"]
    [8 3 "Bip bip bip bip"]
    [3 2 "Coo"]
diff --git a/test/metabase/test/data/dataset_definitions/geographical-tips.edn b/test/metabase/test/data/dataset_definitions/geographical-tips.edn
index 271eafce334efe38559688479a75d214b8dd4eff..97750fc5a817cc924b5ec3a119bd96f98fc5d735 100644
--- a/test/metabase/test/data/dataset_definitions/geographical-tips.edn
+++ b/test/metabase/test/data/dataset_definitions/geographical-tips.edn
@@ -1,11 +1,11 @@
 [["tips" [{:field-name "text"
-           :base-type  :CharField}
+           :base-type  :type/Text}
           {:field-name "url"
-           :base-type :UnknownField}
+           :base-type :type/*}
           {:field-name "venue"
-           :base-type :UnknownField}
+           :base-type :type/*}
           {:field-name "source"
-           :base-type :UnknownField}]
+           :base-type :type/*}]
   [["Lucky's Gluten-Free Café is a atmospheric and delicious place to have a drink during winter."
     {:small "http://cloudfront.net/50576ac9-2211-4198-8915-265d32a6ba82/small.jpg",
      :medium "http://cloudfront.net/50576ac9-2211-4198-8915-265d32a6ba82/med.jpg",
diff --git a/test/metabase/test/data/dataset_definitions/half-valid-urls.edn b/test/metabase/test/data/dataset_definitions/half-valid-urls.edn
index 44e9eb8ccce8ead151697fd75698f123e7b812a3..349176309155017cb7d79d7e5f2996ceb9dc1b58 100644
--- a/test/metabase/test/data/dataset_definitions/half-valid-urls.edn
+++ b/test/metabase/test/data/dataset_definitions/half-valid-urls.edn
@@ -1,5 +1,5 @@
 [["urls" [{:field-name "url"
-           :base-type  :TextField}]
+           :base-type  :type/Text}]
   [["http://www.camsaul.com"]
    ["http://camsaul.com"]
    ["https://en.wikipedia.org/wiki/Toucan"]
diff --git a/test/metabase/test/data/dataset_definitions/places-cam-likes.edn b/test/metabase/test/data/dataset_definitions/places-cam-likes.edn
index e5faa8b12016704e953dace669b6c300499863ca..47b7a40dedf1577dc566514dc2a902e3d55100b5 100644
--- a/test/metabase/test/data/dataset_definitions/places-cam-likes.edn
+++ b/test/metabase/test/data/dataset_definitions/places-cam-likes.edn
@@ -1,7 +1,7 @@
 [["places" [{:field-name "name"
-             :base-type :CharField}
+             :base-type :type/Text}
             {:field-name "liked"
-             :base-type :BooleanField}]
+             :base-type :type/Boolean}]
   [["Tempest" true]
    ["Bullit" true]
    ["The Dentist" false]]]]
diff --git a/test/metabase/test/data/dataset_definitions/sad-toucan-incidents.edn b/test/metabase/test/data/dataset_definitions/sad-toucan-incidents.edn
index 5fb8b7796927fb3e5fba3b68861332ad23aacab7..2032294806ba70bec32ad3642532458ee1846e76 100644
--- a/test/metabase/test/data/dataset_definitions/sad-toucan-incidents.edn
+++ b/test/metabase/test/data/dataset_definitions/sad-toucan-incidents.edn
@@ -1,8 +1,8 @@
 [["incidents" [{:field-name "severity"
-                 :base-type  :IntegerField}
+                 :base-type  :type/Integer}
                 {:field-name   "timestamp"
-                 :base-type    :BigIntegerField
-                 :special-type :timestamp_milliseconds}]
+                 :base-type    :type/BigInteger
+                 :special-type :type/UNIXTimestampMilliseconds}]
    [[4 1433587200000]
     [0 1433965860000]
     [5 1433864520000]
diff --git a/test/metabase/test/data/dataset_definitions/test-data.edn b/test/metabase/test/data/dataset_definitions/test-data.edn
index 60ce41280e30ad1527c0a306178c0e33da475fbb..61e70d5b22f012fb4cb37cd95433fd666bb5a637 100644
--- a/test/metabase/test/data/dataset_definitions/test-data.edn
+++ b/test/metabase/test/data/dataset_definitions/test-data.edn
@@ -23,11 +23,11 @@
 ;;    *  date
 
 [["users" [{:field-name "name"
-            :base-type  :CharField}
+            :base-type  :type/Text}
            {:field-name "last_login"
-            :base-type  :DateTimeField}
+            :base-type  :type/DateTime}
            {:field-name "password"
-            :base-type  :CharField
+            :base-type  :type/Text
             :visibility-type :sensitive}]
   [["Plato Yeshua" #inst "2014-04-01T08:30" "4be68cda-6fd5-4ba7-944e-2b475600bda5"]
    ["Felipinho Asklepios" #inst "2014-12-05T15:15" "5bb19ad9-f3f8-421f-9750-7d398e38428d"]
@@ -45,7 +45,7 @@
    ["Broen Olujimi" #inst "2014-10-03T13:45" "f9b65c74-9f91-4cfd-9248-94a53af82866"]
    ["Rüstem Hebel" #inst "2014-08-01T12:45" "02ad6b15-54b0-4491-bf0f-d781b0a2c4f5"]]]
  ["categories" [{:field-name "name"
-                 :base-type  :CharField}]
+                 :base-type  :type/Text}]
   [["African"]
    ["American"]
    ["Artisan"]
@@ -122,18 +122,18 @@
    ["Wine Bar"]
    ["Winery"]]]
  ["venues" [{:field-name   "name"
-             :base-type    :CharField}
+             :base-type    :type/Text}
             {:field-name   "latitude"
-             :base-type    :FloatField
-             :special-type :latitude}
+             :base-type    :type/Float
+             :special-type :type/Latitude}
             {:field-name   "longitude"
-             :base-type    :FloatField
-             :special-type :longitude}
+             :base-type    :type/Float
+             :special-type :type/Longitude}
             {:field-name   "price"
-             :base-type    :IntegerField
-             :special-type :category}
+             :base-type    :type/Integer
+             :special-type :type/Category}
             {:field-name   "category_id"
-             :base-type    :IntegerField
+             :base-type    :type/Integer
              :fk           :categories}]
   [["Red Medicine" 10.0646 -165.374 3 4]                               ;   1
    ["Stout Burgers & Beers" 34.0996 -118.329 2 11]                     ;   2
@@ -236,13 +236,13 @@
    ["Golden Road Brewing" 34.1505 -118.274 2 10]                       ;  99
    ["Mohawk Bend" 34.0777 -118.265 2 46]]]                             ; 100
  ["checkins" [{:field-name "user_id"
-               :base-type  :IntegerField
+               :base-type  :type/Integer
                :fk         :users}
               {:field-name "venue_id"
-               :base-type  :IntegerField
+               :base-type  :type/Integer
                :fk         :venues}
               {:field-name "date"
-               :base-type  :DateField}]
+               :base-type  :type/Date}]
   [[5 12 #inst "2014-04-07T07"]
    [1 31 #inst "2014-09-18T07"]
    [8 56 #inst "2014-09-15T07"]
diff --git a/test/metabase/test/data/dataset_definitions/tupac-sightings.edn b/test/metabase/test/data/dataset_definitions/tupac-sightings.edn
index 8dc653570b9f81ad4b08d381ddab67639fc12bfb..47359bba4a4fb19ef394969178b8617e36424ca0 100644
--- a/test/metabase/test/data/dataset_definitions/tupac-sightings.edn
+++ b/test/metabase/test/data/dataset_definitions/tupac-sightings.edn
@@ -1,10 +1,10 @@
 [ ;; 151 cities where Tupac was sighted
  ["cities" [{:field-name "name"
-             :base-type  :CharField}
+             :base-type  :type/Text}
             {:field-name "latitude"
-             :base-type  :FloatField}
+             :base-type  :type/Float}
             {:field-name "longitude"
-             :base-type  :FloatField}]
+             :base-type  :type/Float}]
   [["Akron" 41.0817920535084 -81.5219209322972]
    ["Albany" 42.6674396618158 -73.8032049534362]
    ["Albuquerque" 35.1148836731619 -106.627751577878]
@@ -159,7 +159,7 @@
 
  ;; 15 Categories "where" Tupac was sighted
  ["categories" [{:field-name "name"
-                 :base-type  :CharField}]
+                 :base-type  :type/Text}]
   [["At a Restaurant"]
    ["At the Movies"]
    ["Walking Down the Street"]
@@ -178,14 +178,14 @@
 
  ;; 1000 random sightings of Tupac
  ["sightings" [{:field-name "city_id"
-                :base-type  :IntegerField
+                :base-type  :type/Integer
                 :fk         :cities}
                {:field-name "category_id"
-                :base-type  :IntegerField
+                :base-type  :type/Integer
                 :fk         :categories}
                {:field-name   "timestamp"
-                :base-type    :BigIntegerField
-                :special-type :timestamp_seconds}]
+                :base-type    :type/BigInteger
+                :special-type :type/UNIXTimestampSeconds}]
   [[23 14 927183600]
    [65 13 978854400]
    [60 10 886752000]
diff --git a/test/metabase/test/data/h2.clj b/test/metabase/test/data/h2.clj
index a80f29c0eabe49b1ebe209ba2ccc182089ddb9f0..6b9e299bf9a43fe67c5eeec873fa3d017975c464 100644
--- a/test/metabase/test/data/h2.clj
+++ b/test/metabase/test/data/h2.clj
@@ -11,16 +11,15 @@
   (:import metabase.driver.h2.H2Driver))
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "BIGINT"
-   :BooleanField    "BOOL"
-   :CharField       "VARCHAR(254)"
-   :DateField       "DATE"
-   :DateTimeField   "DATETIME"
-   :DecimalField    "DECIMAL"
-   :FloatField      "FLOAT"
-   :IntegerField    "INTEGER"
-   :TextField       "TEXT"
-   :TimeField       "TIME"})
+  {:type/BigInteger "BIGINT"
+   :type/Boolean    "BOOL"
+   :type/Date       "DATE"
+   :type/DateTime   "DATETIME"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "FLOAT"
+   :type/Integer    "INTEGER"
+   :type/Text       "VARCHAR"
+   :type/Time       "TIME"})
 
 ;; ## DatabaseDefinition helper functions
 
@@ -85,4 +84,4 @@
           :engine                             (constantly :h2)
           :format-name                        (u/drop-first-arg s/upper-case)
           :has-questionable-timezone-support? (constantly true)
-          :id-field-type                      (constantly :BigIntegerField)}))
+          :id-field-type                      (constantly :type/BigInteger)}))
diff --git a/test/metabase/test/data/interface.clj b/test/metabase/test/data/interface.clj
index 07d5660f2f73db46a2cb5f47991708fa54aa9e39..da84d0e94787fcc074a63ed91928c34bbda30b69 100644
--- a/test/metabase/test/data/interface.clj
+++ b/test/metabase/test/data/interface.clj
@@ -16,8 +16,8 @@
 
 (s/defrecord FieldDefinition [field-name      :- su/NonBlankString
                               base-type       :- (s/cond-pre {:native su/NonBlankString}
-                                                             (apply s/enum field/base-types))
-                              special-type    :- (s/maybe (apply s/enum field/special-types))
+                                                             su/FieldType)
+                              special-type    :- (s/maybe su/FieldType)
                               visibility-type :- (s/maybe (apply s/enum field/visibility-types))
                               fk              :- (s/maybe s/Keyword)])
 
@@ -105,7 +105,7 @@
     "*OPTIONAL*. Return the base type type that is actually used to store `Fields` of BASE-TYPE.
      The default implementation of this method is an identity fn. This is provided so DBs that don't support a given BASE-TYPE used in the test data
      can specifiy what type we should expect in the results instead.
-     For example, Oracle has `INTEGER` data types, so `:IntegerField` test values are instead stored as `NUMBER`, which we map to `:DecimalField`.")
+     For example, Oracle has `INTEGER` data types, so `:type/Integer` test values are instead stored as `NUMBER`, which we map to `:type/Decimal`.")
 
   (format-name ^String [this, ^String table-or-field-name]
     "*OPTIONAL* Transform a lowercase string `Table` or `Field` name in a way appropriate for this dataset
@@ -116,7 +116,7 @@
      Defaults to `(not (contains? (metabase.driver/features this) :set-timezone)`")
 
   (id-field-type ^clojure.lang.Keyword [this]
-    "*OPTIONAL* Return the `base_type` of the `id` `Field` (e.g. `:IntegerField` or `:BigIntegerField`). Defaults to `:IntegerField`."))
+    "*OPTIONAL* Return the `base_type` of the `id` `Field` (e.g. `:type/Integer` or `:type/BigInteger`). Defaults to `:type/Integer`."))
 
 (def IDatasetLoaderDefaultsMixin
   {:expected-base-type->actual         (u/drop-first-arg identity)
@@ -124,7 +124,7 @@
    :format-name                        (u/drop-first-arg identity)
    :has-questionable-timezone-support? (fn [driver]
                                          (not (contains? (driver/features driver) :set-timezone)))
-   :id-field-type                      (constantly :IntegerField)})
+   :id-field-type                      (constantly :type/Integer)})
 
 
 ;; ## Helper Functions for Creating New Definitions
diff --git a/test/metabase/test/data/mongo.clj b/test/metabase/test/data/mongo.clj
index f626c85b640cb1def6ffccfb0586d06774197d14..883e5b588dd289d38c8a3e3e97016ceecc0bbf17 100644
--- a/test/metabase/test/data/mongo.clj
+++ b/test/metabase/test/data/mongo.clj
@@ -14,29 +14,28 @@
   ([_ _ dbdef]
    (database->connection-details dbdef)))
 
-(defn- destroy-db! [_ dbdef]
+(defn- destroy-db! [dbdef]
   (with-open [mongo-connection (mg/connect (database->connection-details dbdef))]
     (mg/drop-db mongo-connection (i/escaped-name dbdef))))
 
-(defn- create-db! [this {:keys [table-definitions], :as dbdef}]
-  (destroy-db! this dbdef)
-  (with-mongo-connection [^com.mongodb.DB mongo-db (database->connection-details dbdef)]
+(defn- create-db! [{:keys [table-definitions], :as dbdef}]
+  (destroy-db! dbdef)
+  (with-mongo-connection [mongo-db (database->connection-details dbdef)]
     (doseq [{:keys [field-definitions table-name rows]} table-definitions]
-      (let [field-names (->> field-definitions
-                             (map :field-name)
-                             (map keyword))]
+      (let [field-names (for [field-definition field-definitions]
+                          (keyword (:field-name field-definition)))]
         ;; Use map-indexed so we can get an ID for each row (index + 1)
         (doseq [[i row] (map-indexed (partial vector) rows)]
           (let [row (for [v row]
                       ;; Conver all the java.sql.Timestamps to java.util.Date, because the Mongo driver insists on being obnoxious and going from
                       ;; using Timestamps in 2.x to Dates in 3.x
-                      (if (= (type v) java.sql.Timestamp)
+                      (if (instance? java.sql.Timestamp v)
                         (java.util.Date. (.getTime ^java.sql.Timestamp v))
                         v))]
             (try
               ;; Insert each row
               (mc/insert mongo-db (name table-name) (assoc (zipmap field-names row)
-                                                           :_id (inc i)))
+                                                      :_id (inc i)))
               ;; If row already exists then nothing to do
               (catch com.mongodb.MongoException _))))))))
 
@@ -44,8 +43,8 @@
 (u/strict-extend MongoDriver
   i/IDatasetLoader
   (merge i/IDatasetLoaderDefaultsMixin
-         {:create-db!                   create-db!
-          :destroy-db!                  destroy-db!
+         {:create-db!                   (u/drop-first-arg create-db!)
+          :destroy-db!                  (u/drop-first-arg destroy-db!)
           :database->connection-details database->connection-details
           :engine                       (constantly :mongo)
           :format-name                  (fn [_ table-or-field-name]
diff --git a/test/metabase/test/data/mysql.clj b/test/metabase/test/data/mysql.clj
index 288f1a5cae88088d515ac2a6ab72c85b76a158be..da6b36b3587fa4830f64ab11220819bbdc5f9ea8 100644
--- a/test/metabase/test/data/mysql.clj
+++ b/test/metabase/test/data/mysql.clj
@@ -9,16 +9,15 @@
   (:import metabase.driver.mysql.MySQLDriver))
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "BIGINT"
-   :BooleanField    "BOOLEAN" ; Synonym of TINYINT(1)
-   :CharField       "VARCHAR(254)"
-   :DateField       "DATE"
-   :DateTimeField   "TIMESTAMP"
-   :DecimalField    "DECIMAL"
-   :FloatField      "DOUBLE"
-   :IntegerField    "INTEGER"
-   :TextField       "TEXT"
-   :TimeField       "TIME"})
+  {:type/BigInteger "BIGINT"
+   :type/Boolean    "BOOLEAN" ; Synonym of TINYINT(1)
+   :type/Date       "DATE"
+   :type/DateTime   "TIMESTAMP"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "DOUBLE"
+   :type/Integer    "INTEGER"
+   :type/Text       "TEXT"
+   :type/Time       "TIME"})
 
 (defn- database->connection-details [context {:keys [database-name short-lived?]}]
   (merge {:host         "localhost"
diff --git a/test/metabase/test/data/oracle.clj b/test/metabase/test/data/oracle.clj
index 9364c2c04fcc2ee7c7c047dd96ff3ebbc8f1f4fb..b1cee7821e5a643f418dba500b8fbfd1d0934102 100644
--- a/test/metabase/test/data/oracle.clj
+++ b/test/metabase/test/data/oracle.clj
@@ -45,15 +45,14 @@
 
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "NUMBER(*,0)"
-   :BooleanField    "NUMBER(1)"
-   :CharField       "VARCHAR2(254)"
-   :DateField       "DATE"
-   :DateTimeField   "TIMESTAMP"
-   :DecimalField    "DECIMAL"
-   :FloatField      "BINARY_FLOAT"
-   :IntegerField    "INTEGER"
-   :TextField       "VARCHAR2(4000)"}) ; Oracle doesn't have a TEXT type so use the maximum size for a VARCHAR2
+  {:type/BigInteger "NUMBER(*,0)"
+   :type/Boolean    "NUMBER(1)"
+   :type/Date       "DATE"
+   :type/DateTime   "TIMESTAMP"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "BINARY_FLOAT"
+   :type/Integer    "INTEGER"
+   :type/Text       "VARCHAR2(4000)"}) ; Oracle doesn't have a TEXT type so use the maximum size for a VARCHAR2
 
 (defn- drop-table-if-exists-sql [{:keys [database-name]} {:keys [table-name]}]
   (format "BEGIN
@@ -90,11 +89,11 @@
           :default-schema               (constantly session-schema)
           :engine                       (constantly :oracle)
           :expected-base-type->actual   (fn [_ base-type]
-                                          (condp = base-type
-                                            :IntegerField    :DecimalField ; Oracle doesn't have INTEGERs
-                                            :BigIntegerField :DecimalField
+                                          ;; Oracle doesn't have INTEGERs
+                                          (if (isa? base-type :type/Integer)
+                                            :type/Decimal
                                             base-type))
-          :id-field-type                (constantly :DecimalField)}))
+          :id-field-type                (constantly :type/Decimal)}))
 
 (defn- dbspec []
   (sql/connection-details->spec (OracleDriver.) @db-connection-details))
diff --git a/test/metabase/test/data/postgres.clj b/test/metabase/test/data/postgres.clj
index 44ff2aec2ecea6389e8723a201cf9d0c7e1030d6..f85c6f028771f999dc34fa7538fc6ee7db492fd6 100644
--- a/test/metabase/test/data/postgres.clj
+++ b/test/metabase/test/data/postgres.clj
@@ -9,17 +9,17 @@
   (:import metabase.driver.postgres.PostgresDriver))
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "BIGINT"
-   :BooleanField    "BOOL"
-   :CharField       "VARCHAR(254)"
-   :DateField       "DATE"
-   :DateTimeField   "TIMESTAMP"
-   :DecimalField    "DECIMAL"
-   :FloatField      "FLOAT"
-   :IntegerField    "INTEGER"
-   :TextField       "TEXT"
-   :TimeField       "TIME"
-   :UUIDField       "UUID"})
+  {:type/BigInteger "BIGINT"
+   :type/Boolean    "BOOL"
+   :type/Date       "DATE"
+   :type/DateTime   "TIMESTAMP"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "FLOAT"
+   :type/Integer    "INTEGER"
+   :type/IPAddress  "INET"
+   :type/Text       "TEXT"
+   :type/Time       "TIME"
+   :type/UUID       "UUID"})
 
 (defn- database->connection-details [context {:keys [database-name short-lived?]}]
   (merge {:host         "localhost"
diff --git a/test/metabase/test/data/redshift.clj b/test/metabase/test/data/redshift.clj
index b8c44918527e45279e5e4b17f7f64e953d3e6758..7ea648ca03ce96a78d4c3db8ed7017cd16a658d6 100644
--- a/test/metabase/test/data/redshift.clj
+++ b/test/metabase/test/data/redshift.clj
@@ -13,15 +13,14 @@
 
 ;; Time, UUID types aren't supported by redshift
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "BIGINT"
-   :BooleanField    "BOOL"
-   :CharField       "VARCHAR(254)"
-   :DateField       "DATE"
-   :DateTimeField   "TIMESTAMP"
-   :DecimalField    "DECIMAL"
-   :FloatField      "FLOAT8"
-   :IntegerField    "INTEGER"
-   :TextField       "TEXT"})
+  {:type/BigInteger "BIGINT"
+   :type/Boolean    "BOOL"
+   :type/Date       "DATE"
+   :type/DateTime   "TIMESTAMP"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "FLOAT8"
+   :type/Integer    "INTEGER"
+   :type/Text       "TEXT"})
 
 (defn- get-db-env-var
   "Look up the relevant env var for AWS connection details or throw an exception if it's not set.
diff --git a/test/metabase/test/data/sqlite.clj b/test/metabase/test/data/sqlite.clj
index 66e81d828cef9211d68bdbf69d6177f1eff0d5bb..cc5c50d367327cb08dff23b34cccbc29e740caa0 100644
--- a/test/metabase/test/data/sqlite.clj
+++ b/test/metabase/test/data/sqlite.clj
@@ -13,16 +13,15 @@
    :db           (str (i/escaped-name dbdef) ".sqlite")})
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "BIGINT"
-   :BooleanField    "BOOLEAN"
-   :CharField       "VARCHAR(254)"
-   :DateField       "DATE"
-   :DateTimeField   "DATETIME"
-   :DecimalField    "DECIMAL"
-   :FloatField      "DOUBLE"
-   :IntegerField    "INTEGER"
-   :TextField       "TEXT"
-   :TimeField       "TIME"})
+  {:type/BigInteger "BIGINT"
+   :type/Boolean    "BOOLEAN"
+   :type/Date       "DATE"
+   :type/DateTime   "DATETIME"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "DOUBLE"
+   :type/Integer    "INTEGER"
+   :type/Text       "TEXT"
+   :type/Time       "TIME"})
 
 (defn- load-data-stringify-dates
   "Our SQLite JDBC driver doesn't seem to like Dates/Timestamps so just convert them to strings before INSERTing them into the Database."
diff --git a/test/metabase/test/data/sqlserver.clj b/test/metabase/test/data/sqlserver.clj
index 53e8f48a270b8d78dbaf9da3e18207517e0dba72..c9bcff9e4a9dadd0ad078aa82a70eb8c554e4cbc 100644
--- a/test/metabase/test/data/sqlserver.clj
+++ b/test/metabase/test/data/sqlserver.clj
@@ -12,32 +12,28 @@
   (:import metabase.driver.sqlserver.SQLServerDriver))
 
 (def ^:private ^:const field-base-type->sql-type
-  {:BigIntegerField "BIGINT"
-   :BooleanField    "BIT"
-   :CharField       "VARCHAR(254)"
-   :DateField       "DATE"
-   :DateTimeField   "DATETIME"
-   :DecimalField    "DECIMAL"
-   :FloatField      "FLOAT"
-   :IntegerField    "INTEGER"
-   :TextField       "TEXT"
-   :TimeField       "TIME"})
-
-(def ^:private db-name-counter
-  "We destroy and create the same temporary databases serveral times when running our query processor tests. (why?)
-
-   To kick other users off of the database when we destroy it, we `ALTER DATABASE SET SINGLE_USER ROLLBACK IMMEDIATE`.
+  {:type/BigInteger "BIGINT"
+   :type/Boolean    "BIT"
+   :type/Date       "DATE"
+   :type/DateTime   "DATETIME"
+   :type/Decimal    "DECIMAL"
+   :type/Float      "FLOAT"
+   :type/Integer    "INTEGER"
+   :type/Text       "VARCHAR(254)" ; TEXT is considered deprecated -- see https://msdn.microsoft.com/en-us/library/ms187993.aspx
+   :type/Time       "TIME"})
+
+(def ^:private db-name-suffix-number
+  "To kick other users off of the database when we destroy it, we `ALTER DATABASE SET SINGLE_USER ROLLBACK IMMEDIATE`.
    This has the side effect of preventing any other connections to the database. If our tests barf for any reason,
    we're left with a database that can't be connected to until the hanging connection gets killed at some indeterminate point in the future.
    In other cases, JDBC will attempt to reuse connections to the same database, which fail once it it's in SINGLE_USER mode.
 
    To prevent our tests from failing for silly reasons, we'll instead generate database names like `sad-toucan-incidents_100`. We'll pick
-   a random number to start with, and for each subsequent database we create during the test run we'll increment this counter. Thus,
-   we'll create `sad-toucan-incidents_101`, then `tupac-sightings_102`, and so forth."
+   a random number here."
   (atom (rand-int 10000)))
 
 (defn- +suffix [db-name]
-  (str db-name \_ @db-name-counter))
+  (str db-name \_ @db-name-suffix-number))
 
 (defn- get-db-env-var
   "Since we run our tests on non-Windows machines, we need to connect to a remote server for running tests.
@@ -50,7 +46,7 @@
       (throw (Exception. (format "In order to test SQL Server, you must specify the env var MB_SQL_SERVER_%s."
                                  (s/upper-case (name env-var)))))))
 
-(defn- database->connection-details [_ context {:keys [database-name short-lived?]}]
+(defn- database->connection-details [context {:keys [database-name short-lived?]}]
   {:host         (get-db-env-var :host)
    :port         (Integer/parseInt (get-db-env-var :port "1433"))
    :user         (get-db-env-var :user)
@@ -60,7 +56,7 @@
    :short-lived? short-lived?})
 
 
-(defn- drop-db-if-exists-sql [_ {:keys [database-name]}]
+(defn- drop-db-if-exists-sql [{:keys [database-name]}]
   ;; Kill all open connections to the DB & drop it
   (apply format "IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'%s')
                  BEGIN
@@ -69,38 +65,32 @@
                  END;"
          (repeat 3 (+suffix database-name))))
 
-(defn- drop-table-if-exists-sql [_ {:keys [database-name]} {:keys [table-name]}]
+(defn- drop-table-if-exists-sql [{:keys [database-name]} {:keys [table-name]}]
   (let [db-name (+suffix database-name)]
     (format "IF object_id('%s.dbo.%s') IS NOT NULL DROP TABLE \"%s\".dbo.\"%s\";" db-name table-name db-name table-name)))
 
 (defn- qualified-name-components
-  ([_ db-name]
+  ([db-name]
    [(+suffix db-name)])
-  ([_ db-name table-name]
+  ([db-name table-name]
    [(+suffix db-name) "dbo" table-name])
-  ([_ db-name table-name field-name]
+  ([db-name table-name field-name]
    [(+suffix db-name) "dbo" table-name field-name]))
 
-(defn- create-db! [driver dbdef]
-  (swap! db-name-counter inc)
-  (create-db! driver dbdef))
-
 
 (u/strict-extend SQLServerDriver
   generic/IGenericSQLDatasetLoader
   (merge generic/DefaultsMixin
-         {:drop-db-if-exists-sql     drop-db-if-exists-sql
-          :drop-table-if-exists-sql  drop-table-if-exists-sql
+         {:drop-db-if-exists-sql     (u/drop-first-arg drop-db-if-exists-sql)
+          :drop-table-if-exists-sql  (u/drop-first-arg drop-table-if-exists-sql)
           :field-base-type->sql-type (u/drop-first-arg field-base-type->sql-type)
           :pk-sql-type               (constantly "INT IDENTITY(1,1)")
-          :qualified-name-components qualified-name-components})
+          :qualified-name-components (u/drop-first-arg qualified-name-components)})
   i/IDatasetLoader
-  (let [{:keys [create-db!], :as mixin} generic/IDatasetLoaderMixin]
-    (merge mixin
-           {:create-db!                   create-db!
-            :database->connection-details database->connection-details
-            :default-schema               (constantly "dbo")
-            :engine                       (constantly :sqlserver)})))
+  (merge generic/IDatasetLoaderMixin
+         {:database->connection-details (u/drop-first-arg database->connection-details)
+          :default-schema               (constantly "dbo")
+          :engine                       (constantly :sqlserver)}))
 
 
 (defn- cleanup-leftover-dbs!
@@ -109,15 +99,14 @@
   {:expectations-options :before-run}
   []
   (datasets/when-testing-engine :sqlserver
-    (let [connection-spec (sql/connection-details->spec (SQLServerDriver.) (database->connection-details nil :server nil))
+    (let [connection-spec (sql/connection-details->spec (SQLServerDriver.) (database->connection-details :server nil))
           leftover-dbs    (mapv :name (jdbc/query connection-spec "SELECT name
                                                                    FROM   master.dbo.sysdatabases
                                                                    WHERE  name NOT IN ('tempdb', 'master', 'model', 'msdb', 'rdsadmin');"))]
       (with-redefs [+suffix identity]
         (doseq [db leftover-dbs]
-          (try
+          (u/ignore-exceptions
             (println (format "Deleting leftover SQL Server DB '%s'..." db))
             ;; Don't try to kill other connections to this DB with SET SINGLE_USER -- some other instance (eg CI) might be using it
             (jdbc/execute! connection-spec [(format "DROP DATABASE \"%s\";" db)])
-            (println "[ok]")
-            (catch Throwable _)))))))
+            (println "[ok]")))))))
diff --git a/test/metabase/test/mock/moviedb.clj b/test/metabase/test/mock/moviedb.clj
index da84fafede40450e5dd96918fd426346497decb9..f32aea0fe031b746c45d57e2a716497103bac326 100644
--- a/test/metabase/test/mock/moviedb.clj
+++ b/test/metabase/test/mock/moviedb.clj
@@ -7,29 +7,29 @@
   {"movies"  {:name   "movies"
               :schema nil
               :fields #{{:name      "id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "title"
-                         :base-type :TextField}
+                         :base-type :type/Text}
                         {:name      "filming"
-                         :base-type :BooleanField}}}
+                         :base-type :type/Boolean}}}
    "actors"  {:name   "actors"
               :schema nil
               :fields #{{:name      "id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "name"
-                         :base-type :TextField}}}
+                         :base-type :type/Text}}}
    "roles"   {:name   "roles"
               :schema nil
               :fields #{{:name      "id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "movie_id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "actor_id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "character"
-                         :base-type :TextField}
+                         :base-type :type/Text}
                         {:name      "salary"
-                         :base-type :DecimalField}}
+                         :base-type :type/Decimal}}
               :fks    #{{:fk-column-name   "movie_id"
                          :dest-table       {:name "movies"
                                             :schema nil}
@@ -41,11 +41,11 @@
    "reviews" {:name   "reviews"
               :schema nil
               :fields #{{:name      "id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "movie_id"
-                         :base-type :IntegerField}
+                         :base-type :type/Integer}
                         {:name      "stars"
-                         :base-type :IntegerField}}
+                         :base-type :type/Integer}}
               :fks    #{{:fk-column-name   "movie_id"
                          :dest-table       {:name   "movies"
                                             :schema nil}
@@ -102,52 +102,52 @@
   [(merge raw-table-defaults
           {:columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}})
+                             :details {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField"}})]
+                             :details {:base-type "type/Text"}})]
            :name    "actors"})
    (merge raw-table-defaults
           {:columns [(merge raw-field-defaults
                             {:name    "filming"
-                             :details {:base-type "BooleanField"}})
+                             :details {:base-type "type/Boolean"}})
                      (merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}})
+                             :details {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "title"
-                             :details {:base-type "TextField"}})]
+                             :details {:base-type "type/Text"}})]
            :name    "movies"})
    (merge raw-table-defaults
           {:columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}})
+                             :details {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name                "movie_id"
-                             :details             {:base-type "IntegerField"}
+                             :details             {:base-type "type/Integer"}
                              :fk_target_column_id true})
                      (merge raw-field-defaults
                             {:name    "stars"
-                             :details {:base-type "IntegerField"}})]
+                             :details {:base-type "type/Integer"}})]
            :name    "reviews"})
    (merge raw-table-defaults
           {:columns [(merge raw-field-defaults
                             {:name                "actor_id"
-                             :details             {:base-type "IntegerField"}
+                             :details             {:base-type "type/Integer"}
                              :fk_target_column_id true})
                      (merge raw-field-defaults
                             {:name    "character"
-                             :details {:base-type "TextField"}})
+                             :details {:base-type "type/Text"}})
                      (merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}})
+                             :details {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name                "movie_id"
-                             :details             {:base-type "IntegerField"}
+                             :details             {:base-type "type/Integer"}
                              :fk_target_column_id true})
                      (merge raw-field-defaults
                             {:name    "salary"
-                             :details {:base-type "DecimalField"}})]
+                             :details {:base-type "type/Decimal"}})]
            :name    "roles"})])
 
 
@@ -190,15 +190,15 @@
   [(merge table-defaults
           {:name         "actors"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
 
            :display_name "Actors"})
    (merge table-defaults
@@ -206,61 +206,61 @@
            :fields       [(merge field-defaults
                                  {:name         "filming"
                                   :display_name "Filming"
-                                  :base_type    :BooleanField})
+                                  :base_type    :type/Boolean})
                           (merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
                                  {:name         "title"
                                   :display_name "Title"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
 
            :display_name "Movies"})
    (merge table-defaults
           {:name         "reviews"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :fk_target_field_id true
                                   :name               "movie_id"
                                   :display_name       "Movie ID"
-                                  :base_type          :IntegerField})
+                                  :base_type          :type/Integer})
                           (merge field-defaults
                                  {:name         "stars"
                                   :display_name "Stars"
-                                  :base_type    :IntegerField})]
+                                  :base_type    :type/Integer})]
            :display_name "Reviews"})
    (merge table-defaults
           {:name         "roles"
            :fields       [(merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :fk_target_field_id true
                                   :name               "actor_id"
                                   :display_name       "Actor ID"
-                                  :base_type          :IntegerField})
+                                  :base_type          :type/Integer})
                           (merge field-defaults
                                  {:name         "character"
                                   :display_name "Character"
-                                  :base_type    :TextField})
+                                  :base_type    :type/Text})
                           (merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :fk_target_field_id true
                                   :name               "movie_id"
                                   :display_name       "Movie ID"
-                                  :base_type          :IntegerField})
+                                  :base_type          :type/Integer})
                           (merge field-defaults
                                  {:name         "salary"
                                   :display_name "Salary"
-                                  :base_type    :DecimalField})]
+                                  :base_type    :type/Decimal})]
            :display_name "Roles"})])
diff --git a/test/metabase/test/mock/schema_per_customer.clj b/test/metabase/test/mock/schema_per_customer.clj
index 72d82fc0155a6641fa4a75de6a7b1a7692b2329a..28e3beedaae7f4f380a474ac8969c1b827553c43 100644
--- a/test/metabase/test/mock/schema_per_customer.clj
+++ b/test/metabase/test/mock/schema_per_customer.clj
@@ -8,37 +8,37 @@
 (def ^:private ^:const schema-per-customer-tables
   {nil      {"city"   {:name   "city"
                        :fields #{{:name         "id"
-                                  :base-type    :IntegerField
+                                  :base-type    :type/Integer
                                   :pk?          true}
                                  {:name         "name"
-                                  :base-type    :TextField
-                                  :special-type :name}}}
+                                  :base-type    :type/Text
+                                  :special-type :type/Name}}}
              "venue"  {:name   "venue"
                        :fields #{{:name         "id"
-                                  :base-type    :IntegerField
+                                  :base-type    :type/Integer
                                   :pk?          true}
                                  {:name         "name"
-                                  :base-type    :TextField
-                                  :special-type :name}
+                                  :base-type    :type/Text
+                                  :special-type :type/Name}
                                  {:name         "city_id"
-                                  :base-type    :IntegerField}}}
+                                  :base-type    :type/Integer}}}
              "review" {:name   "review"
                        :fields #{{:name         "id"
-                                  :base-type    :IntegerField
+                                  :base-type    :type/Integer
                                   :pk?          true}
                                  {:name         "text"
-                                  :base-type    :TextField
-                                  :special-type :name}
+                                  :base-type    :type/Text
+                                  :special-type :type/Name}
                                  {:name         "venue_id"
-                                  :base-type    :IntegerField}
+                                  :base-type    :type/Integer}
                                  {:name         "reviewer_id"
-                                  :base-type    :IntegerField}}}}
+                                  :base-type    :type/Integer}}}}
    "common" {"user"   {:name   "user"
                        :fields #{{:name         "id"
-                                  :base-type    :IntegerField
+                                  :base-type    :type/Integer
                                   :pk?          true}
                                  {:name         "name"
-                                  :base-type    :TextField}}}}})
+                                  :base-type    :type/Text}}}}})
 
 (defrecord SchemaPerCustomerDriver []
   clojure.lang.Named
@@ -105,31 +105,31 @@
           {:schema  "s3"
            :columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField", :special-type "name"}})]
+                             :details {:base-type "type/Text", :special-type "type/Name"}})]
            :name    "city"})
    (merge raw-table-defaults
           {:schema  "s2"
            :columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name                "reviewer_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "common", :name "user", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})
+                             :details             {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "text"
-                             :details {:base-type "TextField", :special-type "name"}})
+                             :details {:base-type "type/Text", :special-type "type/Name"}})
                      (merge raw-field-defaults
                             {:name                "venue_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "s2", :name "venue", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})]
+                             :details             {:base-type "type/Integer"}})]
            :name    "review"})
    (merge raw-table-defaults
           {:schema  "s3"
@@ -137,24 +137,24 @@
                             {:name                "city_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "s3", :name "city", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})
+                             :details             {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField", :special-type "name"}})]
+                             :details {:base-type "type/Text", :special-type "type/Name"}})]
            :name    "venue"})
    (merge raw-table-defaults
           {:schema  "s2"
            :columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField", :special-type "name"}})]
+                             :details {:base-type "type/Text", :special-type "type/Name"}})]
            :name    "city"})
    (merge raw-table-defaults
           {:schema  "s1"
@@ -162,44 +162,44 @@
                             {:name                "city_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "s1", :name "city", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})
+                             :details             {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField", :special-type "name"}})]
+                             :details {:base-type "type/Text", :special-type "type/Name"}})]
            :name    "venue"})
    (merge raw-table-defaults
           {:schema  "common"
            :columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField"}})]
+                             :details {:base-type "type/Text"}})]
            :name    "user"})
    (merge raw-table-defaults
           {:schema  "s3"
            :columns [(merge raw-field-defaults
                             {:name                "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk               true})
                      (merge raw-field-defaults
                             {:name                "reviewer_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "common", :name "user", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})
+                             :details             {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "text"
-                             :details {:base-type "TextField", :special-type "name"}})
+                             :details {:base-type "type/Text", :special-type "type/Name"}})
                      (merge raw-field-defaults
                             {:name                "venue_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "s3", :name "venue", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})]
+                             :details             {:base-type "type/Integer"}})]
            :name    "review"})
    (merge raw-table-defaults
           {:schema  "s2"
@@ -207,44 +207,44 @@
                             {:name                "city_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "s2", :name "city", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})
+                             :details             {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField", :special-type "name"}})]
+                             :details {:base-type "type/Text", :special-type "type/Name"}})]
            :name    "venue"})
    (merge raw-table-defaults
           {:schema  "s1"
            :columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name                "reviewer_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "common", :name "user", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})
+                             :details             {:base-type "type/Integer"}})
                      (merge raw-field-defaults
                             {:name    "text"
-                             :details {:base-type "TextField", :special-type "name"}})
+                             :details {:base-type "type/Text", :special-type "type/Name"}})
                      (merge raw-field-defaults
                             {:name                "venue_id"
                              :fk_target_column_id true
                              :fk_target_column    {:schema "s1", :name "venue", :col-name "id"}
-                             :details             {:base-type "IntegerField"}})]
+                             :details             {:base-type "type/Integer"}})]
            :name    "review"})
    (merge raw-table-defaults
           {:schema  "s1"
            :columns [(merge raw-field-defaults
                             {:name    "id"
-                             :details {:base-type "IntegerField"}
+                             :details {:base-type "type/Integer"}
                              :is_pk   true})
                      (merge raw-field-defaults
                             {:name    "name"
-                             :details {:base-type "TextField", :special-type "name"}})]
+                             :details {:base-type "type/Text", :special-type "type/Name"}})]
            :name    "city"})])
 
 
@@ -289,202 +289,202 @@
           {:schema       "common"
            :name         "user"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "User"})
    (merge table-defaults
           {:schema       "s1"
            :name         "city"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "City"})
    (merge table-defaults
           {:schema       "s1"
            :name         "review"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "reviewer_id"
                                   :fk_target_field_id true
                                   :display_name       "Reviewer ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "common", :name "user", :col-name "id"}})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "text"
                                   :display_name "Text"
-                                  :base_type    :TextField})
+                                  :base_type    :type/Text})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "venue_id"
                                   :fk_target_field_id true
                                   :display_name       "Venue ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "s1", :name "venue", :col-name "id"}})]
            :display_name "Review"})
    (merge table-defaults
           {:schema       "s1"
            :name         "venue"
            :fields       [(merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "city_id"
                                   :fk_target_field_id true
                                   :display_name       "City ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "s1", :name "city", :col-name "id"}})
                           (merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "Venue"})
    (merge table-defaults
           {:schema       "s2"
            :name         "city"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "City"})
    (merge table-defaults
           {:schema       "s2"
            :name         "review"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "reviewer_id"
                                   :fk_target_field_id true
                                   :display_name       "Reviewer ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "common", :name "user", :col-name "id"}})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "text"
                                   :display_name "Text"
-                                  :base_type    :TextField})
+                                  :base_type    :type/Text})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "venue_id"
                                   :fk_target_field_id true
                                   :display_name       "Venue ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "s2", :name "venue", :col-name "id"}})]
            :display_name "Review"})
    (merge table-defaults
           {:schema       "s2"
            :name         "venue"
            :fields       [(merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "city_id"
                                   :fk_target_field_id true
                                   :display_name       "City ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "s2", :name "city", :col-name "id"}})
                           (merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "Venue"})
    (merge table-defaults
           {:schema       "s3"
            :name         "city"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "City"})
    (merge table-defaults
           {:schema       "s3"
            :name         "review"
            :fields       [(merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "reviewer_id"
                                   :fk_target_field_id true
                                   :display_name       "Reviewer ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "common", :name "user", :col-name "id"}})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "text"
                                   :display_name "Text"
-                                  :base_type    :TextField})
+                                  :base_type    :type/Text})
                           (merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "venue_id"
                                   :fk_target_field_id true
                                   :display_name       "Venue ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "s3", :name "venue", :col-name "id"}})]
            :display_name "Review"})
    (merge table-defaults
           {:schema       "s3"
            :name         "venue"
            :fields       [(merge field-defaults
-                                 {:special_type       :fk
+                                 {:special_type       :type/FK
                                   :name               "city_id"
                                   :fk_target_field_id true
                                   :display_name       "City ID"
-                                  :base_type          :IntegerField
+                                  :base_type          :type/Integer
                                   :fk_target_field    {:schema "s3", :name "city", :col-name "id"}})
                           (merge field-defaults
-                                 {:special_type :id
+                                 {:special_type :type/PK
                                   :name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField})
+                                  :base_type    :type/Integer})
                           (merge field-defaults
-                                 {:special_type :name
+                                 {:special_type :type/Name
                                   :name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField})]
+                                  :base_type    :type/Text})]
            :display_name "Venue"})])
diff --git a/test/metabase/test/mock/toucanery.clj b/test/metabase/test/mock/toucanery.clj
index 5b28627efa26b5c5b458417e194b6f855360a1e6..8dd616e0fd192abc1d953c93ddec6b0ead5874e8 100644
--- a/test/metabase/test/mock/toucanery.clj
+++ b/test/metabase/test/mock/toucanery.clj
@@ -10,33 +10,33 @@
                    :schema nil
                    :fields #{{:name          "id"
                               :pk?           true
-                              :base-type     :IntegerField}
+                              :base-type     :type/Integer}
                              {:name          "ts"
-                              :base-type     :BigIntegerField
-                              :special-type  :timestamp_milliseconds}
+                              :base-type     :type/BigInteger
+                              :special-type  :type/UNIXTimestampMilliseconds}
                              {:name          "toucan"
-                              :base-type     :DictionaryField
+                              :base-type     :type/Dictionary
                               :nested-fields #{{:name          "name"
-                                                :base-type     :TextField}
+                                                :base-type     :type/Text}
                                                {:name          "details"
-                                                :base-type     :DictionaryField
+                                                :base-type     :type/Dictionary
                                                 :nested-fields #{{:name         "age"
-                                                                  :base-type    :IntegerField}
+                                                                  :base-type    :type/Integer}
                                                                  {:name         "weight"
-                                                                  :special-type :category
-                                                                  :base-type    :DecimalField}}}}}
+                                                                  :special-type :type/Category
+                                                                  :base-type    :type/Decimal}}}}}
                              {:name          "buyer"
-                              :base-type     :DictionaryField
+                              :base-type     :type/Dictionary
                               :nested-fields #{{:name      "name"
-                                                :base-type :TextField}
+                                                :base-type :type/Text}
                                                {:name      "cc"
-                                                :base-type :TextField}}}}}
+                                                :base-type :type/Text}}}}}
    "employees" {:name "employees"
                 :schema nil
                 :fields #{{:name      "id"
-                           :base-type :IntegerField}
+                           :base-type :type/Integer}
                           {:name      "name"
-                           :base-type :TextField}}}})
+                           :base-type :type/Text}}}})
 
 (defrecord ToucaneryDriver []
   clojure.lang.Named
@@ -117,65 +117,65 @@
            :fields       [(merge field-defaults
                                  {:name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField
-                                  :special_type :id})
+                                  :base_type    :type/Integer
+                                  :special_type :type/PK})
                           (merge field-defaults
                                  {:name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField
-                                  :special_type :name})]
+                                  :base_type    :type/Text
+                                  :special_type :type/Name})]
            :display_name "Employees"})
    (merge table-defaults
           {:name         "transactions"
            :fields       [(merge field-defaults
                                  {:name         "age"
                                   :display_name "Age"
-                                  :base_type    :IntegerField
+                                  :base_type    :type/Integer
                                   :parent_id    true})
                           (merge field-defaults
                                  {:name         "buyer"
                                   :display_name "Buyer"
-                                  :base_type    :DictionaryField})
+                                  :base_type    :type/Dictionary})
                           (merge field-defaults
                                  {:name         "cc"
                                   :display_name "Cc"
-                                  :base_type    :TextField
+                                  :base_type    :type/Text
                                   :parent_id    true})
                           (merge field-defaults
                                  {:name         "details"
                                   :display_name "Details"
-                                  :base_type    :DictionaryField
+                                  :base_type    :type/Dictionary
                                   :parent_id    true})
                           (merge field-defaults
                                  {:name         "id"
                                   :display_name "ID"
-                                  :base_type    :IntegerField
-                                  :special_type :id})
+                                  :base_type    :type/Integer
+                                  :special_type :type/PK})
                           (merge field-defaults
                                  {:name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField
+                                  :base_type    :type/Text
                                   :parent_id    true
-                                  :special_type :name})
+                                  :special_type :type/Name})
                           (merge field-defaults
                                  {:name         "name"
                                   :display_name "Name"
-                                  :base_type    :TextField
+                                  :base_type    :type/Text
                                   :parent_id    true
-                                  :special_type :name})
+                                  :special_type :type/Name})
                           (merge field-defaults
                                  {:name         "toucan"
                                   :display_name "Toucan"
-                                  :base_type    :DictionaryField})
+                                  :base_type    :type/Dictionary})
                           (merge field-defaults
                                  {:name         "ts"
                                   :display_name "Ts"
-                                  :base_type    :BigIntegerField
-                                  :special_type :timestamp_milliseconds})
+                                  :base_type    :type/BigInteger
+                                  :special_type :type/UNIXTimestampMilliseconds})
                           (merge field-defaults
                                  {:name         "weight"
                                   :display_name "Weight"
-                                  :base_type    :DecimalField
+                                  :base_type    :type/Decimal
                                   :parent_id    true
-                                  :special_type :category})]
+                                  :special_type :type/Category})]
            :display_name "Transactions"})])
diff --git a/test/metabase/test/util.clj b/test/metabase/test/util.clj
index 531f5695503452abada3f4fb65e7d2b6fda46d4e..4b426c2441c6489f332bd0f8f24f298a776db5b0 100644
--- a/test/metabase/test/util.clj
+++ b/test/metabase/test/util.clj
@@ -123,7 +123,7 @@
 
 (u/strict-extend (class Field)
   WithTempDefaults
-  {:with-temp-defaults (fn [_] {:base_type :TextField
+  {:with-temp-defaults (fn [_] {:base_type :type/Text
                                 :name      (random-name)
                                 :position  1
                                 :table_id  (data/id :venues)})})