diff --git a/Elm.cabal b/Elm.cabal
--- a/Elm.cabal
+++ b/Elm.cabal
@@ -1,5 +1,5 @@
 Name:                Elm
-Version:             0.12.1.3
+Version:             0.12.2
 Synopsis:            The Elm language module.
 Description:         Elm aims to make client-side web-development more pleasant.
                      It is a statically/strongly typed, functional reactive
@@ -107,14 +107,17 @@
                        filepath,
                        indents,
                        language-ecmascript >=0.15 && < 1.0,
+                       language-glsl,
                        mtl >= 2,
                        pandoc >= 1.10,
                        parsec >= 3.1.1,
                        pretty,
+                       scientific,
                        text,
                        transformers >= 0.2,
                        union-find,
-                       unordered-containers
+                       unordered-containers,
+                       yaml
 
 Executable elm
   Main-is:             Compiler.hs
@@ -190,14 +193,17 @@
                        filepath,
                        indents,
                        language-ecmascript >=0.15 && < 1.0,
+                       language-glsl,
                        mtl >= 2,
                        pandoc >= 1.10,
                        parsec >= 3.1.1,
+                       scientific,
                        pretty,
                        text,
                        transformers >= 0.2,
                        union-find,
-                       unordered-containers
+                       unordered-containers,
+                       yaml
 
 Executable elm-doc
   Main-is:             Docs.hs
@@ -231,16 +237,19 @@
                        directory,
                        filepath,
                        indents,
+                       language-glsl,
                        mtl >= 2,
                        pandoc >= 1.10,
                        parsec >= 3.1.1,
                        pretty,
+                       scientific,
                        text,
-                       union-find
+                       union-find,
+                       yaml
 
 Test-Suite compiler-tests
   Type:            exitcode-stdio-1.0
-  Hs-Source-Dirs:  tests/hs, compiler
+  Hs-Source-Dirs:  tests/compiler, compiler
   Main-is:         CompilerTest.hs
   other-modules:   Tests.Compiler
                    Tests.Property
@@ -268,19 +277,22 @@
                    filepath,
                    indents,
                    language-ecmascript >=0.15 && < 1.0,
+                   language-glsl,
                    mtl >= 2,
                    pandoc >= 1.10,
                    parsec >= 3.1.1,
                    pretty,
+                   scientific,
                    text,
                    transformers >= 0.2,
                    union-find,
-                   unordered-containers
+                   unordered-containers,
+                   yaml
 
-Test-Suite lib-tests
+Test-Suite library-tests
   Type:            exitcode-stdio-1.0
-  Hs-Source-Dirs:  tests/hs
-  Main-is:         LibTest.hs
+  Hs-Source-Dirs:  tests/libraries
+  Main-is:         LibraryTest.hs
   build-depends:   base,
                    directory,
                    Elm,
diff --git a/compiler/Build/Dependencies.hs b/compiler/Build/Dependencies.hs
--- a/compiler/Build/Dependencies.hs
+++ b/compiler/Build/Dependencies.hs
@@ -1,55 +1,57 @@
 {-# OPTIONS_GHC -W #-}
-module Build.Dependencies (getSortedDependencies, readDeps) where
+module Build.Dependencies (Recipe(..), getBuildRecipe, readDeps) where
 
-import Control.Applicative
 import Control.Monad.Error
 import qualified Control.Monad.State as State
-import qualified Data.Aeson as Json
-import qualified Data.ByteString.Lazy.Char8 as BSC
 import qualified Data.Graph as Graph
 import qualified Data.List as List
 import qualified Data.Map as Map
-import qualified Data.Maybe as Maybe
 import qualified Data.Set as Set
 import System.Directory
 import System.FilePath as FP
 
-import Build.Print (failure)
-
 import qualified SourceSyntax.Module as Module
 import qualified Parse.Parse as Parse
 import qualified Elm.Internal.Paths as Path
 import qualified Elm.Internal.Name as N
+import qualified Elm.Internal.Version as V
 import qualified Elm.Internal.Dependencies as Deps
 
-getSortedDependencies :: [FilePath] -> Module.Interfaces -> FilePath -> IO [String]
-getSortedDependencies srcDirs builtIns root =
-    do extras <- extraDependencies
-       let allSrcDirs = srcDirs ++ Maybe.fromMaybe [] extras
-       result <- runErrorT $ readAllDeps allSrcDirs builtIns root
-       case result of
-         Right deps -> sortDeps deps
-         Left err -> failure err
+data Recipe = Recipe
+    { _elmFiles :: [FilePath]
+    , _jsFiles :: [FilePath]
+    }
 
-extraDependencies :: IO (Maybe [FilePath])
-extraDependencies =
-    do exists <- doesFileExist Path.dependencyFile
-       if not exists then return Nothing else Just <$> getPaths
-    where
-      getPaths = do
-        raw <- BSC.readFile Path.dependencyFile
-        case Json.eitherDecode raw of
-          Right (Deps.Mini deps) -> mapM validate deps
-          Left err ->
-              failure $ "Error reading the " ++ Path.dependencyFile ++ " file:\n" ++ err
+getBuildRecipe :: [FilePath] -> Module.Interfaces -> FilePath -> ErrorT String IO Recipe
+getBuildRecipe srcDirs builtIns root =
+  do directories <- getDependencies
+     jsFiles <- nativeFiles ("." : directories)
+     let allSrcDirs = srcDirs ++ directories
+     nodes <- collectDependencies allSrcDirs builtIns root
+     elmFiles <- sortElmFiles nodes
+     return (Recipe elmFiles jsFiles)
 
-      validate (name,version) = do
-        let path = Path.dependencyDirectory </> toPath name version
-        exists <- doesDirectoryExist path
-        if exists then return path else failure (notFound name version)
+-- | Based on the projects elm_dependencies.json, find all of the paths and
+--   dependency information we might need.
+getDependencies :: ErrorT String IO [FilePath]
+getDependencies =
+    do exists <- liftIO $ doesFileExist Path.dependencyFile
+       if not exists then return [] else getPaths
+    where
+      getPaths :: ErrorT String IO [FilePath]
+      getPaths =
+        Deps.withDeps Path.dependencyFile $ \deps ->
+            mapM getPath (Deps.dependencies deps)
 
-      toPath name version = N.toFilePath name </> show version
+      getPath :: (N.Name, V.Version) -> ErrorT String IO FilePath
+      getPath (name,version) = do
+        let path = Path.dependencyDirectory </> N.toFilePath name </> show version
+        exists <- liftIO $ doesDirectoryExist path
+        if exists
+          then return path
+          else throwError (notFound name version)
 
+      notFound :: N.Name -> V.Version -> String
       notFound name version =
           unlines
           [ "Your " ++ Path.dependencyFile ++ " file says you depend on library"
@@ -58,27 +60,50 @@
           , ""
           , "    elm-get install " ++ show name ++ " " ++ show version ]
 
-type Deps = (FilePath, String, [String])
+nativeFiles :: [FilePath] -> ErrorT String IO [FilePath]
+nativeFiles directories =
+  do exists <- liftIO $ doesFileExist Path.dependencyFile
+     if not exists
+       then return []
+       else concat `fmap` mapM getNativeFiles directories
+  where
+    getNativeFiles dir =
+        Deps.withDeps (dir </> Path.dependencyFile) $ \deps ->
+            return (map (toPath dir) (Deps.native deps))
 
-sortDeps :: [Deps] -> IO [String]
-sortDeps depends =
+    toPath dir moduleName =
+        dir </> joinPath (split moduleName) <.> "js"
+        
+split :: String -> [String]
+split moduleName = go [] moduleName
+  where
+    go paths str =
+        case break (=='.') str of
+          (path, _:rest) -> go (paths ++ [path]) rest
+          (path, [])     -> paths ++ [path]
+
+type DependencyNode = (FilePath, String, [String])
+
+sortElmFiles :: [DependencyNode] -> ErrorT String IO [FilePath]
+sortElmFiles depends =
     if null mistakes
       then return (concat sccs)
-      else failure $ msg ++ unlines (map show mistakes)
+      else throwError $ msg ++ unlines (map show mistakes)
   where
     sccs = map Graph.flattenSCC $ Graph.stronglyConnComp depends
 
     mistakes = filter (\scc -> length scc > 1) sccs
     msg = "A cyclical module dependency or was detected in:\n"
 
-readAllDeps :: [FilePath] -> Module.Interfaces -> FilePath -> ErrorT String IO [Deps]
-readAllDeps srcDirs rawBuiltIns filePath =
+collectDependencies :: [FilePath] -> Module.Interfaces -> FilePath
+                    -> ErrorT String IO [DependencyNode]
+collectDependencies srcDirs rawBuiltIns filePath =
     State.evalStateT (go Nothing filePath) Set.empty
   where
     builtIns :: Set.Set String
     builtIns = Set.fromList $ Map.keys rawBuiltIns
 
-    go :: Maybe String -> FilePath -> State.StateT (Set.Set String) (ErrorT String IO) [Deps]
+    go :: Maybe String -> FilePath -> State.StateT (Set.Set String) (ErrorT String IO) [DependencyNode]
     go parentModuleName filePath = do
       filePath' <- lift $ findSrcFile parentModuleName srcDirs filePath
       (moduleName, deps) <- lift $ readDeps filePath'
@@ -93,9 +118,9 @@
 readDeps path = do
   txt <- lift $ readFile path
   case Parse.dependencies txt of
+    Right o  -> return o
     Left err -> throwError $ msg ++ show err
       where msg = "Error resolving dependencies in " ++ path ++ ":\n"
-    Right o  -> return o
 
 findSrcFile :: Maybe String -> [FilePath] -> FilePath -> ErrorT String IO FilePath
 findSrcFile parentModuleName dirs path =
diff --git a/compiler/Build/Flags.hs b/compiler/Build/Flags.hs
--- a/compiler/Build/Flags.hs
+++ b/compiler/Build/Flags.hs
@@ -7,7 +7,8 @@
 data Flags = Flags
     { make :: Bool
     , files :: [FilePath]
-    , runtime :: Maybe FilePath
+    , set_runtime :: Maybe FilePath
+    , get_runtime :: Bool
     , only_js :: Bool
     , print_types :: Bool
     , scripts :: [FilePath]
@@ -28,8 +29,10 @@
                  &= help "Do not import Prelude by default, used only when compiling standard libraries."
   , scripts = [] &= typFile
               &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
-  , runtime = Nothing &= typFile
-              &= help "Specify a custom location for Elm's runtime system."
+  , set_runtime = Nothing &= typFile
+                  &= help "Specify a custom location for Elm's runtime system."
+  , get_runtime = False
+                  &= help "Print the absolute path to the default Elm runtime."
   , cache_dir = "cache" &= typFile
                 &= help "Directory for files cached to make builds faster. Defaults to cache/ directory."
   , build_dir = "build" &= typFile
@@ -37,7 +40,7 @@
   , src_dir = ["."] &= typFile
               &= help "Additional source directories besides project root. Searched when using --make"
   , print_types = False
-                  &= help "Print out infered types of top-level definitions."
+                  &= help "Print out inferred types of top-level definitions."
   } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
     &= helpArg [explicit, name "help", name "h"]
     &= versionArg [explicit, name "version", name "v", summary (show Version.elmVersion)]
diff --git a/compiler/Build/Print.hs b/compiler/Build/Print.hs
--- a/compiler/Build/Print.hs
+++ b/compiler/Build/Print.hs
@@ -5,6 +5,7 @@
 
 import qualified Data.Map as Map
 import qualified Data.List as List
+import qualified SourceSyntax.Type as T
 import qualified SourceSyntax.Module as M
 import qualified SourceSyntax.PrettyPrint as Pretty
 import qualified Type.Alias as Alias
@@ -18,6 +19,11 @@
 interfaceTypes interfaces iface =
     types interfaces (M.iTypes iface) (M.iAliases iface) (M.iImports iface)
 
+types :: Map.Map k M.ModuleInterface
+      -> Map.Map String T.Type
+      -> [M.Alias]
+      -> [(String, M.ImportMethod)]
+      -> IO ()
 types interfaces types' aliases imports =
     do putStrLn ""
        mapM_ printType (Map.toList types')
@@ -35,4 +41,6 @@
   mapM_ print (List.intersperse (P.text " ") errs)
 
 failure :: String -> IO a
-failure msg = hPutStrLn stderr msg >> exitFailure
+failure msg =
+    do hPutStrLn stderr msg
+       exitFailure
diff --git a/compiler/Build/Utils.hs b/compiler/Build/Utils.hs
--- a/compiler/Build/Utils.hs
+++ b/compiler/Build/Utils.hs
@@ -1,10 +1,12 @@
 {-# OPTIONS_GHC -W #-}
 module Build.Utils where
 
+import Control.Monad.Error
 import System.Directory (doesFileExist)
 import System.Environment (getEnv)
 import System.FilePath ((</>), replaceExtension)
 import qualified Build.Flags as Flag
+import qualified Build.Print as Print
 import qualified Paths_Elm as This
 
 buildPath :: Flag.Flags -> FilePath -> String -> FilePath
@@ -33,3 +35,10 @@
     else do
       env <- getEnv "ELM_HOME"
       return (env </> name)
+
+run :: ErrorT String IO a -> IO a
+run command = do
+  either <- runErrorT command
+  case either of
+    Left err -> Print.failure err
+    Right result -> return result
diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs
--- a/compiler/Compiler.hs
+++ b/compiler/Compiler.hs
@@ -1,16 +1,17 @@
 {-# OPTIONS_GHC -W #-}
 module Main where
 
-import Control.Monad (foldM)
+import Control.Monad (foldM, when)
 import qualified Data.Maybe as Maybe
 import Text.Blaze.Html.Renderer.String (renderHtml)
 import qualified Data.ByteString.Lazy.Char8 as BS
 import qualified System.Console.CmdArgs as CmdArgs
 import System.Directory
+import System.Exit (exitSuccess)
 import System.FilePath
 import GHC.Conc
 
-import Build.Dependencies (getSortedDependencies)
+import Build.Dependencies (getBuildRecipe, Recipe(..))
 import qualified Generate.Html as Html
 import qualified Metadata.Prelude as Prelude
 import qualified Build.Utils as Utils
@@ -24,7 +25,10 @@
 
 compileArgs :: Flag.Flags -> IO ()
 compileArgs flags =
-    case Flag.files flags of
+  do when (Flag.get_runtime flags) $ 
+         do putStrLn Path.runtime
+            exitSuccess
+     case Flag.files flags of
       [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
       fs -> mapM_ (build flags) fs
 
@@ -33,13 +37,15 @@
     do let noPrelude = Flag.no_prelude flags
        builtIns <- Prelude.interfaces noPrelude
 
-       files <- if Flag.make flags
-                then getSortedDependencies (Flag.src_dir flags) builtIns rootFile
-                else return [rootFile]
+       (Recipe elmFiles jsFiles) <-
+           if Flag.make flags
+             then Utils.run (getBuildRecipe (Flag.src_dir flags) builtIns rootFile)
+             else return (Recipe [rootFile] [])
 
-       moduleName <- File.build flags builtIns files
+       moduleName <- File.build flags builtIns elmFiles
 
-       js <- foldM appendToOutput BS.empty files
+       let elmos = map (Utils.elmo flags) elmFiles
+       js <- foldM appendToOutput BS.empty (elmos ++ jsFiles)
 
        (extension, code) <-
            if Flag.only_js flags
@@ -56,12 +62,12 @@
     where
       appendToOutput :: BS.ByteString -> FilePath -> IO BS.ByteString
       appendToOutput js filePath = do
-        src <- BS.readFile (Utils.elmo flags filePath)
+        src <- BS.readFile filePath
         return (BS.append src js)
 
       sources js = map Html.Link (Flag.scripts flags) ++ [ Html.Source js ]
 
       makeHtml js moduleName = ("html", BS.pack $ renderHtml html)
           where
-            rtsPath = Maybe.fromMaybe Path.runtime (Flag.runtime flags)
+            rtsPath = Maybe.fromMaybe Path.runtime (Flag.set_runtime flags)
             html = Html.generate rtsPath (takeBaseName rootFile) (sources js) moduleName ""
diff --git a/compiler/Elm/Internal/Dependencies.hs b/compiler/Elm/Internal/Dependencies.hs
--- a/compiler/Elm/Internal/Dependencies.hs
+++ b/compiler/Elm/Internal/Dependencies.hs
@@ -2,10 +2,13 @@
 module Elm.Internal.Dependencies where
 
 import Control.Applicative
+import Control.Arrow (first)
 import Control.Monad.Error
 import qualified Control.Exception as E
 import Data.Aeson
+import Data.Aeson.Types (Parser)
 import Data.Aeson.Encode.Pretty
+import Data.Maybe (fromMaybe)
 import qualified Data.List as List
 import qualified Data.ByteString.Lazy as BS
 import qualified Data.HashMap.Strict as Map
@@ -23,33 +26,28 @@
     , license :: String
     , repo :: String
     , exposed :: [String]
+    , native :: [String]
     , elmVersion :: V.Version
     , dependencies :: [(N.Name,V.Version)]
     } deriving (Show, Eq, Ord)
 
-data MiniDeps = Mini [(N.Name,V.Version)]
-              deriving (Show, Eq, Ord)
-
-instance ToJSON MiniDeps where
-  toJSON (Mini m) = toJSON m
-
-instance FromJSON MiniDeps where
-    parseJSON (Object obj) = Mini <$> getDependencies obj
-    parseJSON _ = mzero
-
 instance ToJSON Deps where
-  toJSON d = object [
-    "version"         .= version d,
-    "summary"         .= summary d,
-    "description"     .= description d,
-    "license"         .= license d,
-    "repository"      .= repo d,
-    "exposed-modules" .= exposed d,
-    "elm-version"     .= elmVersion d,
-    "dependencies"    .= (jsonDeps . dependencies $ d)
-    ]
-    where jsonDeps = Map.fromList . map (mapFst (T.pack . show))
-          mapFst f (a,b) = (f a, b)
+  toJSON d =
+      object $
+      [ "version"         .= version d
+      , "summary"         .= summary d
+      , "description"     .= description d
+      , "license"         .= license d
+      , "repository"      .= repo d
+      , "exposed-modules" .= exposed d
+      , "elm-version"     .= elmVersion d
+      , "dependencies"    .= (jsonDeps . dependencies $ d)
+      ] ++ nativeModules
+    where
+      jsonDeps = Map.fromList . map (first (T.pack . show))
+      nativeModules
+          | null (native d) = []
+          | otherwise       = [ "native-modules" .= native d ]
 
 instance FromJSON Deps where
     parseJSON (Object obj) =
@@ -69,15 +67,18 @@
                      Right nm -> return nm
 
            exposed <- get obj "exposed-modules" "a list of modules exposed to users"
+           
+           native <- fromMaybe [] <$> (obj .:? "native-modules")
 
            elmVersion <- get obj "elm-version" "the version of the Elm compiler you are using"
 
            deps <- getDependencies obj
 
-           return $ Deps name version summary desc license repo exposed elmVersion deps
+           return $ Deps name version summary desc license repo exposed native elmVersion deps
 
     parseJSON _ = mzero
 
+getDependencies :: Object -> Parser [(N.Name, V.Version)]
 getDependencies obj = 
     toDeps =<< get obj "dependencies" "a listing of your project's dependencies"
     where
@@ -88,7 +89,7 @@
                 (Nothing, _) -> fail $ N.errorMsg f
                 (_, Nothing) -> fail $ "invalid version number " ++ v
 
-
+get :: FromJSON a => Object -> T.Text -> String -> Parser a
 get obj field desc =
     do maybe <- obj .:? field
        case maybe of
@@ -117,12 +118,12 @@
             \like <https://github.com/USER/PROJECT.git> where USER is your GitHub name\n\
             \and PROJECT is the repo you want to upload."
 
-withDeps :: (Deps -> a) -> FilePath -> ErrorT String IO a
-withDeps handle path =
+withDeps :: FilePath -> (Deps -> ErrorT String IO a) -> ErrorT String IO a
+withDeps path handle =
     do json <- readPath
        case eitherDecode json of
          Left err -> throwError $ "Error reading file " ++ path ++ ":\n    " ++ err
-         Right ds -> return (handle ds)
+         Right ds -> handle ds
     where
       readPath :: ErrorT String IO BS.ByteString
       readPath = do
@@ -136,19 +137,20 @@
                     "    <https://github.com/evancz/automaton/blob/master/elm_dependencies.json>"
 
 depsAt :: FilePath -> ErrorT String IO Deps
-depsAt = withDeps id
+depsAt filePath = withDeps filePath return
 
 -- | Encode dependencies in a canonical JSON format
 prettyJSON :: Deps -> BS.ByteString
 prettyJSON = encodePretty' config
   where config = defConfig { confCompare = order }
-        order = keyOrder [ "name",
-                           "version",
-                           "summary",
-                           "description",
-                           "license",
-                           "repo",
-                           "exposed-modules",
-                           "elm-version",
-                           "dependencies"
+        order = keyOrder [ "name"
+                         , "version"
+                         , "summary"
+                         , "description"
+                         , "license"
+                         , "repo"
+                         , "exposed-modules"
+                         , "native-modules"
+                         , "elm-version"
+                         , "dependencies"
                          ]
diff --git a/compiler/Elm/Internal/Utils.hs b/compiler/Elm/Internal/Utils.hs
--- a/compiler/Elm/Internal/Utils.hs
+++ b/compiler/Elm/Internal/Utils.hs
@@ -1,11 +1,12 @@
 {- | This module exports functions for compiling Elm to JS.
 -}
-module Elm.Internal.Utils (compile, moduleName) where
+module Elm.Internal.Utils (compile, moduleName, nameAndImports) where
 
 import qualified Data.List as List
 import qualified Generate.JavaScript as JS
 import qualified Build.Source as Source
-import qualified Parse.Module as Parser
+import Parse.Module (getModuleName)
+import Parse.Parse (dependencies)
 import qualified SourceSyntax.Module as M
 import qualified Text.PrettyPrint as P
 import qualified Metadata.Prelude as Prelude
@@ -25,4 +26,10 @@
 
 -- |This function extracts the module name of a given source program.
 moduleName :: String -> Maybe String
-moduleName = Parser.getModuleName
+moduleName = getModuleName
+
+-- |This function extracts the module name and imported modules from a given
+--  source program.
+nameAndImports :: String -> Maybe (String, [String])
+nameAndImports src =
+    either (const Nothing) Just (dependencies src)
diff --git a/compiler/Generate/JavaScript.hs b/compiler/Generate/JavaScript.hs
--- a/compiler/Generate/JavaScript.hs
+++ b/compiler/Generate/JavaScript.hs
@@ -34,10 +34,11 @@
 
 internalImports :: String -> Statement ()
 internalImports name =
-    VarDeclStmt () 
+    VarDeclStmt ()
     [ varDecl "_N" (obj "Elm.Native")
     , include "_U" "_N.Utils"
     , include "_L" "_N.List"
+    , include "_A" "_N.Array"
     , include "_E" "_N.Error"
     , varDecl "$moduleName" (string name)
     ]
@@ -179,6 +180,9 @@
             pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
             md = pad ++ MD.toHtml doc ++ pad
 
+      GLShader _uid src _tipe ->
+        return $ ObjectLit () [(PropString () "src", literal (Str src))]
+          
       PortIn name tipe ->
           return $ obj "Native.Ports.portIn" `call` [ string name, Port.incoming tipe ]
 
diff --git a/compiler/Generate/JavaScript/Ports.hs b/compiler/Generate/JavaScript/Ports.hs
--- a/compiler/Generate/JavaScript/Ports.hs
+++ b/compiler/Generate/JavaScript/Ports.hs
@@ -38,7 +38,7 @@
 
       Data "Json.Value" [] ->
           obj "Native.Json.fromJS" <| x
-                           
+
       Data ctor []
           | ctor == "Int"       -> from JSNumber
           | ctor == "Float"     -> from JSNumber
@@ -55,9 +55,13 @@
 
           | ctor == "_List" ->
               check x JSArray (obj "_L.fromArray" <| array)
-              where
-                array = DotRef () x (var "map") <| incoming t
 
+          | ctor == "Array.Array" ->
+              check x JSArray (obj "_A.fromJSArray" <| array)
+
+          where
+            array = DotRef () x (var "map") <| incoming t
+
       Data ctor ts
           | Help.isTuple ctor -> check x JSArray tuple
           where
@@ -67,10 +71,10 @@
                           , inc t (BracketRef () x (IntLit () n)))
 
       Data _ _ ->
-          error "bad ADT got to port generation code"
+          error "bad ADT got to incoming port generation code"
 
       Record _ (Just _) ->
-          error "bad record got to port generation code"
+          error "bad record got to incoming port generation code"
 
       Record fields Nothing ->
           check x (JSObject (map fst fields)) object
@@ -117,16 +121,19 @@
           | ctor == "_List" ->
               DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
 
+          | ctor == "Array.Array" ->
+              DotRef () (obj "_A.toJSArray" <| x) (var "map") <| outgoing t
+
       Data ctor ts
           | Help.isTuple ctor ->
               let convert n t = out t $ DotRef () x $ var ('_':show n)
               in  ArrayLit () $ zipWith convert [0..] ts
-                       
+
       Data _ _ ->
-          error "bad ADT got to port generation code"
+          error "bad ADT got to outgoing port generation code"
 
       Record _ (Just _) ->
-          error "bad record got to port generation code"
+          error "bad record got to outgoing port generation code"
 
       Record fields Nothing ->
           ObjectLit () keys
diff --git a/compiler/Parse/Expression.hs b/compiler/Parse/Expression.hs
--- a/compiler/Parse/Expression.hs
+++ b/compiler/Parse/Expression.hs
@@ -44,7 +44,7 @@
 --------  Complex Terms  --------
 
 listTerm :: IParser ParseExpr'
-listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
+listTerm = markdown' <|> glShader' <|> braces (try range <|> ExplicitList <$> commaSep expr)
   where
     range = do
       lo <- expr
@@ -56,6 +56,12 @@
       let uid = show (sourceLine pos) ++ ":" ++ show (sourceColumn pos)
       (rawText, exprs) <- markdown (interpolation uid)
       return (Markdown uid (filter (/='\r') rawText) exprs)
+
+    glShader' = do
+      pos <- getPosition
+      let uid = show (sourceLine pos) ++ ":" ++ show (sourceColumn pos)
+      (rawSrc, tipe) <- glShader
+      return $ GLShader uid (filter (/='\r') rawSrc) tipe
 
     span uid index =
         "<span id=\"md-" ++ uid ++ "-" ++ show index ++ "\">{{ markdown interpolation is in the pipeline, but still needs more testing }}</span>"
diff --git a/compiler/Parse/Helpers.hs b/compiler/Parse/Helpers.hs
--- a/compiler/Parse/Helpers.hs
+++ b/compiler/Parse/Helpers.hs
@@ -8,6 +8,8 @@
 import Data.Char (isUpper)
 import qualified Data.Set as Set
 import qualified Data.Map as Map
+import qualified Language.GLSL.Parser as GLP
+import Language.GLSL.Syntax as GLS
 import Text.Parsec hiding (newline,spaces,State)
 import Text.Parsec.Indent
 import qualified Text.Parsec.Token as T
@@ -16,6 +18,7 @@
 import SourceSyntax.Declaration (Assoc)
 import SourceSyntax.Expression
 import SourceSyntax.Helpers as Help
+import SourceSyntax.Literal as Literal
 import SourceSyntax.PrettyPrint
 import SourceSyntax.Variable as Variable
 
@@ -308,15 +311,61 @@
                 False -> (:) <$> anyChar <*> go
 
 markdown :: ([a] -> IParser (String, [a])) -> IParser (String, [a])
-markdown interpolation = try (string "[markdown|") >> closeMarkdown (++ "") []
+markdown interpolation =
+    do try (string "[markdown|")
+       closeMarkdown id []
     where
-      closeMarkdown md stuff =
+      closeMarkdown markdownBuilder stuff =
           choice [ do try (string "|]")
-                      return (md "", stuff)
-                 , (\(m,s) -> closeMarkdown (md . (m ++)) s) =<< interpolation stuff
+                      return (markdownBuilder "", stuff)
+                 , do (markdown,stuff') <- interpolation stuff
+                      closeMarkdown (markdownBuilder . (markdown++)) stuff'
                  , do c <- anyChar
-                      closeMarkdown (md . ([c]++)) stuff
+                      closeMarkdown (markdownBuilder . (c:)) stuff
                  ]
+
+glShader :: IParser (String, Literal.GLShaderTipe)
+glShader =
+  do try (string "[glShader|")
+     rawSrc <- closeShader id
+     case glSource rawSrc of
+       Left err -> parserFail . show $ err
+       Right tipe -> return (rawSrc, tipe)
+  where
+    closeShader builder = choice
+      [ do try (string "|]")
+           return (builder "")
+      , do c <- anyChar
+           closeShader (builder . (c:))
+      ]
+
+glSource :: String -> Either ParseError Literal.GLShaderTipe
+glSource src =
+  case GLP.parse src of
+    Right (TranslationUnit decls) ->
+      Right . foldr addGLinput emptyDecls . join . map extractGLinputs $ decls
+    Left e -> Left e
+  where 
+    emptyDecls = Literal.GLShaderTipe Map.empty Map.empty Map.empty
+    addGLinput (qual,tipe,name) glDecls = case qual of
+        Attribute -> glDecls { attribute = Map.insert name tipe $ attribute glDecls }
+        Uniform -> glDecls { uniform = Map.insert name tipe $ uniform glDecls }
+        Varying -> glDecls { varying = Map.insert name tipe $ varying glDecls }
+        _ -> error "Should never happen due to below filter"
+    extractGLinputs decl = case decl of
+        Declaration (InitDeclaration (TypeDeclarator (FullType (Just (TypeQualSto qual)) (TypeSpec _prec (TypeSpecNoPrecision tipe _mexpr1)))) [InitDecl name _mexpr2 _mexpr3]) ->
+            if elem qual [Attribute, Varying, Uniform] 
+            then case tipe of 
+                GLS.Int -> return (qual,Literal.Int,name)
+                GLS.Float -> return (qual,Literal.Float,name)
+                GLS.Vec2 -> return (qual,V2,name)
+                GLS.Vec3 -> return (qual,V3,name) 
+                GLS.Vec4 -> return (qual,V4,name)
+                GLS.Mat4 -> return (qual,M4,name)
+                GLS.Sampler2D -> return (qual,Texture,name)
+                _ -> []
+            else []
+        _ -> []
 
 --str :: IParser String
 str = expecting "String" $ do
diff --git a/compiler/SourceSyntax/Expression.hs b/compiler/SourceSyntax/Expression.hs
--- a/compiler/SourceSyntax/Expression.hs
+++ b/compiler/SourceSyntax/Expression.hs
@@ -58,6 +58,7 @@
     -- for type checking and code gen only
     | PortIn String SrcType.Type
     | PortOut String SrcType.Type (GeneralExpr ann def var)
+    | GLShader String String Literal.GLShaderTipe
     deriving (Show)
 
 
@@ -177,6 +178,8 @@
          field (x,e) = variable x <+> P.equals <+> pretty e
 
      Markdown _ _ _ -> P.text "[markdown| ... |]"
+
+     GLShader _ _ _ -> P.text "[glShader| ... |]"
 
      PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
 
diff --git a/compiler/SourceSyntax/Literal.hs b/compiler/SourceSyntax/Literal.hs
--- a/compiler/SourceSyntax/Literal.hs
+++ b/compiler/SourceSyntax/Literal.hs
@@ -1,6 +1,7 @@
 {-# OPTIONS_GHC -Wall #-}
 module SourceSyntax.Literal where
 
+import Data.Map (Map)
 import SourceSyntax.PrettyPrint
 import qualified Text.PrettyPrint as PP
 
@@ -19,3 +20,24 @@
       Chr c -> PP.text . show $ c
       Str s -> PP.text . show $ s
       Boolean bool -> PP.text (show bool)
+
+data GLTipe = Int | Float | V2 | V3 | V4 | M4 | Texture
+  deriving (Show)
+
+glTipeName :: GLTipe -> String
+glTipeName glTipe =
+    case glTipe of
+      Int     -> "Int"
+      Float   -> "Float"
+      V2      -> "Math.Vector2.Vec2"
+      V3      -> "Math.Vector3.Vec3"
+      V4      -> "Math.Vector4.Vec4"
+      M4      -> "Math.Matrix4.Mat4"
+      Texture -> "Graphics.WebGL.Texture"
+
+data GLShaderTipe = GLShaderTipe
+    { attribute :: Map String GLTipe
+    , uniform :: Map String GLTipe
+    , varying :: Map String GLTipe
+    } deriving (Show)
+
diff --git a/compiler/Transform/Canonicalize.hs b/compiler/Transform/Canonicalize.hs
--- a/compiler/Transform/Canonicalize.hs
+++ b/compiler/Transform/Canonicalize.hs
@@ -178,6 +178,7 @@
 
       PortOut name st signal -> PortOut name <$> renameType' env st <*> rnm signal
 
+      GLShader _ _ _ -> return expr
 
 renamePattern :: Env -> P.Pattern -> Either String P.Pattern
 renamePattern env pattern =
diff --git a/compiler/Transform/Expression.hs b/compiler/Transform/Expression.hs
--- a/compiler/Transform/Expression.hs
+++ b/compiler/Transform/Expression.hs
@@ -49,6 +49,7 @@
             Record fields -> Record <$> mapM (\(k,v) -> (,) k <$> go v) fields
             Markdown uid md es -> Markdown uid md <$> mapM go es
             Let defs body -> Let <$> defsTransform defs <*> go body
+            GLShader uid src gltipe -> return $ GLShader uid src gltipe
             PortIn name st ->
                 do portInCheck name st
                    return $ PortIn name st
diff --git a/compiler/Transform/SafeNames.hs b/compiler/Transform/SafeNames.hs
--- a/compiler/Transform/SafeNames.hs
+++ b/compiler/Transform/SafeNames.hs
@@ -54,6 +54,7 @@
       Modify r fs -> Modify (f r) (map (var *** f) fs)
       Record fs -> Record (map (var *** f) fs)
       Markdown uid md es -> Markdown uid md (map f es)
+      GLShader _ _ _ -> expr
       PortIn name st -> PortIn name st
       PortOut name st signal -> PortOut name st (f signal)
 
diff --git a/compiler/Transform/SortDefinitions.hs b/compiler/Transform/SortDefinitions.hs
--- a/compiler/Transform/SortDefinitions.hs
+++ b/compiler/Transform/SortDefinitions.hs
@@ -84,6 +84,8 @@
 
       Markdown uid md es -> Markdown uid md <$> mapM reorder es
 
+      GLShader _ _ _ -> return expr
+
       PortOut name st signal -> PortOut name st <$> reorder signal
 
       PortIn name st -> return $ PortIn name st
diff --git a/compiler/Transform/Substitute.hs b/compiler/Transform/Substitute.hs
--- a/compiler/Transform/Substitute.hs
+++ b/compiler/Transform/Substitute.hs
@@ -40,5 +40,6 @@
       Record fs -> Record (map (second f) fs)
       Literal _ -> expr
       Markdown uid md es -> Markdown uid md (map f es)
+      GLShader _ _ _ -> expr
       PortIn name st -> PortIn name st
       PortOut name st signal -> PortOut name st (f signal)
diff --git a/compiler/Type/Constrain/Expression.hs b/compiler/Type/Constrain/Expression.hs
--- a/compiler/Type/Constrain/Expression.hs
+++ b/compiler/Type/Constrain/Expression.hs
@@ -8,6 +8,7 @@
 import qualified Data.Map as Map
 import qualified Text.PrettyPrint as PP
 
+import SourceSyntax.Literal as Lit
 import SourceSyntax.Annotation as Ann
 import SourceSyntax.Expression
 import qualified SourceSyntax.Pattern as P
@@ -30,6 +31,22 @@
     in
     case expr of
       Literal lit -> liftIO $ Literal.constrain env region lit tipe
+
+      GLShader _uid _src gltipe -> 
+          exists $ \attr -> 
+          exists $ \unif -> 
+            let 
+              shaderTipe a u v = Env.get env Env.types "Graphics.WebGL.Shader" <| a <| u <| v
+              glTipe = Env.get env Env.types . Lit.glTipeName
+              makeRec accessor baseRec = 
+                let decls = accessor gltipe
+                in if Map.size decls == 0
+                   then baseRec
+                   else record (Map.map (\t -> [glTipe t]) decls) baseRec
+              attribute = makeRec Lit.attribute attr
+              uniform = makeRec Lit.uniform unif
+              varying = makeRec Lit.varying (TermN EmptyRecord1)
+            in return . A region $ CEqual tipe (shaderTipe attribute uniform varying)
 
       Var (V.Raw name)
           | name == saveEnvName -> return (A region CSaveEnv)
diff --git a/compiler/Type/ExtraChecks.hs b/compiler/Type/ExtraChecks.hs
--- a/compiler/Type/ExtraChecks.hs
+++ b/compiler/Type/ExtraChecks.hs
@@ -60,8 +60,7 @@
               | otherwise               -> err' True "an unsupported type"
               where
                 primitives =
-                    ["Int","Float","String","Bool","Maybe.Maybe","_List","Json.Value"]
-
+                    ["Int","Float","String","Bool","Maybe.Maybe","_List","Array.Array","Json.Value"]
                 validConstructor =
                     ctor `elem` primitives || Help.isTuple ctor
 
@@ -102,7 +101,7 @@
               , txt [ "It contains ", kind, ":\n" ]
               , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
               , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
-              , txt [ "    Ints, Floats, Bools, Strings, Maybes, Lists, Tuples," ]
+              , txt [ "    Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples," ]
               , txt [ "    Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
               ] ++ if couldBeAlias then aliasWarning else []
 
diff --git a/data/docs.json b/data/docs.json
--- a/data/docs.json
+++ b/data/docs.json
@@ -2576,17 +2576,17 @@
 },
 {
   "name": "Color",
-  "document": "Library for working with colors. Includes\n[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and\n[HSV](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and\nbuilt-in names.\n\n# Creation\n@docs rgb, rgba, hsv, hsva, greyscale, grayscale\n\n# From Other Colors\n@docs complement\n\n# Gradients\n@docs linear, radial\n\n# Built-in Colors\nThese colors come from the [Tango\npalette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines)\nwhich provides aesthetically reasonable defaults for colors. Each color also\ncomes with a light and dark version.\n\n### Standard\n@docs red, orange, yellow, green, blue, purple, brown\n\n### Light\n@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple,\n    lightBrown\n\n### Dark\n@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple,\n    darkBrown\n\n### Eight Shades of Grey\nThese colors are a compatible series of shades of grey, fitting nicely\nwith the Tango palette.\n@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black\n\nThese are identical to the *grey* versions. It seems the spelling is regional, but\nthat has never helped me remember which one I should be writing.\n@docs lightGray, gray, darkGray",
+  "document": "Library for working with colors. Includes\n[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and\n[HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and\nbuilt-in names.\n\n# Creation\n@docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement\n\n# Gradients\n@docs linear, radial\n\n# Extracting Colors\n@docs toRgb, toHsl\n\n# Built-in Colors\nThese colors come from the [Tango\npalette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines)\nwhich provides aesthetically reasonable defaults for colors. Each color also\ncomes with a light and dark version.\n\n### Standard\n@docs red, orange, yellow, green, blue, purple, brown\n\n### Light\n@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown\n\n### Dark\n@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown\n\n### Eight Shades of Grey\nThese colors are a compatible series of shades of grey, fitting nicely\nwith the Tango palette.\n@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black\n\nThese are identical to the *grey* versions. It seems the spelling is regional, but\nthat has never helped me remember which one I should be writing.\n@docs lightGray, gray, darkGray",
   "aliases": [],
   "datatypes": [
     {
       "name": "Color",
       "comment": "",
-      "raw": "data Color = Color Int Int Int Float",
+      "raw": "data Color\n    = RGBA Int Int Int Float\n    | HSLA Float Float Float Float",
       "typeVariables": [],
       "constructors": [
         {
-          "name": "Color",
+          "name": "RGBA",
           "type": {
             "tag": "function",
             "args": [
@@ -2617,6 +2617,39 @@
               "args": []
             }
           }
+        },
+        {
+          "name": "HSLA",
+          "type": {
+            "tag": "function",
+            "args": [
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              },
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              },
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              },
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              }
+            ],
+            "result": {
+              "tag": "adt",
+              "name": "Color",
+              "args": []
+            }
+          }
         }
       ]
     },
@@ -2816,7 +2849,7 @@
     },
     {
       "name": "complement",
-      "comment": "Produce a &ldquo;complementary color&rdquo;.\nThe two colors will accent each other.",
+      "comment": "Produce a &ldquo;complementary color&rdquo;. The two colors will\naccent each other. This is the same as rotating the hue by 180&deg;.",
       "raw": "complement : Color -\u003e Color",
       "type": {
         "tag": "function",
@@ -2935,6 +2968,31 @@
       }
     },
     {
+      "name": "fmod",
+      "comment": "",
+      "raw": "fmod : Float -\u003e Int -\u003e Float",
+      "type": {
+        "tag": "function",
+        "args": [
+          {
+            "tag": "adt",
+            "name": "Float",
+            "args": []
+          },
+          {
+            "tag": "adt",
+            "name": "Int",
+            "args": []
+          }
+        ],
+        "result": {
+          "tag": "adt",
+          "name": "Float",
+          "args": []
+        }
+      }
+    },
+    {
       "name": "gray",
       "comment": "",
       "raw": "gray      : Color",
@@ -3005,9 +3063,9 @@
       }
     },
     {
-      "name": "hsv",
-      "comment": "Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV).  This is very\nconvenient for creating colors that cycle and shift.  Hue is an angle and should\nbe given in standard Elm angles (radians).",
-      "raw": "hsv : Float -\u003e Float -\u003e Float -\u003e Color",
+      "name": "hsl",
+      "comment": "Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives\nyou access to colors more like a color wheel, where all hues are aranged in a\ncircle that you specify with standard Elm angles (radians).\n\n      red   = hsl (degrees   0) 1 0.5\n      green = hsl (degrees 120) 1 0.5\n      blue  = hsl (degrees 240) 1 0.5\n\n      pastelRed = hsl (degrees 0) 0.7 0.7\n\nTo cycle through all colors, just cycle through degrees. The saturation level\nis how vibrant the color is, like a dial between grey and bright colors. The\nlightness level is a dial between white and black.",
+      "raw": "hsl : Float -\u003e Float -\u003e Float -\u003e Color",
       "type": {
         "tag": "function",
         "args": [
@@ -3035,9 +3093,9 @@
       }
     },
     {
-      "name": "hsva",
-      "comment": "Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV)\nwith an alpha component for transparency.",
-      "raw": "hsva : Float -\u003e Float -\u003e Float -\u003e Float -\u003e Color",
+      "name": "hslToRgb",
+      "comment": "",
+      "raw": "hslToRgb : Float -\u003e Float -\u003e Float -\u003e (Float,Float,Float)",
       "type": {
         "tag": "function",
         "args": [
@@ -3055,11 +3113,57 @@
             "tag": "adt",
             "name": "Float",
             "args": []
+          }
+        ],
+        "result": {
+          "tag": "adt",
+          "name": "_Tuple3",
+          "args": [
+            {
+              "tag": "adt",
+              "name": "Float",
+              "args": []
+            },
+            {
+              "tag": "adt",
+              "name": "Float",
+              "args": []
+            },
+            {
+              "tag": "adt",
+              "name": "Float",
+              "args": []
+            }
+          ]
+        }
+      }
+    },
+    {
+      "name": "hsla",
+      "comment": "Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV)\nwith an alpha component for transparency.",
+      "raw": "hsla : Float -\u003e Float -\u003e Float -\u003e Float -\u003e Color",
+      "type": {
+        "tag": "function",
+        "args": [
+          {
+            "tag": "adt",
+            "name": "Float",
+            "args": []
           },
           {
             "tag": "adt",
             "name": "Float",
             "args": []
+          },
+          {
+            "tag": "adt",
+            "name": "Float",
+            "args": []
+          },
+          {
+            "tag": "adt",
+            "name": "Float",
+            "args": []
           }
         ],
         "result": {
@@ -3368,6 +3472,52 @@
       }
     },
     {
+      "name": "rgbToHsl",
+      "comment": "",
+      "raw": "rgbToHsl : Int -\u003e Int -\u003e Int -\u003e (Float,Float,Float)",
+      "type": {
+        "tag": "function",
+        "args": [
+          {
+            "tag": "adt",
+            "name": "Int",
+            "args": []
+          },
+          {
+            "tag": "adt",
+            "name": "Int",
+            "args": []
+          },
+          {
+            "tag": "adt",
+            "name": "Int",
+            "args": []
+          }
+        ],
+        "result": {
+          "tag": "adt",
+          "name": "_Tuple3",
+          "args": [
+            {
+              "tag": "adt",
+              "name": "Float",
+              "args": []
+            },
+            {
+              "tag": "adt",
+              "name": "Float",
+              "args": []
+            },
+            {
+              "tag": "adt",
+              "name": "Float",
+              "args": []
+            }
+          ]
+        }
+      }
+    },
+    {
       "name": "rgba",
       "comment": "Create RGB colors with an alpha component for transparency.\nThe alpha component is specified with numbers between 0 and 1.",
       "raw": "rgba : Int -\u003e Int -\u003e Int -\u003e Float -\u003e Color",
@@ -3399,6 +3549,112 @@
           "tag": "adt",
           "name": "Color",
           "args": []
+        }
+      }
+    },
+    {
+      "name": "toHsl",
+      "comment": "Extract the the components of a color in the HSL format.",
+      "raw": "toHsl : Color -\u003e { hue:Float, saturation:Float, lightness:Float, alpha:Float }",
+      "type": {
+        "tag": "function",
+        "args": [
+          {
+            "tag": "adt",
+            "name": "Color",
+            "args": []
+          }
+        ],
+        "result": {
+          "tag": "record",
+          "fields": [
+            [
+              "hue",
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              }
+            ],
+            [
+              "saturation",
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              }
+            ],
+            [
+              "lightness",
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              }
+            ],
+            [
+              "alpha",
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              }
+            ]
+          ],
+          "extension": null
+        }
+      }
+    },
+    {
+      "name": "toRgb",
+      "comment": "Extract the the components of a color in the RGB format.",
+      "raw": "toRgb : Color -\u003e { red:Int, green:Int, blue:Int, alpha:Float }",
+      "type": {
+        "tag": "function",
+        "args": [
+          {
+            "tag": "adt",
+            "name": "Color",
+            "args": []
+          }
+        ],
+        "result": {
+          "tag": "record",
+          "fields": [
+            [
+              "red",
+              {
+                "tag": "adt",
+                "name": "Int",
+                "args": []
+              }
+            ],
+            [
+              "green",
+              {
+                "tag": "adt",
+                "name": "Int",
+                "args": []
+              }
+            ],
+            [
+              "blue",
+              {
+                "tag": "adt",
+                "name": "Int",
+                "args": []
+              }
+            ],
+            [
+              "alpha",
+              {
+                "tag": "adt",
+                "name": "Float",
+                "args": []
+              }
+            ]
+          ],
+          "extension": null
         }
       }
     },
diff --git a/data/elm-runtime.js b/data/elm-runtime.js
--- a/data/elm-runtime.js
+++ b/data/elm-runtime.js
@@ -243,10 +243,16 @@
 
     // Maps a function over the elements with their index as first argument.
     function indexedMap(f, a) {
+      return indexedMap_(f, a, 0);
+    }
+
+    function indexedMap_(f, a, from) {
       var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
       if (a.height > 0) { newA.lengths = a.lengths; }
       for (var i = 0; i < a.table.length; i++) {
-        newA.table[i] = a.height == 0 ? A2(f, i, a.table[i]) : indexedMap(f, a.table[i]);
+        newA.table[i] = a.height == 0 ? A2(f, from + i, a.table[i])
+                                      : indexedMap_( f, a.table[i]
+                                                   , i == 0 ? 0 : a.lengths[i - 1]);
       }
       return newA;
     }
@@ -721,7 +727,7 @@
         complement: not,
         shiftLeft           : F2(sll),
         shiftRightArithmatic: F2(sra),
-        shiftRightLogical   : F2(srl),
+        shiftRightLogical   : F2(srl)
     };
     
 };
@@ -763,69 +769,25 @@
     var Utils = Elm.Native.Utils.make(elm);
 
     function toCss(c) {
-        return (c._3 === 1)
-            ? ('rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')')
-            : ('rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')');
-    }
-
-    function complement(rgb) {
-        var hsv = toHSV(rgb);
-        hsv.hue = (hsv.hue + 180) % 360;
-        return toRGB(hsv);
-    }
-
-    function hsva(h,s,v,a) {
-        var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
-        var clr = toRGB({hue:degree, saturation:s, value:v});
-        clr._3 = a;
-        return clr;
-    }
-
-    function hsv(h,s,v) {
-        var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
-        return toRGB({hue:degree, saturation:s, value:v});
-    }
-
-    function toHSV(rgb) {
-        var hsv = {};
-        var r = rgb._0 / 255.0, g = rgb._1 / 255.0, b = rgb._2 / 255.0;
-        var M = Math.max(r,g,b);
-        var m = Math.min(r,g,b);
-        var c = M - m;
-
-        var h = 0;
-             if (c === 0) { h = 0; }
-        else if (M === r) { h = ((g - b) / c) % 6; }
-        else if (M === g) { h = ((b - r) / c) + 2; }
-        else if (M === b) { h = ((r - g) / c) + 4; }
-        h *= 60;
-
-        return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) };
-    }
-
-    function between(lo,hi,x) { return lo <= x && x < hi; }
-    function norm(n) { return Math.round(n*255); }
-
-    function toRGB(hsv) {
-        var c = hsv.value * hsv.saturation;
-        var hue = hsv.hue / 60;
-        var x = c * (1 - Math.abs((hue % 2) - 1));
-        var r = 0, g = 0, b = 0;
-             if (between(0,1,hue)) { r = c; g = x; b = 0; }
-        else if (between(1,2,hue)) { r = x; g = c; b = 0; }
-        else if (between(2,3,hue)) { r = 0; g = c; b = x; }
-        else if (between(3,4,hue)) { r = 0; g = x; b = c; }
-        else if (between(4,5,hue)) { r = x; g = 0; b = c; }
-        else if (between(5,6,hue)) { r = c; g = 0; b = x; }
-
-        var m = hsv.value - c;
-        return { ctor:"Color", _0:norm(r+m), _1:norm(g+m), _2:norm(b+m), _3:1 };
+        var format = '';
+        var colors = '';
+        if (c.ctor === 'RGBA') {
+            format = 'rgb';
+            colors = c._0 + ', ' + c._1 + ', ' + c._2;
+        } else {
+            format = 'hsl';
+            colors = (c._0 * 180 / Math.PI) + ', ' +
+                     (c._1 * 100) + '%, ' +
+                     (c._2 * 100) + '%';
+        }
+        if (c._3 === 1) {
+            return format + '(' + colors + ')';
+        } else {
+            return format + 'a(' + colors + ', ' + c._3 + ')';
+        }
     }
 
     return elm.Native.Color.values = {
-        hsva:F4(hsva),
-        hsv:F3(hsv),
-        complement:complement,
         toCss:toCss
     };
 
@@ -893,8 +855,6 @@
     elm.Native.Error = elm.Native.Error || {};
     if (elm.Native.Error.values) return elm.Native.Error.values;
 
-    var fromString = Elm.Native.JavaScript.make(elm).fromString;
-
     function indent(lines) {
         var msg = '';
         for (var i = 0; i < lines.length; ++i) {
@@ -915,10 +875,11 @@
 	throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
     }
 
-    function raise(str) { throw new Error(fromString(str)); }
+    function raise(str) { throw new Error(str); }
 
     return elm.Native.Error.values = { Case: Case, If: If, raise: raise };
 };
+
 function F2(fun) {
   function wrapper(a) { return function(b) { return fun(a,b) } }
   wrapper.arity = 2;
@@ -1168,7 +1129,7 @@
         toString   : F2(toString),
         fromString : fromString,
         fromJS     : fromJS,
-        toJS       : toJS,
+        toJS       : toJS
     };
 
 };
@@ -1463,6 +1424,16 @@
         return fromArray(out);
     }
 
+    /*
+     * Only to be used internally; do some side effects for each elem
+     */
+    function each(action, xs) {
+        while(xs.ctor !== '[]') {
+            action(xs._0);
+            xs = xs._1;
+        }
+    }
+
     Elm.Native.List.values = {
         Nil:Nil,
         Cons:Cons,
@@ -1502,7 +1473,9 @@
         drop:F2(drop),
         repeat:F2(repeat),
 
-        join:F2(join)
+        join:F2(join),
+
+        each:each
     };
     return elm.Native.List.values = Elm.Native.List.values;
 
@@ -1635,7 +1608,7 @@
                 match: result[0],
                 submatches: List.fromArray(subs),
                 index: result.index,
-                number: number,
+                number: number
             });
         }
         return List.fromArray(out);
@@ -1690,7 +1663,7 @@
         contains: F2(contains),
         find: F3(find),
         replace: F4(replace),
-        split: F3(split),
+        split: F3(split)
     };
 };
 Elm.Native.Show = {};
@@ -1923,7 +1896,7 @@
     }
 
     function words(str) {
-        return List.fromArray(str.split(/\s+/g));
+        return List.fromArray(str.trim().split(/\s+/g));
     }
     function lines(str) {
         return List.fromArray(str.split(/\r\n|\r|\n/g));
@@ -2059,7 +2032,7 @@
         toInt: toInt,
         toFloat: toFloat,
         toList: toList,
-        fromList: fromList,
+        fromList: fromList
     };
 };
 Elm.Native.Text = {};
@@ -2187,7 +2160,7 @@
                 html : Utils.makeText(text),
                 align: align,
                 guid : null,
-                args : [],
+                args : []
             };
             var pos = A2(Utils.htmlHeight, 0, raw);
             return A3(Element.newElement, pos._0, pos._1, raw);
@@ -2200,7 +2173,7 @@
             html: text,
             align: null,
             guid: guid,
-            args: [],
+            args: []
         };
         var pos = A2(Utils.htmlHeight, 0, raw);
         return A3(Element.newElement, pos._0, pos._1, raw);
@@ -2226,7 +2199,7 @@
         markdown     : markdown,
 
         toTypefaces:toTypefaces,
-        toLine:toLine,
+        toLine:toLine
     };
 };
 Elm.Native.Trampoline = {};
@@ -2370,8 +2343,17 @@
                 var c = 0;
                 for (var i in x) {
                     ++c;
-                    stack.push({ 'x': x[i], 'y': y[i] });
+                    if (i in y) {
+                        if (i !== 'ctor') {
+                            stack.push({ 'x': x[i], 'y': y[i] });
+                        }
+                    } else {
+                        return false;
+                    }
                 }
+                if ('ctor' in x) {
+                    stack.push({'x': x.ctor, 'y': y.ctor});
+                }
                 if (c !== Object.keys(y).length) {
                     return false;
                 };
@@ -2908,7 +2890,7 @@
                     start: start,
                     end: end,
                     direction: { ctor: direction }
-                },
+                }
             }));
         }
 
@@ -3808,6 +3790,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Array";
    var Basics = Elm.Basics.make(_elm);
@@ -3905,6 +3888,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Basics";
    var Native = Native || {};
@@ -4099,6 +4083,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Bitwise";
    var Native = Native || {};
@@ -4129,6 +4114,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Char";
    var Native = Native || {};
@@ -4167,11 +4153,10 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Color";
    var Basics = Elm.Basics.make(_elm);
-   var Native = Native || {};
-   Native.Color = Elm.Native.Color.make(_elm);
    var _op = {};
    var Radial = F5(function (a,
    b,
@@ -4195,177 +4180,373 @@
              ,_2: c};
    });
    var linear = Linear;
-   var hsv = Native.Color.hsv;
-   var hsva = Native.Color.hsva;
-   var complement = Native.Color.complement;
-   var greyscale = function (p) {
-      return A3(hsv,0,0,1 - p);
-   };
+   var fmod = F2(function (f,n) {
+      return function () {
+         var integer = Basics.floor(f);
+         return Basics.toFloat(A2(Basics.mod,
+         integer,
+         n)) + f - Basics.toFloat(integer);
+      }();
+   });
+   var rgbToHsl = F3(function (red,
+   green,
+   blue) {
+      return function () {
+         var b = Basics.toFloat(blue) / 255;
+         var g = Basics.toFloat(green) / 255;
+         var r = Basics.toFloat(red) / 255;
+         var cMax = A2(Basics.max,
+         A2(Basics.max,r,g),
+         b);
+         var cMin = A2(Basics.min,
+         A2(Basics.min,r,g),
+         b);
+         var c = cMax - cMin;
+         var lightness = (cMax + cMin) / 2;
+         var saturation = _U.eq(lightness,
+         0) ? 0 : c / (1 - Basics.abs(2 * lightness - 1));
+         var hue = Basics.degrees(60) * (_U.eq(cMax,
+         r) ? A2(fmod,
+         (g - b) / c,
+         6) : _U.eq(cMax,
+         g) ? (b - r) / c + 2 : _U.eq(cMax,
+         b) ? (r - g) / c + 4 : _E.If($moduleName,
+         "between lines 140 and 142"));
+         return {ctor: "_Tuple3"
+                ,_0: hue
+                ,_1: saturation
+                ,_2: lightness};
+      }();
+   });
+   var hslToRgb = F3(function (hue,
+   saturation,
+   lightness) {
+      return function () {
+         var hue$ = hue / Basics.degrees(60);
+         var chroma = (1 - Basics.abs(2 * lightness - 1)) * saturation;
+         var x = chroma * (1 - Basics.abs(A2(fmod,
+         hue$,
+         2) - 1));
+         var $ = _U.cmp(hue$,
+         0) < 0 ? {ctor: "_Tuple3"
+                  ,_0: 0
+                  ,_1: 0
+                  ,_2: 0} : _U.cmp(hue$,
+         1) < 0 ? {ctor: "_Tuple3"
+                  ,_0: chroma
+                  ,_1: x
+                  ,_2: 0} : _U.cmp(hue$,
+         2) < 0 ? {ctor: "_Tuple3"
+                  ,_0: x
+                  ,_1: chroma
+                  ,_2: 0} : _U.cmp(hue$,
+         3) < 0 ? {ctor: "_Tuple3"
+                  ,_0: 0
+                  ,_1: chroma
+                  ,_2: x} : _U.cmp(hue$,
+         4) < 0 ? {ctor: "_Tuple3"
+                  ,_0: 0
+                  ,_1: x
+                  ,_2: chroma} : _U.cmp(hue$,
+         5) < 0 ? {ctor: "_Tuple3"
+                  ,_0: x
+                  ,_1: 0
+                  ,_2: chroma} : _U.cmp(hue$,
+         6) < 0 ? {ctor: "_Tuple3"
+                  ,_0: chroma
+                  ,_1: 0
+                  ,_2: x} : {ctor: "_Tuple3"
+                            ,_0: 0
+                            ,_1: 0
+                            ,_2: 0},
+         r = $._0,
+         g = $._1,
+         b = $._2;
+         var m = lightness - chroma / 2;
+         return {ctor: "_Tuple3"
+                ,_0: r + m
+                ,_1: g + m
+                ,_2: b + m};
+      }();
+   });
+   var HSLA = F4(function (a,
+   b,
+   c,
+   d) {
+      return {ctor: "HSLA"
+             ,_0: a
+             ,_1: b
+             ,_2: c
+             ,_3: d};
+   });
+   var hsla = F4(function (hue,
+   saturation,
+   lightness,
+   alpha) {
+      return A4(HSLA,
+      hue - Basics.toFloat(Basics.floor(hue / (2 * Basics.pi))),
+      saturation,
+      lightness,
+      alpha);
+   });
+   var hsl = F3(function (hue,
+   saturation,
+   lightness) {
+      return A4(hsla,
+      hue,
+      saturation,
+      lightness,
+      1);
+   });
    var grayscale = function (p) {
-      return A3(hsv,0,0,1 - p);
+      return A4(HSLA,0,0,1 - p,1);
    };
-   var Color = F4(function (a,
+   var greyscale = function (p) {
+      return A4(HSLA,0,0,1 - p,1);
+   };
+   var RGBA = F4(function (a,
    b,
    c,
    d) {
-      return {ctor: "Color"
+      return {ctor: "RGBA"
              ,_0: a
              ,_1: b
              ,_2: c
              ,_3: d};
    });
-   var rgba = Color;
+   var rgba = RGBA;
    var rgb = F3(function (r,g,b) {
-      return A4(Color,r,g,b,1);
+      return A4(RGBA,r,g,b,1);
    });
-   var lightRed = A4(Color,
+   var complement = function (color) {
+      return function () {
+         switch (color.ctor)
+         {case "HSLA": return A4(hsla,
+              color._0 + Basics.degrees(180),
+              color._1,
+              color._2,
+              color._3);
+            case "RGBA":
+            return function () {
+                 var $ = A3(rgbToHsl,
+                 color._0,
+                 color._1,
+                 color._2),
+                 h = $._0,
+                 s = $._1,
+                 l = $._2;
+                 return A4(hsla,
+                 h + Basics.degrees(180),
+                 s,
+                 l,
+                 color._3);
+              }();}
+         _E.Case($moduleName,
+         "between lines 95 and 101");
+      }();
+   };
+   var toHsl = function (color) {
+      return function () {
+         switch (color.ctor)
+         {case "HSLA": return {_: {}
+                              ,alpha: color._3
+                              ,hue: color._0
+                              ,lightness: color._2
+                              ,saturation: color._1};
+            case "RGBA":
+            return function () {
+                 var $ = A3(rgbToHsl,
+                 color._0,
+                 color._1,
+                 color._2),
+                 h = $._0,
+                 s = $._1,
+                 l = $._2;
+                 return {_: {}
+                        ,alpha: color._3
+                        ,hue: h
+                        ,lightness: l
+                        ,saturation: s};
+              }();}
+         _E.Case($moduleName,
+         "between lines 104 and 111");
+      }();
+   };
+   var toRgb = function (color) {
+      return function () {
+         switch (color.ctor)
+         {case "HSLA":
+            return function () {
+                 var $ = A3(hslToRgb,
+                 color._0,
+                 color._1,
+                 color._2),
+                 r = $._0,
+                 g = $._1,
+                 b = $._2;
+                 return {_: {}
+                        ,alpha: color._3
+                        ,blue: Basics.round(255 * b)
+                        ,green: Basics.round(255 * g)
+                        ,red: Basics.round(255 * r)};
+              }();
+            case "RGBA": return {_: {}
+                                ,alpha: color._3
+                                ,blue: color._2
+                                ,green: color._1
+                                ,red: color._0};}
+         _E.Case($moduleName,
+         "between lines 114 and 122");
+      }();
+   };
+   var lightRed = A4(RGBA,
    239,
    41,
    41,
    1);
-   var red = A4(Color,204,0,0,1);
-   var darkRed = A4(Color,
+   var red = A4(RGBA,204,0,0,1);
+   var darkRed = A4(RGBA,
    164,
    0,
    0,
    1);
-   var lightOrange = A4(Color,
+   var lightOrange = A4(RGBA,
    252,
    175,
    62,
    1);
-   var orange = A4(Color,
+   var orange = A4(RGBA,
    245,
    121,
    0,
    1);
-   var darkOrange = A4(Color,
+   var darkOrange = A4(RGBA,
    206,
    92,
    0,
    1);
-   var lightYellow = A4(Color,
+   var lightYellow = A4(RGBA,
    255,
    233,
    79,
    1);
-   var yellow = A4(Color,
+   var yellow = A4(RGBA,
    237,
    212,
    0,
    1);
-   var darkYellow = A4(Color,
+   var darkYellow = A4(RGBA,
    196,
    160,
    0,
    1);
-   var lightGreen = A4(Color,
+   var lightGreen = A4(RGBA,
    138,
    226,
    52,
    1);
-   var green = A4(Color,
+   var green = A4(RGBA,
    115,
    210,
    22,
    1);
-   var darkGreen = A4(Color,
+   var darkGreen = A4(RGBA,
    78,
    154,
    6,
    1);
-   var lightBlue = A4(Color,
+   var lightBlue = A4(RGBA,
    114,
    159,
    207,
    1);
-   var blue = A4(Color,
+   var blue = A4(RGBA,
    52,
    101,
    164,
    1);
-   var darkBlue = A4(Color,
+   var darkBlue = A4(RGBA,
    32,
    74,
    135,
    1);
-   var lightPurple = A4(Color,
+   var lightPurple = A4(RGBA,
    173,
    127,
    168,
    1);
-   var purple = A4(Color,
+   var purple = A4(RGBA,
    117,
    80,
    123,
    1);
-   var darkPurple = A4(Color,
+   var darkPurple = A4(RGBA,
    92,
    53,
    102,
    1);
-   var lightBrown = A4(Color,
+   var lightBrown = A4(RGBA,
    233,
    185,
    110,
    1);
-   var brown = A4(Color,
+   var brown = A4(RGBA,
    193,
    125,
    17,
    1);
-   var darkBrown = A4(Color,
+   var darkBrown = A4(RGBA,
    143,
    89,
    2,
    1);
-   var black = A4(Color,0,0,0,1);
-   var white = A4(Color,
+   var black = A4(RGBA,0,0,0,1);
+   var white = A4(RGBA,
    255,
    255,
    255,
    1);
-   var lightGrey = A4(Color,
+   var lightGrey = A4(RGBA,
    238,
    238,
    236,
    1);
-   var grey = A4(Color,
+   var grey = A4(RGBA,
    211,
    215,
    207,
    1);
-   var darkGrey = A4(Color,
+   var darkGrey = A4(RGBA,
    186,
    189,
    182,
    1);
-   var lightGray = A4(Color,
+   var lightGray = A4(RGBA,
    238,
    238,
    236,
    1);
-   var gray = A4(Color,
+   var gray = A4(RGBA,
    211,
    215,
    207,
    1);
-   var darkGray = A4(Color,
+   var darkGray = A4(RGBA,
    186,
    189,
    182,
    1);
-   var lightCharcoal = A4(Color,
+   var lightCharcoal = A4(RGBA,
    136,
    138,
    133,
    1);
-   var charcoal = A4(Color,
+   var charcoal = A4(RGBA,
    85,
    87,
    83,
    1);
-   var darkCharcoal = A4(Color,
+   var darkCharcoal = A4(RGBA,
    46,
    52,
    54,
@@ -4373,6 +4554,18 @@
    _elm.Color.values = {_op: _op
                        ,rgba: rgba
                        ,rgb: rgb
+                       ,hsla: hsla
+                       ,hsl: hsl
+                       ,grayscale: grayscale
+                       ,greyscale: greyscale
+                       ,complement: complement
+                       ,toHsl: toHsl
+                       ,toRgb: toRgb
+                       ,fmod: fmod
+                       ,rgbToHsl: rgbToHsl
+                       ,hslToRgb: hslToRgb
+                       ,linear: linear
+                       ,radial: radial
                        ,lightRed: lightRed
                        ,red: red
                        ,darkRed: darkRed
@@ -4405,14 +4598,8 @@
                        ,lightCharcoal: lightCharcoal
                        ,charcoal: charcoal
                        ,darkCharcoal: darkCharcoal
-                       ,grayscale: grayscale
-                       ,greyscale: greyscale
-                       ,complement: complement
-                       ,hsva: hsva
-                       ,hsv: hsv
-                       ,linear: linear
-                       ,radial: radial
-                       ,Color: Color
+                       ,RGBA: RGBA
+                       ,HSLA: HSLA
                        ,Linear: Linear
                        ,Radial: Radial};
    return _elm.Color.values;
@@ -4425,6 +4612,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Date";
    var Maybe = Elm.Maybe.make(_elm);
@@ -4503,6 +4691,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Debug";
    var Native = Native || {};
@@ -4521,6 +4710,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Dict";
    var Basics = Elm.Basics.make(_elm);
@@ -5550,6 +5740,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Either";
    var List = Elm.List.make(_elm);
@@ -5677,6 +5868,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Http";
    var Native = Native || {};
@@ -5746,6 +5938,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Json";
    var Dict = Elm.Dict.make(_elm);
@@ -5801,6 +5994,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Keyboard";
    var Native = Native || {};
@@ -5846,6 +6040,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "List";
    var Basics = Elm.Basics.make(_elm);
@@ -6044,6 +6239,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Maybe";
    var Basics = Elm.Basics.make(_elm);
@@ -6105,6 +6301,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Mouse";
    var Native = Native || {};
@@ -6132,6 +6329,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Random";
    var Native = Native || {};
@@ -6155,6 +6353,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Regex";
    var Maybe = Elm.Maybe.make(_elm);
@@ -6206,6 +6405,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Set";
    var Dict = Elm.Dict.make(_elm);
@@ -6310,6 +6510,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Signal";
    var Basics = Elm.Basics.make(_elm);
@@ -6415,6 +6616,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "String";
    var Maybe = Elm.Maybe.make(_elm);
@@ -6516,6 +6718,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Text";
    var Basics = Elm.Basics.make(_elm);
@@ -6609,6 +6812,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Time";
    var Basics = Elm.Basics.make(_elm);
@@ -6663,6 +6867,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Touch";
    var Native = Native || {};
@@ -6700,6 +6905,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Trampoline";
    var Native = Native || {};
@@ -6727,6 +6933,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Transform2D";
    var Native = Native || {};
@@ -6794,6 +7001,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "WebSocket";
    var Basics = Elm.Basics.make(_elm);
@@ -6814,6 +7022,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Window";
    var Native = Native || {};
@@ -6839,6 +7048,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Graphics.Collage";
    var Basics = Elm.Basics.make(_elm);
@@ -7182,6 +7392,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Graphics.Element";
    var Basics = Elm.Basics.make(_elm);
@@ -7733,6 +7944,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Graphics.Input";
    var Graphics = Graphics || {};
@@ -7779,6 +7991,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "Graphics.Input.Field";
    var Color = Elm.Color.make(_elm);
@@ -7900,6 +8113,7 @@
    var _N = Elm.Native,
    _U = _N.Utils.make(_elm),
    _L = _N.List.make(_elm),
+   _A = _N.Array.make(_elm),
    _E = _N.Error.make(_elm),
    $moduleName = "JavaScript.Experimental";
    var Json = Elm.Json.make(_elm);
@@ -8263,7 +8477,7 @@
 var Transform = Elm.Transform2D.make({});
 var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
 var newElement = Utils.newElement,
-    extract = Utils.extract, fromList = Utils.fromList,
+    colorToCss = Utils.colorToCss, fromList = Utils.fromList,
     fromString = Utils.fromString, addTransform = Utils.addTransform;
 
 function trace(ctx, path) {
@@ -8328,7 +8542,7 @@
     ctx.lineJoin = join === 'Smooth' ? 'round' :
                    join === 'Sharp' ? 'miter' : 'bevel';
     ctx.miterLimit = style.join._0 || 10;
-    ctx.strokeStyle = extract(style.color);
+    ctx.strokeStyle = colorToCss(style.color);
     return line(ctx, style, path);
 }
 
@@ -8354,7 +8568,7 @@
   var len = stops.length;
   for (var i = 0; i < len; ++i) {
     var stop = stops[i];
-    g.addColorStop(stop._0, extract(stop._1));
+    g.addColorStop(stop._0, colorToCss(stop._1));
   }
   return g;
 }
@@ -8363,7 +8577,7 @@
     trace(ctx, path);
     var sty = style.ctor;
     ctx.fillStyle =
-        sty === 'Solid' ? extract(style._0) :
+        sty === 'Solid' ? colorToCss(style._0) :
         sty === 'Texture' ? texture(redo, ctx, style._0) : gradient(ctx, style._0);
     ctx.scale(1,-1);
     ctx.fill();
@@ -8616,7 +8830,7 @@
 'use strict';
 
 var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
-var newElement = Utils.newElement, extract = Utils.extract,
+var newElement = Utils.newElement, colorToCss = Utils.colorToCss,
     addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
     fromList = Utils.fromList, eq = Utils.eq;
 
@@ -8631,7 +8845,7 @@
         e.style.opacity = props.opacity;
     }
     if (props.color.ctor === 'Just') {
-        e.style.backgroundColor = extract(props.color._0);
+        e.style.backgroundColor = colorToCss(props.color._0);
     }
     if (props.tag !== '') { e.id = props.tag; }
     if (props.href !== '') {
@@ -8756,29 +8970,37 @@
     return e;
 }
 
-function goIn(e) { e.style.position = 'absolute'; return e; }
+function goOut(e) { e.style.position = 'absolute'; return e; }
 function goDown(e) { return e }
 function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; }
-function flowWith(f, array) {
-    var container = newElement('div');
-    if (f == goIn) container.style.pointerEvents = 'none';
 
-    for (var i = array.length; i--; ) {
-        container.appendChild(f(render(array[i])));
-    }
-    return container;
+var directionTable = {
+    DUp    : goDown,
+    DDown  : goDown,
+    DLeft  : goRight,
+    DRight : goRight,
+    DIn    : goOut,
+    DOut   : goOut
+};
+function needsReversal(dir) {
+    return dir == 'DUp' || dir == 'DLeft' || dir == 'DIn';
 }
 
 function flow(dir,elist) {
     var array = fromList(elist);
-    switch(dir.ctor) {
-    case "DDown":  array.reverse();
-    case "DUp":    return flowWith(goDown,array);
-    case "DRight": array.reverse();
-    case "DLeft":  return flowWith(goRight,array);
-    case "DOut":   array.reverse();
-    case "DIn":    return flowWith(goIn,array);
+    var container = newElement('div');
+    var goDir = directionTable[dir];
+    if (goDir == goOut) {
+        container.style.pointerEvents = 'none';
     }
+    if (needsReversal(dir)) {
+        array.reverse();
+    }
+    var len = array.length;
+    for (var i = 0; i < len; ++i) {
+        container.appendChild(goDir(render(array[i])));
+    }
+    return container;
 }
 
 function toPos(pos) {
@@ -8858,7 +9080,7 @@
     var elem = e.element;
     switch(elem.ctor) {
     case 'Image':     return image(e.props, elem);
-    case 'Flow':      return flow(elem._0, elem._1);
+    case 'Flow':      return flow(elem._0.ctor, elem._1);
     case 'Container': return container(elem._0, elem._1);
     case 'Spacer':    return newElement('div');
     case 'RawHtml':   return rawHtml(elem);
@@ -8934,14 +9156,12 @@
             return true;
         }
         var currs = fromList(currE._1);
-        var goDir = function(x) { return x; };
-        switch(nextE._0.ctor) {
-        case "DDown":  case "DUp":   goDir = goDown; break;
-        case "DRight": case "DLeft": goDir = goRight; break;
-        case "DOut":   case "DIn":   goDir = goIn; break;
-        }
-        for (var i = kids.length; i-- ;) {
-            update(kids[i],currs[i],nexts[i]);
+        var dir = nextE._0.ctor;
+        var goDir = directionTable[dir];
+        var toReverse = needsReversal(dir);
+        var len = kids.length;
+        for (var i = len; i-- ;) {
+            update(kids[toReverse ? len - i - 1 : i],currs[i],nexts[i]);
             goDir(kids[i]);
         }
         break;
@@ -8977,7 +9197,7 @@
         e.style.opacity = props.opacity;
     }
     var nextColor = (props.color.ctor === 'Just' ?
-                     extract(props.color._0) : '');
+                     colorToCss(props.color._0) : '');
     if (e.style.backgroundColor !== nextColor) {
         e.style.backgroundColor = (nextColor === '' ? 'transparent' : nextColor);
     }
@@ -9034,11 +9254,6 @@
       container.appendChild(elem);
   }
 
-  function extract(c) {
-      if (c._3 === 1) { return 'rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')'; }
-      return 'rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')';
-  }
-
   function addTransform(style, trans) {
     style.transform       = trans;
     style.msTransform     = trans;
@@ -9058,8 +9273,8 @@
   var List = Elm.Native.List.make({});
 
   return {addTo:addTo,
-          newElement:newElement,
-          extract : extract,
+          newElement: newElement,
+          colorToCss: Elm.Native.Color.make({}).toCss,
           fromList: List.toArray,
           fromString: function(s) { return s; },
           toString: function(s) { return s; },
diff --git a/data/interfaces.data b/data/interfaces.data
Binary files a/data/interfaces.data and b/data/interfaces.data differ
diff --git a/tests/compiler/CompilerTest.hs b/tests/compiler/CompilerTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/compiler/CompilerTest.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import Test.Framework
+
+import Tests.Compiler
+import Tests.Property
+
+main :: IO () 
+main = defaultMain [ compilerTests
+                   , propertyTests
+                   ]
diff --git a/tests/compiler/Tests/Compiler.hs b/tests/compiler/Tests/Compiler.hs
new file mode 100644
--- /dev/null
+++ b/tests/compiler/Tests/Compiler.hs
@@ -0,0 +1,45 @@
+module Tests.Compiler (compilerTests)
+       where
+
+import Data.Functor                   ((<$>))
+import Data.Traversable               (traverse)
+import System.FilePath                ((</>))
+import System.FilePath.Find           (find, (==?), extension)
+import Test.Framework
+import Test.Framework.Providers.HUnit (testCase)
+import Test.HUnit                     (Assertion, assertFailure, assertBool)
+import Text.Parsec                    (ParseError)
+
+import Elm.Internal.Utils as Elm
+
+compilerTests :: Test
+compilerTests = buildTest $ do
+  goods <- mkTests goodCompile  =<< getElms "good"
+  bads  <- mkTests badCompile   =<< getElms "bad"
+  return $ testGroup "Compile Tests"
+    [
+      testGroup "Good Tests" goods
+    , testGroup "Bad Tests"  bads
+    ]
+
+  where getElms :: FilePath -> IO [FilePath]
+        getElms fname = find (return True) (extension ==? ".elm") (testsDir </> fname)
+
+        mkTests :: (Either String String -> Assertion) -> [FilePath] -> IO [Test]
+        mkTests h = traverse setupTest
+          where setupTest f = testCase f . mkCompileTest h <$> readFile f
+
+        testsDir = "tests" </> "test-files"
+
+goodCompile :: Either String String -> Assertion
+goodCompile (Left err) = assertFailure err
+goodCompile (Right _)  = assertBool "" True
+
+badCompile :: Either String String -> Assertion
+badCompile (Left _)  = assertBool "" True
+badCompile (Right _) = assertFailure "Compilation succeeded but should have failed"
+  
+mkCompileTest :: ((Either String String) -> Assertion) -- ^ Handler
+                 -> String -- ^ File Contents
+                 -> Assertion
+mkCompileTest handle = handle . Elm.compile
diff --git a/tests/compiler/Tests/Property.hs b/tests/compiler/Tests/Property.hs
new file mode 100644
--- /dev/null
+++ b/tests/compiler/Tests/Property.hs
@@ -0,0 +1,55 @@
+module Tests.Property where
+
+import Control.Applicative ((<*))
+import Test.Framework
+import Test.Framework.Providers.HUnit
+import Test.Framework.Providers.QuickCheck2
+import Test.HUnit (assert)
+import Test.QuickCheck
+import Text.Parsec.Combinator (eof)
+import Text.PrettyPrint as P
+
+import SourceSyntax.Literal as Lit
+import qualified SourceSyntax.Pattern as P
+import SourceSyntax.PrettyPrint  (Pretty, pretty)
+import Parse.Helpers             (IParser, iParse)
+import Parse.Literal             (literal)
+import qualified Parse.Pattern as Pat (expr)
+import qualified Parse.Type as Type (expr)
+import Tests.Property.Arbitrary
+
+propertyTests :: Test
+propertyTests =
+  testGroup "Parse/Print Agreement Tests"
+  [
+    testCase "Long Pattern test" $ assert (prop_parse_print Pat.expr longPat)
+  , testProperty "Literal test" $ prop_parse_print literal
+  , testProperty "Pattern test" $ prop_parse_print Pat.expr
+  , testProperty "Type test" $ prop_parse_print Type.expr
+  ]
+
+  where
+    -- This test was autogenerated from the Pattern test and should be
+    -- left in all its ugly glory.
+    longPat = P.Data "I" [ P.Literal (Lit.Chr '+')
+                         , P.Record
+                           [ "q7yclkcm7k_ikstrczv_"
+                           , "wQRv6gKsvvkjw4b5F"
+                           ,"c9'eFfhk9FTvsMnwF_D"
+                           ,"yqxhEkHvRFwZ"
+                           ,"o"
+                           ,"nbUlCn3y3NnkVoxhW"
+                           ,"iJ0MNy3KZ_lrs"
+                           ,"ug"
+                           ,"sHHsX"
+                           ,"mRKs9d"
+                           ,"o2KiCX5'ZRzHJfRi8" ]
+                         , P.Var "su'BrrbPUK6I33Eq"
+                         ]
+
+prop_parse_print :: (Pretty a, Arbitrary a, Eq a) => IParser a -> a -> Bool
+prop_parse_print p x =
+  either (const False) (== x) . parse_print p $ x
+
+parse_print :: (Pretty a) => IParser a -> a -> Either String a
+parse_print p = either (Left . show) Right . iParse (p <* eof) . P.renderStyle P.style {mode=P.LeftMode} . pretty
diff --git a/tests/compiler/Tests/Property/Arbitrary.hs b/tests/compiler/Tests/Property/Arbitrary.hs
new file mode 100644
--- /dev/null
+++ b/tests/compiler/Tests/Property/Arbitrary.hs
@@ -0,0 +1,128 @@
+{-# OPTIONS_GHC -W -fno-warn-orphans #-}
+module Tests.Property.Arbitrary where
+
+import Control.Applicative       ((<$>), (<*>), pure)
+import Test.QuickCheck.Arbitrary
+import Test.QuickCheck.Gen
+
+import qualified Data.Set as Set
+import qualified Parse.Helpers (reserveds)
+
+import qualified SourceSyntax.Literal as L
+import qualified SourceSyntax.Pattern as P
+import qualified SourceSyntax.Type as T
+
+instance Arbitrary L.Literal where
+  arbitrary =
+      oneof
+      [ L.IntNum   <$> arbitrary
+      , L.FloatNum <$> (arbitrary `suchThat` noE)
+      , L.Chr      <$> arbitrary
+      -- This is too permissive
+      , L.Str      <$> arbitrary
+      -- Booleans aren't actually source syntax 
+      -- , Boolean  <$> arbitrary
+      ]
+
+  shrink lit =
+    case lit of
+      L.IntNum n   -> L.IntNum   <$> shrink n
+      L.FloatNum f -> L.FloatNum <$> (filter noE . shrink $ f)
+      L.Chr c      -> L.Chr      <$> shrink c
+      L.Str s      -> L.Str      <$> shrink s
+      L.Boolean b  -> L.Boolean  <$> shrink b
+
+noE :: Double -> Bool
+noE = notElem 'e' . show
+
+genVector :: Int -> (Int -> Gen a) -> Gen [a]
+genVector n generator = do
+  len <- choose (0,n)
+  let m = n `div` (len + 1)
+  vectorOf len $ generator m
+
+instance Arbitrary P.Pattern where
+  arbitrary = sized pat
+    where
+      pat :: Int -> Gen P.Pattern
+      pat n =
+          oneof
+          [ pure P.Anything
+          , P.Var     <$> lowVar
+          , P.Record  <$> (listOf1 lowVar)
+          , P.Literal <$> arbitrary
+          , P.Alias   <$> lowVar <*> pat (n-1)
+          , P.Data    <$> capVar <*> genVector n pat
+          ]
+
+  shrink pat =
+    case pat of
+      P.Anything  -> []
+      P.Var v     -> P.Var <$> shrinkWHead v
+      P.Literal l -> P.Literal <$> shrink l
+      P.Alias s p -> p : (P.Alias <$> shrinkWHead s <*> shrink p)
+      P.Data s ps -> ps ++ (P.Data <$> shrinkWHead s <*> shrink ps)
+      P.Record fs ->
+          P.Record <$> filter (all notNull) (filter notNull (shrink fs))
+          where
+            notNull = not . null
+
+shrinkWHead :: Arbitrary a => [a] -> [[a]]
+shrinkWHead [] = error "Should be nonempty"
+shrinkWHead (x:xs) = (x:) <$> shrink xs
+
+instance Arbitrary T.Type where
+  arbitrary = sized tipe
+    where
+      tipe :: Int -> Gen T.Type
+      tipe n =
+          let depthTipe = tipe =<< choose (0,n)
+              field = (,) <$> lowVar <*> depthTipe
+              fields = genVector n (\m -> (,) <$> lowVar <*> tipe m)
+              fields1 = (:) <$> field <*> fields
+          in
+              oneof
+              [ T.Lambda <$> depthTipe <*> depthTipe
+              , T.Var    <$> lowVar
+              , T.Data   <$> capVar <*> genVector n tipe
+              , T.Record <$> fields <*> pure Nothing
+              , T.Record <$> fields1 <*> (Just <$> lowVar)
+              ]
+
+  shrink tipe =
+    case tipe of
+      T.Lambda s t  -> s : t : (T.Lambda <$> shrink s <*> shrink t)
+      T.Var _       -> []
+      T.Data n ts   -> ts ++ (T.Data <$> shrinkWHead n <*> shrink ts)
+      T.Record fs t -> map snd fs ++ record
+          where
+            record =
+                case t of
+                  Nothing -> T.Record <$> shrinkList shrinkField fs <*> pure Nothing
+                  Just _ ->
+                      do fields <- filter (not . null) $ shrinkList shrinkField fs
+                         return $ T.Record fields t
+
+            shrinkField (n,t) = (,) <$> shrinkWHead n <*> shrink t
+
+lowVar :: Gen String
+lowVar = notReserved $ (:) <$> lower <*> listOf varLetter
+  where
+    lower = elements ['a'..'z']
+
+capVar :: Gen String
+capVar = notReserved $ (:) <$> upper <*> listOf varLetter
+  where
+    upper = elements ['A'..'Z']
+
+varLetter :: Gen Char
+varLetter = elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ['\'', '_']
+
+notReserved :: Gen String -> Gen String
+notReserved = flip exceptFor Parse.Helpers.reserveds
+
+exceptFor :: (Ord a) => Gen a -> [a] -> Gen a
+exceptFor g xs = g `suchThat` notAnX
+  where
+    notAnX = flip Set.notMember xset
+    xset = Set.fromList xs
diff --git a/tests/hs/CompilerTest.hs b/tests/hs/CompilerTest.hs
deleted file mode 100644
--- a/tests/hs/CompilerTest.hs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Test.Framework
-
-import Tests.Compiler
-import Tests.Property
-
-main :: IO () 
-main = defaultMain [ compilerTests
-                   , propertyTests
-                   ]
diff --git a/tests/hs/LibTest.hs b/tests/hs/LibTest.hs
deleted file mode 100644
--- a/tests/hs/LibTest.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-module Main where
-
-import Control.Monad (unless)
-import Data.List (isInfixOf)
-import System.Directory
-import System.Exit
-import System.FilePath
-import System.Process
-
-import Elm.Internal.Paths as Elm
-
-main :: IO ()
-main = do
-  top <- getCurrentDirectory
-  let ioScript s = top</>"IO"</>s
-  runCmd "git submodule update --init"
-  out <- readProcess "npm" ["ls", "--parseable"] ""
-  unless ("jsdom" `isInfixOf` out) $ runCmd "npm install jsdom"
-  setCurrentDirectory $ top</>"tests"</>"elm"
-  runCmd $ concat [top</>"dist"</>"build"</>"elm"</>"elm --make --only-js --src-dir=" , top</>"automaton", " --src-dir=", top</>"IO", " --src-dir=", top</>"Elm-Test", " Test.elm"]
-  runCmd $ unwords ["cat ", ioScript "prescript.js", Elm.runtime, "build"</>"Test.js", ioScript "handler.js", "> exe.js"]
-  exitWith =<< waitForProcess =<< (runCommand "node exe.js")
-  where runCmd cmd = do
-          putStrLn cmd
-          exitCode <- waitForProcess =<< runCommand cmd
-          case exitCode of
-            ExitSuccess   -> return ()
-            ExitFailure _ -> error "something went wrong"
-
-          
diff --git a/tests/hs/Tests/Compiler.hs b/tests/hs/Tests/Compiler.hs
deleted file mode 100644
--- a/tests/hs/Tests/Compiler.hs
+++ /dev/null
@@ -1,45 +0,0 @@
-module Tests.Compiler (compilerTests)
-       where
-
-import Data.Functor                   ((<$>))
-import Data.Traversable               (traverse)
-import System.FilePath                ((</>))
-import System.FilePath.Find           (find, (==?), extension)
-import Test.Framework
-import Test.Framework.Providers.HUnit (testCase)
-import Test.HUnit                     (Assertion, assertFailure, assertBool)
-import Text.Parsec                    (ParseError)
-
-import Elm.Internal.Utils as Elm
-
-compilerTests :: Test
-compilerTests = buildTest $ do
-  goods <- mkTests goodCompile  =<< getElms "good"
-  bads  <- mkTests badCompile   =<< getElms "bad"
-  return $ testGroup "Compile Tests"
-    [
-      testGroup "Good Tests" goods
-    , testGroup "Bad Tests"  bads
-    ]
-
-  where getElms :: FilePath -> IO [FilePath]
-        getElms fname = find (return True) (extension ==? ".elm") (testsDir </> fname)
-
-        mkTests :: (Either String String -> Assertion) -> [FilePath] -> IO [Test]
-        mkTests h = traverse setupTest
-          where setupTest f = testCase f . mkCompileTest h <$> readFile f
-
-        testsDir = "tests" </> "test-files"
-
-goodCompile :: Either String String -> Assertion
-goodCompile (Left err) = assertFailure err
-goodCompile (Right _)  = assertBool "" True
-
-badCompile :: Either String String -> Assertion
-badCompile (Left _)  = assertBool "" True
-badCompile (Right _) = assertFailure "Compilation succeeded but should have failed"
-  
-mkCompileTest :: ((Either String String) -> Assertion) -- ^ Handler
-                 -> String -- ^ File Contents
-                 -> Assertion
-mkCompileTest handle = handle . Elm.compile
diff --git a/tests/hs/Tests/Property.hs b/tests/hs/Tests/Property.hs
deleted file mode 100644
--- a/tests/hs/Tests/Property.hs
+++ /dev/null
@@ -1,55 +0,0 @@
-module Tests.Property where
-
-import Control.Applicative ((<*))
-import Test.Framework
-import Test.Framework.Providers.HUnit
-import Test.Framework.Providers.QuickCheck2
-import Test.HUnit (assert)
-import Test.QuickCheck
-import Text.Parsec.Combinator (eof)
-import Text.PrettyPrint as P
-
-import SourceSyntax.Literal as Lit
-import qualified SourceSyntax.Pattern as P
-import SourceSyntax.PrettyPrint  (Pretty, pretty)
-import Parse.Helpers             (IParser, iParse)
-import Parse.Literal             (literal)
-import qualified Parse.Pattern as Pat (expr)
-import qualified Parse.Type as Type (expr)
-import Tests.Property.Arbitrary
-
-propertyTests :: Test
-propertyTests =
-  testGroup "Parse/Print Agreement Tests"
-  [
-    testCase "Long Pattern test" $ assert (prop_parse_print Pat.expr longPat)
-  , testProperty "Literal test" $ prop_parse_print literal
-  , testProperty "Pattern test" $ prop_parse_print Pat.expr
-  , testProperty "Type test" $ prop_parse_print Type.expr
-  ]
-
-  where
-    -- This test was autogenerated from the Pattern test and should be
-    -- left in all its ugly glory.
-    longPat = P.Data "I" [ P.Literal (Lit.Chr '+')
-                         , P.Record
-                           [ "q7yclkcm7k_ikstrczv_"
-                           , "wQRv6gKsvvkjw4b5F"
-                           ,"c9'eFfhk9FTvsMnwF_D"
-                           ,"yqxhEkHvRFwZ"
-                           ,"o"
-                           ,"nbUlCn3y3NnkVoxhW"
-                           ,"iJ0MNy3KZ_lrs"
-                           ,"ug"
-                           ,"sHHsX"
-                           ,"mRKs9d"
-                           ,"o2KiCX5'ZRzHJfRi8" ]
-                         , P.Var "su'BrrbPUK6I33Eq"
-                         ]
-
-prop_parse_print :: (Pretty a, Arbitrary a, Eq a) => IParser a -> a -> Bool
-prop_parse_print p x =
-  either (const False) (== x) . parse_print p $ x
-
-parse_print :: (Pretty a) => IParser a -> a -> Either String a
-parse_print p = either (Left . show) Right . iParse (p <* eof) . P.renderStyle P.style {mode=P.LeftMode} . pretty
diff --git a/tests/hs/Tests/Property/Arbitrary.hs b/tests/hs/Tests/Property/Arbitrary.hs
deleted file mode 100644
--- a/tests/hs/Tests/Property/Arbitrary.hs
+++ /dev/null
@@ -1,128 +0,0 @@
-{-# OPTIONS_GHC -W -fno-warn-orphans #-}
-module Tests.Property.Arbitrary where
-
-import Control.Applicative       ((<$>), (<*>), pure)
-import Test.QuickCheck.Arbitrary
-import Test.QuickCheck.Gen
-
-import qualified Data.Set as Set
-import qualified Parse.Helpers (reserveds)
-
-import qualified SourceSyntax.Literal as L
-import qualified SourceSyntax.Pattern as P
-import qualified SourceSyntax.Type as T
-
-instance Arbitrary L.Literal where
-  arbitrary =
-      oneof
-      [ L.IntNum   <$> arbitrary
-      , L.FloatNum <$> (arbitrary `suchThat` noE)
-      , L.Chr      <$> arbitrary
-      -- This is too permissive
-      , L.Str      <$> arbitrary
-      -- Booleans aren't actually source syntax 
-      -- , Boolean  <$> arbitrary
-      ]
-
-  shrink lit =
-    case lit of
-      L.IntNum n   -> L.IntNum   <$> shrink n
-      L.FloatNum f -> L.FloatNum <$> (filter noE . shrink $ f)
-      L.Chr c      -> L.Chr      <$> shrink c
-      L.Str s      -> L.Str      <$> shrink s
-      L.Boolean b  -> L.Boolean  <$> shrink b
-
-noE :: Double -> Bool
-noE = notElem 'e' . show
-
-genVector :: Int -> (Int -> Gen a) -> Gen [a]
-genVector n generator = do
-  len <- choose (0,n)
-  let m = n `div` (len + 1)
-  vectorOf len $ generator m
-
-instance Arbitrary P.Pattern where
-  arbitrary = sized pat
-    where
-      pat :: Int -> Gen P.Pattern
-      pat n =
-          oneof
-          [ pure P.Anything
-          , P.Var     <$> lowVar
-          , P.Record  <$> (listOf1 lowVar)
-          , P.Literal <$> arbitrary
-          , P.Alias   <$> lowVar <*> pat (n-1)
-          , P.Data    <$> capVar <*> genVector n pat
-          ]
-
-  shrink pat =
-    case pat of
-      P.Anything  -> []
-      P.Var v     -> P.Var <$> shrinkWHead v
-      P.Literal l -> P.Literal <$> shrink l
-      P.Alias s p -> p : (P.Alias <$> shrinkWHead s <*> shrink p)
-      P.Data s ps -> ps ++ (P.Data <$> shrinkWHead s <*> shrink ps)
-      P.Record fs ->
-          P.Record <$> filter (all notNull) (filter notNull (shrink fs))
-          where
-            notNull = not . null
-
-shrinkWHead :: Arbitrary a => [a] -> [[a]]
-shrinkWHead [] = error "Should be nonempty"
-shrinkWHead (x:xs) = (x:) <$> shrink xs
-
-instance Arbitrary T.Type where
-  arbitrary = sized tipe
-    where
-      tipe :: Int -> Gen T.Type
-      tipe n =
-          let depthTipe = tipe =<< choose (0,n)
-              field = (,) <$> lowVar <*> depthTipe
-              fields = genVector n (\m -> (,) <$> lowVar <*> tipe m)
-              fields1 = (:) <$> field <*> fields
-          in
-              oneof
-              [ T.Lambda <$> depthTipe <*> depthTipe
-              , T.Var    <$> lowVar
-              , T.Data   <$> capVar <*> genVector n tipe
-              , T.Record <$> fields <*> pure Nothing
-              , T.Record <$> fields1 <*> (Just <$> lowVar)
-              ]
-
-  shrink tipe =
-    case tipe of
-      T.Lambda s t  -> s : t : (T.Lambda <$> shrink s <*> shrink t)
-      T.Var _       -> []
-      T.Data n ts   -> ts ++ (T.Data <$> shrinkWHead n <*> shrink ts)
-      T.Record fs t -> map snd fs ++ record
-          where
-            record =
-                case t of
-                  Nothing -> T.Record <$> shrinkList shrinkField fs <*> pure Nothing
-                  Just _ ->
-                      do fields <- filter (not . null) $ shrinkList shrinkField fs
-                         return $ T.Record fields t
-
-            shrinkField (n,t) = (,) <$> shrinkWHead n <*> shrink t
-
-lowVar :: Gen String
-lowVar = notReserved $ (:) <$> lower <*> listOf varLetter
-  where
-    lower = elements ['a'..'z']
-
-capVar :: Gen String
-capVar = notReserved $ (:) <$> upper <*> listOf varLetter
-  where
-    upper = elements ['A'..'Z']
-
-varLetter :: Gen Char
-varLetter = elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ['\'', '_']
-
-notReserved :: Gen String -> Gen String
-notReserved = flip exceptFor Parse.Helpers.reserveds
-
-exceptFor :: (Ord a) => Gen a -> [a] -> Gen a
-exceptFor g xs = g `suchThat` notAnX
-  where
-    notAnX = flip Set.notMember xset
-    xset = Set.fromList xs
diff --git a/tests/libraries/LibraryTest.hs b/tests/libraries/LibraryTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/libraries/LibraryTest.hs
@@ -0,0 +1,49 @@
+module Main where
+
+import Control.Monad (unless)
+import Data.List (isInfixOf)
+import System.Directory
+import System.Exit
+import System.FilePath
+import System.Process
+
+import Elm.Internal.Paths as Elm
+
+main :: IO ()
+main = do
+  top <- getCurrentDirectory
+
+  -- setup submodules and npm
+  runCmd "git" ["submodule", "update", "--init"]
+  out <- readProcess "npm" ["ls", "--parseable"] ""
+  unless ("jsdom" `isInfixOf` out) $ runCmd "npm" ["install","jsdom"]
+
+  -- setup actual library tests
+  setCurrentDirectory $ top </> "tests" </> "libraries"
+  let localCompiler = joinPath [ top, "dist", "build", "elm", "elm" ]
+  runCmd localCompiler [ "--make"
+                       , "--only-js"
+                       , "--src-dir=" ++ top </> "automaton"
+                       , "--src-dir=" ++ top </> "IO"
+                       , "--src-dir=" ++ top </> "Elm-Test"
+                       , "Test.elm"
+                       ]
+
+  -- run tests
+  let ioScript s = top </> "IO" </> s
+      files = [ ioScript "prescript.js"
+              , Elm.runtime
+              , "build" </> "Test.js"
+              , ioScript "handler.js"
+              ]
+  exe <- readProcess "cat" files ""
+  writeFile "exe.js" exe
+  exitWith =<< waitForProcess =<< (runCommand "node exe.js")
+
+runCmd :: String -> [String] -> IO ()
+runCmd cmd args = do
+  putStrLn (cmd ++ " " ++ unwords args)
+  (exitCode, _stdout, stderr) <- readProcessWithExitCode cmd args ""
+  case exitCode of
+    ExitSuccess   -> return ()
+    ExitFailure _ -> error stderr
