packages feed

elm-core-sources (empty) → 1.0.0

raw patch · 65 files changed

+11861/−0 lines, 65 filesdep +basedep +bytestringdep +containerssetup-changed

Dependencies added: base, bytestring, containers, file-embed, template-haskell

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Evan Czaplicki
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Evan Czaplicki nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ elm-core-sources.cabal view
@@ -0,0 +1,51 @@+Name: elm-core-sources
+Version: 1.0.0
+Synopsis:       Source files for the Elm runtime and standard libraries
+Description:     
+    Embeds the  standard libraries and runtime files of the Elm language as Haskell strings,
+    so that they can be used for compilation and served in a Haskell web server.
+    For more information on the Elm language, see http://elm-lang.org.
+Homepage: http://github.com/JoeyEremondi/elm-build-lib
+
+License: BSD3
+License-file: LICENSE
+
+cabal-version:  >=1.6
+build-type:     Simple
+author:         Evan Czaplicki
+Maintainer:     joey@eremondi.com
+Copyright:      Copyright: (c) 2014 Evan Czaplicki
+
+Category: Compiler, Language
+
+Extra-source-files: src/*.elm
+    
+    ,src/Json/*.elm
+
+    ,src/Graphics/*.elm
+     
+    ,src/Graphics/Input/*.elm
+    
+    ,src/Graphics/Input/*.elm
+    
+    src/Native/*.js
+    
+    ,src/Native/Graphics/*.js
+         
+source-repository head
+  type: git
+  location: git://github.com/JoeyEremondi/elm-build-lib
+
+
+
+library
+  exposed-modules: Language.Elm.CoreSources
+  hs-source-dirs:  haskell
+
+  build-depends:   base >=4.2 && <5
+                   , containers
+                   , template-haskell
+                   , file-embed
+                   , bytestring
+  ghc-options:     -Wall
+
+ haskell/Language/Elm/CoreSources.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE TemplateHaskell #-}
+module Language.Elm.CoreSources where
+
+import Data.FileEmbed
+import Data.ByteString.Char8 (unpack)
+
+{-|
+JavaScript Header to append at the beginning of a complete, linked Elm program.
+-}
+header :: String
+header = "var Elm = Elm || { Native: {} };\n"
+  
+{-|
+Source for the Elm Runtime library
+-}
+runtime :: String
+runtime =  unpack $(embedFile  "src/Native/Runtime.js")
+
+{-|
+Dictionary mapping strings of the form "Native.ModuleName" to the JS source code
+for that stdlib native module.
+-}
+nativeSources ::  [(String, String)]
+nativeSources = map (\(x,y) -> (x, unpack y)) $ [
+        ("Native.Array", $(embedFile  "src/Native/Array.js"))
+        , ("Native.Basics", $(embedFile  "src/Native/Basics.js"))
+        , ("Native.Bitwise", $(embedFile  "src/Native/Bitwise.js"))
+        , ("Native.Char", $(embedFile  "src/Native/Char.js"))
+        , ("Native.Color", $(embedFile  "src/Native/Color.js"))
+        , ("Native.Date", $(embedFile  "src/Native/Date.js"))
+        , ("Native.Debug", $(embedFile  "src/Native/Debug.js"))
+        , ("Native.Http", $(embedFile  "src/Native/Http.js"))
+        , ("Native.Json", $(embedFile  "src/Native/Json.js"))
+        , ("Native.Keyboard", $(embedFile  "src/Native/Keyboard.js"))
+        , ("Native.List", $(embedFile  "src/Native/List.js"))
+        , ("Native.Mouse", $(embedFile  "src/Native/Mouse.js"))
+        , ("Native.Ports", $(embedFile  "src/Native/Ports.js"))
+        , ("Native.Regex", $(embedFile  "src/Native/Regex.js"))
+        , ("Native.Show", $(embedFile  "src/Native/Show.js"))
+        , ("Native.Signal", $(embedFile  "src/Native/Signal.js"))
+        , ("Native.String", $(embedFile  "src/Native/String.js"))
+        , ("Native.Text", $(embedFile  "src/Native/Text.js"))
+        , ("Native.Time", $(embedFile  "src/Native/Time.js"))
+        , ("Native.Touch", $(embedFile  "src/Native/Touch.js"))
+        , ("Native.Trampoline", $(embedFile  "src/Native/Trampoline.js"))
+        , ("Native.Transform2D", $(embedFile  "src/Native/Transform2D.js"))
+        , ("Native.Utils", $(embedFile  "src/Native/Utils.js"))
+        , ("Native.WebSocket", $(embedFile  "src/Native/WebSocket.js"))
+        , ("Native.Window", $(embedFile  "src/Native/Window.js"))
+        
+        , ("Native.Graphics.Collage", $(embedFile  "src/Native/Graphics/Collage.js"))
+        , ("Native.Graphics.Element", $(embedFile  "src/Native/Graphics/Element.js"))
+        , ("Native.Graphics.Input", $(embedFile  "src/Native/Graphics/Input.js"))
+
+
+        ]
+
+{-|
+List of .elm sources for the Elm Standard Library
+-}        
+stdlibSources :: [String]
+stdlibSources = map unpack [$(embedFile  "src/Array.elm")
+   ,$(embedFile  "src/Array.elm")
+   ,$(embedFile  "src/Basics.elm")
+   ,$(embedFile  "src/Bitwise.elm")
+   ,$(embedFile  "src/Char.elm")
+   ,$(embedFile  "src/Color.elm")
+   ,$(embedFile  "src/Date.elm")
+   ,$(embedFile  "src/Debug.elm")
+   ,$(embedFile  "src/Dict.elm")
+   ,$(embedFile  "src/Http.elm")
+   ,$(embedFile  "src/Keyboard.elm")
+   ,$(embedFile  "src/List.elm")
+   ,$(embedFile  "src/Maybe.elm")
+   ,$(embedFile  "src/Mouse.elm")
+   ,$(embedFile  "src/Random.elm")
+   ,$(embedFile  "src/Regex.elm")
+   ,$(embedFile  "src/Result.elm")
+   ,$(embedFile  "src/Set.elm")
+   ,$(embedFile  "src/Signal.elm")
+   ,$(embedFile  "src/String.elm")
+   ,$(embedFile  "src/Text.elm")
+   ,$(embedFile  "src/Time.elm")
+   ,$(embedFile  "src/Touch.elm")
+   ,$(embedFile  "src/Trampoline.elm")
+   ,$(embedFile  "src/Transform2D.elm")
+   ,$(embedFile  "src/WebSocket.elm")
+   ,$(embedFile  "src/Window.elm")
+   
+   ,$(embedFile  "src/Json/Encode.elm")
+   ,$(embedFile  "src/Json/Decode.elm")
+   
+   ,$(embedFile  "src/Graphics/Collage.elm")
+   ,$(embedFile  "src/Graphics/Element.elm")
+   ,$(embedFile  "src/Graphics/Input.elm")
+   
+   ,$(embedFile  "src/Graphics/Input/Field.elm")
+   ]
+ src/Array.elm view
@@ -0,0 +1,180 @@+module Array where
+
+{-| A library for fast immutable arrays. The elements in an array must have the
+same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast
+reads, updates, and appends.
+
+# Creating Arrays
+@docs empty, repeat, initialize, fromList
+
+# Basics
+@docs length, push, append
+
+# Get and Set
+@docs get, set
+
+# Taking Arrays Apart
+@docs slice, toList, toIndexedList
+
+# Mapping and Folding
+@docs map, indexedMap, foldl, foldr
+-}
+
+import Native.Array
+import Basics (..)
+import Maybe (..)
+import List
+
+type Array a = Array
+
+{-| Initialize an array. `initialize n f` creates an array of length `n` with
+the element at index `i` initialized to the result of `(f i)`.
+
+    initialize 4 identity    == fromList [0,1,2,3]
+    initialize 4 (\n -> n*n) == fromList [0,1,4,9]
+    initialize 4 (always 0)  == fromList [0,0,0,0]
+-}
+initialize : Int -> (Int -> a) -> Array a
+initialize = Native.Array.initialize
+
+{-| Creates an array with a given length, filled with a default element.
+
+    repeat 5 0     == fromList [0,0,0,0,0]
+    repeat 3 "cat" == fromList ["cat","cat","cat"]
+
+Notice that `repeat 3 x` is the same as `initialize 3 (always x)`.
+-}
+repeat : Int -> a -> Array a
+repeat n e = initialize n (always e)
+
+{-| Create an array from a list. -}
+fromList : List a -> Array a
+fromList = Native.Array.fromList
+
+{-| Create a list of elements from an array.
+
+    toList (fromList [3,5,8]) == [3,5,8]
+-}
+toList : Array a -> List a
+toList = Native.Array.toList
+
+-- TODO: make this a native function.
+{-| Create an indexed list from an array. Each element of the array will be
+paired with its index.
+
+    toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")]
+-}
+toIndexedList : Array a -> List (Int, a)
+toIndexedList array =
+    List.map2 (,) [ 0 .. Native.Array.length array - 1 ] (Native.Array.toList array)
+
+{-| Apply a function on every element in an array.
+
+    map sqrt (fromList [1,4,9]) == fromList [1,2,3]
+-}
+map : (a -> b) -> Array a -> Array b
+map = Native.Array.map
+
+{-| Apply a function on every element with its index as first argument.
+
+    indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10]
+-}
+indexedMap : (Int -> a -> b) -> Array a -> Array b
+indexedMap = Native.Array.indexedMap
+
+{-| Reduce an array from the left. Read `foldl` as &ldquo;fold from the left&rdquo;.
+
+    foldl (::) [] (fromList [1,2,3]) == [3,2,1]
+-}
+foldl : (a -> b -> b) -> b -> Array a -> b
+foldl = Native.Array.foldl
+
+{-| Reduce an array from the right. Read `foldr` as &ldquo;fold from the right&rdquo;.
+
+    foldr (+) 0 (repeat 3 5) == 15
+-}
+foldr : (a -> b -> b) -> b -> Array a -> b
+foldr = Native.Array.foldr
+
+{-| Keep only elements that satisfy the predicate:
+
+    filter isEven (fromList [1..6]) == (fromList [2,4,6])
+-}
+filter : (a -> Bool) -> Array a -> Array a
+filter isOkay arr =
+    let update x xs = if isOkay x then Native.Array.push x xs else xs
+    in
+        Native.Array.foldl update Native.Array.empty arr
+
+{-| Return an empty array.
+
+    length empty == 0
+-}
+empty : Array a
+empty = Native.Array.empty
+
+{-| Push an element to the end of an array.
+
+    push 3 (fromList [1,2]) == fromList [1,2,3]
+-}
+push : a -> Array a -> Array a
+push = Native.Array.push
+
+{-| Return Just the element at the index or Nothing if the index is out of range.
+
+    get  0 (fromList [0,1,2]) == Just 0
+    get  2 (fromList [0,1,2]) == Just 2
+    get  5 (fromList [0,1,2]) == Nothing
+    get -1 (fromList [0,1,2]) == Nothing
+
+The `(?)` operator from the `Maybe` library makes it easy to give a default
+value.
+-}
+get : Int -> Array a -> Maybe a
+get i array =
+    if 0 <= i && i < Native.Array.length array
+      then Just (Native.Array.get i array)
+      else Nothing
+
+
+{-| Set the element at a particular index. Returns an updated array.
+If the index is out of range, the array is unaltered.
+
+    set 1 7 (fromList [1,2,3]) == fromList [1,7,3]
+-}
+set : Int -> a -> Array a -> Array a
+set = Native.Array.set
+
+
+{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a
+zero-based index where we will start our slice. The `end` is a zero-based index
+that indicates the end of the slice. The slice extracts up to but not including
+`end`.
+
+    slice  0  3 (fromList [0,1,2,3,4]) == fromList [0,1,2]
+    slice  1  4 (fromList [0,1,2,3,4]) == fromList [1,2,3]
+
+Both the `start` and `end` indexes can be negative, indicating an offset from
+the end of the array.
+
+    slice  1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3]
+    slice -2  5 (fromList [0,1,2,3,4]) == fromList [3,4]
+
+This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array`
+-}
+slice : Int -> Int -> Array a -> Array a
+slice = Native.Array.slice
+
+{-| Return the length of an array.
+
+    length (fromList [1,2,3]) == 3
+-}
+length : Array a -> Int
+length = Native.Array.length
+
+{-| Append two arrays to a new one.
+
+    append (repeat 2 42) (repeat 3 81) == fromList [42,42,81,81,81]
+-}
+append : Array a -> Array a -> Array a
+append = Native.Array.append
+ src/Basics.elm view
@@ -0,0 +1,458 @@+
+module Basics where
+
+{-| Tons of useful functions that get imported by default.
+
+# Equality
+@docs (==), (/=)
+
+# Comparison
+
+These functions only work on `comparable` types. This includes numbers,
+characters, strings, lists of comparable things, and tuples of comparable
+things. Note that tuples with 7 or more elements are not comparable; why
+are your tuples so big?
+
+@docs (<), (>), (<=), (>=), max, min, Order, compare
+
+# Booleans
+@docs not, (&&), (||), xor, otherwise
+
+# Mathematics
+@docs (+), (-), (*), (/), (^), (//), rem, (%), negate, abs, sqrt, clamp, logBase, e
+
+# Trigonometry
+@docs pi, cos, sin, tan, acos, asin, atan, atan2
+
+# Number Conversions
+@docs round, floor, ceiling, truncate, toFloat
+
+# Angle Conversions
+All angle conversions result in &ldquo;standard Elm angles&rdquo;
+which happen to be radians.
+
+@docs degrees, radians, turns
+
+# Polar Coordinates
+@docs toPolar, fromPolar
+
+# Floating Point Checks
+@docs isNaN, isInfinite
+
+# Strings and Lists
+@docs toString, (++)
+
+# Tuples
+@docs fst, snd
+
+# Higher-Order Helpers
+@docs identity, always, (<|), (|>), (<<), (>>), flip, curry, uncurry
+
+-}
+
+import Native.Basics
+import Native.Ports
+import Native.Show
+import Native.Utils
+import Native.Runtime
+
+
+{-| Convert radians to standard Elm angles (radians). -}
+radians : Float -> Float
+radians t = t
+
+{-| Convert degrees to standard Elm angles (radians). -}
+degrees : Float -> Float
+degrees = Native.Basics.degrees
+
+{-| Convert turns to standard Elm angles (radians).
+One turn is equal to 360&deg;.
+-}
+turns : Float -> Float
+turns = Native.Basics.turns
+
+{-| Convert polar coordinates (r,&theta;) to cartesian coordinates (x,y). -}
+fromPolar : (Float,Float) -> (Float,Float)
+fromPolar = Native.Basics.fromPolar
+
+{-| Convert cartesian coordinates (x,y) to polar coordinates (r,&theta;). -}
+toPolar : (Float,Float) -> (Float,Float)
+toPolar = Native.Basics.toPolar
+
+(+) : number -> number -> number
+(+) = Native.Basics.add
+
+(-) : number -> number -> number
+(-) = Native.Basics.sub
+
+(*) : number -> number -> number
+(*) = Native.Basics.mul
+
+{-| Floating point division. -}
+(/) : Float -> Float -> Float
+(/) = Native.Basics.floatDiv
+
+infixl 6 +
+infixl 6 -
+infixl 7 *
+infixl 7 /
+infixl 8 ^
+
+infixl 7 //
+infixl 7 %
+infixl 7 `rem`
+
+{-| Integer division. The remainder is discarded. -}
+(//) : Int -> Int -> Int
+(//) = Native.Basics.div
+
+{-| Find the remainder after dividing one number by another.
+
+     7 `rem` 2 == 1
+    -1 `rem` 4 == -1
+-}
+rem : Int -> Int -> Int
+rem = Native.Basics.rem
+
+{-| Perform [modular arithmetic](http://en.wikipedia.org/wiki/Modular_arithmetic).
+
+     7 % 2 == 1
+    -1 % 4 == 3
+-}
+(%) : Int -> Int -> Int
+(%) = Native.Basics.mod
+
+{-| Exponentiation
+
+    3^2 == 9`
+-}
+(^) : number -> number -> number
+(^) = Native.Basics.exp
+
+cos : Float -> Float
+cos = Native.Basics.cos
+
+sin : Float -> Float
+sin = Native.Basics.sin
+
+tan : Float -> Float
+tan = Native.Basics.tan
+
+acos : Float -> Float
+acos = Native.Basics.acos
+
+asin : Float -> Float
+asin = Native.Basics.asin
+
+{-| You probably do not want to use this. It takes `(y/x)` as the
+argument, so there is no way to know whether the negative signs comes from
+the `y` or `x`. Thus, the resulting angle is always between &pi;/2 and -&pi;/2
+(in quadrants I and IV). You probably want to use `atan2` instead.
+-}
+atan : Float -> Float
+atan = Native.Basics.atan
+
+{-| This helps you find the angle of a cartesian coordinate.
+You will almost certainly want to use this instead of `atan`.
+So `atan2 y x` computes *atan(y/x)* but also keeps track of which
+quadrant the angle should really be in. The result will be between
+&pi; and -&pi;, giving you the full range of angles.
+-}
+atan2 : Float -> Float -> Float
+atan2 = Native.Basics.atan2
+
+{-| Take the square root of a number. -}
+sqrt : Float -> Float
+sqrt = Native.Basics.sqrt
+
+{-| Negate a number.
+
+    negate 42 == -42
+    negate -42 == 42
+    negate 0 == 0
+-}
+negate : number -> number
+negate = Native.Basics.negate
+
+{-| Take the absolute value of a number. -}
+abs : number -> number
+abs = Native.Basics.abs
+
+{-| Calculate the logarithm of a number with a given base.
+
+    logBase 10 100 == 2
+    logBase 2 256 == 8
+-}
+logBase : Float -> Float -> Float
+logBase = Native.Basics.logBase
+
+{-| Clamps a number within a given range. With the expression
+`clamp 100 200 x` the results are as follows:
+
+    100     if x < 100
+     x      if 100 <= x < 200
+    200     if 200 <= x
+-}
+clamp : number -> number -> number -> number
+clamp = Native.Basics.clamp
+
+{-| An approximation of pi. -}
+pi : Float
+pi = Native.Basics.pi
+
+{-| An approximation of e. -}
+e : Float
+e = Native.Basics.e
+
+(==) : a -> a -> Bool
+(==) = Native.Basics.eq
+
+(/=) : a -> a -> Bool
+(/=) = Native.Basics.neq
+
+(<)  : comparable -> comparable -> Bool
+(<)  = Native.Basics.lt
+
+(>)  : comparable -> comparable -> Bool
+(>)  = Native.Basics.gt
+
+(<=) : comparable -> comparable -> Bool
+(<=) = Native.Basics.le
+
+(>=) : comparable -> comparable -> Bool
+(>=) = Native.Basics.ge
+
+infix 4 ==
+infix 4 /=
+infix 4 <
+infix 4 >
+infix 4 <=
+infix 4 >=
+
+{-| Compare any two comparable values. Comparable values include `String`, `Char`,
+`Int`, `Float`, `Time`, or a list or tuple containing comparable values.
+These are also the only values that work as `Dict` keys or `Set` members.
+-}
+compare : comparable -> comparable -> Order
+compare = Native.Basics.compare
+
+{-| Represents the relative ordering of two things.
+The relations are less than, equal to, and greater than.
+-}
+type Order = LT | EQ | GT
+
+{-| Find the smaller of two comparables. -}
+min : comparable -> comparable -> comparable
+min = Native.Basics.min
+
+{-| Find the larger of two comparables. -}
+max : comparable -> comparable -> comparable
+max = Native.Basics.max
+
+{-| The logical AND operator. `True` if both inputs are `True`.
+This operator short-circuits to `False` if the first argument is `False`.
+-}
+(&&) : Bool -> Bool -> Bool
+(&&) = Native.Basics.and
+
+{-| The logical OR operator. `True` if one or both inputs are `True`.
+This operator short-circuits to `True` if the first argument is True.
+-}
+(||) : Bool -> Bool -> Bool
+(||) = Native.Basics.or
+
+infixr 3 &&
+infixr 2 ||
+
+{-| The exclusive-or operator. `True` if exactly one input is `True`. -}
+xor : Bool -> Bool -> Bool
+xor = Native.Basics.xor
+
+{-| Negate a boolean value.
+
+    not True == False
+    not False == True
+-}
+not : Bool -> Bool
+not = Native.Basics.not
+
+{-| Equal to `True`. Useful as the last case of a multi-way-if. -}
+otherwise : Bool
+otherwise = True
+
+
+-- Conversions
+
+{-| Round a number to the nearest integer. -}
+round : Float -> Int
+round = Native.Basics.round
+
+{-| Truncate a number, rounding towards zero. -}
+truncate : Float -> Int
+truncate = Native.Basics.truncate
+
+{-| Floor function, rounding down. -}
+floor : Float -> Int
+floor = Native.Basics.floor
+
+{-| Ceiling function, rounding up. -}
+ceiling : Float -> Int
+ceiling = Native.Basics.ceiling
+
+{-| Convert an integer into a float. -}
+toFloat : Int -> Float
+toFloat = Native.Basics.toFloat
+
+{- | Determine whether a float is an undefined or unrepresentable number.
+NaN stands for *not a number* and it is [a standardized part of floating point
+numbers](http://en.wikipedia.org/wiki/NaN).
+
+    isNaN (0/0)     == True
+    isNaN (sqrt -1) == True
+    isNaN (1/0)     == False  -- infinity is a number
+    isNaN 1         == False
+-}
+isNaN : Float -> Bool
+isNaN = Native.Basics.isNaN
+
+{- | Determine whether a float is positive or negative infinity.
+
+    isInfinite (0/0)     == False
+    isInfinite (sqrt -1) == False
+    isInfinite (1/0)     == True
+    isInfinite 1         == False
+
+Notice that NaN is not infinite! For float `n` to be finite implies that
+`not (isInfinite n || isNaN n)` evaluates to `True`.
+-}
+isInfinite : Float -> Bool
+isInfinite = Native.Basics.isInfinite
+
+
+{-| Turn any kind of value into a string.
+
+    toString 42    == "42"
+    toString [1,2] == "[1,2]"
+-}
+toString : a -> String
+toString = Native.Show.toString
+
+
+{-| Put two appendable things together. This includes strings, lists, and text.
+
+    "hello" ++ "world" == "helloworld"
+    [1,1,2] ++ [3,5,8] == [1,1,2,3,5,8]
+-}
+(++) : appendable -> appendable -> appendable
+(++) = Native.Utils.append
+
+infixr 5 ++
+
+
+-- Function Helpers
+
+{-| Function composition, passing results along in the suggested direction. For
+example, the following code checks if the square root of a number is odd:
+
+    not << isEven << sqrt
+
+You can think of this operator as equivalent to the following:
+
+    (g << f)  ==  (\x -> g (f x))
+
+So our example expands out to something like this:
+
+    \n -> not (isEven (sqrt n))
+-}
+(<<) : (b -> c) -> (a -> b) -> (a -> c)
+(<<) g f x = g (f x)
+
+{-| Function composition, passing results along in the suggested direction. For
+example, the following code checks if the square root of a number is odd:
+
+    sqrt >> isEven >> not
+
+This direction of function composition seems less pleasant than `(<<)` which
+reads nicely in expressions like: `filter (not << isRegistered) students`
+-}
+(>>) : (a -> b) -> (b -> c) -> (a -> c)
+(>>) f g x = g (f x)
+
+{-| Forward function application `x |> f == f x`. This function is useful
+for avoiding parenthesis and writing code in a more natural way.
+Consider the following code to create a pentagon:
+
+    scale 2 (move (10,10) (filled blue (ngon 5 30)))
+
+This can also be written as:
+
+    ngon 5 30
+      |> filled blue
+      |> move (10,10)
+      |> scale 2
+-}
+(|>) : a -> (a -> b) -> b
+x |> f = f x
+
+{-| Backward function application `f <| x == f x`. This function is useful for
+avoiding parenthesis. Consider the following code to create a text element:
+
+    leftAligned (monospace (fromString "code"))
+
+This can also be written as:
+
+    leftAligned << monospace <| fromString "code"
+-}
+(<|) : (a -> b) -> a -> b
+f <| x = f x
+
+infixr 9 <<
+infixl 9 >>
+infixr 0 <|
+infixl 0 |>
+
+{-| Given a value, returns exactly the same value. This is called
+[the identity function](http://en.wikipedia.org/wiki/Identity_function).
+-}
+identity : a -> a
+identity x = x
+
+{-| Create a [constant function](http://en.wikipedia.org/wiki/Constant_function),
+a function that *always* returns the same value regardless of what input you give.
+It is defined as:
+
+    always a b = a
+
+It totally ignores the second argument, so `always 42` is a function that always
+returns 42. When you are dealing with higher-order functions, this comes in
+handy more often than you might expect. For example, creating a zeroed out list
+of length ten would be:
+
+    map (always 0) [0..9]
+-}
+always : a -> b -> a
+always a _ = a
+
+{-| Given a 2-tuple, returns the first value. -}
+fst : (a,b) -> a
+fst (a,_) = a
+
+{-| Given a 2-tuple, returns the second value. -}
+snd : (a,b) -> b
+snd (_,b) = b
+
+{-| Flip the order of the first two arguments to a function. -}
+flip : (a -> b -> c) -> (b -> a -> c)
+flip f b a = f a b
+
+{-| Change how arguments are passed to a function.
+This splits paired arguments into two separate arguments.
+-}
+curry : ((a,b) -> c) -> a -> b -> c
+curry f a b = f (a,b)
+
+{-| Change how arguments are passed to a function.
+This combines two arguments into a single pair.
+-}
+uncurry : (a -> b -> c) -> (a,b) -> c
+uncurry f (a,b) = f a b
+ src/Bitwise.elm view
@@ -0,0 +1,74 @@+module Bitwise where
+
+{-| Library for [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation).
+
+# Basic Operations
+
+@docs and, or, xor, complement
+
+# Bit Shifts
+
+@docs shiftLeft, shiftRight, shiftRightLogical
+-}
+
+import Native.Bitwise
+
+{-| Bitwise AND
+-}
+and : Int -> Int -> Int
+and = Native.Bitwise.and
+
+{-| Bitwise OR
+-}
+or : Int -> Int -> Int
+or = Native.Bitwise.or
+
+{-| Bitwise XOR
+-}
+xor : Int -> Int -> Int
+xor = Native.Bitwise.xor
+
+{-| Flip each bit individually, often called bitwise NOT
+-}
+complement : Int -> Int
+complement = Native.Bitwise.complement
+
+{-| Shift bits to the left by a given offset, filling new bits with zeros.
+This can be used to multiply numbers by powers of two.
+
+    8 `shiftLeft` 1 == 16
+    8 `shiftLeft` 2 == 32
+-}
+shiftLeft : Int -> Int -> Int
+shiftLeft = Native.Bitwise.shiftLeft
+
+{-| Shift bits to the right by a given offset, filling new bits with
+whatever is the topmost bit. This can be used to divide numbers by powers of two.
+
+     32 `shiftRight` 1 == 16
+     32 `shiftRight` 2 == 8
+    -32 `shiftRight` 1 == -16
+
+This is called an [arithmatic right
+shift](http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift),
+often written (>>), and sometimes called a sign-propagating
+right shift because it fills empty spots with copies of the highest bit.
+-}
+shiftRight : Int -> Int -> Int
+shiftRight = Native.Bitwise.shiftRightArithmatic
+
+{-| Shift bits to the right by a given offset, filling new bits with
+zeros.
+
+     32 `shiftRightLogical` 1 == 16
+     32 `shiftRightLogical` 2 == 8
+    -32 `shiftRightLogical` 1 == 2147483632
+
+This is called an [logical right
+shift](http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift), often written (>>>),
+and sometimes called a zero-fill right shift because it fills empty spots
+with zeros.
+-}
+shiftRightLogical : Int -> Int -> Int
+shiftRightLogical = Native.Bitwise.shiftRightLogical
+
+ src/Char.elm view
@@ -0,0 +1,62 @@+
+module Char where
+
+{-| Functions for working with characters. Character literals are enclosed in
+`'a'` pair of single quotes.
+
+# Classification
+@docs isUpper, isLower, isDigit, isOctDigit, isHexDigit
+
+# Conversion
+@docs toUpper, toLower, toLocaleUpper, toLocaleLower, toCode, fromCode
+
+-}
+
+import Native.Char
+
+{-| True for upper case letters. -}
+isUpper : Char -> Bool
+isUpper = Native.Char.isUpper
+
+{-| True for lower case letters. -}
+isLower : Char -> Bool
+isLower = Native.Char.isLower
+
+{-| True for ASCII digits `[0-9]`. -}
+isDigit : Char -> Bool
+isDigit = Native.Char.isDigit
+
+{-| True for ASCII octal digits `[0-7]`. -}
+isOctDigit : Char -> Bool
+isOctDigit = Native.Char.isOctDigit
+
+{-| True for ASCII hexadecimal digits `[0-9a-fA-F]`. -}
+isHexDigit : Char -> Bool
+isHexDigit = Native.Char.isHexDigit
+
+{-| Convert to upper case. -}
+toUpper : Char -> Char
+toUpper = Native.Char.toUpper
+
+{-| Convert to lower case. -}
+toLower : Char -> Char
+toLower = Native.Char.toLower
+
+{-| Convert to upper case, according to any locale-specific case mappings. -}
+toLocaleUpper : Char -> Char
+toLocaleUpper = Native.Char.toLocaleUpper
+
+{-| Convert to lower case, according to any locale-specific case mappings. -}
+toLocaleLower : Char -> Char
+toLocaleLower = Native.Char.toLocaleLower
+
+type alias KeyCode = Int
+
+{-| Convert to unicode. Used with the `Keyboard` library, which expects the
+input to be uppercase. -}
+toCode : Char -> KeyCode
+toCode = Native.Char.toCode
+
+{-| Convert from unicode. -}
+fromCode : KeyCode -> Char
+fromCode = Native.Char.fromCode
+ src/Color.elm view
@@ -0,0 +1,273 @@+module Color where
+
+{-| Library for working with colors. Includes
+[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and
+[HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and
+built-in names.
+
+# Creation
+@docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement
+
+# Gradients
+@docs linear, radial
+
+# Extracting Colors
+@docs toRgb, toHsl
+
+# Built-in Colors
+These colors come from the [Tango
+palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines)
+which provides aesthetically reasonable defaults for colors. Each color also
+comes with a light and dark version.
+
+### Standard
+@docs red, orange, yellow, green, blue, purple, brown
+
+### Light
+@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown
+
+### Dark
+@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown
+
+### Eight Shades of Grey
+These colors are a compatible series of shades of grey, fitting nicely
+with the Tango palette.
+@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black
+
+These are identical to the *grey* versions. It seems the spelling is regional, but
+that has never helped me remember which one I should be writing.
+@docs lightGray, gray, darkGray
+
+-}
+
+import Basics (..)
+import Native.Color
+
+type Color
+    = RGBA Int Int Int Float
+    | HSLA Float Float Float Float
+
+{-| Create RGB colors with an alpha component for transparency.
+The alpha component is specified with numbers between 0 and 1. -}
+rgba : Int -> Int -> Int -> Float -> Color
+rgba = RGBA
+
+{-| Create RGB colors from numbers between 0 and 255 inclusive. -}
+rgb : Int -> Int -> Int -> Color
+rgb r g b = RGBA r g b 1
+
+{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV)
+with an alpha component for transparency.
+-}
+hsla : Float -> Float -> Float -> Float -> Color
+hsla hue saturation lightness alpha =
+    HSLA (hue - turns (toFloat (floor (hue / (2*pi))))) saturation lightness alpha
+
+{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives
+you access to colors more like a color wheel, where all hues are aranged in a
+circle that you specify with standard Elm angles (radians).
+
+    red   = hsl (degrees   0) 1 0.5
+    green = hsl (degrees 120) 1 0.5
+    blue  = hsl (degrees 240) 1 0.5
+
+    pastelRed = hsl (degrees 0) 0.7 0.7
+
+To cycle through all colors, just cycle through degrees. The saturation level
+is how vibrant the color is, like a dial between grey and bright colors. The
+lightness level is a dial between white and black.
+-}
+hsl : Float -> Float -> Float -> Color
+hsl hue saturation lightness =
+    hsla hue saturation lightness 1
+
+{-| Produce a gray based on the input. 0 is white, 1 is black. -}
+grayscale : Float -> Color
+grayscale p = HSLA 0 0 (1-p) 1
+
+greyscale : Float -> Color
+greyscale p = HSLA 0 0 (1-p) 1
+
+{-| Produce a &ldquo;complementary color&rdquo;. The two colors will
+accent each other. This is the same as rotating the hue by 180&deg;.
+-}
+complement : Color -> Color
+complement color =
+    case color of
+      HSLA h s l a -> hsla (h + degrees 180) s l a
+      RGBA r g b a -> let (h,s,l) = rgbToHsl r g b
+                      in  hsla (h + degrees 180) s l a
+
+{-| Extract the components of a color in the HSL format.
+-}
+toHsl : Color -> { hue:Float, saturation:Float, lightness:Float, alpha:Float }
+toHsl color =
+    case color of
+      HSLA h s l a -> { hue=h, saturation=s, lightness=l, alpha=a }
+      RGBA r g b a ->
+          let (h,s,l) = rgbToHsl r g b
+          in  { hue=h, saturation=s, lightness=l, alpha=a }
+
+{-| Extract the components of a color in the RGB format.
+-}
+toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float }
+toRgb color =
+    case color of
+      RGBA r g b a -> { red=r, green=g, blue=b, alpha=a }
+      HSLA h s l a ->
+          let (r,g,b) = hslToRgb h s l
+          in  { red   = round (255 * r)
+              , green = round (255 * g)
+              , blue  = round (255 * b)
+              , alpha = a
+              }
+
+fmod : Float -> Int -> Float
+fmod f n =
+  let integer = floor f
+  in  toFloat (integer % n) + f - toFloat integer
+
+rgbToHsl : Int -> Int -> Int -> (Float,Float,Float)
+rgbToHsl red green blue =
+  let r = toFloat red   / 255
+      g = toFloat green / 255
+      b = toFloat blue  / 255
+
+      cMax = max (max r g) b
+      cMin = min (min r g) b
+
+      c = cMax - cMin
+
+      hue = degrees 60 * if | cMax == r -> ((g - b) / c) `fmod` 6
+                            | cMax == g -> ((b - r) / c) + 2
+                            | cMax == b -> ((r - g) / c) + 4
+
+      lightness = (cMax + cMin) / 2
+
+      saturation =
+          if lightness == 0
+            then 0
+            else c / (1 - abs (2 * lightness - 1))
+  in
+      (hue, saturation, lightness)
+
+hslToRgb : Float -> Float -> Float -> (Float,Float,Float)
+hslToRgb hue saturation lightness =
+  let chroma = (1 - abs (2 * lightness - 1)) * saturation
+      hue' = hue / degrees 60
+
+      x = chroma * (1 - abs (fmod hue' 2 - 1))
+
+      (r,g,b) = if | hue' < 0  -> (0, 0, 0)
+                   | hue' < 1  -> (chroma, x, 0)
+                   | hue' < 2  -> (x, chroma, 0)
+                   | hue' < 3  -> (0, chroma, x)
+                   | hue' < 4  -> (0, x, chroma)
+                   | hue' < 5  -> (x, 0, chroma)
+                   | hue' < 6  -> (chroma, 0, x)
+                   | otherwise -> (0, 0, 0)
+
+      m = lightness - chroma / 2
+  in
+      (r + m, g + m, b + m)
+
+--toV3 : Color -> V3
+
+--toV4 : Color -> V4
+
+type Gradient
+  = Linear (Float,Float) (Float,Float) (List (Float,Color))
+  | Radial (Float,Float) Float (Float,Float) Float (List (Float,Color))
+
+{-| Create a linear gradient. Takes a start and end point and then a series of
+&ldquo;color stops&rdquo; that indicate how to interpolate between the start and
+end points. See [this example](http://elm-lang.org/edit/examples/Elements/LinearGradient.elm) for a
+more visual explanation. -}
+linear : (number, number) -> (number, number) -> List (Float,Color) -> Gradient
+linear = Linear
+
+{-| Create a radial gradient. First takes a start point and inner radius.  Then
+takes an end point and outer radius. It then takes a series of &ldquo;color
+stops&rdquo; that indicate how to interpolate between the inner and outer
+circles. See [this example](http://elm-lang.org/edit/examples/Elements/RadialGradient.elm) for a
+more visual explanation. -}
+radial : (number,number) -> number -> (number,number) -> number -> List (Float,Color) -> Gradient
+radial = Radial
+
+
+-- BUILT-IN COLORS
+
+lightRed    : Color
+lightRed    = RGBA 239 41 41 1
+red    : Color
+red    = RGBA 204  0  0 1
+darkRed    : Color
+darkRed    = RGBA 164  0  0 1
+
+lightOrange : Color
+lightOrange = RGBA 252 175 62 1
+orange : Color
+orange = RGBA 245 121  0 1
+darkOrange : Color
+darkOrange = RGBA 206  92  0 1
+
+lightYellow : Color
+lightYellow = RGBA 255 233 79 1
+yellow : Color
+yellow = RGBA 237 212  0 1
+darkYellow : Color
+darkYellow = RGBA 196 160  0 1
+
+lightGreen  : Color
+lightGreen  = RGBA 138 226  52 1
+green  : Color
+green  = RGBA 115 210  22 1
+darkGreen  : Color
+darkGreen  = RGBA  78 154   6 1
+
+lightBlue   : Color
+lightBlue   = RGBA 114 159 207 1
+blue   : Color
+blue   = RGBA  52 101 164 1
+darkBlue   : Color
+darkBlue   = RGBA  32  74 135 1
+
+lightPurple : Color
+lightPurple = RGBA 173 127 168 1
+purple : Color
+purple = RGBA 117  80 123 1
+darkPurple : Color
+darkPurple = RGBA  92  53 102 1
+
+lightBrown  : Color
+lightBrown  = RGBA 233 185 110 1
+brown  : Color
+brown  = RGBA 193 125  17 1
+darkBrown  : Color
+darkBrown  = RGBA 143  89   2 1
+
+black         : Color
+black         = RGBA  0   0   0  1
+white         : Color
+white         = RGBA 255 255 255 1
+
+lightGrey     : Color
+lightGrey     = RGBA 238 238 236 1
+grey          : Color
+grey          = RGBA 211 215 207 1
+darkGrey      : Color
+darkGrey      = RGBA 186 189 182 1
+
+lightGray : Color
+lightGray = RGBA 238 238 236 1
+gray      : Color
+gray      = RGBA 211 215 207 1
+darkGray  : Color
+darkGray  = RGBA 186 189 182 1
+
+lightCharcoal : Color
+lightCharcoal = RGBA 136 138 133 1
+charcoal      : Color
+charcoal      = RGBA  85  87  83 1
+darkCharcoal  : Color
+darkCharcoal  = RGBA  46  52  54 1
+ src/Date.elm view
@@ -0,0 +1,77 @@+
+module Date where
+
+{-| Library for working with dates. Email the mailing list if you encounter
+issues with internationalization or locale formatting.
+
+# Conversions
+@docs fromString, toTime, fromTime
+
+# Extractions
+@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second
+
+-}
+
+import Native.Date
+import Time (Time)
+import Result (Result)
+
+type Date = Date
+
+{-| Represents the days of the week. -}
+type Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun
+
+{-| Represents the month of the year. -}
+type Month
+    = Jan | Feb | Mar | Apr
+    | May | Jun | Jul | Aug
+    | Sep | Oct | Nov | Dec
+
+{-| Attempt to read a date from a string. -}
+fromString : String -> Result String Date
+fromString = Native.Date.read
+
+{-| Convert a date into a time since midnight (UTC) of 1 January 1990 (i.e.
+[UNIX time](http://en.wikipedia.org/wiki/Unix_time)). Given the date 23 June
+1990 at 11:45AM this returns the corresponding time. -}
+toTime : Date -> Time
+toTime = Native.Date.toTime
+
+{-| Take a UNIX time and convert it to a `Date`. -}
+fromTime : Time -> Date
+fromTime = Native.Date.fromTime
+
+{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM
+this returns the integer `1990`. -}
+year : Date -> Int
+year = Native.Date.year
+
+{-| Extract the month of a given date. Given the date 23 June 1990 at 11:45AM
+this returns the Month `Jun` as defined below. -}
+month : Date -> Month
+month = Native.Date.month
+
+{-| Extract the day of a given date. Given the date 23 June 1990 at 11:45AM
+this returns the integer `23`. -}
+day : Date -> Int
+day = Native.Date.day
+
+{-| Extract the day of the week for a given date. Given the date 23 June
+1990 at 11:45AM this returns the Day `Thu` as defined below. -}
+dayOfWeek : Date -> Day
+dayOfWeek = Native.Date.dayOfWeek
+
+{-| Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM
+this returns the integer `11`. -}
+hour : Date -> Int
+hour = Native.Date.hour
+
+{-| Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM
+this returns the integer `45`. -}
+minute : Date -> Int
+minute = Native.Date.minute
+
+{-| Extract the second of a given date. Given the date 23 June 1990 at 11:45AM
+this returns the integer `0`. -}
+second : Date -> Int
+second = Native.Date.second
+ src/Debug.elm view
@@ -0,0 +1,88 @@+module Debug where
+{-| This library is for investigating bugs or performance problems. It should
+*not* be used in production code.
+
+# Console Debugging
+@docs log, crash
+
+# Time-Travel Debugging
+@docs watch, watchSummary, trace
+-}
+
+import Graphics.Collage (Form)
+import Native.Debug
+
+
+{-| Log a tagged value on the developer console, and then return the value.
+
+    1 + log "number" 1        -- equals 2, logs "number: 1"
+    length (log "start" [])   -- equals 0, logs "start: []"
+
+Notice that `log` is not a pure function! It should *only* be used for
+investigating bugs or performance problems.
+-}
+log : String -> a -> a
+log = Native.Debug.log
+
+{-| Crash the program with an error message. This is an uncatchable error,
+intended for code that is soon-to-be-implemented. For example, if you are
+working with a large ADT and have partially completed a case expression, it may
+make sense to do this:
+
+    data Entity = Ship | Fish | Captain | Seagull
+
+    drawEntity entity =
+        case entity of
+          Ship -> ...
+          Fish -> ...
+          _ -> Debug.crash ("drawEntity not implemented for " ++ show entity ++ " yet!")
+
+Note that incomplete pattern matches are *very* bad practice! They are one of
+the very few ways to crash an Elm program, and they are completely avoidable.
+Production code should not have incomplete pattern matches!
+
+**Use this if** you want to do some testing while you are partway through
+writing a function.
+
+**Do not use this if** you want to do some typical try-catch exception handling.
+Use the `Maybe` or `Either` libraries instead.
+-}
+crash : String -> a
+crash = Native.Debug.crash
+
+{-| Watch a particular value in the debugger. Say we want to know the value of
+a variable called `velocity` because it may not be updated correctly. Adding
+`Debug.watch` allows us to name the value and show it with the debugger.
+
+	  Debug.watch "velocity" velocity == velocity
+
+Notice that the result of evaluating this expression is exactly the same as
+not having the expression at all. That means it's easy to add to any value.
+-}
+watch : String -> a -> a
+watch = Native.Debug.watch
+
+{-| Watch a summary of a particular value in the debugger. This function is
+pretty much the same as `watch` but it lets you specify a way to summarize
+the value you are interested in. For example, maybe you only want to see part
+of a record:
+
+	  Debug.watchSummary "velocity" .velocity object
+
+This is the same as just writing `object`, but it creates a watch that *only*
+looks at the value of `object.velocity`. You can also show summary statistics
+like length of a list:
+
+	  Debug.watchSummary "Number of clicks" length clicks
+
+Again, this evaluates to `clicks` but we get to see how long that list is in
+the debugger.
+-}
+watchSummary : String -> (a -> b) -> a -> a
+watchSummary = Native.Debug.watchSummary
+
+{-| Trace all past positions of a `Form` in the debugger. Add this to a `Form`
+and you will see a line tracing its entire history.
+-}
+trace : String -> Form -> Form
+trace = Native.Debug.tracePath
+ src/Dict.elm view
@@ -0,0 +1,484 @@+module Dict
+    ( Dict
+    , empty, singleton, insert, update
+    , get, remove, member
+    , filter
+    , partition
+    , foldl, foldr, map
+    , union, intersect, diff
+    , keys, values
+    , toList, fromList
+    ) where
+
+{-| A dictionary mapping unique keys to values. The keys can be any comparable
+type. This includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or
+lists of comparable types.
+
+Insert, remove, and query operations all take *O(log n)* time.
+
+# Build
+@docs empty, singleton, insert, update, remove
+
+# Query
+@docs member, get
+
+# Combine
+@docs union, intersect, diff
+
+# Lists
+@docs keys, values, toList, fromList
+
+# Transform
+@docs map, foldl, foldr, filter, partition
+
+-}
+
+
+import Basics (..)
+import Maybe (..)
+import List
+import List (..)
+import Native.Debug
+import String
+
+
+-- BBlack and NBlack should only be used during the deletion
+-- algorithm. Any other occurrence is a bug and should fail an assert.
+type NColor
+    = Red
+    | Black
+    | BBlack  -- Double Black, counts as 2 blacks for the invariant
+    | NBlack  -- Negative Black, counts as -1 blacks for the invariant
+
+
+showNColor : NColor -> String
+showNColor c =
+  case c of
+    Red    -> "Red"
+    Black  -> "Black"
+    BBlack -> "BBlack"
+    NBlack -> "NBlack"
+
+
+type LeafColor
+    = LBlack
+    | LBBlack -- Double Black, counts as 2
+
+
+showLColor : LeafColor -> String
+showLColor color =
+    case color of
+      LBlack  -> "LBlack"
+      LBBlack -> "LBBlack"
+
+
+type Dict k v
+    = RBNode NColor k v (Dict k v) (Dict k v)
+    | RBEmpty LeafColor
+
+
+{-| Create an empty dictionary. -}
+empty : Dict comparable v
+empty = RBEmpty LBlack
+
+
+min : Dict k v -> (k,v)
+min dict =
+    case dict of
+      RBNode _ key value (RBEmpty LBlack) _ ->
+          (key, value)
+
+      RBNode _ _ _ left _ ->
+          min left
+
+      RBEmpty LBlack ->
+          Native.Debug.crash "(min Empty) is not defined"
+
+
+max : Dict k v -> (k, v)
+max dict =
+    case dict of
+      RBNode _ key value _ (RBEmpty _) ->
+          (key, value)
+
+      RBNode _ _ _ _ right ->
+          max right
+
+      RBEmpty _ ->
+          Native.Debug.crash "(max Empty) is not defined"
+
+
+{-| Get the value associated with a key. If the key is not found, return
+`Nothing`. This is useful when you are not sure if a key will be in the
+dictionary.
+
+    animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
+
+    get "Tom"   animals == Just Cat
+    get "Mouse" animals == Just Mouse
+    get "Spike" animals == Nothing
+
+The `(?)` operator from the `Maybe` library makes it easy to give a default
+value.
+-}
+get : comparable -> Dict comparable v -> Maybe v
+get targetKey dict =
+    case dict of
+      RBEmpty LBlack ->
+          Nothing
+
+      RBNode _ key value left right ->
+          case compare targetKey key of
+            LT -> get targetKey left
+            EQ -> Just value
+            GT -> get targetKey right
+
+
+{-| Determine if a key is in a dictionary. -}
+member : comparable -> Dict comparable v -> Bool
+member key dict =
+    case get key dict of
+      Just _ -> True
+      Nothing -> False
+
+
+ensureBlackRoot : Dict k v -> Dict k v
+ensureBlackRoot dict =
+    case dict of
+      RBNode Red key value left right ->
+          RBNode Black key value left right
+
+      RBNode Black _ _ _ _ ->
+          dict
+
+      RBEmpty LBlack ->
+          dict
+
+
+{-| Insert a key-value pair into a dictionary. Replaces value when there is
+a collision. -}
+insert : comparable -> v -> Dict comparable v -> Dict comparable v
+insert key value dict =
+    update key (always (Just value)) dict
+
+
+{-| Remove a key-value pair from a dictionary. If the key is not found,
+no changes are made. -}
+remove : comparable -> Dict comparable v -> Dict comparable v
+remove key dict =
+    update key (always Nothing) dict
+
+
+type Flag = Insert | Remove | Same
+
+showFlag : Flag -> String
+showFlag f = case f of
+  Insert -> "Insert"
+  Remove -> "Remove"
+  Same   -> "Same"
+
+
+{-| Update the value of a dictionary for a specific key with a given function. -}
+update : comparable -> (Maybe v -> Maybe v) -> Dict comparable v -> Dict comparable v
+update k alter dict = 
+  let up dict =
+          case dict of
+            RBEmpty LBlack ->
+                case alter Nothing of
+                  Nothing -> (Same, empty)
+                  Just v  -> (Insert, RBNode Red k v empty empty)
+
+            RBNode clr key value left right ->
+                case compare k key of
+                  EQ ->
+                    case alter (Just value) of
+                      Nothing -> (Remove, rem clr left right)
+                      Just newValue ->
+                          (Same, RBNode clr key newValue left right)
+
+                  LT ->
+                    let (flag, newLeft) = up left in
+                    case flag of
+                      Same   -> (Same, RBNode clr key value newLeft right)
+                      Insert -> (Insert, balance clr key value newLeft right)
+                      Remove -> (Remove, bubble clr key value newLeft right)
+
+                  GT ->
+                    let (flag, newRight) = up right in
+                    case flag of
+                      Same   -> (Same, RBNode clr key value left newRight)
+                      Insert -> (Insert, balance clr key value left newRight)
+                      Remove -> (Remove, bubble clr key value left newRight)
+
+      (flag, updatedDict) = up dict
+  in
+      case flag of
+        Same   -> updatedDict
+        Insert -> ensureBlackRoot updatedDict
+        Remove -> blacken updatedDict
+
+
+{-| Create a dictionary with one key-value pair. -}
+singleton : comparable -> v -> Dict comparable v
+singleton key value =
+    insert key value (RBEmpty LBlack)
+
+
+isBBlack : Dict k v -> Bool
+isBBlack dict =
+    case dict of
+      RBNode BBlack _ _ _ _ -> True
+      RBEmpty LBBlack -> True
+      _ -> False
+
+
+moreBlack : NColor -> NColor
+moreBlack color =
+    case color of
+      Black  -> BBlack
+      Red    -> Black
+      NBlack -> Red
+      BBlack -> Native.Debug.crash "Can't make a double black node more black!"
+
+
+lessBlack : NColor -> NColor
+lessBlack color =
+    case color of
+      BBlack -> Black
+      Black  -> Red
+      Red    -> NBlack
+      NBlack -> Native.Debug.crash "Can't make a negative black node less black!"
+
+
+lessBlackTree : Dict k v -> Dict k v
+lessBlackTree dict =
+    case dict of
+      RBNode c k v l r -> RBNode (lessBlack c) k v l r
+      RBEmpty LBBlack -> RBEmpty LBlack
+
+
+reportRemBug : String -> NColor -> String -> String -> a
+reportRemBug msg c lgot rgot =
+  Native.Debug.crash <|
+    String.concat
+    [ "Internal red-black tree invariant violated, expected "
+    , msg, " and got ", showNColor c, "/", lgot, "/", rgot
+    , "\nPlease report this bug to <https://github.com/elm-lang/Elm/issues>"
+    ]
+
+
+-- Remove the top node from the tree, may leave behind BBlacks
+rem : NColor -> Dict k v -> Dict k v -> Dict k v
+rem c l r =
+    case (l, r) of
+      (RBEmpty _, RBEmpty _) ->
+          case c of
+            Red   -> RBEmpty LBlack
+            Black -> RBEmpty LBBlack
+
+      (RBEmpty cl, RBNode cr k' v' l' r') ->
+          case (c, cl, cr) of
+            (Black, LBlack, Red) ->
+                RBNode Black k' v' l' r'
+
+            _ ->
+                reportRemBug "Black/LBlack/Red" c (showLColor cl) (showNColor cr)
+
+      (RBNode cl k' v' l' r', RBEmpty cr) ->
+          case (c, cl, cr) of
+            (Black, Red, LBlack) ->
+                RBNode Black k' v' l' r'
+
+            _ ->
+                reportRemBug "Black/Red/LBlack" c (showNColor cl) (showLColor cr)
+
+      -- l and r are both RBNodes
+      (RBNode cl kl vl ll rl, RBNode cr kr vr lr rr) ->
+          let l = RBNode cl kl vl ll rl
+              r = RBNode cr kr vr lr rr
+              (k, v) = max l
+              l'     = remove_max cl kl vl ll rl
+          in
+              bubble c k v l' r
+
+
+-- Kills a BBlack or moves it upward, may leave behind NBlack
+bubble : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
+bubble c k v l r =
+    if isBBlack l || isBBlack r
+        then balance (moreBlack c) k v (lessBlackTree l) (lessBlackTree r)
+        else RBNode c k v l r
+
+
+-- Removes rightmost node, may leave root as BBlack
+remove_max : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
+remove_max c k v l r =
+    case r of
+      RBEmpty _ ->
+          rem c l r
+
+      RBNode cr kr vr lr rr ->
+          bubble c k v l (remove_max cr kr vr lr rr)
+
+
+-- generalized tree balancing act
+balance : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
+balance c k v l r =
+    balance_node (RBNode c k v l r)
+
+
+blackish : Dict k v -> Bool
+blackish t =
+    case t of
+      RBNode c _ _ _ _ -> c == Black || c == BBlack
+      RBEmpty _        -> True
+
+
+balance_node : Dict k v -> Dict k v
+balance_node t = 
+  let assemble col xk xv yk yv zk zv a b c d = 
+        RBNode (lessBlack col) yk yv (RBNode Black xk xv a b) (RBNode Black zk zv c d)
+  in 
+   if blackish t
+   then case t of
+     RBNode col zk zv (RBNode Red yk yv (RBNode Red xk xv a b) c) d ->
+       assemble col xk xv yk yv zk zv a b c d
+     RBNode col zk zv (RBNode Red xk xv a (RBNode Red yk yv b c)) d ->
+       assemble col xk xv yk yv zk zv a b c d
+     RBNode col xk xv a (RBNode Red zk zv (RBNode Red yk yv b c) d) ->
+       assemble col xk xv yk yv zk zv a b c d
+     RBNode col xk xv a (RBNode Red yk yv b (RBNode Red zk zv c d)) ->
+       assemble col xk xv yk yv zk zv a b c d
+
+     RBNode BBlack xk xv a (RBNode NBlack zk zv (RBNode Black yk yv b c) d) ->
+       case d of
+         (RBNode Black _ _ _ _) -> 
+           RBNode Black yk yv (RBNode Black xk xv a b) (balance Black zk zv c (redden d))
+         _ -> t
+
+     RBNode BBlack zk zv (RBNode NBlack xk xv a (RBNode Black yk yv b c)) d ->
+       case a of
+         (RBNode Black _ _ _ _) -> 
+           RBNode Black yk yv (balance Black xk xv (redden a) b) (RBNode Black zk zv c d)
+         _ -> t
+     _ -> t
+   else t
+
+
+-- make the top node black
+blacken : Dict k v -> Dict k v
+blacken t =
+    case t of
+      RBEmpty _ -> RBEmpty LBlack
+      RBNode _ k v l r -> RBNode Black k v l r
+
+
+-- make the top node red
+redden : Dict k v -> Dict k v
+redden t =
+    case t of
+      RBEmpty _ -> Native.Debug.crash "can't make a Leaf red"
+      RBNode _ k v l r -> RBNode Red k v l r
+
+
+{-| Apply a function to all values in a dictionary. -}
+map : (comparable -> a -> b) -> Dict comparable a -> Dict comparable b
+map f dict =
+    case dict of
+      RBEmpty LBlack ->
+          RBEmpty LBlack
+
+      RBNode clr key value left right ->
+          RBNode clr key (f key value) (map f left) (map f right)
+
+
+{-| Fold over the key-value pairs in a dictionary, in order from lowest
+key to highest key. -}
+foldl : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b
+foldl f acc dict =
+    case dict of
+      RBEmpty LBlack -> acc
+
+      RBNode _ key value left right ->
+          foldl f (f key value (foldl f acc left)) right
+
+
+{-| Fold over the key-value pairs in a dictionary, in order from highest
+key to lowest key. -}
+foldr : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b
+foldr f acc t =
+    case t of
+      RBEmpty LBlack -> acc
+
+      RBNode _ key value left right ->
+          foldr f (f key value (foldr f acc right)) left
+
+
+{-| Combine two dictionaries. If there is a collision, preference is given
+to the first dictionary. -}
+union : Dict comparable v -> Dict comparable v -> Dict comparable v
+union t1 t2 =
+    foldl insert t2 t1
+
+
+{-| Keep a key-value pair when its key appears in the second dictionary.
+Preference is given to values in the first dictionary. -}
+intersect : Dict comparable v -> Dict comparable v -> Dict comparable v
+intersect t1 t2 =
+    filter (\k _ -> k `member` t2) t1
+
+
+{-| Keep a key-value pair when its key does not appear in the second dictionary.
+Preference is given to the first dictionary. -}
+diff : Dict comparable v -> Dict comparable v -> Dict comparable v
+diff t1 t2 =
+    foldl (\k v t -> remove k t) t1 t2
+
+
+{-| Get all of the keys in a dictionary. -}
+keys : Dict comparable v -> List comparable
+keys dict =
+    foldr (\key value keyList -> key :: keyList) [] dict
+
+
+{-| Get all of the values in a dictionary. -}
+values : Dict comparable v -> List v
+values dict =
+    foldr (\key value valueList -> value :: valueList) [] dict
+
+
+{-| Convert a dictionary into an association list of key-value pairs. -}
+toList : Dict comparable v -> List (comparable,v)
+toList dict =
+    foldr (\key value list -> (key,value) :: list) [] dict
+
+
+{-| Convert an association list into a dictionary. -}
+fromList : List (comparable,v) -> Dict comparable v
+fromList assocs =
+    List.foldl (\(key,value) dict -> insert key value dict) empty assocs
+
+
+{-| Keep a key-value pair when it satisfies a predicate. -}
+filter : (comparable -> v -> Bool) -> Dict comparable v -> Dict comparable v
+filter predicate dictionary =
+    let add key value dict =
+            if predicate key value
+                then insert key value dict
+                else dict
+    in
+        foldl add empty dictionary
+
+
+{-| Partition a dictionary according to a predicate. The first dictionary
+contains all key-value pairs which satisfy the predicate, and the second
+contains the rest.
+-}
+partition : (comparable -> v -> Bool) -> Dict comparable v -> (Dict comparable v, Dict comparable v)
+partition predicate dict =
+    let add key value (t1, t2) =
+            if predicate key value
+                then (insert key value t1, t2)
+                else (t1, insert key value t2)
+    in
+        foldl add (empty, empty) dict
+ src/Graphics/Collage.elm view
@@ -0,0 +1,265 @@+module Graphics.Collage where
+
+{-| The collage API is for freeform graphics. You can move, rotate, scale, etc.
+all sorts of forms including lines, shapes, images, and elements.
+
+# Unstructured Graphics
+@docs collage
+ 
+# Creating Forms
+@docs toForm, filled, textured, gradient, outlined, traced
+ 
+# Transforming Forms
+@docs move, moveX, moveY, scale, rotate, alpha
+ 
+# Grouping Forms
+Grouping forms makes it easier to write modular graphics code. You can create
+a form that is a composite of many subforms. From there it is easy to transform
+it as a single unit.
+
+@docs group, groupTransform
+ 
+# Shapes
+@docs rect, oval, square, circle, ngon, polygon
+
+# Paths
+@docs segment, path
+ 
+# Line Styles
+@docs solid, dashed, dotted, LineStyle, LineCap, LineJoin, defaultLine
+
+-}
+
+import Basics (..)
+import List
+import Transform2D (Transform2D)
+import Transform2D as T
+import Native.Graphics.Collage
+import Graphics.Element (Element)
+import Color (Color, black, Gradient)
+
+
+type alias Form =
+    { theta : Float
+    , scale : Float
+    , x : Float
+    , y : Float
+    , alpha : Float
+    , form : BasicForm
+    }
+
+type FillStyle
+    = Solid Color
+    | Texture String
+    | Grad Gradient
+
+{-| The shape of the ends of a line. -}
+type LineCap = Flat | Round | Padded
+
+{-| The shape of the &ldquo;joints&rdquo; of a line, where each line segment
+meets. `Sharp` takes an argument to limit the length of the joint. This
+defaults to 10.
+-}
+type LineJoin = Smooth | Sharp Float | Clipped
+
+{-| All of the attributes of a line style. This lets you build up a line style
+however you want. You can also update existing line styles with record updates.
+-}
+type alias LineStyle =
+    { color : Color
+    , width : Float
+    , cap   : LineCap
+    , join  : LineJoin
+    , dashing : List Int
+    , dashOffset : Int
+    }
+
+{-| The default line style, which is solid black with flat caps and sharp joints.
+You can use record updates to build the line style you
+want. For example, to make a thicker line, you could say:
+
+    { defaultLine | width <- 10 }
+-}
+defaultLine : LineStyle
+defaultLine =
+    { color = black
+    , width = 1
+    , cap   = Flat
+    , join  = Sharp 10
+    , dashing = []
+    , dashOffset = 0
+    }
+
+{-| Create a solid line style with a given color. -}
+solid : Color -> LineStyle
+solid  clr = { defaultLine | color <- clr }
+
+{-| Create a dashed line style with a given color. Dashing equals `[8,4]`. -}
+dashed : Color -> LineStyle
+dashed clr = { defaultLine | color <- clr, dashing <- [8,4] }
+
+{-| Create a dotted line style with a given color. Dashing equals `[3,3]`. -}
+dotted : Color -> LineStyle
+dotted clr = { defaultLine | color <- clr, dashing <- [3,3] }
+
+type BasicForm
+    = FPath LineStyle Path
+    | FShape ShapeStyle Shape
+    | FImage Int Int (Int,Int) String
+    | FElement Element
+    | FGroup Transform2D (List Form)
+
+type ShapeStyle
+    = Line LineStyle
+    | Fill FillStyle
+
+
+form : BasicForm -> Form
+form f = { theta=0, scale=1, x=0, y=0, alpha=1, form=f }
+
+fill style shape = form (FShape (Fill style) shape)
+
+{-| Create a filled in shape. -}
+filled : Color -> Shape -> Form
+filled color shape = fill (Solid color) shape
+
+{-| Create a textured shape. The texture is described by some url and is
+tiled to fill the entire shape.
+-}
+textured : String -> Shape -> Form
+textured src shape = fill (Texture src) shape
+
+{-| Fill a shape with a [gradient](Color#linear). -}
+gradient : Gradient -> Shape -> Form
+gradient grad shape = fill (Grad grad) shape
+
+{-| Outline a shape with a given line style. -}
+outlined : LineStyle -> Shape -> Form
+outlined style shape = form (FShape (Line style) shape)
+
+{-| Trace a path with a given line style. -}
+traced : LineStyle -> Path -> Form
+traced style path = form (FPath style path)
+
+{-| Create a sprite from a sprite sheet. It cuts out a rectangle
+at a given position.
+-}
+sprite : Int -> Int -> (Int,Int) -> String -> Form
+sprite w h pos src = form (FImage w h pos src)
+
+{-| Turn any `Element` into a `Form`. This lets you use text, gifs, and video
+in your collage. This means you can move, rotate, and scale
+an `Element` however you want.
+-}
+toForm : Element -> Form
+toForm e = form (FElement e)
+
+{-| Flatten many forms into a single `Form`. This lets you move and rotate them
+as a single unit, making it possible to build small, modular components.
+-}
+group : List Form -> Form
+group fs = form (FGroup T.identity fs)
+
+{-| Flatten many forms into a single `Form` and then apply a matrix
+transformation.
+-}
+groupTransform : Transform2D -> List Form -> Form
+groupTransform matrix fs = form (FGroup matrix fs)
+
+{-| Move a form by the given amount. This is a relative translation so
+`(move (10,10) form)` would move `form` ten pixels up and ten pixels to the
+right.
+-}
+move : (Float,Float) -> Form -> Form
+move (x,y) f = { f | x <- f.x + x, y <- f.y + y }
+
+{-| Move a shape in the x direction. This is relative so `(moveX 10 form)` moves
+`form` 10 pixels to the right.
+-}
+moveX : Float -> Form -> Form
+moveX x f = { f | x <- f.x + x }
+
+{-| Move a shape in the y direction. This is relative so `(moveY 10 form)` moves
+`form` upwards by 10 pixels.
+-}
+moveY : Float -> Form -> Form
+moveY y f = { f | y <- f.y + y }
+
+{-| Scale a form by a given factor. Scaling by 2 doubles the size.
+-}
+scale : Float -> Form -> Form
+scale s f = { f | scale <- f.scale * s }
+
+{-| Rotate a form by a given angle. Rotate takes standard Elm angles (radians)
+and turns things counterclockwise. So to turn `form` 30&deg; to the left
+you would say, `(rotate (degrees 30) form)`.
+-}
+rotate : Float -> Form -> Form
+rotate t f = { f | theta <- f.theta + t }
+
+{-| Set the alpha of a `Form`. The default is 1, and 0 is totally transparent. -}
+alpha : Float -> Form -> Form
+alpha a f = { f | alpha <- a }
+
+{-| A collage is a collection of 2D forms. There are no strict positioning
+relationships between forms, so you are free to do all kinds of 2D graphics.
+-}
+collage : Int -> Int -> List Form -> Element
+collage = Native.Graphics.Collage.collage
+
+
+type alias Path = List (Float,Float)
+
+{-| Create a path that follows a sequence of points. -}
+path : List (Float,Float) -> Path
+path ps = ps
+
+{-| Create a path along a given line segment. -}
+segment : (Float,Float) -> (Float,Float) -> Path
+segment p1 p2 = [p1,p2]
+
+type alias Shape = List (Float,Float)
+
+{-| Create an arbitrary polygon by specifying its corners in order.
+`polygon` will automatically close all shapes, so the given list
+of points does not need to start and end with the same position.
+-}
+polygon : List (Float,Float) -> Shape
+polygon points = points
+
+{-| A rectangle with a given width and height. -}
+rect : Float -> Float -> Shape
+rect w h = let hw = w/2
+               hh = h/2
+           in  [ (0-hw,0-hh), (0-hw,hh), (hw,hh), (hw,0-hh) ]
+
+{-| A square with a given edge length. -}
+square : Float -> Shape
+square n = rect n n
+
+{-| An oval with a given width and height. -}
+oval : Float -> Float -> Shape
+oval w h =
+  let n = 50
+      t = 2 * pi / n
+      hw = w/2
+      hh = h/2
+      f i = (hw * cos (t*i), hh * sin (t*i))
+  in  List.map f [0..n-1]
+
+{-| A circle with a given radius. -}
+circle : Float -> Shape
+circle r = oval (2*r) (2*r)
+
+{-| A regular polygon with N sides. The first argument specifies the number
+of sides and the second is the radius. So to create a pentagon with radius
+30 you would say:
+
+    ngon 5 30
+-}
+ngon : Int -> Float -> Shape
+ngon n r =
+  let m = toFloat n
+      t = 2 * pi / m
+      f i = ( r * cos (t*i), r * sin (t*i) )
+  in  List.map f [0..m-1]
+ src/Graphics/Element.elm view
@@ -0,0 +1,394 @@+module Graphics.Element where
+{-| Graphical elements that snap together to build complex widgets and layouts.
+Each Element is a rectangle with a known width and height, making them easy to
+combine and position.
+
+# Images
+@docs image, fittedImage, croppedImage, tiledImage
+
+# Styling
+@docs width, height, size, color, opacity, link, tag
+
+# Inspection
+@docs widthOf, heightOf, sizeOf
+
+# Layout
+@docs flow, up, down, left, right, inward, outward
+
+## Layout Aliases
+There are also some convenience functions for working
+with `flow` in specific cases:
+
+@docs layers, above, below, beside
+
+# Positioning
+@docs empty, spacer, container
+
+## Specific Positions
+
+To create a `Position` you can use any of the built-in positions
+which cover nine common positions.
+@docs middle, midTop, midBottom, midLeft, midRight, topLeft, topRight,
+      bottomLeft, bottomRight
+
+If you need more precision, you can create custom positions.
+
+@docs absolute, relative, middleAt, midTopAt, midBottomAt, midLeftAt,
+      midRightAt, topLeftAt, topRightAt, bottomLeftAt, bottomRightAt
+-}
+
+import Basics (..)
+import Native.Graphics.Element
+import List as List
+import Color (..)
+import Maybe ( Maybe(..) )
+
+
+type alias Properties = {
+  id      : Int,
+  width   : Int,
+  height  : Int,
+  opacity : Float,
+  color   : Maybe Color,
+  href    : String,
+  tag     : String,
+  hover   : (),
+  click   : ()
+ }
+
+
+type alias Element =
+    { props : Properties
+    , element : ElementPrim
+    }
+
+
+{-| An Element that takes up no space. Good for things that appear conditionally:
+
+    flow down [ img1, if showMore then img2 else empty ]
+-}
+empty : Element
+empty = spacer 0 0
+
+
+{-| Get the width of an Element -}
+widthOf : Element -> Int
+widthOf e =
+    e.props.width
+
+
+{-| Get the height of an Element -}
+heightOf : Element -> Int
+heightOf e =
+    e.props.height
+
+
+{-| Get the width and height of an Element -}
+sizeOf : Element -> (Int,Int)
+sizeOf e =
+    (e.props.width, e.props.height)
+
+
+{-| Create an `Element` with a given width. -}
+width : Int -> Element -> Element
+width nw e =
+    let p = e.props
+
+        props =
+            case e.element of
+              Image _ w h _ ->
+                  { p |
+                      height <- round (toFloat h / toFloat w * toFloat nw)
+                  }
+
+              RawHtml ->
+                  { p |
+                      height <- snd (Native.Graphics.Element.htmlHeight nw e.element)
+                  }
+
+              _ -> p
+    in
+        { element = e.element
+        , props = { props | width <- nw }
+        }
+
+
+{-| Create an `Element` with a given height. -}
+height : Int -> Element -> Element
+height nh e =
+    let p = e.props
+        props =
+            case e.element of
+              Image _ w h _ ->
+                  { p |
+                      width <- round (toFloat w / toFloat h * toFloat nh)
+                  }
+              _ -> p
+    in
+        { element = e.element
+        , props = { p | height <- nh }
+        }
+
+
+{-| Create an `Element` with a new width and height. -}
+size : Int -> Int -> Element -> Element
+size w h e =
+    height h (width w e)
+
+
+{-| Create an `Element` with a given opacity. Opacity is a number between 0 and 1
+where 0 means totally clear.
+-}
+opacity : Float -> Element -> Element
+opacity o e =
+    let p = e.props
+    in
+        { element = e.element
+        , props = { p | opacity <- o }
+        }
+
+
+{-| Create an `Element` with a given background color. -}
+color : Color -> Element -> Element
+color c e = let p = e.props in
+            { element = e.element
+            , props = { p | color <- Just c}
+            }
+
+
+{-| Create an `Element` with a tag. This lets you link directly to it.
+The element `(tag "all-about-badgers" thirdParagraph)` can be reached
+with a link like this: `/facts-about-animals.elm#all-about-badgers`
+-}
+tag : String -> Element -> Element
+tag name e =
+    let p = e.props
+    in
+        { element = e.element
+        , props = { p | tag <- name }
+        }
+
+
+{-| Create an `Element` that is a hyper-link. -}
+link : String -> Element -> Element
+link href e =
+    let p = e.props
+    in
+        { element = e.element
+        , props = { p | href <- href }
+        }
+
+
+newElement w h e =
+  { props = Properties (Native.Graphics.Element.guid ()) w h 1 Nothing "" "" () ()
+  , element = e
+  }
+
+
+type ElementPrim
+    = Image ImageStyle Int Int String
+    | Container Position Element
+    | Flow Direction (List Element)
+    | Spacer
+    | RawHtml
+    | Custom -- for custom Elements implemented in JS, see collage for example
+
+type ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
+
+
+{-| Create an image given a width, height, and image source. -}
+image : Int -> Int -> String -> Element
+image w h src =
+    newElement w h (Image Plain w h src)
+
+
+{-| Create a fitted image given a width, height, and image source.
+This will crop the picture to best fill the given dimensions.
+-}
+fittedImage : Int -> Int -> String -> Element
+fittedImage w h src =
+    newElement w h (Image Fitted w h src)
+
+
+{-| Create a cropped image. Take a rectangle out of the picture starting
+at the given top left coordinate. If you have a 140-by-140 image,
+the following will cut a 100-by-100 square out of the middle of it.
+
+    croppedImage (20,20) 100 100 "yogi.jpg"
+-}
+croppedImage : (Int,Int) -> Int -> Int -> String -> Element
+croppedImage pos w h src =
+    newElement w h (Image (Cropped pos) w h src)
+
+tiledImage : Int -> Int -> String -> Element
+tiledImage w h src =
+    newElement w h (Image Tiled w h src)
+
+
+type Three = P | Z | N
+
+type Pos = Absolute Int | Relative Float
+
+type alias Position =
+    { horizontal : Three
+    , vertical : Three
+    , x : Pos
+    , y : Pos
+    }
+
+
+{-| Put an element in a container. This lets you position the element really
+easily, and there are tons of ways to set the `Position`.
+To center `element` exactly in a 300-by-300 square you would say:
+
+    container 300 300 middle element
+
+By setting the color of the container, you can create borders.
+-}
+container : Int -> Int -> Position -> Element -> Element
+container w h pos e =
+    newElement w h (Container pos e)
+
+
+{-| Create an empty box. This is useful for getting your spacing right and
+for making borders.
+-}
+spacer : Int -> Int -> Element
+spacer w h =
+    newElement w h Spacer
+
+
+type Direction = DUp | DDown | DLeft | DRight | DIn | DOut
+
+
+{-| Have a list of elements flow in a particular direction.
+The `Direction` starts from the first element in the list.
+
+    flow right [a,b,c]
+
+        +---+---+---+
+        | a | b | c |
+        +---+---+---+
+-}
+flow : Direction -> List Element -> Element
+flow dir es =
+  let ws = List.map widthOf es
+      hs = List.map heightOf es
+      newFlow w h = newElement w h (Flow dir es)
+  in 
+  if es == [] then empty else
+  case dir of
+    DUp    -> newFlow (List.maximum ws) (List.sum hs)
+    DDown  -> newFlow (List.maximum ws) (List.sum hs)
+    DLeft  -> newFlow (List.sum ws) (List.maximum hs)
+    DRight -> newFlow (List.sum ws) (List.maximum hs)
+    DIn    -> newFlow (List.maximum ws) (List.maximum hs)
+    DOut   -> newFlow (List.maximum ws) (List.maximum hs)
+
+
+{-| Stack elements vertically.
+To put `a` above `b` you would say: ``a `above` b``
+-}
+above : Element -> Element -> Element
+above hi lo =
+    newElement
+        (max (widthOf hi) (widthOf lo))
+        (heightOf hi + heightOf lo)
+        (Flow DDown [hi,lo])
+
+
+{-| Stack elements vertically.
+To put `a` below `b` you would say: ``a `below` b``
+-}
+below : Element -> Element -> Element
+below lo hi =
+    newElement
+        (max (widthOf hi) (widthOf lo))
+        (heightOf hi + heightOf lo)
+        (Flow DDown [hi,lo])
+
+
+{-| Put elements beside each other horizontally.
+To put `a` beside `b` you would say: ``a `beside` b`` 
+-}
+beside : Element -> Element -> Element
+beside lft rht =
+    newElement
+        (widthOf lft + widthOf rht)
+        (max (heightOf lft) (heightOf rht))
+        (Flow right [lft,rht])
+
+
+{-| Layer elements on top of each other, starting from the bottom:
+`layers == flow outward`
+-}
+layers : List Element -> Element
+layers es = 
+  let ws = List.map widthOf es
+      hs = List.map heightOf es
+  in
+      newElement (List.maximum ws) (List.maximum hs) (Flow DOut es)
+
+
+-- Repetitive things --
+
+absolute : Int -> Pos
+absolute = Absolute
+relative : Float -> Pos
+relative = Relative
+
+middle      : Position
+middle      = { horizontal=Z, vertical=Z, x=Relative 0.5, y=Relative 0.5 }
+topLeft     : Position
+topLeft     = { horizontal=N, vertical=P, x=Absolute 0, y=Absolute 0 }
+topRight    : Position
+topRight    = { topLeft | horizontal <- P }
+bottomLeft  : Position
+bottomLeft  = { topLeft | vertical <- N }
+bottomRight : Position
+bottomRight = { bottomLeft | horizontal <- P }
+midLeft     : Position
+midLeft     = { middle  | horizontal <- N, x <- Absolute 0 }
+midRight    : Position
+midRight    = { midLeft | horizontal <- P }
+midTop      : Position
+midTop      = { middle  | vertical <- P, y <- Absolute 0 }
+midBottom   : Position
+midBottom   = { midTop  | vertical <- N }
+
+middleAt          : Pos -> Pos -> Position
+middleAt      x y = { horizontal = Z, vertical = Z, x = x, y = y }
+topLeftAt         : Pos -> Pos -> Position
+topLeftAt     x y = { horizontal = N, vertical = P, x = x, y = y }
+topRightAt        : Pos -> Pos -> Position
+topRightAt    x y = { horizontal = P, vertical = P, x = x, y = y }
+bottomLeftAt      : Pos -> Pos -> Position
+bottomLeftAt  x y = { horizontal = N, vertical = N, x = x, y = y }
+bottomRightAt     : Pos -> Pos -> Position
+bottomRightAt x y = { horizontal = P, vertical = N, x = x, y = y }
+midLeftAt         : Pos -> Pos -> Position
+midLeftAt     x y = { horizontal = N, vertical = Z, x = x, y = y }
+midRightAt        : Pos -> Pos -> Position
+midRightAt    x y = { horizontal = P, vertical = Z, x = x, y = y }
+midTopAt          : Pos -> Pos -> Position
+midTopAt      x y = { horizontal = Z, vertical = P, x = x, y = y }
+midBottomAt       : Pos -> Pos -> Position
+midBottomAt   x y = { horizontal = Z, vertical = N, x = x, y = y }
+
+up : Direction
+up = DUp
+
+down : Direction
+down = DDown
+
+left : Direction
+left = DLeft
+
+right : Direction
+right = DRight
+
+inward : Direction
+inward = DIn
+
+outward : Direction
+outward = DOut
+ src/Graphics/Input.elm view
@@ -0,0 +1,152 @@+module Graphics.Input where
+{-| This module is for creating input widgets such as buttons and text fields.
+All functions in this library report to a [`Signal.Input`](Signal#customSignal).
+
+# Basic Input Elements
+
+To learn about text fields, see the
+[`Graphics.Input.Field`](Graphics-Input-Field) library.
+
+@docs button, customButton, checkbox, dropDown
+
+# Clicks and Hovers
+@docs clickable, hoverable
+
+-}
+
+import Signal
+import Graphics.Element (Element)
+import Native.Graphics.Input
+
+
+{-| Create a standard button. The following example begins making a basic
+calculator:
+
+    type Keys = Number Int | Plus | Minus | Clear
+
+    keys : Signal.Channel Keys
+    keys = Signal.channel Clear
+
+    calculator : Element
+    calculator =
+        flow right
+          [ button (Signal.send keys (Number 1)) "1"
+          , button (Signal.send keys (Number 2)) "2"
+          , button (Signal.send keys    Plus   ) "+"
+          ]
+
+If the user presses the "+" button, `keys.signal` will update to `Plus`. If the
+users presses "2", `keys.signal` will update to `(Number 2)`.
+-}
+button : Signal.Message -> String -> Element
+button =
+  Native.Graphics.Input.button
+
+
+{-| Same as `button` but lets you customize buttons to look however you want.
+
+    click : Signal.Channel
+    click = Signal.channel ()
+
+    prettyButton : Element
+    prettyButton =
+        customButton (Signal.send click ())
+            (image 100 40 "/button_up.jpg")
+            (image 100 40 "/button_hover.jpg")
+            (image 100 40 "/button_down.jpg")
+-}
+customButton : Signal.Message -> Element -> Element -> Element -> Element
+customButton =
+  Native.Graphics.Input.customButton
+
+
+{-| Create a checkbox. The following example creates three synced checkboxes:
+
+    check : Signal.Channel Bool
+    check = Signal.channel False
+
+    boxes : Bool -> Element
+    boxes checked =
+        let box = container 40 40 middle (checkbox (Signal.send check) checked)
+        in
+            flow right [ box, box, box ]
+
+    main : Signal Element
+    main = boxes <~ Signal.subscribe check
+-}
+checkbox : (Bool -> Signal.Message) -> Bool -> Element
+checkbox =
+  Native.Graphics.Input.checkbox
+
+
+{-| Create a drop-down menu.  The following drop-down lets you choose your
+favorite British sport:
+
+    type Sport = Football | Cricket | Snooker
+
+    sport : Signal.Channel (Maybe Sport)
+    sport = Signal.channel Nothing
+
+    sportDropDown : Element
+    sportDropDown =
+        dropDown (Signal.send sport)
+          [ (""        , Nothing)
+          , ("Football", Just Football)
+          , ("Cricket" , Just Cricket)
+          , ("Snooker" , Just Snooker)
+          ]
+
+If the user selects "Football" from the drop down menue, `Signal.subscribe sport`
+will update to `Just Football`.
+-}
+dropDown : (a -> Signal.Message) -> List (String, a) -> Element
+dropDown =
+  Native.Graphics.Input.dropDown
+
+
+{-| Detect mouse hovers over a specific `Element`. In the following example,
+we will create a hoverable picture called `cat`.
+
+    hover : Signal.Channel Bool
+    hover = Signal.channel False
+
+    cat : Element
+    cat =
+      image 30 30 "/cat.jpg"
+        |> hoverable (Signal.send hover)
+
+When the mouse hovers above the `cat` element, `hover.signal` will become
+`True`. When the mouse leaves it, `hover.signal` will become `False`.
+-}
+hoverable : (Bool -> Signal.Message) -> Element -> Element
+hoverable =
+  Native.Graphics.Input.hoverable
+
+
+{-| Detect mouse clicks on a specific `Element`. In the following example,
+we will create a clickable picture called `cat`.
+
+    type Picture = Cat | Hat
+
+    picture : Signal.Channel Picture
+    picture = Signal.channel Cat
+
+    cat : Element
+    cat =
+      image 30 30 "/cat.jpg"
+        |> clickable (Signal.send picture Cat)
+
+    hat : Element
+    hat =
+      image 30 30 "/hat.jpg"
+        |> clickable (Signal.send picture Hat)
+
+When the user clicks on the `cat` element, `picture.signal` receives
+an update containing the value `Cat`. When the user clicks on the `hat` element,
+`picture.signal` receives an update containing the value `Hat`. This lets you
+distinguish which element was clicked. In a more complex example, they could be
+distinguished with IDs or more complex data structures.
+-}
+clickable : Signal.Message -> Element -> Element
+clickable =
+  Native.Graphics.Input.clickable
+ src/Graphics/Input/Field.elm view
@@ -0,0 +1,195 @@+module Graphics.Input.Field where
+{-| This library provides an API for creating and updating text fields.
+Text fields use exactly the same approach as [`Graphics.Input`](Graphics-Input)
+for modelling user input, allowing you to keep track of new events and update
+text fields programmatically.
+
+# Create Fields
+@docs field, password, email
+
+# Field Content
+@docs Content, Selection, Direction, noContent
+
+# Field Style
+@docs defaultStyle, Style, Outline, noOutline, Highlight, noHighlight, Dimensions, uniformly
+-}
+
+import Color (Color)
+import Color
+import Graphics.Element (Element)
+import Native.Graphics.Input
+import Signal
+import Text
+
+{-| Create uniform dimensions:
+
+    uniformly 4 == { left=4, right=4, top=4, bottom=4 }
+
+The following example creates an outline where the left, right, top, and bottom
+edges all have width 1:
+
+    Outline grey (uniformly 1) 4
+-}
+uniformly : Int -> Dimensions
+uniformly n = Dimensions n n n n
+
+{-| For setting dimensions of a field's padding or outline. The left, right,
+top, and bottom may all have different sizes. The following example creates
+dimensions such that the left and right are twice as wide as the top and bottom:
+
+    myDimensions : Int -> Dimensions
+    myDimensions n =
+        { left = 2 * n
+        , right = 2 * n
+        , top = n
+        , bottom = n
+        }
+-}
+type alias Dimensions =
+    { left:Int
+    , right:Int
+    , top:Int
+    , bottom:Int
+    }
+
+{-| A field can have a outline around it. This lets you set its color, width,
+and radius. The radius allows you to round the corners of your field. Set the
+width to zero to make it invisible. Here is an example outline that is grey
+and thin with slightly rounded corners:
+
+    { color = grey, width = uniformly 1, radius = 4 }
+-}
+type alias Outline =
+    { color:Color
+    , width:Dimensions
+    , radius:Int
+    }
+
+{-| An outline with zero width, so you cannot see it. -}
+noOutline : Outline
+noOutline = Outline Color.grey (uniformly 0) 0
+
+{-| When a field has focus, it has a blue highlight around it by default. The
+`Highlight` lets you set the `color` and `width` of this highlight. Set the
+`width` to zero to turn the highlight off. Here is an example highlight that
+is blue and thin:
+
+    { color = blue, width = 1 }
+-}
+type alias Highlight =
+    { color:Color
+    , width:Int
+    }
+
+{-| A highlight with zero width, so you cannot see it. -}
+noHighlight : Highlight
+noHighlight = Highlight Color.blue 0
+
+{-| Describe the style of a text box. `style` describes the style of the text
+itself using [`Text.Style`](/Text#Style). `highlight` describes the glowing blue
+highlight that shows up when the field has focus. `outline` describes the line
+surrounding the text field, and `padding` adds whitespace between the `outline`
+and the text.
+
+The width and height of the text box *includes* the `padding` and `outline`.
+Say we have a text box that is 40 pixels tall. It has a uniform outline of
+1 pixel and a uniform padding of 5 pixels. Both of these must be subtracted
+from the total height to determine how much room there is for text. The
+`padding` and `outline` appear on the top and bottom, so there will be 28
+vertical pixels remaining for the text (40 - 1 - 5 - 5 - 1).
+-}
+type alias Style =
+    { padding   : Dimensions
+    , outline   : Outline
+    , highlight : Highlight
+    , style     : Text.Style
+    }
+
+{-| The default style for a text field. The outline is `Color.grey` with width
+1 and radius 2. The highlight is `Color.blue` with width 1, and the default
+text color is black.
+-}
+defaultStyle : Style
+defaultStyle =
+    { padding   = uniformly 4
+    , outline   = Outline Color.grey (uniformly 1) 2
+    , highlight = Highlight Color.blue 1
+    , style     = Text.defaultStyle
+    }
+
+{-| Represents the current content of a text field. For example:
+
+    content = Content "She sells sea shells" (Selection 0 3 Backward)
+
+This means the user highlighted the substring `"She"` backwards. The value of
+`content.string` is `"She sells sea shells"`.
+-}
+type alias Content =
+    { string:String
+    , selection:Selection
+    }
+
+{-| The selection within a text field. `start` is never greater than `end`:
+
+    Selection 0 0 Forward  -- cursor precedes all characters
+
+    Selection 5 9 Backward -- highlighting characters starting after
+                           -- the 5th and ending after the 9th
+-}
+type alias Selection =
+    { start:Int
+    , end:Int
+    , direction:Direction
+    }
+
+{-| The direction of selection. When the user highlights a selection in a text
+field, they must do it in a particular direction. This determines which end of
+the selection moves when they change the selection by pressing Shift-Left or
+Shift-Right.
+-}
+type Direction = Forward | Backward
+
+{-| A field with no content:
+
+    Content "" (Selection 0 0 Forward)
+-}
+noContent : Content
+noContent = Content "" (Selection 0 0 Forward)
+
+{-| Create a text field. The following example creates a time-varying element
+called `nameField`. As the user types their name, the field will be updated
+to match what they have entered.
+
+    name : Signal.Channel Content
+    name = Signal.channel noContent
+
+    nameField : Signal Element
+    nameField =
+        field defaultStyle (Signal.send name) "Name" <~ Signal.subscribe name
+
+When we use the `field` function, we first give it a visual style. This is
+the first argument so that it is easier to define your own custom field
+(`myField = field myStyle`). The next two arguments are a `Handle` and a
+handler function that processes or augments events before sending them along
+to the associated `Input`. In the example above we use the `identity` function to
+pass events along unchanged to the `name` `Input`. We then provide the
+place-holder message to use when no input has been provided yet. Finally,
+we give the current `Content` of the field. This argument is last because
+it is most likely to change frequently, making function composition easier.
+-}
+field : Style -> (Content -> Signal.Message) -> String -> Content -> Element
+field = Native.Graphics.Input.field
+
+{-| Same as `field` but the UI element blocks out each characters. -}
+password : Style -> (Content -> Signal.Message) -> String -> Content -> Element
+password = Native.Graphics.Input.password
+
+{-| Same as `field` but it adds an annotation that this field is for email
+addresses. This is helpful for auto-complete and for mobile users who may
+get a custom keyboard with an `@` and `.com` button.
+-}
+email : Style -> (Content -> Signal.Message) -> String -> Content -> Element
+email = Native.Graphics.Input.email
+
+-- area : (Content -> Signal.Message) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> Content -> Element
+-- area = Native.Graphics.Input.area
+ src/Http.elm view
@@ -0,0 +1,59 @@+module Http where
+{-| A library for asynchronous HTTP requests. See the `WebSocket`
+library if you have very strict latency requirements.
+
+# Sending Requests
+@docs send, sendGet
+
+# Creating Requests
+@docs get, post, request
+
+# Responses
+@docs Response
+-}
+
+import Signal (Signal)
+import Signal
+import Native.Http
+
+{-| The datatype for responses. Success contains only the returned message.
+Failures contain both an error code and an error message.
+-}
+type Response a
+    = Success a
+    | Waiting
+    | Failure Int String
+
+type alias Request a =
+    { verb : String
+    , url  : String
+    , body : a
+    , headers : List (String,String)
+    }
+
+{-| Create a customized request. Arguments are request type (get, post, put,
+delete, etc.), target url, data, and a list of additional headers.
+-}
+request : String -> String -> String -> List (String,String) -> Request String
+request = Request
+
+{-| Create a GET request to the given url. -}
+get : String -> Request String
+get url = Request "GET" url "" []
+
+{-| Create a POST request to the given url, carrying the given data. -}
+post : String -> String -> Request String
+post url body = Request "POST" url body []
+
+{-| Performs an HTTP request with the given requests. Produces a signal
+that carries the responses.
+-}
+send : Signal (Request a) -> Signal (Response String)
+send = Native.Http.send
+
+{-| Performs an HTTP GET request with the given urls. Produces a signal
+that carries the responses.
+-}
+sendGet : Signal String -> Signal (Response String)
+sendGet requestStrings =
+    send (Signal.map get requestStrings)
+ src/Json/Decode.elm view
@@ -0,0 +1,498 @@+module Json.Decode where
+{-| A way to turn JSON strings and JS values into Elm values.
+
+# Run a Decoder
+@docs decodeString, decodeValue
+
+# Primitives
+@docs string, int, float, bool, null
+
+# Arrays
+@docs list, array,
+  tuple1, tuple2, tuple3, tuple4, tuple5, tuple6, tuple7, tuple8
+
+# Objects
+@docs (:=), at,
+  object1, object2, object3, object4, object5, object6, object7, object8,
+  keyValuePairs, dict
+
+# Oddly Shaped Values
+@docs maybe, oneOf, map, fail, succeed, andThen
+
+# "Creative" Values
+@docs value, customDecoder
+-}
+
+
+import Native.Json
+import Array (Array)
+import Dict
+import Dict (Dict)
+import Json.Encode as JsonEncode
+import List
+import Maybe (Maybe)
+import Result (Result)
+
+
+type Decoder a = Decoder
+
+type alias Value = JsonEncode.Value
+
+
+{-| Transform the value returned by a decoder. Most useful when paired with
+the `oneOf` function.
+
+    nullOr : Decoder a -> Decoder (Maybe a)
+    nullOr decoder =
+        oneOf
+          [ null Nothing
+          , map Just decoder
+          ]
+
+    type UserID = OldID Int | NewID String
+
+    -- 1234 or "1234abc"
+    userID : Decoder UserID
+    userID =
+        oneOf
+          [ map OldID int
+          , map NewID string
+          ]
+-}
+map : (a -> b) -> Decoder a -> Decoder b
+map =
+    Native.Json.decodeObject1
+
+
+decodeString : Decoder a -> String -> Result String a
+decodeString =
+    Native.Json.runDecoderString
+
+
+-- OBJECTS
+
+{-| Access a nested field, making it easy to dive into big structures. This is
+really a helper function so you do not need to write `(:=)` so many times.
+
+    -- object.target.value = 'hello'
+
+    value : Decoder String
+    value =
+        at ["target", "value"] string
+
+    at fields decoder =
+        List.foldr (:=) decoder fields
+-}
+at : List String -> Decoder a -> Decoder a
+at fields decoder =
+    List.foldr (:=) decoder fields
+
+
+{-| Decode an object if it has a certain field.
+
+    nameAndAge : Decoder (String,Int)
+    nameAndAge =
+        object2 (,)
+          ("name" := string)
+          ("age" := int)
+
+    optionalProfession : Decoder (Maybe String)
+    optionalProfession =
+        maybe ("profession" := string)
+-}
+(:=) : String -> Decoder a -> Decoder a
+(:=) =
+    Native.Json.decodeField
+
+
+object1 : (a -> value) -> Decoder a -> Decoder value
+object1 =
+    Native.Json.decodeObject1
+
+
+{-| Use two different decoders on a JS value. This is nice for extracting
+multiple fields from an object.
+
+    point : Decoder (Float,Float)
+    point =
+        object2 (,)
+          ("x" := float)
+          ("y" := float)
+-}
+object2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value
+object2 =
+    Native.Json.decodeObject2
+
+
+{-| Use two different decoders on a JS value. This is nice for extracting
+multiple fields from an object.
+
+    type Task = { task : String, id : Int, completed : Bool }
+
+    point : Decoder (Float,Float)
+    point =
+        object3 Task
+          ("task" := string)
+          ("id" := int)
+          ("completed" := bool)
+-}
+object3 : (a -> b -> c -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder value
+object3 =
+    Native.Json.decodeObject3
+
+
+object4 : (a -> b -> c -> d -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder value
+object4 =
+    Native.Json.decodeObject4
+
+
+object5 : (a -> b -> c -> d -> e -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder value
+object5 =
+    Native.Json.decodeObject5
+
+
+object6 : (a -> b -> c -> d -> e -> f -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder value
+object6 =
+    Native.Json.decodeObject6
+
+
+object7 : (a -> b -> c -> d -> e -> f -> g -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder value
+object7 =
+    Native.Json.decodeObject7
+
+
+object8 : (a -> b -> c -> d -> e -> f -> g -> h -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder h -> Decoder value
+object8 =
+    Native.Json.decodeObject8
+
+
+{-| Turn any object into a list of key-value pairs.
+
+    -- { tom: 89, sue: 92, bill: 97, ... }
+    grades : Decoder (List (String, Int))
+    grades =
+        keyValuePairs int
+-}
+keyValuePairs : Decoder a -> Decoder (List (String, a))
+keyValuePairs =
+    Native.Json.decodeKeyValuePairs
+
+
+{-| Turn any object into a dictionary of key-value pairs.
+
+    -- { mercury: 0.33, venus: 4.87, earth: 5.97, ... }
+    planetMasses : Decoder (Dict String Int)
+    planetMasses =
+        dict float
+-}
+dict : Decoder a -> Decoder (Dict String a)
+dict decoder =
+    map Dict.fromList (keyValuePairs decoder)
+
+
+
+{-| Try out a couple different decoders. This is helpful when you are dealing
+with something with a very strange shape and when `andThen` does not help
+narrow things down so you can be more targeted.
+
+    -- [ [3,4], { x:0, y:0 }, [5,12] ]
+
+    points : Decoder (List (Float,Float))
+    points =
+        list point
+
+    point : (Float,Float)
+    point =
+        oneOf
+        [ tuple2 (,) float float
+        , object2 (,) ("x" := float) ("y" := float)
+        ]
+-}
+oneOf : List (Decoder a) -> Decoder a
+oneOf =
+    Native.Json.oneOf
+
+
+{-| Extract a string.
+
+    -- ["John","Doe"]
+
+    name : Decoder (String, String)
+    name =
+        tuple2 (,) string string
+-}
+string : Decoder String
+string =
+    Native.Json.decodeString
+
+
+{-| Extract a float.
+
+    -- [ 6.022, 3.1415, 1.618 ]
+
+    numbers : Decoder (List Float)
+    numbers =
+        list float
+-}
+float : Decoder Float
+float =
+    Native.Json.decodeFloat
+
+
+{-| Extract an integer.
+
+    -- { ... age: 42 ... }
+
+    age : Decoder Int
+    age =
+        "age" := int
+-}
+int : Decoder Int
+int =
+    Native.Json.decodeInt
+
+
+{-| Extract a boolean.
+
+    -- { ... checked: true ... }
+
+    checked : Decoder Bool
+    checked =
+        "checked" := true
+-}
+bool : Decoder Bool
+bool =
+    Native.Json.decodeBool
+
+
+{-| Extract a list from a JS array.
+
+    -- [1,2,3,4]
+
+    numbers : Decoder [Int]
+    numbers =
+        list int
+-}
+list : Decoder a -> Decoder (List a)
+list =
+    Native.Json.decodeList
+
+
+{-| Extract an Array from a JS array.
+
+    -- [1,2,3,4]
+
+    numbers : Decoder (Array Int)
+    numbers =
+        array int
+-}
+array : Decoder a -> Decoder (Array a)
+array =
+    Native.Json.decodeArray
+
+
+{-| Extract a null value. Primarily useful for creating *other* decoders.
+
+    nullOr : Decoder a -> Decoder (Maybe a)
+    nullOr decoder =
+        oneOf
+        [ null Nothing
+        , map Just decoder
+        ]
+
+
+    numbers : Decoder [Int]
+    numbers =
+        list (oneOf [ int, null 0 ])
+-}
+null : a -> Decoder a
+null =
+    Native.Json.decodeNull
+
+
+{-| Great for handling optional fields. The following code decodes JSON
+objects that may not have a profession field.
+
+    -- { name: "Tom", age: 31, profession: "plumber" }
+    -- { name: "Sue", age: 42 }
+
+    type alias Person =
+        { name : String
+        , age : Int
+        , profession : Maybe String
+        }
+
+    person : Decoder Person
+    person =
+        object3 Person
+          ("name" := string)
+          ("age" := int)
+          (maybe ("profession" := string))
+-}
+maybe : Decoder a -> Decoder (Maybe a)
+maybe =
+    Native.Json.decodeMaybe
+
+  
+{-| Bring in an arbitrary JSON value. Useful if you need to work with crazily
+formatted data. For example, this lets you create a parser for "variadic" lists
+where the first few types are different, followed by 0 or more of the same
+type.
+
+    variadic2 : (a -> b -> List c -> value) -> Decoder a -> Decoder b -> Decoder (List c) -> Decoder value
+    variadic2 f a b cs =
+        customDecoder (list value) \jsonList ->
+            case jsonList of
+              one :: two :: rest ->
+                  Result.map3 f
+                    (decodeValue a one)
+                    (decodeValue b two)
+                    (decodeValue cs rest)
+
+              _ -> Result.Err "expecting at least two elements in the array"
+-}
+value : Decoder Value
+value =
+    Native.Json.decodeValue
+
+
+decodeValue : Decoder a -> Value -> Result String a
+decodeValue =
+    Native.Json.runDecoderValue
+
+
+customDecoder : Decoder a -> (a -> Result String b) -> Decoder b
+customDecoder =
+    Native.Json.customDecoder
+
+
+{-| Helpful when one field will determine the shape of a bunch of other fields.
+
+    type Shape
+        = Rectangle Float Float
+        | Circle Float
+
+    shape : Decoder Shape
+    shape =
+      ("tag" := string) `andThen` shapeInfo
+
+    shapeInfo : String -> Decoder Shape
+    shapeInfo tag =
+      case tag of
+        "rectangle" ->
+            object2 Rectangle
+              ("width" := float)
+              ("height" := float)
+
+        "circle" ->
+            object1 Circle
+              ("radius" := float)
+
+        _ ->
+            fail (tag ++ " is not a recognized tag for shapes")
+-}
+andThen : Decoder a -> (a -> Decoder b) -> Decoder b
+andThen =
+    Native.Json.andThen
+
+
+{-| A decoder that always fails. Useful when paired with `andThen` or `oneOf`
+to improve error messages when things go wrong. For example, the following
+decoder is able to provide a much more specific error message when `fail` is
+the last option.
+
+    point : (Float,Float)
+    point =
+        oneOf
+        [ tuple2 (,) float float
+        , object2 (,) ("x" := float) ("y" := float)
+        , fail "expecting some kind of point"
+        ]
+-}
+fail : String -> Decoder a
+fail =
+    Native.Json.fail
+
+
+{-| A decoder that always succeeds. Useful when paired with `andThen` or
+`oneOf` but everything is supposed to work out at the end. For example,
+maybe you have an optional field that can have a default value when it is
+missing.
+
+    -- { x:3, y:4 } or { x:3, y:4, z:5 }
+
+    point3D : Decoder (Float,Float,Float)
+    point3D =
+        object (,,)
+          ("x" := float)
+          ("y" := float)
+          (oneOf [ "z" := float, succeed 0 ])
+-}
+succeed : a -> Decoder a
+succeed =
+    Native.Json.succeed
+
+
+-- TUPLES
+
+tuple1 : (a -> value) -> Decoder a -> Decoder value
+tuple1 =
+    Native.Json.decodeTuple1
+
+
+{-| Handle an array with exactly two values. Useful for points and simple
+pairs.
+
+    -- [3,4] or [0,0]
+    point : Decoder (Float,Float)
+    point =
+        tuple2 (,) float float
+
+    -- ["John","Doe"] or ["Hermann","Hesse"]
+    name : Decoder Name
+    name =
+        tuple2 Name string string
+
+    type alias Name = { first : String, last : String }
+-}
+tuple2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value
+tuple2 =
+    Native.Json.decodeTuple2
+
+
+{-| Handle an array with exactly three values.
+
+    -- [3,4,5] or [0,0,0]
+    point3D : Decoder (Float,Float,Float)
+    point3D =
+        tuple3 (,,) float float float
+
+-}
+tuple3 : (a -> b -> c -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder value
+tuple3 =
+    Native.Json.decodeTuple3
+
+
+tuple4 : (a -> b -> c -> d -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder value
+tuple4 =
+    Native.Json.decodeTuple4
+
+
+tuple5 : (a -> b -> c -> d -> e -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder value
+tuple5 =
+    Native.Json.decodeTuple5
+
+
+tuple6 : (a -> b -> c -> d -> e -> f -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder value
+tuple6 =
+    Native.Json.decodeTuple6
+
+
+tuple7 : (a -> b -> c -> d -> e -> f -> g -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder value
+tuple7 =
+    Native.Json.decodeTuple7
+
+
+tuple8 : (a -> b -> c -> d -> e -> f -> g -> h -> value) -> Decoder a -> Decoder b -> Decoder c -> Decoder d -> Decoder e -> Decoder f -> Decoder g -> Decoder h -> Decoder value
+tuple8 =
+    Native.Json.decodeTuple8
+ src/Json/Encode.elm view
@@ -0,0 +1,85 @@+
+module Json.Encode where
+
+{-| Library for turning Elm values into JSON values.
+
+# Encoding
+@docs encode
+
+# Primatives
+@docs string, int, float, bool, null
+
+# Arrays
+@docs list, array
+
+# Objects
+@docs object
+-}
+
+import Array (Array)
+import Native.Json
+
+
+type Value = Value
+
+
+{-| Convert a `Value` into a prettified string. The first argument specifies
+the amount of indentation in the resulting string.
+
+    person =
+        object
+          [ ("name", string "Tom")
+          , ("age", int 42)
+          ]
+
+    compact = encode 0 person
+    -- {"name":"Tom","age":42}
+
+    readable = encode 4 person
+    -- {
+    --     "name": "Tom",
+    --     "age": 42
+    -- }
+-}
+encode : Int -> Value -> String
+encode =
+    Native.Json.encode
+
+
+string : String -> Value
+string =
+    Native.Json.identity
+
+int : Int -> Value
+int =
+    Native.Json.identity
+
+
+float : Float -> Value
+float =
+    Native.Json.identity
+
+
+bool : Bool -> Value
+bool =
+    Native.Json.identity
+
+
+null : Value
+null =
+    Native.Json.encodeNull
+
+
+object : List (String, Value) -> Value
+object =
+    Native.Json.encodeObject
+
+
+array : Array Value -> Value
+array =
+    Native.Json.encodeArray
+
+
+list : List Value -> Value
+list =
+    Native.Json.encodeList
+ src/Keyboard.elm view
@@ -0,0 +1,82 @@+module Keyboard where
+{-| Library for working with keyboard input.
+
+# Representing Keys
+@docs KeyCode
+
+# Directions
+@docs arrows, wasd, directions
+
+# Specific Keys
+The following signals are `True` when the particular key is pressed and `False`
+otherwise.
+
+@docs enter, space, ctrl, shift, alt, meta
+
+# General Keypresses
+@docs isDown, keysDown, lastPressed
+
+-}
+
+import Signal (Signal)
+import Native.Keyboard
+
+{-| Type alias to make it clearer what integers are supposed to represent
+in this library. Use `Char.toCode` and `Char.fromCode` to convert key codes
+to characters. Use the uppercase character with `toCode`.
+-}
+type alias KeyCode = Int
+
+{-| Custom key directions to support different locales. The order is up, down,
+left, right.
+-}
+directions : KeyCode -> KeyCode -> KeyCode -> KeyCode -> Signal { x:Int, y:Int }
+directions = Native.Keyboard.directions
+
+{-| A signal of records indicating which arrow keys are pressed.
+
+  * `{ x = 0, y = 0 }` when pressing no arrows.
+  * `{ x =-1, y = 0 }` when pressing the left arrow.
+  * `{ x = 1, y = 1 }` when pressing the up and right arrows.
+  * `{ x = 0, y =-1 }` when pressing the down, left, and right arrows.
+-}
+arrows : Signal { x:Int, y:Int }
+arrows = directions 38 40 37 39
+
+{-| Just like the arrows signal, but this uses keys w, a, s, and d,
+which are common controls for many computer games.
+-}
+wasd : Signal { x:Int, y:Int }
+wasd = directions 87 83 65 68
+
+{-| Whether an arbitrary key is pressed. -}
+isDown : KeyCode -> Signal Bool
+isDown = Native.Keyboard.isDown
+
+alt   : Signal Bool
+alt   = Native.Keyboard.alt
+
+ctrl  : Signal Bool
+ctrl  = isDown 17
+
+{-| The meta key is the Windows key on Windows and the Command key on Mac.
+-}
+meta  : Signal Bool
+meta  = Native.Keyboard.meta
+
+shift : Signal Bool
+shift = isDown 16
+
+space : Signal Bool
+space = isDown 32
+
+enter : Signal Bool
+enter = isDown 13
+
+{-| List of keys that are currently down. -}
+keysDown : Signal (List KeyCode)
+keysDown = Native.Keyboard.keysDown
+
+{-| The latest key that has been pressed. -}
+lastPressed : Signal KeyCode
+lastPressed = Native.Keyboard.lastPressed
+ src/List.elm view
@@ -0,0 +1,383 @@+module List where
+
+{-| A library for manipulating lists of values. Every value in a
+list must have the same type.
+
+# Basics
+@docs isEmpty, length, reverse, member
+
+# Sub-lists
+@docs head, tail, filter, take, drop
+
+# Putting Lists Together
+@docs repeat, (::), append, concat, intersperse
+
+# Taking Lists Apart
+@docs partition, unzip
+
+# Mapping
+@docs map, map2, map3, map4, map5
+
+If you can think of a legitimate use of `mapN` where `N` is 6 or more, please
+let us know on [the list](https://groups.google.com/forum/#!forum/elm-discuss).
+The current sentiment is that it is already quite error prone once you get to
+4 and possibly should be approached another way.
+
+# Special Maps
+@docs filterMap, concatMap, indexedMap
+
+# Folding
+@docs foldr, foldl
+
+# Special Folds
+@docs sum, product, maximum, minimum, all, any, foldr1, foldl1, scanl, scanl1
+
+# Sorting
+@docs sort, sortBy, sortWith
+
+-}
+
+import Basics (..)
+import Maybe ( Maybe(Just,Nothing) )
+import Native.List
+
+
+{-| Add an element to the front of a list. Pronounced *cons*.
+
+    1 :: [2,3] == [1,2,3]
+    1 :: [] == [1]
+-}
+(::) : a -> List a -> List a
+(::) = Native.List.cons
+
+
+infixr 5 ::
+
+
+{-| Extract the first element of a list. List must be non-empty.
+
+    head [1,2,3] == 1
+-}
+head : List a -> a
+head = Native.List.head
+
+
+{-| Extract the elements after the head of the list. List must be non-empty.
+
+    tail [1,2,3] == [2,3]
+-}
+tail : List a -> List a
+tail = Native.List.tail
+
+
+{-| Determine if a list is empty.
+
+    isEmpty [] == True
+-}
+isEmpty : List a -> Bool
+isEmpty xs =
+    case xs of
+      [] -> True
+      _  -> False
+
+
+member : a -> List a -> Bool
+member =
+  Native.List.member
+
+
+{-| Apply a function to every element of a list.
+
+    map sqrt [1,4,9] == [1,2,3]
+
+    map not [True,False,True] == [False,True,False]
+-}
+map : (a -> b) -> List a -> List b
+map = Native.List.map
+
+{-| Same as `map` but the function is also applied to the index of each
+element (starting at zero).
+
+    indexedMap (,) ["Tom","Sue","Bob"] == [ (0,"Tom"), (1,"Sue"), (2,"Bob") ]
+-}
+indexedMap : (Int -> a -> b) -> List a -> List b
+indexedMap f xs =
+    map2 f [ 0 .. length xs - 1 ] xs
+
+{-| Reduce a list from the left.
+
+    foldl (::) [] [1,2,3] == [3,2,1]
+-}
+foldl : (a -> b -> b) -> b -> List a -> b
+foldl = Native.List.foldl
+
+{-| Reduce a list from the right.
+
+    foldr (+) 0 [1,2,3] == 6
+-}
+foldr : (a -> b -> b) -> b -> List a -> b
+foldr = Native.List.foldr
+
+{-| Reduce a list from the left without a base case. List must be non-empty. -}
+foldl1 : (a -> a -> a) -> List a -> a
+foldl1 = Native.List.foldl1
+
+{-| Reduce a list from the right without a base case. List must be non-empty. -}
+foldr1 : (a -> a -> a) -> List a -> a
+foldr1 = Native.List.foldr1
+
+{-| Reduce a list from the left, building up all of the intermediate results into a list.
+
+    scanl (+) 0 [1,2,3,4] == [0,1,3,6,10]
+-}
+scanl : (a -> b -> b) -> b -> List a -> List b
+scanl = Native.List.scanl
+
+{-| Same as scanl but it doesn't require a base case. List must be non-empty.
+
+    scanl1 (+) [1,2,3,4] == [1,3,6,10]
+-}
+scanl1 : (a -> a -> a) -> List a -> List a
+scanl1 = Native.List.scanl1
+
+{-| Keep only elements that satisfy the predicate.
+
+    filter isEven [1..6] == [2,4,6]
+-}
+filter : (a -> Bool) -> List a -> List a
+filter = Native.List.filter
+
+{-| Apply a function that may succeed to all values in the list, but only keep
+the successes.
+
+    String.toInt : String -> Maybe Int
+
+    filterMap String.toInt ["3", "4.0", "5", "hats"] == [3,5]
+-}
+filterMap : (a -> Maybe b) -> List a -> List b
+filterMap f xs = foldr (maybeCons f) [] xs
+
+maybeCons : (a -> Maybe b) -> a -> List b -> List b
+maybeCons f mx xs =
+    case f mx of
+      Just x -> x :: xs
+      Nothing -> xs
+
+{-| Determine the length of a list.
+
+    length [1,2,3] == 3
+-}
+length : List a -> Int
+length = Native.List.length
+
+{-| Reverse a list.
+
+    reverse [1..4] == [4,3,2,1]
+-}
+reverse : List a -> List a
+reverse = Native.List.reverse
+
+{-| Determine if all elements satisfy the predicate.
+
+    all isEven [2,4] == True
+    all isEven [2,3] == False
+    all isEven [] == True
+-}
+all : (a -> Bool) -> List a -> Bool
+all = Native.List.all
+
+{-| Determine if any elements satisfy the predicate.
+
+    any isEven [2,3] == True
+    any isEven [1,3] == False
+    any isEven [] == False
+-}
+any : (a -> Bool) -> List a -> Bool
+any = Native.List.any
+
+
+{-| Put two lists together.
+
+    append [1,1,2] [3,5,8] == [1,1,2,3,5,8]
+    append ['a','b'] ['c'] == ['a','b','c']
+-}
+append : List a -> List a -> List a
+append = Native.List.append
+
+
+{-| Concatenate a bunch of lists into a single list:
+
+    concat [[1,2],[3],[4,5]] == [1,2,3,4,5]
+-}
+concat : List (List a) -> List a
+concat lists =
+    foldr append [] lists
+
+
+{-| Map a given function onto a list and flatten the resulting lists.
+
+    concatMap f xs == concat (map f xs)
+-}
+concatMap : (a -> List b) -> List a -> List b
+concatMap f list =
+    concat (map f list)
+
+
+{-| Get the sum of the list elements.
+
+    sum [1..4] == 10
+-}
+sum : List number -> number
+sum numbers =
+    foldl (+) 0 numbers
+
+
+{-| Get the product of the list elements.
+
+    product [1..4] == 24
+-}
+product : List number -> number
+product numbers =
+    foldl (*) 1 numbers
+
+
+{-| Find the maximum element in a non-empty list.
+
+    maximum [1,4,2] == 4
+-}
+maximum : List comparable -> comparable
+maximum = foldl1 max
+
+
+{-| Find the minimum element in a non-empty list.
+
+    minimum [3,2,1] == 1
+-}
+minimum : List comparable -> comparable
+minimum = foldl1 min
+
+
+{-| Partition a list based on a predicate. The first list contains all values
+that satisfy the predicate, and the second list contains all the value that do
+not.
+
+    partition (\x -> x < 3) [0..5] == ([0,1,2], [3,4,5])
+    partition isEven        [0..5] == ([0,2,4], [1,3,5])
+-}
+partition : (a -> Bool) -> List a -> (List a, List a)
+partition pred list =
+    let step x (trues, falses) =
+            if pred x
+                then (x :: trues, falses)
+                else (trues, x :: falses)
+    in
+        foldr step ([],[]) list
+
+
+{-| Combine two lists, combining them with the given function.
+If one list is longer, the extra elements are dropped.
+
+    map2 (+) [1,2,3] [1,2,3,4] == [2,4,6]
+
+    map2 (,) [1,2,3] ['a','b'] == [ (1,'a'), (2,'b') ]
+
+    pairs : List a -> List b -> List (a,b)
+    pairs lefts rights =
+        map2 (,) lefts rights
+-}
+map2 : (a -> b -> result) -> List a -> List b -> List result
+map2 = Native.List.map2
+
+map3 : (a -> b -> c -> result) -> List a -> List b -> List c -> List result
+map3 = Native.List.map3
+
+map4 : (a -> b -> c -> d -> result) -> List a -> List b -> List c -> List d -> List result
+map4 = Native.List.map4
+
+map5 : (a -> b -> c -> d -> e -> result) -> List a -> List b -> List c -> List d -> List e -> List result
+map5 = Native.List.map5
+
+
+{-| Decompose a list of tuples into a tuple of lists.
+
+    unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True])
+-}
+unzip : List (a,b) -> (List a, List b)
+unzip pairs =
+    let step (x,y) (xs,ys) =
+          (x :: xs, y :: ys)
+    in
+        foldr step ([], []) pairs
+
+
+{-| Places the given value between all members of the given list.
+
+    intersperse "on" ["turtles","turtles","turtles"] == ["turtles","on","turtles","on","turtles"]
+-}
+intersperse : a -> List a -> List a
+intersperse sep xs =
+    case xs of
+      [] -> []
+      hd :: tl ->
+          let step x rest = sep :: x :: rest
+              spersed = foldr step [] tl
+          in
+              hd :: spersed
+
+{-| Take the first *n* members of a list.
+
+    take 2 [1,2,3,4] == [1,2]
+-}
+take : Int -> List a -> List a
+take = Native.List.take
+
+{-| Drop the first *n* members of a list.
+
+    drop 2 [1,2,3,4] == [3,4]
+-}
+drop : Int -> List a -> List a
+drop = Native.List.drop
+
+{-| Create a list with *n* copies of a value:
+
+    repeat 3 (0,0) == [(0,0),(0,0),(0,0)]
+-}
+repeat : Int -> a -> List a
+repeat = Native.List.repeat
+
+{-| Sort values from lowest to highest
+
+    sort [3,1,5] == [1,3,5]
+-}
+sort : List comparable -> List comparable
+sort = Native.List.sort
+
+{-| Sort values by a derived property.
+
+    alice = { name="Alice", height=1.62 }
+    bob   = { name="Bob"  , height=1.85 }
+    chuck = { name="Chuck", height=1.76 }
+
+    sortBy .name   [chuck,alice,bob] == [alice,bob,chuck]
+    sortBy .height [chuck,alice,bob] == [alice,chuck,bob]
+
+    sortBy String.length ["mouse","cat"] == ["cat","mouse"]
+-}
+sortBy : (a -> comparable) ->  List a -> List a
+sortBy = Native.List.sortBy
+
+{-| Sort values with a custom comparison function.
+
+    sortWith flippedComparison [1..5] == [5,4,3,2,1]
+
+    flippedComparison a b =
+        case compare a b of
+          LT -> GT
+          EQ -> EQ
+          GT -> LT
+
+This is also the most general sort function, allowing you
+to define any other: `sort == sortWith compare`
+-}
+sortWith : (a -> a -> Order) ->  List a -> List a
+sortWith = Native.List.sortWith
+ src/Maybe.elm view
@@ -0,0 +1,112 @@+module Maybe (Maybe(Just,Nothing), andThen, map, withDefault, oneOf) where
+
+{-| This library fills a bunch of important niches in Elm. A `Maybe` can help
+you with optional arguments, error handling, and records with optional fields.
+
+# Definition
+@docs Maybe
+
+# Common Helpers
+@docs map, withDefault, oneOf
+
+# Chaining Maybes
+@docs andThen
+
+-}
+
+{-| Represent values that may or may not exist. It can be useful if you have a
+record field that is only filled in sometimes. Or if a function takes a value
+sometimes, but does not absolutely need it.
+
+    -- A person, but maybe we do not know their age.
+    type alias Person =
+        { name : String
+        , age : Maybe Int
+        }
+
+    tom = { name = "Tom", age = Just 42 }
+    sue = { name = "Sue", age = Nothing }
+-}
+type Maybe a = Just a | Nothing
+
+
+{-| Provide a default value, turning an optional value into a normal value.
+This comes in handy when paired with functions like `Dict.get` which gives back
+a `Maybe`.
+
+    withDefault 100 (Just 42)   -- 42
+    withDefault 100 Nothing     -- 100
+
+    withDefault "unknown" (Dict.get "Tom" Dict.empty)   -- "unknown"
+
+-}
+withDefault : a -> Maybe a -> a
+withDefault default maybe =
+    case maybe of
+      Just value -> value
+      Nothing -> default
+
+
+{-| Pick the first `Maybe` that actually has a value. Useful when you want to
+try a couple different things, but there is no default value.
+
+    oneOf [ Nothing, Just 42, Just 71 ] == Just 42
+    oneOf [ Nothing, Nothing, Just 71 ] == Just 71
+    oneOf [ Nothing, Nothing, Nothing ] == Nothing
+-}
+oneOf : List (Maybe a) -> Maybe a
+oneOf maybes =
+  case maybes of
+    [] ->
+        Nothing
+
+    maybe :: rest ->
+        case maybe of
+          Nothing -> oneOf rest
+          Just _ -> maybe
+
+
+{-| Transform an `Maybe` value with a given function:
+
+    map sqrt (Just 9) == Just 3
+    map sqrt Nothing == Nothing
+-}
+map : (a -> b) -> Maybe a -> Maybe b
+map f maybe =
+    case maybe of
+      Just value -> Just (f value)
+      Nothing -> Nothing
+
+
+{-| Chain together many computations that may fail. It is helpful to see its
+definition:
+
+    andThen : Maybe a -> (a -> Maybe b) -> Maybe b
+    andThen maybe callback =
+        case maybe of
+          Just value -> callback value
+          Nothing -> Nothing
+
+This means we only continue with the callback if things are going well. For
+example, say you need to use (`toInt : String -> Maybe Int`) to parse a month
+and make sure it is between 1 and 12:
+
+    toValidMonth : Int -> Maybe Int
+    toValidMonth month =
+        if month >= 1 && month <= 12
+            then Just month
+            else Nothing
+
+    toMonth : String -> Maybe Int
+    toMonth rawString =
+        toInt rawString `andThen` toValidMonth
+
+If `toInt` fails and results in `Nothing` this entire chain of operations will
+short-circuit and result in `Nothing`. If `toValidMonth` results in `Nothing`,
+again the chain of computations will result in `Nothing`.
+-}
+andThen : Maybe a -> (a -> Maybe b) -> Maybe b
+andThen maybeValue callback =
+    case maybeValue of
+        Just value -> callback value
+        Nothing -> Nothing
+ src/Mouse.elm view
@@ -0,0 +1,36 @@+
+module Mouse where
+
+{-| Library for working with mouse input.
+
+# Position
+@docs position, x, y
+
+# Button Status
+@docs isDown, clicks
+
+-}
+
+import Signal (Signal)
+import Native.Mouse
+
+{-| The current mouse position. -}
+position : Signal (Int,Int)
+position = Native.Mouse.position
+
+{-| The current x-coordinate of the mouse. -}
+x : Signal Int
+x = Native.Mouse.x
+
+{-| The current y-coordinate of the mouse. -}
+y : Signal Int
+y = Native.Mouse.y
+
+{-| The current state of the left mouse-button.
+True when the button is down, and false otherwise. -}
+isDown : Signal Bool
+isDown = Native.Mouse.isDown
+
+{-| Always equal to unit. Event triggers on every mouse click. -}
+clicks : Signal ()
+clicks = Native.Mouse.clicks
+ src/Native/Array.js view
@@ -0,0 +1,711 @@+Elm.Native.Array = {};
+Elm.Native.Array.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Array = elm.Native.Array || {};
+    if (elm.Native.Array.values) return elm.Native.Array.values;
+    if ('values' in Elm.Native.Array)
+      return elm.Native.Array.values = Elm.Native.Array.values;
+
+    var List = Elm.Native.List.make(elm);
+
+    // A RRB-Tree has two distinct data types.
+    // Leaf -> "height"  is always 0
+    //         "table"   is an array of elements
+    // Node -> "height"  is always greater than 0
+    //         "table"   is an array of child nodes
+    //         "lengths" is an array of accumulated lengths of the child nodes
+
+    // M is the maximal table size. 32 seems fast. E is the allowed increase
+    // of search steps when concatting to find an index. Lower values will 
+    // decrease balancing, but will increase search steps.
+    var M = 32;
+    var E = 2;
+
+    // An empty array.
+    var empty = { ctor:"_Array", height:0, table:new Array() };
+
+    function get(i, array) {
+        if (i < 0 || i >= length(array)) {
+            throw new Error("Index " + i + " is out of range. Check the length of " +
+                            "your array first or use getMaybe or getWithDefault.");
+        }
+        return unsafeGet(i, array);
+    }
+
+    function unsafeGet(i, array) {
+      for (var x = array.height; x > 0; x--) {
+        var slot = i >> (x * 5);
+        while (array.lengths[slot] <= i) {
+          slot++;
+        }
+        if (slot > 0) {
+          i -= array.lengths[slot - 1];
+        }
+        array = array.table[slot];
+      }
+      return array.table[i];
+    }
+
+    // Sets the value at the index i. Only the nodes leading to i will get
+    // copied and updated.
+    function set(i, item, array) {
+      if (i < 0 || length(array) <= i) {
+        return array;
+      }
+      return unsafeSet(i, item, array);
+    }
+
+    function unsafeSet(i, item, array) {
+      array = nodeCopy(array);
+
+      if (array.height == 0) {
+        array.table[i] = item;
+      } else {
+        var slot = getSlot(i, array);
+        if (slot > 0) {
+          i -= array.lengths[slot - 1];
+        }
+        array.table[slot] = unsafeSet(i, item, array.table[slot]);
+      }
+      return array;
+    }
+
+    function initialize(len, f) {
+      if (len == 0) { return empty; }
+      var h = Math.floor(Math.log(len)/Math.log(M));
+      return initialize_(f, h, 0, len);
+    }
+
+    function initialize_(f, h, from, to) {
+      if (h == 0) {
+        var table = new Array((to - from) % (M + 1));
+        for (var i = 0; i < table.length; i++) {
+          table[i] = f(from + i);
+        }
+        return { ctor:"_Array", height:0, table:table };
+      }
+
+      var step = Math.pow(M, h);
+      var table = new Array(Math.ceil((to - from) / step));
+      var lengths = new Array(table.length);
+      for (var i = 0; i < table.length; i++) {
+        table[i] = initialize_( f, h - 1, from + (i * step)
+                              , Math.min(from + ((i + 1) * step), to));
+        lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
+      }
+      return { ctor:"_Array", height:h, table:table, lengths:lengths };
+    }
+
+    function fromList(list) {
+      if (list == List.Nil) { return empty; }
+
+      // Allocate M sized blocks (table) and write list elements to it.
+      var table = new Array(M);
+      var nodes = new Array();
+      var i = 0;
+
+      while (list.ctor !== '[]') {
+        table[i] = list._0;
+        list = list._1;
+        i++;
+
+        // table is full, so we can push a leaf containing it into the
+        // next node.
+        if (i == M) {
+          fromListPush({ ctor:"_Array", height:0, table:table }
+                      , nodes);
+          table = new Array(M);
+          i = 0;
+        }
+      }
+
+      // Maybe there is something left on the table.
+      if (i > 0) {
+        fromListPush({ ctor:"_Array", height:0, table:table.splice(0,i) }
+                    , nodes);
+      }
+
+      // Go through all of the nodes and eventually push them into higher nodes.
+      for (var h = 0; h < nodes.length - 1; h++) {
+        if (nodes[h].table.length > 0) {
+          fromListPush(nodes[h], nodes);
+        }
+      }
+
+      var head = nodes[nodes.length - 1];
+      if (head.height > 0 && head.table.length == 1) {
+        return head.table[0];
+      } else {
+        return head;
+      }
+    }
+
+    // Push a node into a higher node as a child.
+    function fromListPush(toPush, nodes) {
+      var h = toPush.height;
+
+      // Maybe the node on this height does not exist.
+      if (nodes.length == h) {
+        nodes.push({ ctor:"_Array", height:h + 1
+                                  , table:new Array()
+                                  , lengths:new Array() });
+      }
+
+      nodes[h].table.push(toPush);
+      var len = length(toPush);
+      if (nodes[h].lengths.length > 0) {
+        len += nodes[h].lengths[nodes[h].lengths.length - 1];
+      }
+      nodes[h].lengths.push(len);
+
+      if (nodes[h].table.length == M) {
+        fromListPush(nodes[h], nodes);
+        nodes[h] = { ctor:"_Array", height:h + 1
+                                  , table:new Array()
+                                  , lengths:new Array() };
+      }
+    }
+
+    // Pushes an item via push_ to the bottom right of a tree.
+    function push(item, a) {
+      var pushed = push_(item, a);
+      if (pushed !== null) {
+        return pushed;
+      }
+
+      var newTree = create(item, a.height);
+      return siblise(a, newTree);
+    }
+
+    // Recursively tries to push an item to the bottom-right most
+    // tree possible. If there is no space left for the item,
+    // null will be returned.
+    function push_(item, a) {
+      // Handle resursion stop at leaf level.
+      if (a.height == 0) {
+        if (a.table.length < M) {
+          var newA = { ctor:"_Array", height:0, table:a.table.slice() };
+          newA.table.push(item);
+          return newA;
+        } else {
+          return null;
+        }
+      }
+
+      // Recursively push
+      var pushed = push_(item, botRight(a));
+
+      // There was space in the bottom right tree, so the slot will
+      // be updated.
+      if (pushed != null) {
+        var newA = nodeCopy(a);
+        newA.table[newA.table.length - 1] = pushed;
+        newA.lengths[newA.lengths.length - 1]++;
+        return newA
+      }
+
+      // When there was no space left, check if there is space left
+      // for a new slot with a tree which contains only the item
+      // at the bottom.
+      if (a.table.length < M) {
+        var newSlot = create(item, a.height - 1);
+        var newA = nodeCopy(a);
+        newA.table.push(newSlot);
+        newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot));
+        return newA
+      } else {
+        return null;
+      }
+    }
+
+    // Converts an array into a list of elements.
+    function toList(a) {
+      return toList_(List.Nil, a);
+    }
+
+    function toList_(list, a) {
+      for (var i = a.table.length - 1; i >= 0; i--) {
+        list = a.height == 0 ? List.Cons(a.table[i], list) : toList_(list, a.table[i]);
+      }
+      return list;
+    }
+
+    // Maps a function over the elements of an array.
+    function map(f, a) {
+      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 ? f(a.table[i]) : map(f, a.table[i]);
+      }
+      return newA;
+    }
+
+    // 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, from + i, a.table[i])
+                                      : indexedMap_( f, a.table[i]
+                                                   , i == 0 ? 0 : a.lengths[i - 1]);
+      }
+      return newA;
+    }
+
+    function foldl(f, b, a) {
+      if (a.height == 0) {
+        for (var i = 0; i < a.table.length; i++) {
+          b = A2(f, a.table[i], b);
+        }
+      } else {
+        for (var i = 0; i < a.table.length; i++) {
+          b = foldl(f, b, a.table[i]);
+        }
+      }
+      return b;
+    }
+
+    function foldr(f, b, a) {
+      if (a.height == 0) {
+        for (var i = a.table.length; i--; ) {
+          b = A2(f, a.table[i], b);
+        }
+      } else {
+        for (var i = a.table.length; i--; ) {
+          b = foldl(f, b, a.table[i]);
+        }
+      }
+      return b;
+    }
+
+    // TODO: currently, it slices the right, then the left. This can be
+    // optimized.
+    function slice(from, to, a) {
+      if (from < 0) { from += length(a); }
+      if (to < 0)   { to += length(a); }
+      return sliceLeft(from, sliceRight(to, a));
+    }
+
+    function sliceRight(to, a) {
+      if (to == length(a)) {
+        return a;
+      }
+
+      // Handle leaf level.
+      if (a.height == 0) {
+        var newA = { ctor:"_Array", height:0 };
+        newA.table = a.table.slice(0, to);
+        return newA;
+      }
+
+      // Slice the right recursively.
+      var right = getSlot(to, a);
+      var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]);
+
+      // Maybe the a node is not even needed, as sliced contains the whole slice.
+      if (right == 0) {
+        return sliced;
+      }
+
+      // Create new node.
+      var newA = { ctor:"_Array", height:a.height
+                                , table:a.table.slice(0, right)
+                                , lengths:a.lengths.slice(0, right) };
+      if (sliced.table.length > 0) {
+        newA.table[right] = sliced;
+        newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
+      }
+      return newA;
+    }
+
+    function sliceLeft(from, a) {
+      if (from == 0) {
+        return a;
+      }
+
+      // Handle leaf level.
+      if (a.height == 0) {
+        var newA = { ctor:"_Array", height:0 };
+        newA.table = a.table.slice(from, a.table.length + 1);
+        return newA;
+      }
+
+      // Slice the left recursively.
+      var left = getSlot(from, a);
+      var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]);
+
+      // Maybe the a node is not even needed, as sliced contains the whole slice.
+      if (left == a.table.length - 1) {
+        return sliced;
+      }
+
+      // Create new node.
+      var newA = { ctor:"_Array", height:a.height
+                                , table:a.table.slice(left, a.table.length + 1)
+                                , lengths:new Array(a.table.length - left) };
+      newA.table[0] = sliced;
+      var len = 0;
+      for (var i = 0; i < newA.table.length; i++) {
+        len += length(newA.table[i]);
+        newA.lengths[i] = len;
+      }
+
+      return newA;
+    }
+
+    // Appends two trees.
+    function append(a,b) {
+      if (a.table.length === 0) {
+        return b;
+      }
+      if (b.table.length === 0) {
+        return a;
+      }
+
+      var c = append_(a, b);
+
+      // Check if both nodes can be crunshed together.
+      if (c[0].table.length + c[1].table.length <= M) {
+        if (c[0].table.length === 0) {
+          return c[1];
+        }
+        if (c[1].table.length === 0) {
+          return c[0];
+        }
+
+        // Adjust .table and .lengths
+        c[0].table = c[0].table.concat(c[1].table);
+        if (c[0].height > 0) {
+          var len = length(c[0]);
+          for (var i = 0; i < c[1].lengths.length; i++) {
+            c[1].lengths[i] += len;
+          }
+          c[0].lengths = c[0].lengths.concat(c[1].lengths);
+        }
+
+        return c[0];
+      }
+
+      if (c[0].height > 0) {
+        var toRemove = calcToRemove(a, b);
+        if (toRemove > E) {
+          c = shuffle(c[0], c[1], toRemove);
+        }
+      }
+
+      return siblise(c[0], c[1]);
+    }
+
+    // Returns an array of two nodes; right and left. One node _may_ be empty.
+    function append_(a, b) {
+      if (a.height === 0 && b.height === 0) {
+        return [a, b];
+      }
+
+      if (a.height !== 1 || b.height !== 1) {
+        if (a.height === b.height) {
+          a = nodeCopy(a);
+          b = nodeCopy(b);
+          var appended = append_(botRight(a), botLeft(b));
+
+          insertRight(a, appended[1]);
+          insertLeft(b, appended[0]);
+        } else if (a.height > b.height) {
+          a = nodeCopy(a);
+          var appended = append_(botRight(a), b);
+
+          insertRight(a, appended[0]);
+          b = parentise(appended[1], appended[1].height + 1);
+        } else {
+          b = nodeCopy(b);
+          var appended = append_(a, botLeft(b));
+
+          var left = appended[0].table.length === 0 ? 0 : 1;
+          var right = left === 0 ? 1 : 0;
+          insertLeft(b, appended[left]);
+          a = parentise(appended[right], appended[right].height + 1);
+        }
+      }
+
+      // Check if balancing is needed and return based on that.
+      if (a.table.length === 0 || b.table.length === 0) {
+        return [a,b];
+      }
+
+      var toRemove = calcToRemove(a, b);
+      if (toRemove <= E) {
+        return [a,b];
+      }
+      return shuffle(a, b, toRemove);
+    }
+
+    // Helperfunctions for append_. Replaces a child node at the side of the parent.
+    function insertRight(parent, node) {
+      var index = parent.table.length - 1;
+      parent.table[index] = node;
+      parent.lengths[index] = length(node)
+      parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0;
+    }
+
+    function insertLeft(parent, node) {
+      if (node.table.length > 0) {
+        parent.table[0] = node;
+        parent.lengths[0] = length(node);
+
+        var len = length(parent.table[0]);
+        for (var i = 1; i < parent.lengths.length; i++) {
+          len += length(parent.table[i]);
+          parent.lengths[i] = len;
+        }
+      } else {
+        parent.table.shift();
+        for (var i = 1; i < parent.lengths.length; i++) {
+          parent.lengths[i] = parent.lengths[i] - parent.lengths[0];
+        }
+        parent.lengths.shift();
+      }
+    }
+
+    // Returns the extra search steps for E. Refer to the paper.
+    function calcToRemove(a, b) {
+      var subLengths = 0;
+      for (var i = 0; i < a.table.length; i++) {
+        subLengths += a.table[i].table.length;
+      }
+      for (var i = 0; i < b.table.length; i++) {
+        subLengths += b.table[i].table.length;
+      }
+
+      var toRemove = a.table.length + b.table.length
+      return toRemove - (Math.floor((subLengths - 1) / M) + 1);
+    }
+
+    // get2, set2 and saveSlot are helpers for accessing elements over two arrays.
+    function get2(a, b, index) {
+      return index < a.length ? a[index] : b[index - a.length];
+    }
+
+    function set2(a, b, index, value) {
+      if (index < a.length) {
+        a[index] = value;
+      } else {
+        b[index - a.length] = value;
+      }
+    }
+
+    function saveSlot(a, b, index, slot) {
+      set2(a.table, b.table, index, slot);
+
+      var l = (index == 0 || index == a.lengths.length) ?
+                0 : get2(a.lengths, a.lengths, index - 1);
+      set2(a.lengths, b.lengths, index, l + length(slot));
+    }
+
+    // Creates a node or leaf with a given length at their arrays for perfomance.
+    // Is only used by shuffle.
+    function createNode(h, length) {
+      if (length < 0) { length = 0; }
+      var a = { ctor:"_Array", height:h, table:new Array(length) };
+      if (h > 0) {
+        a.lengths = new Array(length);
+      }
+      return a;
+    }
+
+    // Returns an array of two balanced nodes.
+    function shuffle(a, b, toRemove) {
+      var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove));
+      var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove));
+
+      // Skip the slots with size M. More precise: copy the slot references
+      // to the new node
+      var read = 0;
+      while (get2(a.table, b.table, read).table.length % M == 0) {
+        set2(newA.table, newB.table, read, get2(a.table, b.table, read));
+        set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read));
+        read++;
+      }
+
+      // Pulling items from left to right, caching in a slot before writing
+      // it into the new nodes.
+      var write = read;
+      var slot = new createNode(a.height - 1, 0);
+      var from = 0;
+
+      // If the current slot is still containing data, then there will be at
+      // least one more write, so we do not break this loop yet.
+      while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) {
+        // Find out the max possible items for copying.
+        var source = get2(a.table, b.table, read);
+        var to = Math.min(M - slot.table.length, source.table.length)
+
+        // Copy and adjust size table.
+        slot.table = slot.table.concat(source.table.slice(from, to));
+        if (slot.height > 0) {
+          var len = slot.lengths.length;
+          for (var i = len; i < len + to - from; i++) {
+            slot.lengths[i] = length(slot.table[i]);
+            slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0);
+          }
+        }
+
+        from += to;
+
+        // Only proceed to next slots[i] if the current one was
+        // fully copied.
+        if (source.table.length <= to) {
+          read++; from = 0;
+        }
+
+        // Only create a new slot if the current one is filled up.
+        if (slot.table.length == M) {
+          saveSlot(newA, newB, write, slot);
+          slot = createNode(a.height - 1,0);
+          write++;
+        }
+      }
+
+      // Cleanup after the loop. Copy the last slot into the new nodes.
+      if (slot.table.length > 0) {
+        saveSlot(newA, newB, write, slot);
+        write++;
+      }
+
+      // Shift the untouched slots to the left
+      while (read < a.table.length + b.table.length ) {
+        saveSlot(newA, newB, write, get2(a.table, b.table, read));
+        read++; write++;
+      }
+
+      return [newA, newB];
+    }
+
+    // Navigation functions
+    function botRight(a) { return a.table[a.table.length - 1]; }
+    function botLeft(a)  { return a.table[0]; }
+
+    // Copies a node for updating. Note that you should not use this if
+    // only updating only one of "table" or "lengths" for performance reasons.
+    function nodeCopy(a) {
+      var newA = { ctor:"_Array", height:a.height
+                                , table:a.table.slice() };
+      if (a.height > 0) { newA.lengths = a.lengths.slice(); }
+      return newA;
+    }
+
+    // Returns how many items are in the tree.
+    function length(array) {
+      if (array.height == 0) {
+        return array.table.length;
+      } else {
+        return array.lengths[array.lengths.length - 1];
+      }
+    }
+
+    // Calculates in which slot of "table" the item probably is, then
+    // find the exact slot via forward searching in  "lengths". Returns the index.
+    function getSlot(i, a) {
+      var slot = i >> (5 * a.height);
+      while (a.lengths[slot] <= i) {
+        slot++;
+      }
+      return slot;
+    }
+
+    // Recursively creates a tree with a given height containing
+    // only the given item.
+    function create(item, h) {
+      if (h == 0) {
+        return { ctor:"_Array", height:0
+                              , table:[item] };
+      } else {
+        return { ctor:"_Array", height:h
+                              , table:[create(item, h - 1)]
+                              , lengths:[1] };
+      }
+    }
+
+    // Recursively creates a tree that contains the given tree.
+    function parentise(tree, h) {
+      if (h == tree.height) {
+        return tree;
+      } else {
+        return { ctor:"_Array", height:h
+                              , table:[parentise(tree, h - 1)]
+                              , lengths:[length(tree)] };
+      }
+    }
+
+    // Emphasizes blood brotherhood beneath two trees.
+    function siblise(a, b) {
+      return { ctor:"_Array", height:a.height + 1
+                            , table:[a, b]
+                            , lengths:[length(a), length(a) + length(b)] };
+    }
+
+    function toJSArray(a) {
+      var jsArray = new Array(length(a));
+      toJSArray_(jsArray, 0, a);
+      return jsArray;
+    }
+
+    function toJSArray_(jsArray, i, a) {
+      for (var t = 0; t < a.table.length; t++) {
+        if (a.height == 0) {
+          jsArray[i + t] = a.table[t];
+        } else {
+          var inc = t == 0 ? 0 : a.lengths[t - 1];
+          toJSArray_(jsArray, i + inc, a.table[t]);
+        }
+      }
+    }
+
+    function fromJSArray(jsArray) {
+      if (jsArray.length == 0) { return empty; }
+      var h = Math.floor(Math.log(jsArray.length) / Math.log(M));
+      return fromJSArray_(jsArray, h, 0, jsArray.length);
+    }
+
+    function fromJSArray_(jsArray, h, from, to) {
+      if (h == 0) {
+        return { ctor:"_Array", height:0
+                              , table:jsArray.slice(from, to) };
+      }
+
+      var step = Math.pow(M, h);
+      var table = new Array(Math.ceil((to - from) / step));
+      var lengths = new Array(table.length);
+      for (var i = 0; i < table.length; i++) {
+        table[i] = fromJSArray_( jsArray, h - 1, from + (i * step)
+                               , Math.min(from + ((i + 1) * step), to));
+        lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
+      }
+      return { ctor:"_Array", height:h, table:table, lengths:lengths };
+    }
+
+    Elm.Native.Array.values = {
+      empty:empty,
+      fromList:fromList,
+      toList:toList,
+      initialize:F2(initialize),
+      append:F2(append),
+      push:F2(push),
+      slice:F3(slice),
+      get:F2(get),
+      set:F3(set),
+      map:F2(map),
+      indexedMap:F2(indexedMap),
+      foldl:F3(foldl),
+      foldr:F3(foldr),
+      length:length,
+
+      toJSArray:toJSArray,
+      fromJSArray:fromJSArray
+    };
+
+    return elm.Native.Array.values = Elm.Native.Array.values;
+}
+ src/Native/Basics.js view
@@ -0,0 +1,118 @@+
+Elm.Native.Basics = {};
+Elm.Native.Basics.make = function(elm) {
+  elm.Native = elm.Native || {};
+  elm.Native.Basics = elm.Native.Basics || {};
+  if (elm.Native.Basics.values) return elm.Native.Basics.values;
+
+  var Utils = Elm.Native.Utils.make(elm);
+
+  function div(a, b) {
+      return (a/b)|0;
+  }
+  function rem(a, b) {
+      return a % b;
+  }
+  function mod(a, b) {
+        if (b === 0) {
+            throw new Error("Cannot perform mod 0. Division by zero error.");
+        }
+        var r = a % b;
+        var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r+b) : -mod(-a,-b));
+
+        return m === b ? 0 : m;
+  }
+  function logBase(base, n) {
+      return Math.log(n) / Math.log(base);
+  }
+  function negate(n) {
+      return -n;
+  }
+  function abs(n) {
+      return n < 0 ? -n : n;
+  }
+
+  function min(a, b) {
+      return Utils.cmp(a,b) < 0 ? a : b;
+  }
+  function max(a, b) {
+      return Utils.cmp(a,b) > 0 ? a : b;
+  }
+  function clamp(lo, hi, n) {
+      return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n;
+  }
+
+  function xor(a, b) {
+      return a !== b;
+  }
+  function not(b) {
+      return !b;
+  }
+  function isInfinite(n) {
+      return n === Infinity || n === -Infinity
+  }
+
+  function truncate(n) {
+      return n|0;
+  }
+
+  function degrees(d) {
+      return d * Math.PI / 180;
+  }
+  function turns(t) {
+      return 2 * Math.PI * t;
+  }
+  function fromPolar(point) {
+      var r = point._0;
+      var t = point._1;
+      return Utils.Tuple2(r * Math.cos(t), r * Math.sin(t));
+  }
+  function toPolar(point) {
+      var x = point._0;
+      var y = point._1;
+      return Utils.Tuple2(Math.sqrt(x * x + y * y), Math.atan2(y,x));
+  }
+
+  var basics = {
+      div: F2(div),
+      rem: F2(rem),
+      mod: F2(mod),
+
+      pi: Math.PI,
+      e: Math.E,
+      cos: Math.cos,
+      sin: Math.sin,
+      tan: Math.tan,
+      acos: Math.acos,
+      asin: Math.asin,
+      atan: Math.atan,
+      atan2: F2(Math.atan2),
+
+      degrees:  degrees,
+      turns:  turns,
+      fromPolar:  fromPolar,
+      toPolar:  toPolar,
+
+      sqrt: Math.sqrt,
+      logBase: F2(logBase),
+      negate: negate,
+      abs: abs,
+      min: F2(min),
+      max: F2(max),
+      clamp: F3(clamp),
+      compare: Utils.compare,
+
+      xor: F2(xor),
+      not: not,
+
+      truncate: truncate,
+      ceiling: Math.ceil,
+      floor: Math.floor,
+      round: Math.round,
+      toFloat: function(x) { return x; },
+      isNaN: isNaN,
+      isInfinite: isInfinite
+  };
+
+  return elm.Native.Basics.values = basics;
+};
+ src/Native/Bitwise.js view
@@ -0,0 +1,25 @@+Elm.Native.Bitwise = {};
+Elm.Native.Bitwise.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Bitwise = elm.Native.Bitwise || {};
+    if (elm.Native.Bitwise.values) return elm.Native.Bitwise.values;
+
+    function and(a,b) { return a & b; }
+    function or (a,b) { return a | b; }
+    function xor(a,b) { return a ^ b; }
+    function not(a) { return ~a; }
+    function sll(a,offset) { return a << offset; }
+    function sra(a,offset) { return a >> offset; }
+    function srl(a,offset) { return a >>> offset; }
+
+    return elm.Native.Bitwise.values = {
+        and: F2(and),
+        or : F2(or ),
+        xor: F2(xor),
+        complement: not,
+        shiftLeft           : F2(sll),
+        shiftRightArithmatic: F2(sra),
+        shiftRightLogical   : F2(srl)
+    };
+    
+};
+ src/Native/Char.js view
@@ -0,0 +1,31 @@+Elm.Native.Char = {};
+Elm.Native.Char.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Char = elm.Native.Char || {};
+    if (elm.Native.Char.values) return elm.Native.Char.values;
+
+    var Utils = Elm.Native.Utils.make(elm);
+
+    function isBetween(lo,hi) { return function(chr) {
+	var c = chr.charCodeAt(0);
+	return lo <= c && c <= hi;
+    };
+                              }
+    var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0));
+    var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0));
+    var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0));
+
+    return elm.Native.Char.values = {
+        fromCode : function(c) { return String.fromCharCode(c); },
+        toCode   : function(c) { return c.toUpperCase().charCodeAt(0); },
+        toUpper  : function(c) { return Utils.chr(c.toUpperCase()); },
+        toLower  : function(c) { return Utils.chr(c.toLowerCase()); },
+        toLocaleUpper : function(c) { return Utils.chr(c.toLocaleUpperCase()); },
+        toLocaleLower : function(c) { return Utils.chr(c.toLocaleLowerCase()); },
+        isLower    : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)),
+        isUpper    : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)),
+        isDigit    : isDigit,
+        isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)),
+        isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); }
+    };
+};
+ src/Native/Color.js view
@@ -0,0 +1,30 @@+Elm.Native.Color = {};
+Elm.Native.Color.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Color = elm.Native.Color || {};
+    if (elm.Native.Color.values) return elm.Native.Color.values;
+
+    function toCss(c) {
+        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 = {
+        toCss:toCss
+    };
+
+};
+ src/Native/Date.js view
@@ -0,0 +1,39 @@+Elm.Native.Date = {};
+Elm.Native.Date.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Date = elm.Native.Date || {};
+    if (elm.Native.Date.values) return elm.Native.Date.values;
+
+    var Result = Elm.Result.make(elm);
+
+    function dateNow() {
+        return new window.Date;
+    }
+
+    function readDate(str) {
+        var date = new window.Date(str);
+        return isNaN(date.getTime())
+            ? Result.Err("unable to parse '" + str + "' as a date")
+            : Result.Ok(date);
+    }
+
+    var dayTable = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+    var monthTable =
+        ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
+         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; 
+
+
+    return elm.Native.Date.values = {
+        read    : readDate,
+        year    : function(d) { return d.getFullYear(); },
+        month   : function(d) { return { ctor:monthTable[d.getMonth()] }; },
+        day     : function(d) { return d.getDate(); },
+        hour    : function(d) { return d.getHours(); },
+        minute  : function(d) { return d.getMinutes(); },
+        second  : function(d) { return d.getSeconds(); },
+        toTime  : function(d) { return d.getTime(); },
+        fromTime: function(t) { return new window.Date(t); },
+        dayOfWeek : function(d) { return { ctor:dayTable[d.getDay()] }; }
+    };
+
+};
+ src/Native/Debug.js view
@@ -0,0 +1,65 @@+Elm.Native.Debug = {};
+Elm.Native.Debug.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Debug = elm.Native.Debug || {};
+    if (elm.Native.Debug.values) return elm.Native.Debug.values;
+    if ('values' in Elm.Native.Debug)
+        return elm.Native.Debug.values = Elm.Native.Debug.values;
+
+    var toString = Elm.Native.Show.make(elm).toString;
+    var replace = Elm.Native.Utils.make(elm).replace;
+
+    function log(tag, value) {
+        var msg = tag + ': ' + toString(value);
+        var process = process || {};
+        if (process.stdout) {
+            process.stdout.write(msg);
+        } else {
+            console.log(msg);
+        }
+        return value;
+    }
+
+    function crash(message) {
+        throw new Error(message);
+    }
+
+    function tracePath(debugId, form) {
+        return replace([["debugTracePathId",debugId]], form);
+    }
+
+    function WatchTracker() {
+        this.frames = [{}];
+        this.clear = function() {
+            this.watches = {};
+        };
+        this.pushFrame = function() {
+            var lastFrame = this.frames[this.frames.length - 1];
+            this.frames.push(lastFrame);
+        }
+        this.notify = function(tag, value) {
+            this.frames[this.frames.length - 1][tag] = value;
+        };
+    }
+    var watchTracker = new WatchTracker();
+
+    function watch(tag, value) {
+        watchTracker.notify(tag, value);
+        return value;
+    }
+
+    function watchSummary(tag, f, value) {
+        watchTracker.notify(tag, f(value));
+        return value;
+    }
+
+    Elm.Native.Debug.values = {
+        crash: crash,
+        tracePath: F2(tracePath),
+        log: F2(log),
+        watch: F2(watch),
+        watchSummary:F3(watchSummary),
+        watchTracker: watchTracker
+    };
+    return elm.Native.Debug.values = Elm.Native.Debug.values;
+};
+ src/Native/Graphics/Collage.js view
@@ -0,0 +1,415 @@+
+// setup
+Elm.Native = Elm.Native || {};
+Elm.Native.Graphics = Elm.Native.Graphics || {};
+Elm.Native.Graphics.Collage = Elm.Native.Graphics.Collage || {};
+
+// definition
+Elm.Native.Graphics.Collage.make = function(localRuntime) {
+    'use strict';
+
+    // attempt to short-circuit
+    if ('values' in Elm.Native.Graphics.Collage) {
+        return Elm.Native.Graphics.Collage.values;
+    }
+
+    // okay, we cannot short-ciruit, so now we define everything
+    var Color = Elm.Native.Color.make(localRuntime);
+    var List = Elm.Native.List.make(localRuntime);
+    var Transform = Elm.Transform2D.make(localRuntime);
+
+    var Element = Elm.Graphics.Element.make(localRuntime);
+    var NativeElement = Elm.Native.Graphics.Element.make(localRuntime);
+
+
+    function trace(ctx, path) {
+        var points = List.toArray(path);
+        var i = points.length - 1;
+        if (i <= 0) {
+            return;
+        }
+        ctx.moveTo(points[i]._0, points[i]._1);
+        while (i--) {
+            ctx.lineTo(points[i]._0, points[i]._1);
+        }
+        if (path.closed) {
+            i = points.length - 1;
+            ctx.lineTo(points[i]._0, points[i]._1);
+        }
+    }
+
+    function line(ctx,style,path) {
+        (style.dashing.ctor === '[]')
+            ? trace(ctx, path)
+            : customLineHelp(ctx, style, path);
+        ctx.scale(1,-1);
+        ctx.stroke();
+    }
+
+    function customLineHelp(ctx, style, path) {
+        var points = List.toArray(path);
+        if (path.closed) {
+            points.push(points[0]);
+        }
+        var pattern = List.toArray(style.dashing);
+        var i = points.length - 1;
+        if (i <= 0) {
+            return;
+        }
+        var x0 = points[i]._0, y0 = points[i]._1;
+        var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0;
+        var pindex = 0, plen = pattern.length;
+        var draw = true, segmentLength = pattern[0];
+        ctx.moveTo(x0,y0);
+        while (i--) {
+            x1 = points[i]._0; y1 = points[i]._1;
+            dx = x1 - x0; dy = y1 - y0;
+            remaining = Math.sqrt(dx * dx + dy * dy);
+            while (segmentLength <= remaining) {
+                x0 += dx * segmentLength / remaining;
+                y0 += dy * segmentLength / remaining;
+                ctx[draw ? 'lineTo' : 'moveTo'](x0, y0);
+                // update starting position
+                dx = x1 - x0; dy = y1 - y0;
+                remaining = Math.sqrt(dx * dx + dy * dy);
+                // update pattern
+                draw = !draw;
+                pindex = (pindex + 1) % plen;
+                segmentLength = pattern[pindex];
+            }
+            if (remaining > 0) {
+                ctx[draw ? 'lineTo' : 'moveTo'](x1, y1);
+                segmentLength -= remaining;
+            }
+            x0 = x1; y0 = y1;
+        }
+    }
+
+    function drawLine(ctx, style, path) {
+        ctx.lineWidth = style.width;
+
+        var cap = style.cap.ctor;
+        ctx.lineCap = cap === 'Flat'
+            ? 'butt'
+            : cap === 'Round'
+                ? 'round'
+                : 'square';
+
+        var join = style.join.ctor;
+        ctx.lineJoin = join === 'Smooth'
+            ? 'round'
+            : join === 'Sharp'
+                ? 'miter'
+                : 'bevel';
+
+        ctx.miterLimit = style.join._0 || 10;
+        ctx.strokeStyle = Color.toCss(style.color);
+
+        return line(ctx, style, path);
+    }
+
+    function texture(redo, ctx, src) {
+        var img = new Image();
+        img.src = src;
+        img.onload = redo;
+        return ctx.createPattern(img, 'repeat');
+    }
+
+    function gradient(ctx, grad) {
+        var g;
+        var stops = [];
+        if (grad.ctor === 'Linear') {
+            var p0 = grad._0, p1 = grad._1;
+            g = ctx.createLinearGradient(p0._0, -p0._1, p1._0, -p1._1);
+            stops = List.toArray(grad._2);
+        } else {
+            var p0 = grad._0, p2 = grad._2;
+            g = ctx.createRadialGradient(p0._0, -p0._1, grad._1, p2._0, -p2._1, grad._3);
+            stops = List.toArray(grad._4);
+        }
+        var len = stops.length;
+        for (var i = 0; i < len; ++i) {
+            var stop = stops[i];
+            g.addColorStop(stop._0, Color.toCss(stop._1));
+        }
+        return g;
+    }
+
+    function drawShape(redo, ctx, style, path) {
+        trace(ctx, path);
+        var sty = style.ctor;
+        ctx.fillStyle = sty === 'Solid'
+            ? Color.toCss(style._0)
+            : sty === 'Texture'
+                ? texture(redo, ctx, style._0)
+                : gradient(ctx, style._0);
+
+        ctx.scale(1,-1);
+        ctx.fill();
+    }
+
+    function drawImage(redo, ctx, form) {
+        var img = new Image();
+        img.onload = redo;
+        img.src = form._3;
+        var w = form._0,
+            h = form._1,
+            pos = form._2,
+            srcX = pos._0,
+            srcY = pos._1,
+            srcW = w,
+            srcH = h,
+            destX = -w/2,
+            destY = -h/2,
+            destW = w,
+            destH = h;
+
+        ctx.scale(1,-1);
+        ctx.drawImage(img, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
+    }
+
+    function renderForm(redo, ctx, form) {
+        ctx.save();
+        var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
+        if (x !== 0 || y !== 0) ctx.translate(x, y);
+        if (theta !== 0) ctx.rotate(theta);
+        if (scale !== 1) ctx.scale(scale,scale);
+        if (form.alpha !== 1) ctx.globalAlpha = ctx.globalAlpha * form.alpha;
+        ctx.beginPath();
+        var f = form.form;
+        switch(f.ctor) {
+        case 'FPath' : drawLine(ctx, f._0, f._1); break;
+        case 'FImage': drawImage(redo, ctx, f); break;
+        case 'FShape':
+          if (f._0.ctor === 'Line') {
+            f._1.closed = true;
+            drawLine(ctx, f._0._0, f._1);
+          } else {
+            drawShape(redo, ctx, f._0._0, f._1);
+          }
+        break;
+        }
+        ctx.restore();
+    }
+
+    function formToMatrix(form) {
+       var scale = form.scale;
+       var matrix = A6( Transform.matrix, scale, 0, 0, scale, form.x, form.y );
+
+       var theta = form.theta
+       if (theta !== 0) {
+           matrix = A2( Transform.multiply, matrix, Transform.rotation(theta) );
+       }
+
+       return matrix;
+    }
+
+    function str(n) {
+        if (n < 0.00001 && n > -0.00001) return 0;
+        return n;
+    }
+
+    function makeTransform(w, h, form, matrices) {
+        var props = form.form._0.props;
+        var m = A6( Transform.matrix, 1, 0, 0, -1,
+                    (w - props.width ) / 2,
+                    (h - props.height) / 2 );
+        var len = matrices.length;
+        for (var i = 0; i < len; ++i) {
+            m = A2( Transform.multiply, m, matrices[i] );
+        }
+        m = A2( Transform.multiply, m, formToMatrix(form) );
+
+        return 'matrix(' + str( m[0]) + ', ' + str( m[3]) + ', ' +
+                           str(-m[1]) + ', ' + str(-m[4]) + ', ' +
+                           str( m[2]) + ', ' + str( m[5]) + ')';
+    }
+
+    function stepperHelp(list) {
+        var arr = List.toArray(list);
+        var i = 0;
+        function peekNext() {
+            return i < arr.length ? arr[i].form.ctor : '';
+        }
+        // assumes that there is a next element
+        function next() {
+            var out = arr[i];
+            ++i;
+            return out;
+        }
+        return {
+            peekNext:peekNext,
+            next:next
+        };
+    }
+
+    function formStepper(forms) {
+        var ps = [stepperHelp(forms)];
+        var matrices = [];
+        var alphas = [];
+        function peekNext() {
+            var len = ps.length;
+            var formType = '';
+            for (var i = 0; i < len; ++i ) {
+                if (formType = ps[i].peekNext()) return formType;
+            }
+            return '';
+        }
+        // assumes that there is a next element
+        function next(ctx) {
+            while (!ps[0].peekNext()) {
+                ps.shift();
+                matrices.pop();
+                alphas.shift();
+                if (ctx) { ctx.restore(); }
+            }
+            var out = ps[0].next();
+            var f = out.form;
+            if (f.ctor === 'FGroup') {
+                ps.unshift(stepperHelp(f._1));
+                var m = A2(Transform.multiply, f._0, formToMatrix(out));
+                ctx.save();
+                ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
+                matrices.push(m);
+
+                var alpha = (alphas[0] || 1) * out.alpha;
+                alphas.unshift(alpha);
+                ctx.globalAlpha = alpha;
+            }
+            return out;
+        }
+        function transforms() { return matrices; }
+        function alpha() { return alphas[0] || 1; }
+        return {
+            peekNext:peekNext,
+            next:next,
+            transforms:transforms,
+            alpha:alpha
+        };
+    }
+
+    function makeCanvas(w,h) {
+        var canvas = NativeElement.createNode('canvas');
+        canvas.style.width  = w + 'px';
+        canvas.style.height = h + 'px';
+        canvas.style.display = "block";
+        canvas.style.position = "absolute";
+        canvas.width  = w;
+        canvas.height = h;
+        return canvas;
+    }
+
+    function render(model) {
+        var div = NativeElement.createNode('div');
+        div.style.overflow = 'hidden';
+        div.style.position = 'relative';
+        update(div, model, model);
+        return div;
+    }
+
+    function nodeStepper(w,h,div) {
+        var kids = div.childNodes;
+        var i = 0;
+        function transform(transforms, ctx) {
+            ctx.translate(w/2, h/2);
+            ctx.scale(1,-1);
+            var len = transforms.length;
+            for (var i = 0; i < len; ++i) {
+                var m = transforms[i];
+                ctx.save();
+                ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
+            }
+            return ctx;
+        }
+        function nextContext(transforms) {
+            while (i < kids.length) {
+                var node = kids[i];
+                if (node.getContext) {
+                    node.width = w;
+                    node.height = h;
+                    node.style.width = w + 'px';
+                    node.style.height = h + 'px';
+                    ++i;
+                    return transform(transforms, node.getContext('2d'));
+                }
+                div.removeChild(node);
+            }
+            var canvas = makeCanvas(w,h);
+            div.appendChild(canvas);
+            // we have added a new node, so we must step our position
+            ++i;
+            return transform(transforms, canvas.getContext('2d'));
+        }
+        function addElement(matrices, alpha, form) {
+            var kid = kids[i];
+            var elem = form.form._0;
+
+            var node = (!kid || kid.getContext)
+                ? NativeElement.render(elem)
+                : NativeElement.update(kid, kid.oldElement, elem);
+
+            node.style.position = 'absolute';
+            node.style.opacity = alpha * form.alpha * elem.props.opacity;
+            NativeElement.addTransform(node.style, makeTransform(w, h, form, matrices));
+            node.oldElement = elem;
+            ++i;
+            if (!kid) {
+                div.appendChild(node);
+            } else if (kid.getContext) {
+                div.insertBefore(node, kid);
+            }
+        }
+        function clearRest() {
+            while (i < kids.length) {
+                div.removeChild(kids[i]);
+            }
+        }
+        return { nextContext:nextContext, addElement:addElement, clearRest:clearRest };
+    }
+
+
+    function update(div, _, model) {
+        var w = model.w;
+        var h = model.h;
+
+        var forms = formStepper(model.forms);
+        var nodes = nodeStepper(w,h,div);
+        var ctx = null;
+        var formType = '';
+
+        while (formType = forms.peekNext()) {
+            // make sure we have context if we need it
+            if (ctx === null && formType !== 'FElement') {
+                ctx = nodes.nextContext(forms.transforms());
+                ctx.globalAlpha = forms.alpha();
+            }
+
+            var form = forms.next(ctx);
+            // if it is FGroup, all updates are made within formStepper when next is called.
+            if (formType === 'FElement') {
+                // update or insert an element, get a new context
+                nodes.addElement(forms.transforms(), forms.alpha(), form);
+                ctx = null;
+            } else if (formType !== 'FGroup') {
+                renderForm(function() { update(div, model, model); }, ctx, form);
+            }
+        }
+        nodes.clearRest();
+        return div;
+    }
+
+
+    function collage(w,h,forms) {
+        return A3(Element.newElement, w, h, {
+            ctor: 'Custom',
+            type: 'Collage',
+            render: render,
+            update: update,
+            model: {w:w, h:h, forms:forms}
+      	});
+    }
+
+    return Elm.Native.Graphics.Collage.values = {
+        collage:F3(collage)
+    };
+};
+ src/Native/Graphics/Element.js view
@@ -0,0 +1,523 @@+
+// setup
+Elm.Native = Elm.Native || {};
+Elm.Native.Graphics = Elm.Native.Graphics || {};
+Elm.Native.Graphics.Element = Elm.Native.Graphics.Element || {};
+
+// definition
+Elm.Native.Graphics.Element.make = function(localRuntime) {
+    'use strict';
+
+    // attempt to short-circuit
+    if ('values' in Elm.Native.Graphics.Element) {
+        return Elm.Native.Graphics.Element.values;
+    }
+
+    var Color = Elm.Native.Color.make(localRuntime);
+    var List = Elm.Native.List.make(localRuntime);
+    var Utils = Elm.Native.Utils.make(localRuntime);
+
+
+    function createNode(elementType) {
+        var node = document.createElement(elementType);
+        node.style.padding = "0";
+        node.style.margin = "0";
+        return node;
+    }
+
+    function setProps(elem, node) {
+        var props = elem.props;
+
+        var element = elem.element;
+        var width = props.width - (element.adjustWidth || 0);
+        var height = props.height - (element.adjustHeight || 0);
+        node.style.width  = (width |0) + 'px';
+        node.style.height = (height|0) + 'px';
+
+        if (props.opacity !== 1) {
+            node.style.opacity = props.opacity;
+        }
+
+        if (props.color.ctor === 'Just') {
+            node.style.backgroundColor = Color.toCss(props.color._0);
+        }
+
+        if (props.tag !== '') {
+            node.id = props.tag;
+        }
+
+        if (props.hover.ctor !== '_Tuple0') {
+            addHover(node, props.hover);
+        }
+
+        if (props.click.ctor !== '_Tuple0') {
+            addClick(node, props.click);
+        }
+
+        if (props.href !== '') {
+            var anchor = createNode('a');
+            anchor.href = props.href;
+            anchor.style.display = 'block';
+            anchor.style.pointerEvents = 'auto';
+            anchor.appendChild(node);
+            node = anchor;
+        }
+
+        return node;
+    }
+
+    function addClick(e, handler) {
+        e.style.pointerEvents = 'auto';
+        e.elm_click_handler = handler;
+        function trigger(ev) {
+            e.elm_click_handler(Utils.Tuple0);
+            ev.stopPropagation();
+        }
+        e.elm_click_trigger = trigger;
+        e.addEventListener('click', trigger);
+    }
+
+    function removeClick(e, handler) {
+        if (e.elm_click_trigger) {
+            e.removeEventListener('click', e.elm_click_trigger);
+            e.elm_click_trigger = null;
+            e.elm_click_handler = null;
+        }
+    }
+
+    function addHover(e, handler) {
+        e.style.pointerEvents = 'auto';
+        e.elm_hover_handler = handler;
+        e.elm_hover_count = 0;
+
+        function over(evt) {
+            if (e.elm_hover_count++ > 0) return;
+            e.elm_hover_handler(true);
+            evt.stopPropagation();
+        }
+        function out(evt) {
+            if (e.contains(evt.toElement || evt.relatedTarget)) return;
+            e.elm_hover_count = 0;
+            e.elm_hover_handler(false);
+            evt.stopPropagation();
+        }
+        e.elm_hover_over = over;
+        e.elm_hover_out = out;
+        e.addEventListener('mouseover', over);
+        e.addEventListener('mouseout', out);
+    }
+
+    function removeHover(e) {
+        e.elm_hover_handler = null;
+        if (e.elm_hover_over) {
+            e.removeEventListener('mouseover', e.elm_hover_over);
+            e.elm_hover_over = null;
+        }
+        if (e.elm_hover_out) {
+            e.removeEventListener('mouseout', e.elm_hover_out);
+            e.elm_hover_out = null;
+        }
+    }
+
+    function image(props, img) {
+        switch (img._0.ctor) {
+        case 'Plain':   return plainImage(img._3);
+        case 'Fitted':  return fittedImage(props.width, props.height, img._3);
+        case 'Cropped': return croppedImage(img,props.width,props.height,img._3);
+        case 'Tiled':   return tiledImage(img._3);
+        }
+    }
+
+    function plainImage(src) {
+        var img = createNode('img');
+        img.src = src;
+        img.name = src;
+        img.style.display = "block";
+        return img;
+    }
+
+    function tiledImage(src) {
+        var div = createNode('div');
+        div.style.backgroundImage = 'url(' + src + ')';
+        return div;
+    }
+
+    function fittedImage(w, h, src) {
+        var div = createNode('div');
+        div.style.background = 'url(' + src + ') no-repeat center';
+        div.style.webkitBackgroundSize = 'cover';
+        div.style.MozBackgroundSize = 'cover';
+        div.style.OBackgroundSize = 'cover';
+        div.style.backgroundSize = 'cover';
+        return div;
+    }
+
+    function croppedImage(elem, w, h, src) {
+        var pos = elem._0._0;
+        var e = createNode('div');
+        e.style.overflow = "hidden";
+
+        var img = createNode('img');
+        img.onload = function() {
+            var sw = w / elem._1, sh = h / elem._2;
+            img.style.width = ((this.width * sw)|0) + 'px';
+            img.style.height = ((this.height * sh)|0) + 'px';
+            img.style.marginLeft = ((- pos._0 * sw)|0) + 'px';
+            img.style.marginTop = ((- pos._1 * sh)|0) + 'px';
+        };
+        img.src = src;
+        img.name = src;
+        e.appendChild(img);
+        return e;
+    }
+
+    function goOut(node) {
+        node.style.position = 'absolute';
+        return node;
+    }
+    function goDown(node) {
+        return node;
+    }
+    function goRight(node) {
+        node.style.styleFloat = 'left';
+        node.style.cssFloat = 'left';
+        return node;
+    }
+
+    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 = List.toArray(elist);
+        var container = createNode('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) {
+        switch(pos.ctor) {
+        case "Absolute": return  pos._0 + "px";
+        case "Relative": return (pos._0 * 100) + "%";
+        }
+    }
+
+    // must clear right, left, top, bottom, and transform
+    // before calling this function
+    function setPos(pos,elem,e) {
+        var element = elem.element;
+        var props = elem.props;
+        var w = props.width + (element.adjustWidth ? element.adjustWidth : 0);
+        var h = props.height + (element.adjustHeight ? element.adjustHeight : 0);
+
+        e.style.position = 'absolute';
+        e.style.margin = 'auto';
+        var transform = '';
+        switch(pos.horizontal.ctor) {
+        case 'P': e.style.right = toPos(pos.x); e.style.removeProperty('left'); break;
+        case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) ';
+        case 'N': e.style.left = toPos(pos.x); e.style.removeProperty('right'); break;
+        }
+        switch(pos.vertical.ctor) {
+        case 'N': e.style.bottom = toPos(pos.y); e.style.removeProperty('top'); break;
+        case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)';
+        case 'P': e.style.top = toPos(pos.y); e.style.removeProperty('bottom'); break;
+        }
+        if (transform !== '') {
+            addTransform(e.style, transform);
+        }
+        return e;
+    }
+
+    function addTransform(style, transform) {
+        style.transform       = transform;
+        style.msTransform     = transform;
+        style.MozTransform    = transform;
+        style.webkitTransform = transform;
+        style.OTransform      = transform;
+    }
+
+    function container(pos,elem) {
+        var e = render(elem);
+        setPos(pos, elem, e);
+        var div = createNode('div');
+        div.style.position = 'relative';
+        div.style.overflow = 'hidden';
+        div.appendChild(e);
+        return div;
+    }
+
+    function rawHtml(elem) {
+        var html = elem.html;
+        var guid = elem.guid;
+        var align = elem.align;
+
+        var div = createNode('div');
+        div.innerHTML = html;
+        div.style.visibility = "hidden";
+        if (align) {
+            div.style.textAlign = align;
+        }
+        div.style.visibility = 'visible';
+        div.style.pointerEvents = 'auto';
+        return div;
+    }
+
+    function render(elem) {
+        return setProps(elem, makeElement(elem));
+    }
+    function makeElement(e) {
+        var elem = e.element;
+        switch(elem.ctor) {
+        case 'Image':     return image(e.props, elem);
+        case 'Flow':      return flow(elem._0.ctor, elem._1);
+        case 'Container': return container(elem._0, elem._1);
+        case 'Spacer':    return createNode('div');
+        case 'RawHtml':   return rawHtml(elem);
+        case 'Custom':    return elem.render(elem.model);
+        }
+    }
+
+    function updateAndReplace(node, curr, next) {
+        var newNode = update(node, curr, next);
+        if (newNode !== node) {
+            node.parentNode.replaceChild(newNode, node);
+        }
+        return newNode;
+    }
+
+    function update(node, curr, next) {
+        var rootNode = node;
+        if (node.tagName === 'A') {
+            node = node.firstChild;
+        }
+        if (curr.props.id === next.props.id) {
+            updateProps(node, curr, next);
+            return rootNode;
+        }
+        if (curr.element.ctor !== next.element.ctor) {
+            return render(next);
+        }
+        var nextE = next.element;
+        var currE = curr.element;
+        switch(nextE.ctor) {
+        case "Spacer":
+            updateProps(node, curr, next);
+            return rootNode;
+
+        case "RawHtml":
+            // only markdown blocks have guids, so this must be a text block
+            if (nextE.guid === null) {
+                if(currE.html.valueOf() !== nextE.html.valueOf()) {
+                    node.innerHTML = nextE.html;
+                }
+                updateProps(node, curr, next);
+                return rootNode;
+            }
+            if (nextE.guid !== currE.guid) {
+                return render(next);
+            }
+            updateProps(node, curr, next);
+            return rootNode;
+
+        case "Image":
+            if (nextE._0.ctor === 'Plain') {
+                if (nextE._3 !== currE._3) {
+                    node.src = nextE._3;
+                }
+            } else if (!Utils.eq(nextE,currE) ||
+                       next.props.width !== curr.props.width ||
+                       next.props.height !== curr.props.height) {
+                return render(next);
+            }
+            updateProps(node, curr, next);
+            return rootNode;
+
+        case "Flow":
+            var arr = List.toArray(nextE._1);
+            for (var i = arr.length; i--; ) {
+                arr[i] = arr[i].element.ctor;
+            }
+            if (nextE._0.ctor !== currE._0.ctor) {
+                return render(next);
+            }
+            var nexts = List.toArray(nextE._1);
+            var kids = node.childNodes;
+            if (nexts.length !== kids.length) {
+                return render(next);
+            }
+            var currs = List.toArray(currE._1);
+            var dir = nextE._0.ctor;
+            var goDir = directionTable[dir];
+            var toReverse = needsReversal(dir);
+            var len = kids.length;
+            for (var i = len; i-- ;) {
+                var subNode = kids[toReverse ? len - i - 1 : i];
+                goDir(updateAndReplace(subNode, currs[i], nexts[i]));
+            }
+            updateProps(node, curr, next);
+            return rootNode;
+
+        case "Container":
+            var subNode = node.firstChild;
+            var newSubNode = updateAndReplace(subNode, currE._1, nextE._1);
+            setPos(nextE._0, nextE._1, newSubNode);
+            updateProps(node, curr, next);
+            return rootNode;
+
+        case "Custom":
+            if (currE.type === nextE.type) {
+                var updatedNode = nextE.update(node, currE.model, nextE.model);
+                updateProps(updatedNode, curr, next);
+                return updatedNode;
+            } else {
+                return render(next);
+            }
+        }
+    }
+
+    function updateProps(node, curr, next) {
+        var nextProps = next.props;
+        var currProps = curr.props;
+
+        var element = next.element;
+        var width = nextProps.width - (element.adjustWidth || 0);
+        var height = nextProps.height - (element.adjustHeight || 0);
+        if (width !== currProps.width) {
+            node.style.width = (width|0) + 'px';
+        }
+        if (height !== currProps.height) {
+            node.style.height = (height|0) + 'px';
+        }
+
+        if (nextProps.opacity !== currProps.opacity) {
+            node.style.opacity = nextProps.opacity;
+        }
+
+        var nextColor = nextProps.color.ctor === 'Just'
+            ? Color.toCss(nextProps.color._0)
+            : '';
+        if (node.style.backgroundColor !== nextColor) {
+            node.style.backgroundColor = nextColor;
+        }
+
+        if (nextProps.tag !== currProps.tag) {
+            node.id = nextProps.tag;
+        }
+
+        if (nextProps.href !== currProps.href) {
+            if (currProps.href === '') {
+                // add a surrounding href
+                var anchor = createNode('a');
+                anchor.href = nextProps.href;
+                anchor.style.display = 'block';
+                anchor.style.pointerEvents = 'auto';
+
+                node.parentNode.replaceChild(anchor, node);
+                anchor.appendChild(node);
+            } else if (nextProps.href === '') {
+                // remove the surrounding href
+                var anchor = node.parentNode;
+                anchor.parentNode.replaceChild(node, anchor);
+            } else {
+                // just update the link
+                node.parentNode.href = nextProps.href;
+            }
+        }
+
+        // update click and hover handlers
+        var removed = false;
+
+        // update hover handlers
+        if (currProps.hover.ctor === '_Tuple0') {
+            if (nextProps.hover.ctor !== '_Tuple0') {
+                addHover(node, nextProps.hover);
+            }
+        }
+        else {
+            if (nextProps.hover.ctor === '_Tuple0') {
+                removed = true;
+                removeHover(node);
+            }
+            else {
+                node.elm_hover_handler = nextProps.hover;
+            }
+        }
+
+        // update click handlers
+        if (currProps.click.ctor === '_Tuple0') {
+            if (nextProps.click.ctor !== '_Tuple0') {
+                addClick(node, nextProps.click);
+            }
+        }
+        else {
+            if (nextProps.click.ctor === '_Tuple0') {
+                removed = true;
+                removeClick(node);
+            } else {
+                node.elm_click_handler = nextProps.click;
+            }
+        }
+
+        // stop capturing clicks if 
+        if (removed
+            && nextProps.hover.ctor === '_Tuple0'
+            && nextProps.click.ctor === '_Tuple0')
+        {
+            node.style.pointerEvents = 'none';
+        }
+    }
+
+
+    function htmlHeight(width, rawHtml) {
+        // create dummy node
+        var temp = document.createElement('div');
+        temp.innerHTML = rawHtml.html;
+        if (width > 0) {
+            temp.style.width = width + "px";
+        }
+        temp.style.visibility = "hidden";
+        temp.style.styleFloat = "left";
+        temp.style.cssFloat   = "left";
+
+        document.body.appendChild(temp);
+
+        // get dimensions
+        var style = window.getComputedStyle(temp, null);
+        var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
+        var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
+        document.body.removeChild(temp);
+        return Utils.Tuple2(w,h);
+    }
+
+
+    return Elm.Native.Graphics.Element.values = {
+        render: render,
+        update: update,
+        updateAndReplace: updateAndReplace,
+
+        createNode: createNode,
+        addTransform: addTransform,
+        htmlHeight: F2(htmlHeight),
+        guid: Utils.guid
+    };
+
+};
+ src/Native/Graphics/Input.js view
@@ -0,0 +1,415 @@+// setup
+Elm.Native = Elm.Native || {};
+Elm.Native.Graphics = Elm.Native.Graphics || {};
+Elm.Native.Graphics.Input = Elm.Native.Graphics.Input || {};
+
+// definition
+Elm.Native.Graphics.Input.make = function(localRuntime) {
+    'use strict';
+
+    // attempt to short-circuit
+    if ('values' in Elm.Native.Graphics.Input) {
+        return Elm.Native.Graphics.Input.values;
+    }
+
+    var Color = Elm.Native.Color.make(localRuntime);
+    var List = Elm.Native.List.make(localRuntime);
+    var Text = Elm.Native.Text.make(localRuntime);
+    var Utils = Elm.Native.Utils.make(localRuntime);
+
+    var Element = Elm.Graphics.Element.make(localRuntime);
+    var NativeElement = Elm.Native.Graphics.Element.make(localRuntime);
+
+
+    function renderDropDown(model) {
+        var drop = NativeElement.createNode('select');
+        drop.style.border = '0 solid';
+        drop.style.pointerEvents = 'auto';
+        drop.style.display = 'block';
+
+        drop.elm_values = List.toArray(model.values);
+        drop.elm_handler = model.handler;
+        var values = drop.elm_values;
+
+        for (var i = 0; i < values.length; ++i) {
+            var option = NativeElement.createNode('option');
+            var name = values[i]._0;
+            option.value = name;
+            option.innerHTML = name;
+            drop.appendChild(option);
+        }
+        drop.addEventListener('change', function() {
+            drop.elm_handler(drop.elm_values[drop.selectedIndex]._1)();
+        });
+
+        return drop;
+    }
+
+    function updateDropDown(node, oldModel, newModel) {
+        node.elm_values = List.toArray(newModel.values);
+        node.elm_handler = newModel.handler;
+
+        var values = node.elm_values;
+        var kids = node.childNodes;
+        var kidsLength = kids.length;
+
+        var i = 0;
+        for (; i < kidsLength && i < values.length; ++i) {
+            var option = kids[i];
+            var name = values[i]._0;
+            option.value = name;
+            option.innerHTML = name;
+        }
+        for (; i < kidsLength; ++i) {
+            node.removeChild(node.lastChild);
+        }
+        for (; i < values.length; ++i) {
+            var option = NativeElement.createNode('option');
+            var name = values[i]._0;
+            option.value = name;
+            option.innerHTML = name;
+            node.appendChild(option);
+        }
+        return node;
+    }
+
+    function dropDown(handler, values) {
+        return A3(Element.newElement, 100, 24, {
+            ctor: 'Custom',
+            type: 'DropDown',
+            render: renderDropDown,
+            update: updateDropDown,
+            model: {
+                values: values,
+                handler: handler
+            }
+        });
+    }
+
+    function renderButton(model) {
+        var node = NativeElement.createNode('button');
+        node.style.display = 'block';
+        node.style.pointerEvents = 'auto';
+        node.elm_message = model.message;
+        function click() {
+            node.elm_message();
+        }
+        node.addEventListener('click', click);
+        node.innerHTML = model.text;
+        return node;
+    }
+
+    function updateButton(node, oldModel, newModel) {
+        node.elm_message = newModel.message;
+        var txt = newModel.text;
+        if (oldModel.text !== txt) {
+            node.innerHTML = txt;
+        }
+        return node;
+    }
+
+    function button(message, text) {
+        return A3(Element.newElement, 100, 40, {
+            ctor: 'Custom',
+            type: 'Button',
+            render: renderButton,
+            update: updateButton,
+            model: {
+                message: message,
+                text:text
+            }
+        });
+    }
+
+    function renderCustomButton(model) {
+        var btn = NativeElement.createNode('div');
+        btn.style.pointerEvents = 'auto';
+        btn.elm_message = model.message;
+
+        btn.elm_up    = NativeElement.render(model.up);
+        btn.elm_hover = NativeElement.render(model.hover);
+        btn.elm_down  = NativeElement.render(model.down);
+
+        btn.elm_up.style.display = 'block';
+        btn.elm_hover.style.display = 'none';
+        btn.elm_down.style.display = 'none';
+  
+        btn.appendChild(btn.elm_up);
+        btn.appendChild(btn.elm_hover);
+        btn.appendChild(btn.elm_down);
+
+        function swap(visibleNode, hiddenNode1, hiddenNode2) {
+            visibleNode.style.display = 'block';
+            hiddenNode1.style.display = 'none';
+            hiddenNode2.style.display = 'none';
+        }
+
+        var overCount = 0;
+        function over(e) {
+            if (overCount++ > 0) return;
+            swap(btn.elm_hover, btn.elm_down, btn.elm_up);
+        }
+        function out(e) {
+            if (btn.contains(e.toElement || e.relatedTarget)) return;
+            overCount = 0;
+            swap(btn.elm_up, btn.elm_down, btn.elm_hover);
+        }
+        function up() {
+            swap(btn.elm_hover, btn.elm_down, btn.elm_up);
+            btn.elm_message();
+        }
+        function down() {
+            swap(btn.elm_down, btn.elm_hover, btn.elm_up);
+        }
+
+        btn.addEventListener('mouseover', over);
+        btn.addEventListener('mouseout' , out);
+        btn.addEventListener('mousedown', down);
+        btn.addEventListener('mouseup'  , up);
+
+        return btn;
+    }
+
+    function updateCustomButton(node, oldModel, newModel) {
+        node.elm_message = newModel.message;
+
+        var kids = node.childNodes;
+        var styleUp    = kids[0].style.display;
+        var styleHover = kids[1].style.display;
+        var styleDown  = kids[2].style.display;
+
+        NativeElement.updateAndReplace(kids[0], oldModel.up, newModel.up);
+        NativeElement.updateAndReplace(kids[1], oldModel.hover, newModel.hover);
+        NativeElement.updateAndReplace(kids[2], oldModel.down, newModel.down);
+
+        var kids = node.childNodes;
+        kids[0].style.display = styleUp;
+        kids[1].style.display = styleHover;
+        kids[2].style.display = styleDown;
+
+        return node;
+    }
+
+    function max3(a,b,c) {
+        var ab = a > b ? a : b;
+        return ab > c ? ab : c;
+    }
+
+    function customButton(message, up, hover, down) {
+        return A3(Element.newElement,
+                  max3(up.props.width, hover.props.width, down.props.width),
+                  max3(up.props.height, hover.props.height, down.props.height),
+                  { ctor: 'Custom',
+                    type: 'CustomButton',
+                    render: renderCustomButton,
+                    update: updateCustomButton,
+                    model: {
+                        message: message,
+                        up: up,
+                        hover: hover,
+                        down: down
+                    }
+                  });
+    }
+
+    function renderCheckbox(model) {
+        var node = NativeElement.createNode('input');
+        node.type = 'checkbox';
+        node.checked = model.checked;
+        node.style.display = 'block';
+        node.style.pointerEvents = 'auto';
+        node.elm_handler = model.handler;
+        function change() {
+            node.elm_handler(node.checked)();
+        }
+        node.addEventListener('change', change);
+        return node;
+    }
+
+    function updateCheckbox(node, oldModel, newModel) {
+        node.elm_handler = newModel.handler;
+        node.checked = newModel.checked;
+        return node;
+    }
+
+    function checkbox(handler, checked) {
+        return A3(Element.newElement, 13, 13, {
+            ctor: 'Custom',
+            type: 'CheckBox',
+            render: renderCheckbox,
+            update: updateCheckbox,
+            model: { handler:handler, checked:checked }
+        });
+    }
+
+    function setRange(node, start, end, dir) {
+        if (node.parentNode) {
+            node.setSelectionRange(start, end, dir);
+        } else {
+            setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
+        }
+    }
+
+    function updateIfNeeded(css, attribute, latestAttribute) {
+        if (css[attribute] !== latestAttribute) {
+            css[attribute] = latestAttribute;
+        }
+    }
+    function cssDimensions(dimensions) {
+        return dimensions.top    + 'px ' +
+               dimensions.right  + 'px ' +
+               dimensions.bottom + 'px ' +
+               dimensions.left   + 'px';
+    }
+    function updateFieldStyle(css, style) {
+        updateIfNeeded(css, 'padding', cssDimensions(style.padding));
+
+        var outline = style.outline;
+        updateIfNeeded(css, 'border-width', cssDimensions(outline.width));
+        updateIfNeeded(css, 'border-color', Color.toCss(outline.color));
+        updateIfNeeded(css, 'border-radius', outline.radius + 'px');
+
+        var highlight = style.highlight;
+        if (highlight.width === 0) {
+            css.outline = 'none';
+        } else {
+            updateIfNeeded(css, 'outline-width', highlight.width + 'px');
+            updateIfNeeded(css, 'outline-color', Color.toCss(highlight.color));
+        }
+
+        var textStyle = style.style;
+        updateIfNeeded(css, 'color', Color.toCss(textStyle.color));
+        if (textStyle.typeface.ctor !== '[]') {
+            updateIfNeeded(css, 'font-family', Text.toTypefaces(textStyle.typeface));
+        }
+        if (textStyle.height.ctor !== "Nothing") {
+            updateIfNeeded(css, 'font-size', textStyle.height._0 + 'px');
+        }
+        updateIfNeeded(css, 'font-weight', textStyle.bold ? 'bold' : 'normal');
+        updateIfNeeded(css, 'font-style', textStyle.italic ? 'italic' : 'normal');
+        if (textStyle.line.ctor !== 'Nothing') {
+            updateIfNeeded(css, 'text-decoration', Text.toLine(textStyle.line._0));
+        }
+    }
+
+    function renderField(model) {
+        var field = NativeElement.createNode('input');
+        updateFieldStyle(field.style, model.style);
+        field.style.borderStyle = 'solid';
+        field.style.pointerEvents = 'auto';
+
+        field.type = model.type;
+        field.placeholder = model.placeHolder;
+        field.value = model.content.string;
+
+        field.elm_handler = model.handler;
+        field.elm_old_value = field.value;
+
+        function inputUpdate(event) {
+            var curr = field.elm_old_value;
+            var next = field.value;
+            if (curr === next) {
+                return;
+            }
+
+            var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
+            var start = field.selectionStart;
+            var end = field.selectionEnd;
+            field.value = field.elm_old_value;
+
+            field.elm_handler({
+                _:{},
+                string: next,
+                selection: {
+                    _:{},
+                    start: start,
+                    end: end,
+                    direction: { ctor: direction }
+                }
+            })();
+        }
+
+        field.addEventListener('input', inputUpdate);
+        field.addEventListener('focus', function() {
+            field.elm_hasFocus = true;
+        });
+        field.addEventListener('blur', function() {
+            field.elm_hasFocus = false;
+        });
+
+        return field;
+    }
+
+    function updateField(field, oldModel, newModel) {
+        if (oldModel.style !== newModel.style) {
+            updateFieldStyle(field.style, newModel.style);
+        }
+        field.elm_handler = newModel.handler;
+
+        field.type = newModel.type;
+        field.placeholder = newModel.placeHolder;
+        var value = newModel.content.string;
+        field.value = value;
+        field.elm_old_value = value;
+        if (field.elm_hasFocus) {
+            var selection = newModel.content.selection;
+            var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
+            setRange(field, selection.start, selection.end, direction);
+        }
+        return field;
+    }
+
+    function mkField(type) {
+        function field(style, handler, placeHolder, content) {
+            var padding = style.padding;
+            var outline = style.outline.width;
+            var adjustWidth = padding.left + padding.right + outline.left + outline.right;
+            var adjustHeight = padding.top + padding.bottom + outline.top + outline.bottom;
+            return A3(Element.newElement, 200, 30, {
+                ctor: 'Custom',
+                type: type + 'Field',
+                adjustWidth: adjustWidth,
+                adjustHeight: adjustHeight,
+                render: renderField,
+                update: updateField,
+                model: {
+                    handler:handler,
+                    placeHolder:placeHolder,
+                    content:content,
+                    style:style,
+                    type:type
+                }
+            });
+        }
+        return F4(field);
+    }
+
+    function hoverable(handler, elem) {
+        function onHover(bool) {
+            handler(bool)();
+        }
+        var props = Utils.replace([['hover',onHover]], elem.props);
+        return { props:props, element:elem.element };
+    }
+
+    function clickable(message, elem) {
+        function onClick() {
+            message();
+        }
+        var props = Utils.replace([['click',onClick]], elem.props);
+        return { props:props, element:elem.element };
+    }
+
+    return Elm.Native.Graphics.Input.values = {
+        button: F2(button),
+        customButton: F4(customButton),
+        checkbox: F2(checkbox),
+        dropDown: F2(dropDown),
+        field: mkField('text'),
+        email: mkField('email'),
+        password: mkField('password'),
+        hoverable: F2(hoverable),
+        clickable: F2(clickable)
+    };
+
+};
+ src/Native/Http.js view
@@ -0,0 +1,63 @@+Elm.Native.Http = {};
+Elm.Native.Http.make = function(elm) {
+
+    elm.Native = elm.Native || {};
+    elm.Native.Http = elm.Native.Http || {};
+    if (elm.Native.Http.values) return elm.Native.Http.values;
+
+    var List = Elm.List.make(elm);
+    var Signal = Elm.Signal.make(elm);
+
+    function registerReq(queue,responses) {
+        return function(req) {
+            if (req.url.length > 0) {
+                sendReq(queue,responses,req);
+            }
+        };
+    }
+
+    function updateQueue(queue,responses) {
+        if (queue.length > 0) {
+            elm.notify(responses.id, queue[0].value);
+            if (queue[0].value.ctor !== 'Waiting') {
+                queue.shift();
+                setTimeout(function() { updateQueue(queue,responses); }, 0);
+            }
+        }
+    }
+
+    function sendReq(queue,responses,req) {
+        var response = { value: { ctor:'Waiting' } };
+        queue.push(response);
+
+        var request = (window.ActiveXObject
+                       ? new ActiveXObject("Microsoft.XMLHTTP")
+                       : new XMLHttpRequest());
+
+        request.onreadystatechange = function(e) {
+            if (request.readyState === 4) {
+                response.value = (request.status >= 200 && request.status < 300 ?
+                                  { ctor:'Success', _0:request.responseText } :
+                                  { ctor:'Failure', _0:request.status, _1:request.statusText });
+                setTimeout(function() { updateQueue(queue,responses); }, 0);
+            }
+        };
+        request.open(req.verb, req.url, true);
+        function setHeader(pair) {
+            request.setRequestHeader( pair._0, pair._1 );
+        }
+        A2( List.map, setHeader, req.headers );
+        request.send(req.body);
+    }
+
+    function send(requests) {
+        var responses = Signal.constant(elm.Http.values.Waiting);
+        var sender = A2( Signal.map, registerReq([],responses), requests );
+        function f(x) { return function(y) { return x; } }
+        return A3( Signal.map2, f, responses, sender );
+    }
+
+    return elm.Native.Http.values = {
+        send:send
+    };
+};
+ src/Native/Json.js view
@@ -0,0 +1,485 @@+Elm.Native.Json = {};
+Elm.Native.Json.make = function(localRuntime) {
+    localRuntime.Native = localRuntime.Native || {};
+    localRuntime.Native.Json = localRuntime.Native.Json || {};
+    if (localRuntime.Native.Json.values) {
+        return localRuntime.Native.Json.values;
+    }
+
+    var ElmArray = Elm.Native.Array.make(localRuntime);
+    var List = Elm.Native.List.make(localRuntime);
+    var Maybe = Elm.Maybe.make(localRuntime);
+    var Result = Elm.Result.make(localRuntime);
+    var Utils = Elm.Native.Utils.make(localRuntime);
+
+
+    function crash(expected, actual) {
+        throw new Error(
+            'expecting ' + expected + ' but got ' + JSON.stringify(actual)
+        );
+    }
+
+
+    // PRIMITIVE VALUES
+
+    function decodeNull(successValue) {
+        return function(value) {
+            if (value === null) {
+                return successValue;
+            }
+            crash('null', value);
+        };
+    }
+
+
+    function decodeString(value) {
+        if (typeof value === 'string' || value instanceof String) {
+            return value;
+        }
+        crash('a String', value);
+    }
+
+
+    function decodeFloat(value) {
+        if (typeof value === 'number') {
+            return value;
+        }
+        crash('a Float', value);
+    }
+
+
+    function decodeInt(value) {
+        if (typeof value === 'number' && (value|0) === value) {
+            return value;
+        }
+        crash('an Int', value);
+    }
+
+
+    function decodeBool(value) {
+        if (typeof value === 'boolean') {
+            return value;
+        }
+        crash('a Bool', value);
+    }
+
+
+    // ARRAY
+
+    function decodeArray(decoder) {
+        return function(value) {
+            if (value instanceof Array) {
+                var len = value.length;
+                var array = new Array(len);
+                for (var i = len; i-- ; ) {
+                    array[i] = decoder(value[i]);
+                }
+                return ElmArray.fromJSArray(array);
+            }
+            crash('an Array', value);
+        };
+    }
+
+
+    // LIST
+
+    function decodeList(decoder) {
+        return function(value) {
+            if (value instanceof Array) {
+                var len = value.length;
+                var list = List.Nil;
+                for (var i = len; i-- ; ) {
+                    list = List.Cons( decoder(value[i]), list );
+                }
+                return list;
+            }
+            crash('a List', value);
+        };
+    }
+
+
+    // MAYBE
+
+    function decodeMaybe(decoder) {
+        return function(value) {
+            try {
+                return Maybe.Just(decoder(value));
+            } catch(e) {
+                return Maybe.Nothing;
+            }
+        };
+    }
+
+
+    // FIELDS
+
+    function decodeField(field, decoder) {
+        return function(value) {
+            var subValue = value[field];
+            if (subValue !== undefined) {
+                return decoder(subValue);
+            }
+            crash("an object with field '" + field + "'", value);
+        };
+    }
+
+
+    // OBJECTS
+
+    function decodeKeyValuePairs(decoder) {
+        return function(value) {
+            var isObject =
+                typeof value === 'object'
+                    && value !== null
+                    && !(value instanceof Array);
+
+            if (isObject) {
+                var keyValuePairs = List.Nil;
+                for (var key in value) {
+                    var elmValue = decoder(value[key]);
+                    var pair = Utils.Tuple2(key, elmValue);
+                    keyValuePairs = List.Cons(pair, keyValuePairs);
+                }
+                return keyValuePairs;
+            }
+
+            crash("an object", value);
+        };
+    }
+
+    function decodeObject1(f, d1) {
+        return function(value) {
+            return f(d1(value));
+        };
+    }
+
+    function decodeObject2(f, d1, d2) {
+        return function(value) {
+            return A2( f, d1(value), d2(value) );
+        };
+    }
+
+    function decodeObject3(f, d1, d2, d3) {
+        return function(value) {
+            return A3( f, d1(value), d2(value), d3(value) );
+        };
+    }
+
+    function decodeObject4(f, d1, d2, d3, d4) {
+        return function(value) {
+            return A4( f, d1(value), d2(value), d3(value), d4(value) );
+        };
+    }
+
+    function decodeObject5(f, d1, d2, d3, d4, d5) {
+        return function(value) {
+            return A5( f, d1(value), d2(value), d3(value), d4(value), d5(value) );
+        };
+    }
+
+    function decodeObject6(f, d1, d2, d3, d4, d5, d6) {
+        return function(value) {
+            return A6( f,
+                d1(value),
+                d2(value),
+                d3(value),
+                d4(value),
+                d5(value),
+                d6(value)
+            );
+        };
+    }
+
+    function decodeObject7(f, d1, d2, d3, d4, d5, d6, d7) {
+        return function(value) {
+            return A7( f,
+                d1(value),
+                d2(value),
+                d3(value),
+                d4(value),
+                d5(value),
+                d6(value),
+                d7(value)
+            );
+        };
+    }
+
+    function decodeObject8(f, d1, d2, d3, d4, d5, d6, d7, d8) {
+        return function(value) {
+            return A8( f,
+                d1(value),
+                d2(value),
+                d3(value),
+                d4(value),
+                d5(value),
+                d6(value),
+                d7(value),
+                d8(value)
+            );
+        };
+    }
+
+
+    // TUPLES
+
+    function decodeTuple1(f, d1) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 1 ) {
+                crash('a Tuple of length 1', value);
+            }
+            return f( d1(value[0]) );
+        };
+    }
+
+    function decodeTuple2(f, d1, d2) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 2 ) {
+                crash('a Tuple of length 2', value);
+            }
+            return A2( f, d1(value[0]), d2(value[1]) );
+        };
+    }
+
+    function decodeTuple3(f, d1, d2, d3) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 3 ) {
+                crash('a Tuple of length 3', value);
+            }
+            return A3( f, d1(value[0]), d2(value[1]), d3(value[2]) );
+        };
+    }
+
+
+    function decodeTuple4(f, d1, d2, d3, d4) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 4 ) {
+                crash('a Tuple of length 4', value);
+            }
+            return A4( f, d1(value[0]), d2(value[1]), d3(value[2]), d4(value[3]) );
+        };
+    }
+
+
+    function decodeTuple5(f, d1, d2, d3, d4, d5) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 5 ) {
+                crash('a Tuple of length 5', value);
+            }
+            return A5( f,
+                d1(value[0]),
+                d2(value[1]),
+                d3(value[2]),
+                d4(value[3]),
+                d5(value[4])
+            );
+        };
+    }
+
+
+    function decodeTuple6(f, d1, d2, d3, d4, d5, d6) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 6 ) {
+                crash('a Tuple of length 6', value);
+            }
+            return A6( f,
+                d1(value[0]),
+                d2(value[1]),
+                d3(value[2]),
+                d4(value[3]),
+                d5(value[4]),
+                d6(value[5])
+            );
+        };
+    }
+
+    function decodeTuple7(f, d1, d2, d3, d4, d5, d6, d7) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 7 ) {
+                crash('a Tuple of length 7', value);
+            }
+            return A7( f,
+                d1(value[0]),
+                d2(value[1]),
+                d3(value[2]),
+                d4(value[3]),
+                d5(value[4]),
+                d6(value[5]),
+                d7(value[6])
+            );
+        };
+    }
+
+
+    function decodeTuple8(f, d1, d2, d3, d4, d5, d6, d7, d8) {
+        return function(value) {
+            if ( !(value instanceof Array) || value.length !== 8 ) {
+                crash('a Tuple of length 8', value);
+            }
+            return A8( f,
+                d1(value[0]),
+                d2(value[1]),
+                d3(value[2]),
+                d4(value[3]),
+                d5(value[4]),
+                d6(value[5]),
+                d7(value[6]),
+                d8(value[7])
+            );
+        };
+    }
+
+
+    // CUSTOM DECODERS
+
+    function decodeValue(value) {
+        return value;
+    }
+
+    function runDecoderValue(decoder, value) {
+        try {
+            return Result.Ok(decoder(value));
+        } catch(e) {
+            return Result.Err(e.message);
+        }
+    }
+
+    function customDecoder(decoder, callback) {
+        return function(value) {
+            var result = callback(decoder(value));
+            if (result.ctor === 'Err') {
+                throw new Error('custom decoder failed: ' + result._0);
+            }
+            return result._0;
+        }
+    }
+
+    function andThen(decode, callback) {
+        return function(value) {
+            var result = decode(value);
+            return callback(result)(value);
+        }
+    }
+
+    function fail(msg) {
+        return function(value) {
+            throw new Error(msg);
+        }
+    }
+
+    function succeed(successValue) {
+        return function(value) {
+            return successValue;
+        }
+    }
+
+
+    // ONE OF MANY
+
+    function oneOf(decoders) {
+        return function(value) {
+            var errors = [];
+            var temp = decoders;
+            while (temp.ctor !== '[]') {
+                try {
+                    return temp._0(value);
+                } catch(e) {
+                    errors.push(e.message);
+                }
+                temp = temp._1;
+            }
+            throw new Error('expecting one of the following:\n    ' + errors.join('\n    '));
+        }
+    }
+
+    function get(decoder, value) {
+        try {
+            return Result.Ok(decoder(value));
+        } catch(e) {
+            return Result.Err(e.message);
+        }
+    }
+
+
+    // ENCODE / DECODE
+
+    function runDecoderString(decoder, string) {
+        try {
+            return Result.Ok(decoder(JSON.parse(string)));
+        } catch(e) {
+            return Result.Err(e.message);
+        }
+    }
+
+    function encode(indentLevel, value) {
+        return JSON.stringify(value, null, indentLevel);
+    }
+
+    function identity(value) {
+        return value;
+    }
+
+    function encodeObject(keyValuePairs) {
+        var obj = {};
+        while (keyValuePairs.ctor !== '[]') {
+            var pair = keyValuePairs._0;
+            obj[pair._0] = pair._1;
+            keyValuePairs = keyValuePairs._1;
+        }
+        return obj;
+    }
+
+    return localRuntime.Native.Json.values = {
+        encode: F2(encode),
+        runDecoderString: F2(runDecoderString),
+        runDecoderValue: F2(runDecoderValue),
+
+        get: F2(get),
+        oneOf: oneOf,
+
+        decodeNull: decodeNull,
+        decodeInt: decodeInt,
+        decodeFloat: decodeFloat,
+        decodeString: decodeString,
+        decodeBool: decodeBool,
+
+        decodeMaybe: decodeMaybe,
+
+        decodeList: decodeList,
+        decodeArray: decodeArray,
+
+        decodeField: F2(decodeField),
+
+        decodeObject1: F2(decodeObject1),
+        decodeObject2: F3(decodeObject2),
+        decodeObject3: F4(decodeObject3),
+        decodeObject4: F5(decodeObject4),
+        decodeObject5: F6(decodeObject5),
+        decodeObject6: F7(decodeObject6),
+        decodeObject7: F8(decodeObject7),
+        decodeObject8: F9(decodeObject8),
+        decodeKeyValuePairs: decodeKeyValuePairs,
+
+        decodeTuple1: F2(decodeTuple1),
+        decodeTuple2: F3(decodeTuple2),
+        decodeTuple3: F4(decodeTuple3),
+        decodeTuple4: F5(decodeTuple4),
+        decodeTuple5: F6(decodeTuple5),
+        decodeTuple6: F7(decodeTuple6),
+        decodeTuple7: F8(decodeTuple7),
+        decodeTuple8: F9(decodeTuple8),
+
+        andThen: F2(andThen),
+        decodeValue: decodeValue,
+        customDecoder: F2(customDecoder),
+        fail: fail,
+        succeed: succeed,
+
+        identity: identity,
+        encodeNull: null,
+        encodeArray: ElmArray.toJSArray,
+        encodeList: List.toArray,
+        encodeObject: encodeObject
+
+    };
+
+};
+ src/Native/Keyboard.js view
@@ -0,0 +1,154 @@+Elm.Native.Keyboard = {};
+Elm.Native.Keyboard.make = function(elm) {
+
+    elm.Native = elm.Native || {};
+    elm.Native.Keyboard = elm.Native.Keyboard || {};
+    if (elm.Native.Keyboard.values) return elm.Native.Keyboard.values;
+
+    // Duplicated from Native.Signal
+    function send(node, timestep, changed) {
+        var kids = node.kids;
+        for (var i = kids.length; i--; ) {
+            kids[i].recv(timestep, changed, node.id);
+        }
+    }
+
+    var Signal = Elm.Signal.make(elm);
+    var NList = Elm.Native.List.make(elm);
+    var Utils = Elm.Native.Utils.make(elm);
+
+    var downEvents = Signal.constant(null);
+    var upEvents = Signal.constant(null);
+    var blurEvents = Signal.constant(null);
+
+    elm.addListener([downEvents.id], document, 'keydown', function down(e) {
+        elm.notify(downEvents.id, e);
+    });
+
+    elm.addListener([upEvents.id], document, 'keyup', function up(e) {
+        elm.notify(upEvents.id, e);
+    });
+
+    elm.addListener([blurEvents.id], window, 'blur', function blur(e) {
+        elm.notify(blurEvents.id, null);
+    });
+
+    function state(alt, meta, keyCodes) {
+        return {
+            alt: alt,
+            meta: meta,
+            keyCodes: keyCodes
+        };
+    }
+    var emptyState = state(false, false, NList.Nil);
+
+    function KeyMerge(down, up, blur) {
+        var args = [down,up,blur];
+        this.id = Utils.guid();
+        // Ignore starting values here
+        this.value = emptyState;
+        this.kids = [];
+        
+        var n = args.length;
+        var count = 0;
+        var isChanged = false;
+
+        this.recv = function(timestep, changed, parentID) {
+            ++count;
+            if (changed) { 
+                // We know this a change must only be one of the following cases
+                if (parentID === down.id && !A2(NList.member, down.value.keyCode, this.value.keyCodes)) {
+                    isChanged = true;
+                    var v = down.value;
+                    var newCodes = NList.Cons(v.keyCode, this.value.keyCodes);
+                    this.value = state(v.altKey, v.metaKey, newCodes);
+                }
+                else if (parentID === up.id) {
+                    isChanged = true;
+                    var v = up.value;
+                    var notEq = function(kc) { return kc !== v.keyCode };
+                    var newCodes = A2(NList.filter, notEq, this.value.keyCodes);
+                    this.value = state(v.altKey, v.metaKey, newCodes);
+                }
+                else if (parentID === blur.id) {
+                    isChanged = true;
+                    this.value = emptyState;
+                }
+            }
+            if (count == n) {
+                send(this, timestep, isChanged);
+                isChanged = false;
+                count = 0;
+            }
+        };
+
+        for (var i = n; i--; ) {
+            args[i].kids.push(this);
+            args[i].defaultNumberOfKids += 1;
+        }
+    }
+
+    var keyMerge = new KeyMerge(downEvents,upEvents,blurEvents);
+
+    // select a part of a keyMerge and dropRepeats the result
+    function keySignal(f) {
+        var signal = A2(Signal.map, f, keyMerge);
+        // must set the default number of kids to make it possible to filter
+        // these signals if they are not actually used.
+        keyMerge.defaultNumberOfKids += 1;
+        signal.defaultNumberOfKids = 1;
+        var filtered = Signal.dropRepeats(signal);
+        filtered.defaultNumberOfKids = 0;
+        return filtered;
+    }
+
+    // break keyMerge into parts
+    var keysDown = keySignal(function getKeyCodes(v) {
+        return v.keyCodes;
+    });
+    var alt = keySignal(function getKeyCodes(v) {
+        return v.alt;
+    });
+    var meta = keySignal(function getKeyCodes(v) {
+        return v.meta;
+    });
+
+    function dir(up, down, left, right) {
+        function toDirections(state) {
+            var keyCodes = state.keyCodes;
+            var x = 0, y = 0;
+            while (keyCodes.ctor === "::") {
+                switch (keyCodes._0) {
+                case left : --x; break;
+                case right: ++x; break;
+                case up   : ++y; break;
+                case down : --y; break;
+                }
+                keyCodes = keyCodes._1;
+            }
+            return { _:{}, x:x, y:y };
+        }
+        return keySignal(toDirections);
+    }
+
+    function is(key) {
+        return keySignal(function(v) {
+            return A2( NList.member, key, v.keyCodes );
+        });
+    }
+
+    var lastPressed = A2(Signal.map, function(e) {
+        return e ? e.keyCode : 0;
+    }, downEvents);
+    downEvents.defaultNumberOfKids += 1;
+
+    return elm.Native.Keyboard.values = {
+        isDown:is,
+        alt: alt,
+        meta: meta,
+        directions:F4(dir),
+        keysDown:keysDown,
+        lastPressed:lastPressed
+    };
+
+};
+ src/Native/List.js view
@@ -0,0 +1,326 @@+Elm.Native.List = {};
+Elm.Native.List.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.List = elm.Native.List || {};
+    if (elm.Native.List.values) return elm.Native.List.values;
+    if ('values' in Elm.Native.List)
+        return elm.Native.List.values = Elm.Native.List.values;
+
+    var Utils = Elm.Native.Utils.make(elm);
+
+    var Nil = Utils.Nil;
+    var Cons = Utils.Cons;
+
+    function throwError(f) {
+        throw new Error("Function '" + f + "' expects a non-empty list!");
+    }
+
+    function toArray(xs) {
+        var out = [];
+        while (xs.ctor !== '[]') {
+            out.push(xs._0);
+            xs = xs._1;
+        }
+        return out;
+    }
+
+    function fromArray(arr) {
+        var out = Nil;
+        for (var i = arr.length; i--; ) {
+            out = Cons(arr[i], out);
+        }
+        return out;
+    }
+
+    function range(lo,hi) {
+        var lst = Nil;
+        if (lo <= hi) {
+            do { lst = Cons(hi,lst) } while (hi-->lo);
+        }
+        return lst
+    }
+
+    function head(v) {
+        return v.ctor === '[]' ? throwError('head') : v._0;
+    }
+    function tail(v) {
+        return v.ctor === '[]' ? throwError('tail') : v._1;
+    }
+
+    function last(xs) {
+        if (xs.ctor === '[]') { throwError('last'); }
+        var out = xs._0;
+        while (xs.ctor !== '[]') {
+            out = xs._0;
+            xs = xs._1;
+        }
+        return out;
+    }
+
+    function map(f, xs) {
+        var arr = [];
+        while (xs.ctor !== '[]') {
+            arr.push(f(xs._0));
+            xs = xs._1;
+        }
+        return fromArray(arr);
+    }
+
+    // f defined similarly for both foldl and foldr (NB: different from Haskell)
+    // ie, foldl : (a -> b -> b) -> b -> [a] -> b
+    function foldl(f, b, xs) {
+        var acc = b;
+        while (xs.ctor !== '[]') {
+            acc = A2(f, xs._0, acc);
+            xs = xs._1;
+        }
+        return acc;
+    }
+
+    function foldr(f, b, xs) {
+        var arr = toArray(xs);
+        var acc = b;
+        for (var i = arr.length; i--; ) {
+            acc = A2(f, arr[i], acc);
+        }
+        return acc;
+    }
+
+    function foldl1(f, xs) {
+        return xs.ctor === '[]' ? throwError('foldl1') : foldl(f, xs._0, xs._1);
+    }
+
+    function foldr1(f, xs) {
+        if (xs.ctor === '[]') { throwError('foldr1'); }
+        var arr = toArray(xs);
+        var acc = arr.pop();
+        for (var i = arr.length; i--; ) {
+            acc = A2(f, arr[i], acc);
+        }
+        return acc;
+    }
+
+    function scanl(f, b, xs) {
+        var arr = toArray(xs);
+        arr.unshift(b);
+        var len = arr.length;
+        for (var i = 1; i < len; ++i) {
+            arr[i] = A2(f, arr[i], arr[i-1]);
+        }
+        return fromArray(arr);
+    }
+
+    function scanl1(f, xs) {
+        return xs.ctor === '[]' ? throwError('scanl1') : scanl(f, xs._0, xs._1);
+    }
+
+    function filter(pred, xs) {
+        var arr = [];
+        while (xs.ctor !== '[]') {
+            if (pred(xs._0)) { arr.push(xs._0); }
+            xs = xs._1;
+        }
+        return fromArray(arr);
+    }
+
+    function length(xs) {
+        var out = 0;
+        while (xs.ctor !== '[]') {
+            out += 1;
+            xs = xs._1;
+        }
+        return out;
+    }
+
+    function member(x, xs) {
+        while (xs.ctor !== '[]') {
+            if (Utils.eq(x,xs._0)) return true;
+            xs = xs._1;
+        }
+        return false;
+    }
+
+    function reverse(xs) {
+        return fromArray(toArray(xs).reverse());
+    }
+
+    function append(xs, ys) {
+        if (xs.ctor === '[]') {
+            return ys;
+        }
+        var root = Cons(xs._0, Nil);
+        var curr = root;
+        xs = xs._1;
+        while (xs.ctor !== '[]') {
+            curr._1 = Cons(xs._0, Nil);
+            xs = xs._1;
+            curr = curr._1;
+        }
+        curr._1 = ys;
+        return root;
+    }
+
+    function all(pred, xs) {
+        while (xs.ctor !== '[]') {
+            if (!pred(xs._0)) return false;
+            xs = xs._1;
+        }
+        return true;
+    }
+
+    function any(pred, xs) {
+        while (xs.ctor !== '[]') {
+            if (pred(xs._0)) return true;
+            xs = xs._1;
+        }
+        return false;
+    }
+
+    function map2(f, xs, ys) {
+        var arr = [];
+        while (xs.ctor !== '[]' && ys.ctor !== '[]') {
+            arr.push(A2(f, xs._0, ys._0));
+            xs = xs._1;
+            ys = ys._1;
+        }
+        return fromArray(arr);
+    }
+
+    function map3(f, xs, ys, zs) {
+        var arr = [];
+        while (xs.ctor !== '[]' && ys.ctor !== '[]' && zs.ctor !== '[]') {
+            arr.push(A3(f, xs._0, ys._0, zs._0));
+            xs = xs._1;
+            ys = ys._1;
+            zs = zs._1;
+        }
+        return fromArray(arr);
+    }
+
+    function map4(f, ws, xs, ys, zs) {
+        var arr = [];
+        while (   ws.ctor !== '[]'
+               && xs.ctor !== '[]'
+               && ys.ctor !== '[]'
+               && zs.ctor !== '[]')
+        {
+            arr.push(A4(f, ws._0, xs._0, ys._0, zs._0));
+            ws = ws._1;
+            xs = xs._1;
+            ys = ys._1;
+            zs = zs._1;
+        }
+        return fromArray(arr);
+    }
+
+    function map5(f, vs, ws, xs, ys, zs) {
+        var arr = [];
+        while (   vs.ctor !== '[]'
+               && ws.ctor !== '[]'
+               && xs.ctor !== '[]'
+               && ys.ctor !== '[]'
+               && zs.ctor !== '[]')
+        {
+            arr.push(A5(f, vs._0, ws._0, xs._0, ys._0, zs._0));
+            vs = vs._1;
+            ws = ws._1;
+            xs = xs._1;
+            ys = ys._1;
+            zs = zs._1;
+        }
+        return fromArray(arr);
+    }
+
+    function sort(xs) {
+        return fromArray(toArray(xs).sort(Utils.cmp));
+    }
+
+    function sortBy(f, xs) {
+        return fromArray(toArray(xs).sort(function(a,b){
+            return Utils.cmp(f(a), f(b));
+        }));
+    }
+
+    function sortWith(f, xs) {
+        return fromArray(toArray(xs).sort(function(a,b){
+            var ord = f(a)(b).ctor;
+            return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
+        }));
+    }
+
+    function nth(xs, n) {
+        return toArray(xs)[n];
+    }
+
+    function take(n, xs) {
+        var arr = [];
+        while (xs.ctor !== '[]' && n > 0) {
+            arr.push(xs._0);
+            xs = xs._1;
+            --n;
+        }
+        return fromArray(arr);
+    }
+
+    function drop(n, xs) {
+        while (xs.ctor !== '[]' && n > 0) {
+            xs = xs._1;
+            --n;
+        }
+        return xs;
+    }
+
+    function repeat(n, x) {
+        var arr = [];
+        var pattern = [x];
+        while (n > 0) {
+            if (n & 1) arr = arr.concat(pattern);
+            n >>= 1, pattern = pattern.concat(pattern);
+        }
+        return fromArray(arr);
+    }
+
+
+    Elm.Native.List.values = {
+        Nil:Nil,
+        Cons:Cons,
+        cons:F2(Cons),
+        toArray:toArray,
+        fromArray:fromArray,
+        range:range,
+        append: F2(append),
+
+        head:head,
+        tail:tail,
+        last:last,
+
+        map:F2(map),
+        foldl:F3(foldl),
+        foldr:F3(foldr),
+
+        foldl1:F2(foldl1),
+        foldr1:F2(foldr1),
+        scanl:F3(scanl),
+        scanl1:F2(scanl1),
+        filter:F2(filter),
+        length:length,
+        member:F2(member),
+        reverse:reverse,
+
+        all:F2(all),
+        any:F2(any),
+        map2:F3(map2),
+        map3:F4(map3),
+        map4:F5(map4),
+        map5:F6(map5),
+        sort:sort,
+        sortBy:F2(sortBy),
+        sortWith:F2(sortWith),
+        nth:F2(nth),
+        take:F2(take),
+        drop:F2(drop),
+        repeat:F2(repeat)
+    };
+    return elm.Native.List.values = Elm.Native.List.values;
+
+};
+ src/Native/Mouse.js view
@@ -0,0 +1,60 @@+Elm.Native = Elm.Native || {};
+Elm.Native.Mouse = {};
+Elm.Native.Mouse.make = function(localRuntime) {
+
+    localRuntime.Native = localRuntime.Native || {};
+    localRuntime.Native.Mouse = localRuntime.Native.Mouse || {};
+    if (localRuntime.Native.Mouse.values) {
+        return localRuntime.Native.Mouse.values;
+    }
+
+    var Signal = Elm.Signal.make(localRuntime);
+    var Utils = Elm.Native.Utils.make(localRuntime);
+
+    var position = Signal.constant(Utils.Tuple2(0,0));
+    position.defaultNumberOfKids = 2;
+
+    // do not move x and y into Elm. By setting their default number
+    // of kids, it is possible to detatch the mouse listeners if
+    // they are not needed.
+    function fst(pair) {
+        return pair._0;
+    }
+    function snd(pair) {
+        return pair._0;
+    }
+
+    var x = A2( Signal.map, fst, position );
+    x.defaultNumberOfKids = 0;
+
+    var y = A2( Signal.map, snd, position );
+    y.defaultNumberOfKids = 0;
+
+    var isDown = Signal.constant(false);
+    var clicks = Signal.constant(Utils.Tuple0);
+
+    var node = localRuntime.isFullscreen()
+        ? document
+        : localRuntime.node;
+
+    localRuntime.addListener([clicks.id], node, 'click', function click() {
+        localRuntime.notify(clicks.id, Utils.Tuple0);
+    });
+    localRuntime.addListener([isDown.id], node, 'mousedown', function down() {
+        localRuntime.notify(isDown.id, true);
+    });
+    localRuntime.addListener([isDown.id], node, 'mouseup', function up() {
+        localRuntime.notify(isDown.id, false);
+    });
+    localRuntime.addListener([position.id], node, 'mousemove', function move(e) {
+        localRuntime.notify(position.id, Utils.getXY(e));
+    });
+
+    return localRuntime.Native.Mouse.values = {
+        position: position,
+        x: x,
+        y: y,
+        isDown: isDown,
+        clicks: clicks
+    };
+};
+ src/Native/Ports.js view
@@ -0,0 +1,92 @@+Elm.Native.Ports = {};
+Elm.Native.Ports.make = function(localRuntime) {
+    localRuntime.Native = localRuntime.Native || {};
+    localRuntime.Native.Ports = localRuntime.Native.Ports || {};
+    if (localRuntime.Native.Ports.values) {
+        return localRuntime.Native.Ports.values;
+    }
+
+    var Signal;
+
+    function incomingSignal(converter) {
+        converter.isSignal = true;
+        return converter;
+    }
+
+    function outgoingSignal(converter) {
+        if (!Signal) {
+            Signal = Elm.Signal.make(localRuntime);
+        }
+        return function(signal) {
+            var subscribers = []
+            function subscribe(handler) {
+                subscribers.push(handler);
+            }
+            function unsubscribe(handler) {
+                subscribers.pop(subscribers.indexOf(handler));
+            }
+            A2( Signal.map, function(value) {
+                var val = converter(value);
+                var len = subscribers.length;
+                for (var i = 0; i < len; ++i) {
+                    subscribers[i](val);
+                }
+            }, signal);
+            return { subscribe:subscribe, unsubscribe:unsubscribe };
+        }
+    }
+
+    function portIn(name, converter) {
+        var jsValue = localRuntime.ports.incoming[name];
+        if (jsValue === undefined) {
+            throw new Error("Initialization Error: port '" + name +
+                            "' was not given an input!");
+        }
+        localRuntime.ports.uses[name] += 1;
+        try {
+            var elmValue = converter(jsValue);
+        } catch(e) {
+            throw new Error("Initialization Error on port '" + name + "': \n" + e.message);
+        }
+
+        // just return a static value if it is not a signal
+        if (!converter.isSignal) {
+            return elmValue;
+        }
+
+        // create a signal if necessary
+        if (!Signal) {
+            Signal = Elm.Signal.make(localRuntime);
+        }
+        var signal = Signal.constant(elmValue);
+        function send(jsValue) {
+            try {
+                var elmValue = converter(jsValue);
+            } catch(e) {
+                throw new Error("Error sending to port '" + name + "': \n" + e.message);
+            }
+            setTimeout(function() {
+                localRuntime.notify(signal.id, elmValue);
+            }, 0);
+        }
+        localRuntime.ports.outgoing[name] = { send:send };
+        return signal;
+    }
+
+    function portOut(name, converter, value) {
+        try {
+            localRuntime.ports.outgoing[name] = converter(value);
+        } catch(e) {
+            throw new Error("Initialization Error on port '" + name + "': \n" + e.message);
+        }
+        return value;
+    }
+
+    return localRuntime.Native.Ports.values = {
+        incomingSignal: incomingSignal,
+        outgoingSignal: outgoingSignal,
+        portOut: portOut,
+        portIn: portIn
+    };
+};
+
+ src/Native/Regex.js view
@@ -0,0 +1,103 @@+Elm.Native.Regex = {};
+Elm.Native.Regex.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Regex = elm.Native.Regex || {};
+    if (elm.Native.Regex.values) return elm.Native.Regex.values;
+    if ('values' in Elm.Native.Regex)
+        return elm.Native.Regex.values = Elm.Native.Regex.values;
+
+    var List = Elm.Native.List.make(elm);
+    var Maybe = Elm.Maybe.make(elm);
+
+    function escape(str) {
+        return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+    }
+    function caseInsensitive(re) {
+        return new RegExp(re.source, 'gi');
+    }
+    function regex(raw) {
+        return new RegExp(raw, 'g');
+    }
+
+    function contains(re, string) {
+        return string.match(re) !== null;
+    }
+
+    function find(n, re, str) {
+        n = n.ctor === "All" ? Infinity : n._0;
+        var out = [];
+        var number = 0;
+        var string = str;
+        var result;
+        while (number++ < n && (result = re.exec(string))) {
+            var i = result.length - 1;
+            var subs = new Array(i);
+            while (i > 0) {
+                var submatch = result[i];
+                subs[--i] = submatch === undefined
+                    ? Maybe.Nothing
+                    : Maybe.Just(submatch);
+            }
+            out.push({
+                _:{},
+                match: result[0],
+                submatches: List.fromArray(subs),
+                index: result.index,
+                number: number
+            });
+        }
+        return List.fromArray(out);
+    }
+
+    function replace(n, re, replacer, string) {
+        n = n.ctor === "All" ? Infinity : n._0;
+        var count = 0;
+        function jsReplacer(match) {
+            if (count++ > n) return match;
+            var i = arguments.length-3;
+            var submatches = new Array(i);
+            while (i > 0) {
+                var submatch = arguments[i];
+                submatches[--i] = submatch === undefined
+                    ? Maybe.Nothing
+                    : Maybe.Just(submatch);
+            }
+            return replacer({
+                _:{},
+                match:match,
+                submatches:List.fromArray(submatches),
+                index:arguments[i-1],
+                number:count
+            });
+        }
+        return string.replace(re, jsReplacer);
+    }
+
+    function split(n, re, str) {
+        if (n === Infinity) {
+            return List.fromArray(string.split(re));
+        }
+        var string = str;
+        var result;
+        var out = [];
+        var start = re.lastIndex;
+        while (n--) {
+            if (!(result = re.exec(string))) break;
+            out.push(string.slice(start, result.index));
+            start = re.lastIndex;
+        }
+        out.push(string.slice(start));
+        return List.fromArray(out);
+    }
+
+    return Elm.Native.Regex.values = {
+        regex: regex,
+        caseInsensitive: caseInsensitive,
+        escape: escape,
+
+        contains: F2(contains),
+        find: F3(find),
+        replace: F4(replace),
+        split: F3(split)
+    };
+};
+ src/Native/Runtime.js view
@@ -0,0 +1,560 @@+
+if (!Elm.fullscreen) {
+
+    (function() {
+        'use strict';
+
+        var Display = { FULLSCREEN: 0, COMPONENT: 1, NONE: 2 };
+
+        Elm.fullscreen = function(module, ports) {
+            var container = document.createElement('div');
+            document.body.appendChild(container);
+            return init(Display.FULLSCREEN, container, module, ports || {});
+        };
+
+        Elm.embed = function(module, container, ports) {
+            var tag = container.tagName;
+            if (tag !== 'DIV') {
+                throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
+            } else if (container.hasChildNodes()) {
+                throw new Error('Elm.node must be given an empty DIV. No children allowed!');
+            }
+            return init(Display.COMPONENT, container, module, ports || {});
+        };
+
+        Elm.worker = function(module, ports) {
+            return init(Display.NONE, {}, module, ports || {});
+        };
+
+        function init(display, container, module, ports, moduleToReplace) {
+            // defining state needed for an instance of the Elm RTS
+            var inputs = [];
+
+            /* OFFSET
+             * Elm's time traveling debugger lets you interrupt the smooth flow of time
+             * by pausing and continuing program execution. To ensure the user sees a
+             * program that moves smoothly through the pause/continue time gap,
+             * we need to adjsut the value of Date.now().
+             */
+            var timer = function() {
+                var inducedDelay = 0;
+
+                var now = function() {
+                    return Date.now() - inducedDelay;
+                };
+
+                var addDelay = function(d) {
+                    inducedDelay += d;
+                    return inducedDelay;
+                };
+
+                return {
+                    now : now,
+                    addDelay : addDelay
+                }
+            }();
+
+            var updateInProgress = false;
+            function notify(id, v) {
+                if (updateInProgress) {
+                    throw new Error(
+                        'The notify function has been called synchronously!\n' +
+                        'This can lead to frames being dropped.\n' +
+                        'Definitely report this to <https://github.com/elm-lang/Elm/issues>\n');
+                }
+                updateInProgress = true;
+                var timestep = timer.now();
+                for (var i = inputs.length; i--; ) {
+                    inputs[i].recv(timestep, id, v);
+                }
+                updateInProgress = false;
+            }
+            function setTimeout(func, delay) {
+                window.setTimeout(func, delay);
+            }
+
+            var listeners = [];
+            function addListener(relevantInputs, domNode, eventName, func) {
+                domNode.addEventListener(eventName, func);
+                var listener = {
+                    relevantInputs: relevantInputs,
+                    domNode: domNode,
+                    eventName: eventName,
+                    func: func
+                };
+                listeners.push(listener);
+            }
+
+            var portUses = {}
+            for (var key in ports) {
+                portUses[key] = 0;
+            }
+            // create the actual RTS. Any impure modules will attach themselves to this
+            // object. This permits many Elm programs to be embedded per document.
+            var elm = {
+                notify: notify,
+                setTimeout: setTimeout,
+                node: container,
+                addListener: addListener,
+                inputs: inputs,
+                timer: timer,
+                ports: { incoming:ports, outgoing:{}, uses:portUses },
+
+                isFullscreen: function() { return display === Display.FULLSCREEN; },
+                isEmbed: function() { return display === Display.COMPONENT; },
+                isWorker: function() { return display === Display.NONE; }
+            };
+
+            function swap(newModule) {
+                removeListeners(listeners);
+                var div = document.createElement('div');
+                var newElm = init(display, div, newModule, ports, elm);
+                inputs = [];
+                // elm.swap = newElm.swap;
+                return newElm;
+            }
+
+            function dispose() {
+                removeListeners(listeners);
+                inputs = [];
+            }
+
+            var Module = {};
+            try {
+                Module = module.make(elm);
+                checkPorts(elm);
+            } catch(e) {
+                var code = document.createElement('code');
+
+                var lines = e.message.split('\n');
+                code.appendChild(document.createTextNode(lines[0]));
+                code.appendChild(document.createElement('br'));
+                code.appendChild(document.createElement('br'));
+                for (var i = 1; i < lines.length; ++i) {
+                    code.appendChild(document.createTextNode('\u00A0 \u00A0 ' + lines[i]));
+                    code.appendChild(document.createElement('br'));
+                }
+                code.appendChild(document.createElement('br'));
+                code.appendChild(document.createTextNode("Open the developer console for more details."));
+
+                container.appendChild(code);
+                throw e;
+            }
+            inputs = filterDeadInputs(inputs);
+            filterListeners(inputs, listeners);
+            addReceivers(elm.ports.outgoing);
+            if (display !== Display.NONE) {
+                var graphicsNode = initGraphics(elm, Module);
+            }
+            if (typeof moduleToReplace !== 'undefined') {
+                hotSwap(moduleToReplace, elm);
+
+                // rerender scene if graphics are enabled.
+                if (typeof graphicsNode !== 'undefined') {
+                    graphicsNode.recv(0, true, 0);
+                }
+            }
+
+            return {
+                swap:swap,
+                ports:elm.ports.outgoing,
+                dispose:dispose
+            };
+        };
+
+        function checkPorts(elm) {
+            var portUses = elm.ports.uses;
+            for (var key in portUses) {
+                var uses = portUses[key]
+                if (uses === 0) {
+                    throw new Error(
+                        "Initialization Error: provided port '" + key +
+                        "' to a module that does not take it as in input.\n" +
+                        "Remove '" + key + "' from the module initialization code.");
+                } else if (uses > 1) {
+                    throw new Error(
+                        "Initialization Error: port '" + key +
+                        "' has been declared multiple times in the Elm code.\n" +
+                        "Remove declarations until there is exactly one.");
+                }
+            }
+        }
+
+
+        //// FILTER SIGNALS ////
+
+        // TODO: move this code into the signal module and create a function
+        // Signal.initializeGraph that actually instantiates everything.
+
+        function filterListeners(inputs, listeners) {
+            loop:
+            for (var i = listeners.length; i--; ) {
+                var listener = listeners[i];
+                for (var j = inputs.length; j--; ) {
+                    if (listener.relevantInputs.indexOf(inputs[j].id) >= 0) {
+                        continue loop;
+                    }
+                }
+                listener.domNode.removeEventListener(listener.eventName, listener.func);
+            }
+        }
+
+        function removeListeners(listeners) {
+            for (var i = listeners.length; i--; ) {
+                var listener = listeners[i];
+                listener.domNode.removeEventListener(listener.eventName, listener.func);
+            }
+        }
+
+        // add receivers for built-in ports if they are defined
+        function addReceivers(ports) {
+            if ('log' in ports) {
+                ports.log.subscribe(function(v) { console.log(v) });
+            }
+            if ('stdout' in ports) {
+                var process = process || {};
+                var handler = process.stdout
+                    ? function(v) { process.stdout.write(v); }
+                    : function(v) { console.log(v); };
+                ports.stdout.subscribe(handler);
+            }
+            if ('stderr' in ports) {
+                var process = process || {};
+                var handler = process.stderr
+                    ? function(v) { process.stderr.write(v); }
+                    : function(v) { console.log('Error:' + v); };
+                ports.stderr.subscribe(handler);
+            }
+            if ('title' in ports) {
+                if (typeof ports.title === 'string') {
+                    document.title = ports.title;
+                } else {
+                    ports.title.subscribe(function(v) { document.title = v; });
+                }
+            }
+            if ('redirect' in ports) {
+                ports.redirect.subscribe(function(v) {
+                    if (v.length > 0) window.location = v;
+                });
+            }
+            if ('favicon' in ports) {
+                if (typeof ports.favicon === 'string') {
+                    changeFavicon(ports.favicon);
+                } else {
+                    ports.favicon.subscribe(changeFavicon);
+                }
+            }
+            function changeFavicon(src) {
+                var link = document.createElement('link');
+                var oldLink = document.getElementById('elm-favicon');
+                link.id = 'elm-favicon';
+                link.rel = 'shortcut icon';
+                link.href = src;
+                if (oldLink) {
+                    document.head.removeChild(oldLink);
+                }
+                document.head.appendChild(link);
+            }
+        }
+
+
+        function filterDeadInputs(inputs) {
+            var temp = [];
+            for (var i = inputs.length; i--; ) {
+                if (isAlive(inputs[i])) temp.push(inputs[i]);
+            }
+            return temp;
+        }
+
+
+        function isAlive(input) {
+            if (!('defaultNumberOfKids' in input)) return true;
+            var len = input.kids.length;
+            if (len === 0) return false;
+            if (len > input.defaultNumberOfKids) return true;
+            var alive = false;
+            for (var i = len; i--; ) {
+                alive = alive || isAlive(input.kids[i]);
+            }
+            return alive;
+        }
+
+
+        ////  RENDERING  ////
+
+        function initGraphics(elm, Module) {
+            if (!('main' in Module)) {
+                throw new Error("'main' is missing! What do I display?!");
+            }
+
+            var signalGraph = Module.main;
+
+            // make sure the signal graph is actually a signal & extract the visual model
+            var Signal = Elm.Signal.make(elm);
+            if (!('recv' in signalGraph)) {
+                signalGraph = Signal.constant(signalGraph);
+            }
+            var initialScene = signalGraph.value;
+
+            // Add the initialScene to the DOM
+            var Element = Elm.Native.Graphics.Element.make(elm);
+            elm.node.appendChild(Element.render(initialScene));
+
+            var _requestAnimationFrame =
+                typeof requestAnimationFrame !== 'undefined'
+                    ? requestAnimationFrame
+                    : function(cb) { setTimeout(cb, 1000/60); }
+                    ;
+
+            // domUpdate is called whenever the main Signal changes.
+            //
+            // domUpdate and drawCallback implement a small state machine in order
+            // to schedule only 1 draw per animation frame. This enforces that
+            // once draw has been called, it will not be called again until the
+            // next frame.
+            //
+            // drawCallback is scheduled whenever
+            // 1. The state transitions from PENDING_REQUEST to EXTRA_REQUEST, or
+            // 2. The state transitions from NO_REQUEST to PENDING_REQUEST
+            //
+            // Invariants:
+            // 1. In the NO_REQUEST state, there is never a scheduled drawCallback.
+            // 2. In the PENDING_REQUEST and EXTRA_REQUEST states, there is always exactly 1
+            //    scheduled drawCallback.
+            var NO_REQUEST = 0;
+            var PENDING_REQUEST = 1;
+            var EXTRA_REQUEST = 2;
+            var state = NO_REQUEST;
+            var savedScene = initialScene;
+            var scheduledScene = initialScene;
+
+            function domUpdate(newScene) {
+                scheduledScene = newScene;
+
+                switch (state) {
+                    case NO_REQUEST:
+                        _requestAnimationFrame(drawCallback);
+                        state = PENDING_REQUEST;
+                        return;
+                    case PENDING_REQUEST:
+                        state = PENDING_REQUEST;
+                        return;
+                    case EXTRA_REQUEST:
+                        state = PENDING_REQUEST;
+                        return;
+                }
+            }
+
+            function drawCallback() {
+                switch (state) {
+                    case NO_REQUEST:
+                        // This state should not be possible. How can there be no
+                        // request, yet somehow we are actively fulfilling a
+                        // request?
+                        throw new Error(
+                            "Unexpected draw callback.\n" +
+                            "Please report this to <https://github.com/elm-lang/core/issues>."
+                        );
+
+                    case PENDING_REQUEST:
+                        // At this point, we do not *know* that another frame is
+                        // needed, but we make an extra request to rAF just in
+                        // case. It's possible to drop a frame if rAF is called
+                        // too late, so we just do it preemptively.
+                        _requestAnimationFrame(drawCallback);
+                        state = EXTRA_REQUEST;
+
+                        // There's also stuff we definitely need to draw.
+                        draw();
+                        return;
+
+                    case EXTRA_REQUEST:
+                        // Turns out the extra request was not needed, so we will
+                        // stop calling rAF. No reason to call it all the time if
+                        // no one needs it.
+                        state = NO_REQUEST;
+                        return;
+                }
+            }
+
+            function draw() {
+                Element.updateAndReplace(elm.node.firstChild, savedScene, scheduledScene);
+                if (elm.Native.Window) {
+                    elm.Native.Window.values.resizeIfNeeded();
+                }
+                savedScene = scheduledScene;
+            }
+
+            var renderer = A2(Signal.map, domUpdate, signalGraph);
+
+            // must check for resize after 'renderer' is created so
+            // that changes show up.
+            if (elm.Native.Window) {
+                elm.Native.Window.values.resizeIfNeeded();
+            }
+
+            return renderer;
+        }
+
+        //// HOT SWAPPING ////
+
+        // Returns boolean indicating if the swap was successful.
+        // Requires that the two signal graphs have exactly the same
+        // structure.
+        function hotSwap(from, to) {
+            function similar(nodeOld,nodeNew) {
+                var idOkay = nodeOld.id === nodeNew.id;
+                var lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
+                return idOkay && lengthOkay;
+            }
+            function swap(nodeOld,nodeNew) {
+                nodeNew.value = nodeOld.value;
+                return true;
+            }
+            var canSwap = depthFirstTraversals(similar, from.inputs, to.inputs);
+            if (canSwap) {
+                depthFirstTraversals(swap, from.inputs, to.inputs);
+            }
+            from.node.parentNode.replaceChild(to.node, from.node);
+
+            return canSwap;
+        }
+
+        // Returns false if the node operation f ever fails.
+        function depthFirstTraversals(f, queueOld, queueNew) {
+            if (queueOld.length !== queueNew.length) return false;
+            queueOld = queueOld.slice(0);
+            queueNew = queueNew.slice(0);
+
+            var seen = [];
+            while (queueOld.length > 0 && queueNew.length > 0) {
+                var nodeOld = queueOld.pop();
+                var nodeNew = queueNew.pop();
+                if (seen.indexOf(nodeOld.id) < 0) {
+                    if (!f(nodeOld, nodeNew)) return false;
+                    queueOld = queueOld.concat(nodeOld.kids);
+                    queueNew = queueNew.concat(nodeNew.kids);
+                    seen.push(nodeOld.id);
+                }
+            }
+            return true;
+        }
+    }());
+
+    function F2(fun) {
+        function wrapper(a) { return function(b) { return fun(a,b) } }
+        wrapper.arity = 2;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F3(fun) {
+        function wrapper(a) {
+            return function(b) { return function(c) { return fun(a,b,c) }}
+        }
+        wrapper.arity = 3;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F4(fun) {
+        function wrapper(a) { return function(b) { return function(c) {
+            return function(d) { return fun(a,b,c,d) }}}
+        }
+        wrapper.arity = 4;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F5(fun) {
+        function wrapper(a) { return function(b) { return function(c) {
+            return function(d) { return function(e) { return fun(a,b,c,d,e) }}}}
+        }
+        wrapper.arity = 5;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F6(fun) {
+        function wrapper(a) { return function(b) { return function(c) {
+            return function(d) { return function(e) { return function(f) {
+            return fun(a,b,c,d,e,f) }}}}}
+        }
+        wrapper.arity = 6;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F7(fun) {
+        function wrapper(a) { return function(b) { return function(c) {
+            return function(d) { return function(e) { return function(f) {
+            return function(g) { return fun(a,b,c,d,e,f,g) }}}}}}
+        }
+        wrapper.arity = 7;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F8(fun) {
+        function wrapper(a) { return function(b) { return function(c) {
+            return function(d) { return function(e) { return function(f) {
+            return function(g) { return function(h) {
+            return fun(a,b,c,d,e,f,g,h)}}}}}}}
+        }
+        wrapper.arity = 8;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function F9(fun) {
+        function wrapper(a) { return function(b) { return function(c) {
+            return function(d) { return function(e) { return function(f) {
+            return function(g) { return function(h) { return function(i) {
+            return fun(a,b,c,d,e,f,g,h,i) }}}}}}}}
+        }
+        wrapper.arity = 9;
+        wrapper.func = fun;
+        return wrapper;
+    }
+
+    function A2(fun,a,b) {
+        return fun.arity === 2
+            ? fun.func(a,b)
+            : fun(a)(b);
+    }
+    function A3(fun,a,b,c) {
+        return fun.arity === 3
+            ? fun.func(a,b,c)
+            : fun(a)(b)(c);
+    }
+    function A4(fun,a,b,c,d) {
+        return fun.arity === 4
+            ? fun.func(a,b,c,d)
+            : fun(a)(b)(c)(d);
+    }
+    function A5(fun,a,b,c,d,e) {
+        return fun.arity === 5
+            ? fun.func(a,b,c,d,e)
+            : fun(a)(b)(c)(d)(e);
+    }
+    function A6(fun,a,b,c,d,e,f) {
+        return fun.arity === 6
+            ? fun.func(a,b,c,d,e,f)
+            : fun(a)(b)(c)(d)(e)(f);
+    }
+    function A7(fun,a,b,c,d,e,f,g) {
+        return fun.arity === 7
+            ? fun.func(a,b,c,d,e,f,g)
+            : fun(a)(b)(c)(d)(e)(f)(g);
+    }
+    function A8(fun,a,b,c,d,e,f,g,h) {
+        return fun.arity === 8
+            ? fun.func(a,b,c,d,e,f,g,h)
+            : fun(a)(b)(c)(d)(e)(f)(g)(h);
+    }
+    function A9(fun,a,b,c,d,e,f,g,h,i) {
+        return fun.arity === 9
+            ? fun.func(a,b,c,d,e,f,g,h,i)
+            : fun(a)(b)(c)(d)(e)(f)(g)(h)(i);
+    }
+}
+ src/Native/Show.js view
@@ -0,0 +1,150 @@+Elm.Native.Show = {};
+Elm.Native.Show.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Show = elm.Native.Show || {};
+    if (elm.Native.Show.values) return elm.Native.Show.values;
+
+    var _Array;
+    var Dict;
+    var List;
+    var Utils = Elm.Native.Utils.make(elm);
+
+    var toString = function(v) {
+        var type = typeof v;
+        if (type === "function") {
+            var name = v.func ? v.func.name : v.name;
+            return '<function' + (name === '' ? '' : ': ') + name + '>';
+        }
+        else if (type === "boolean") {
+            return v ? "True" : "False";
+        }
+        else if (type === "number") {
+            return v + "";
+        }
+        else if ((v instanceof String) && v.isChar) {
+            return "'" + addSlashes(v) + "'";
+        }
+        else if (type === "string") {
+            return '"' + addSlashes(v) + '"';
+        }
+        else if (type === "object" && '_' in v && probablyPublic(v)) {
+            var output = [];
+            for (var k in v._) {
+                for (var i = v._[k].length; i--; ) {
+                    output.push(k + " = " + toString(v._[k][i]));
+                }
+            }
+            for (var k in v) {
+                if (k === '_') continue;
+                output.push(k + " = " + toString(v[k]));
+            }
+            if (output.length === 0) {
+                return "{}";
+            }
+            return "{ " + output.join(", ") + " }";
+        }
+        else if (type === "object" && 'ctor' in v) {
+            if (v.ctor.substring(0,6) === "_Tuple") {
+                var output = [];
+                for (var k in v) {
+                    if (k === 'ctor') continue;
+                    output.push(toString(v[k]));
+                }
+                return "(" + output.join(",") + ")";
+            }
+            else if (v.ctor === "_Array") {
+                if (!_Array) {
+                    _Array = Elm.Array.make(elm);
+                }
+                var list = _Array.toList(v);
+                return "Array.fromList " + toString(list);
+            }
+            else if (v.ctor === "::") {
+                var output = '[' + toString(v._0);
+                v = v._1;
+                while (v.ctor === "::") {
+                    output += "," + toString(v._0);
+                    v = v._1;
+                }
+                return output + ']';
+            }
+            else if (v.ctor === "[]") {
+                return "[]";
+            }
+            else if (v.ctor === "RBNode" || v.ctor === "RBEmpty") {
+                if (!Dict) {
+                    Dict = Elm.Dict.make(elm);
+                }
+                if (!List) {
+                    List = Elm.List.make(elm);
+                }
+                var list = Dict.toList(v);
+                var name = "Dict";
+                if (list.ctor === "::" && list._0._1.ctor === "_Tuple0") {
+                    name = "Set";
+                    list = A2(List.map, function(x){return x._0}, list);
+                }
+                return name + ".fromList " + toString(list);
+            }
+            else {
+                var output = "";
+                for (var i in v) {
+                    if (i === 'ctor') continue;
+                    var str = toString(v[i]);
+                    var parenless = str[0] === '{' || str[0] === '<' || str.indexOf(' ') < 0;
+                    output += ' ' + (parenless ? str : '(' + str + ')');
+                }
+                return v.ctor + output;
+            }
+        }
+        if (type === 'object' && 'recv' in v) {
+            return '<signal>';
+        }
+        return "<internal structure>";
+    };
+
+    function addSlashes(str) {
+        return str.replace(/\\/g, '\\\\')
+                  .replace(/\n/g, '\\n')
+                  .replace(/\t/g, '\\t')
+                  .replace(/\r/g, '\\r')
+                  .replace(/\v/g, '\\v')
+                  .replace(/\0/g, '\\0')
+                  .replace(/\'/g, "\\'")
+                  .replace(/\"/g, '\\"');
+    }
+
+    function probablyPublic(v) {
+        var keys = Object.keys(v);
+        var len = keys.length;
+        if (len === 3
+            && 'props' in v
+            && 'element' in v)
+        {
+            return false;
+        }
+        else if (len === 5
+            && 'horizontal' in v
+            && 'vertical' in v
+            && 'x' in v
+            && 'y' in v)
+        {
+            return false;
+        }
+        else if (len === 7
+            && 'theta' in v
+            && 'scale' in v
+            && 'x' in v
+            && 'y' in v
+            && 'alpha' in v
+            && 'form' in v)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    return elm.Native.Show.values = {
+        toString: toString
+    };
+};
+ src/Native/Signal.js view
@@ -0,0 +1,235 @@+
+Elm.Native.Signal = {};
+Elm.Native.Signal.make = function(localRuntime) {
+
+  localRuntime.Native = localRuntime.Native || {};
+  localRuntime.Native.Signal = localRuntime.Native.Signal || {};
+  if (localRuntime.Native.Signal.values) {
+      return localRuntime.Native.Signal.values;
+  }
+
+  var Utils = Elm.Native.Utils.make(localRuntime);
+
+  function broadcastToKids(node, timestep, changed) {
+    var kids = node.kids;
+    for (var i = kids.length; i--; ) {
+      kids[i].recv(timestep, changed, node.id);
+    }
+  }
+
+  function Input(base) {
+    this.id = Utils.guid();
+    this.value = base;
+    this.kids = [];
+    this.defaultNumberOfKids = 0;
+    this.recv = function(timestep, eid, v) {
+      var changed = eid === this.id;
+      if (changed) {
+        this.value = v;
+      }
+      broadcastToKids(this, timestep, changed);
+      return changed;
+    };
+    localRuntime.inputs.push(this);
+  }
+
+  function LiftN(update, args) {
+    this.id = Utils.guid();
+    this.value = update();
+    this.kids = [];
+
+    var n = args.length;
+    var count = 0;
+    var isChanged = false;
+
+    this.recv = function(timestep, changed, parentID) {
+      ++count;
+      if (changed) { isChanged = true; }
+      if (count == n) {
+        if (isChanged) { this.value = update(); }
+        broadcastToKids(this, timestep, isChanged);
+        isChanged = false;
+        count = 0;
+      }
+    };
+    for (var i = n; i--; ) { args[i].kids.push(this); }
+  }
+
+  function map(func, a) {
+    function update() { return func(a.value); }
+    return new LiftN(update, [a]);
+  }
+  function map2(func, a, b) {
+    function update() { return A2( func, a.value, b.value ); }
+    return new LiftN(update, [a,b]);
+  }
+  function map3(func, a, b, c) {
+    function update() { return A3( func, a.value, b.value, c.value ); }
+    return new LiftN(update, [a,b,c]);
+  }
+  function map4(func, a, b, c, d) {
+    function update() { return A4( func, a.value, b.value, c.value, d.value ); }
+    return new LiftN(update, [a,b,c,d]);
+  }
+  function map5(func, a, b, c, d, e) {
+    function update() { return A5( func, a.value, b.value, c.value, d.value, e.value ); }
+    return new LiftN(update, [a,b,c,d,e]);
+  }
+
+  function Foldp(step, state, input) {
+    this.id = Utils.guid();
+    this.value = state;
+    this.kids = [];
+
+    this.recv = function(timestep, changed, parentID) {
+      if (changed) {
+          this.value = A2( step, input.value, this.value );
+      }
+      broadcastToKids(this, timestep, changed);
+    };
+    input.kids.push(this);
+  }
+
+  function foldp(step, state, input) {
+      return new Foldp(step, state, input);
+  }
+
+  function DropIf(pred,base,input) {
+    this.id = Utils.guid();
+    this.value = pred(input.value) ? base : input.value;
+    this.kids = [];
+    this.recv = function(timestep, changed, parentID) {
+      var chng = changed && !pred(input.value);
+      if (chng) { this.value = input.value; }
+      broadcastToKids(this, timestep, chng);
+    };
+    input.kids.push(this);
+  }
+
+  function DropRepeats(input) {
+    this.id = Utils.guid();
+    this.value = input.value;
+    this.kids = [];
+    this.recv = function(timestep, changed, parentID) {
+      var chng = changed && !Utils.eq(this.value,input.value);
+      if (chng) { this.value = input.value; }
+      broadcastToKids(this, timestep, chng);
+    };
+    input.kids.push(this);
+  }
+
+  function timestamp(a) {
+    function update() { return Utils.Tuple2(localRuntime.timer.now(), a.value); }
+    return new LiftN(update, [a]);
+  }
+
+  function SampleOn(s1,s2) {
+    this.id = Utils.guid();
+    this.value = s2.value;
+    this.kids = [];
+
+    var count = 0;
+    var isChanged = false;
+
+    this.recv = function(timestep, changed, parentID) {
+      if (parentID === s1.id) isChanged = changed;
+      ++count;
+      if (count == 2) {
+        if (isChanged) { this.value = s2.value; }
+        broadcastToKids(this, timestep, isChanged);
+        count = 0;
+        isChanged = false;
+      }
+    };
+    s1.kids.push(this);
+    s2.kids.push(this);
+  }
+
+  function sampleOn(s1,s2) { return new SampleOn(s1,s2); }
+
+  function delay(t,s) {
+      var delayed = new Input(s.value);
+      var firstEvent = true;
+      function update(v) {
+        if (firstEvent) {
+            firstEvent = false; return;
+        }
+        setTimeout(function() {
+            localRuntime.notify(delayed.id, v);
+        }, t);
+      }
+      function first(a,b) { return a; }
+      return new SampleOn(delayed, map2(F2(first), delayed, map(update,s)));
+  }
+
+  function Merge(s1,s2) {
+      this.id = Utils.guid();
+      this.value = s1.value;
+      this.kids = [];
+
+      var next = null;
+      var count = 0;
+      var isChanged = false;
+
+      this.recv = function(timestep, changed, parentID) {
+        ++count;
+        if (changed) {
+            isChanged = true;
+            if (parentID == s2.id && next === null) { next = s2.value; }
+            if (parentID == s1.id) { next = s1.value; }
+        }
+
+        if (count == 2) {
+            if (isChanged) { this.value = next; next = null; }
+            broadcastToKids(this, timestep, isChanged);
+            isChanged = false;
+            count = 0;
+        }
+      };
+      s1.kids.push(this);
+      s2.kids.push(this);
+  }
+
+  function merge(s1,s2) {
+      return new Merge(s1,s2);
+  }
+
+
+    // SIGNAL INPUTS
+
+    function input(initialValue) {
+        return new Input(initialValue);
+    }
+
+    function send(input, value) {
+        return function() {
+            localRuntime.notify(input.id, value);
+        };
+    }
+
+    function subscribe(input) {
+        return input;
+    }
+
+
+  return localRuntime.Native.Signal.values = {
+    constant : function(v) { return new Input(v); },
+    map  : F2(map ),
+    map2 : F3(map2),
+    map3 : F4(map3),
+    map4 : F5(map4),
+    map5 : F6(map5),
+    foldp : F3(foldp),
+    delay : F2(delay),
+    merge : F2(merge),
+    keepIf : F3(function(pred,base,sig) {
+      return new DropIf(function(x) {return !pred(x);},base,sig); }),
+    dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }),
+    dropRepeats : function(s) { return new DropRepeats(s);},
+    sampleOn : F2(sampleOn),
+    timestamp : timestamp,
+    input: input,
+    send: F2(send),
+    subscribe: subscribe
+  };
+};
+ src/Native/String.js view
@@ -0,0 +1,269 @@+Elm.Native.String = {};
+Elm.Native.String.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.String = elm.Native.String || {};
+    if (elm.Native.String.values) return elm.Native.String.values;
+    if ('values' in Elm.Native.String) {
+        return elm.Native.String.values = Elm.Native.String.values;
+    }
+
+    var Char = Elm.Char.make(elm);
+    var List = Elm.Native.List.make(elm);
+    var Maybe = Elm.Maybe.make(elm);
+    var Result = Elm.Result.make(elm);
+    var Utils = Elm.Native.Utils.make(elm);
+
+    function isEmpty(str) {
+        return str.length === 0;
+    }
+    function cons(chr,str) {
+        return chr + str;
+    }
+    function uncons(str) {
+        var hd;
+        return (hd = str[0])
+            ? Maybe.Just(Utils.Tuple2(Utils.chr(hd), str.slice(1)))
+            : Maybe.Nothing;
+    }
+    function append(a,b) {
+        return a + b;
+    }
+    function concat(strs) {
+        return List.toArray(strs).join('');
+    }
+    function length(str) {
+        return str.length;
+    }
+    function map(f,str) {
+        var out = str.split('');
+        for (var i = out.length; i--; ) {
+            out[i] = f(Utils.chr(out[i]));
+        }
+        return out.join('');
+    }
+    function filter(pred,str) {
+        return str.split('').map(Utils.chr).filter(pred).join('');
+    }
+    function reverse(str) {
+        return str.split('').reverse().join('');
+    }
+    function foldl(f,b,str) {
+        var len = str.length;
+        for (var i = 0; i < len; ++i) {
+            b = A2(f, Utils.chr(str[i]), b);
+        }
+        return b;
+    }
+    function foldr(f,b,str) {
+        for (var i = str.length; i--; ) {
+            b = A2(f, Utils.chr(str[i]), b);
+        }
+        return b;
+    }
+
+    function split(sep, str) {
+        return List.fromArray(str.split(sep));
+    }
+    function join(sep, strs) {
+        return List.toArray(strs).join(sep);
+    }
+    function repeat(n, str) {
+        var result = '';
+        while (n > 0) {
+            if (n & 1) result += str;
+            n >>= 1, str += str;
+        }
+        return result;
+    }
+
+    function slice(start, end, str) {
+        return str.slice(start,end);
+    }
+    function left(n, str) {
+        return n < 1 ? "" : str.slice(0,n);
+    }
+    function right(n, str) {
+        return n < 1 ? "" : str.slice(-n);
+    }
+    function dropLeft(n, str) {
+        return n < 1 ? str : str.slice(n);
+    }
+    function dropRight(n, str) {
+        return n < 1 ? str : str.slice(0,-n);
+    }
+
+    function pad(n,chr,str) {
+        var half = (n - str.length) / 2;
+        return repeat(Math.ceil(half),chr) + str + repeat(half|0,chr);
+    }
+    function padRight(n,chr,str) {
+        return str + repeat(n - str.length, chr);
+    }
+    function padLeft(n,chr,str) {
+        return repeat(n - str.length, chr) + str;
+    }
+
+    function trim(str) {
+        return str.trim();
+    }
+    function trimLeft(str) {
+        return str.trimLeft();
+    }
+    function trimRight(str) {
+        return str.trimRight();
+    }
+
+    function words(str) {
+        return List.fromArray(str.trim().split(/\s+/g));
+    }
+    function lines(str) {
+        return List.fromArray(str.split(/\r\n|\r|\n/g));
+    }
+
+    function toUpper(str) {
+        return str.toUpperCase();
+    }
+    function toLower(str) {
+        return str.toLowerCase();
+    }
+
+    function any(pred, str) {
+        for (var i = str.length; i--; ) {
+            if (pred(Utils.chr(str[i]))) return true;
+        }
+        return false;
+    }
+    function all(pred, str) {
+        for (var i = str.length; i--; ) {
+            if (!pred(Utils.chr(str[i]))) return false;
+        }
+        return true;
+    }
+
+    function contains(sub, str) {
+        return str.indexOf(sub) > -1;
+    }
+    function startsWith(sub, str) {
+        return str.indexOf(sub) === 0;
+    }
+    function endsWith(sub, str) {
+        return str.length >= sub.length &&
+               str.lastIndexOf(sub) === str.length - sub.length;
+    }
+    function indexes(sub, str) {
+        var subLen = sub.length;
+        var i = 0;
+        var is = [];
+        while ((i = str.indexOf(sub, i)) > -1) {
+            is.push(i);
+            i = i + subLen;
+        }
+        return List.fromArray(is);
+    }
+
+    function toInt(s) {
+        var len = s.length;
+        if (len === 0) {
+            return Result.Err("could not convert string '" + s + "' to an Int" );
+        }
+        var start = 0;
+        if (s[0] == '-') {
+            if (len === 1) {
+                return Result.Err("could not convert string '" + s + "' to an Int" );
+            }
+            start = 1;
+        }
+        for (var i = start; i < len; ++i) {
+            if (!Char.isDigit(s[i])) {
+                return Result.Err("could not convert string '" + s + "' to an Int" );
+            }
+        }
+        return Result.Ok(parseInt(s, 10));
+    }
+
+    function toFloat(s) {
+        var len = s.length;
+        if (len === 0) {
+            return Result.Err("could not convert string '" + s + "' to a Float" );
+        }
+        var start = 0;
+        if (s[0] == '-') {
+            if (len === 1) {
+                return Result.Err("could not convert string '" + s + "' to a Float" );
+            }
+            start = 1;
+        }
+        var dotCount = 0;
+        for (var i = start; i < len; ++i) {
+            if (Char.isDigit(s[i])) {
+                continue;
+            }
+            if (s[i] === '.') {
+                dotCount += 1;
+                if (dotCount <= 1) {
+                    continue;
+                }
+            }
+            return Result.Err("could not convert string '" + s + "' to a Float" );
+        }
+        return Result.Ok(parseFloat(s));
+    }
+
+    function toList(str) {
+        return List.fromArray(str.split('').map(Utils.chr));
+    }
+    function fromList(chars) {
+        return List.toArray(chars).join('');
+    }
+
+    return Elm.Native.String.values = {
+        isEmpty: isEmpty,
+        cons: F2(cons),
+        uncons: uncons,
+        append: F2(append),
+        concat: concat,
+        length: length,
+        map: F2(map),
+        filter: F2(filter),
+        reverse: reverse,
+        foldl: F3(foldl),
+        foldr: F3(foldr),
+
+        split: F2(split),
+        join: F2(join),
+        repeat: F2(repeat),
+
+        slice: F3(slice),
+        left: F2(left),
+        right: F2(right),
+        dropLeft: F2(dropLeft),
+        dropRight: F2(dropRight),
+
+        pad: F3(pad),
+        padLeft: F3(padLeft),
+        padRight: F3(padRight),
+
+        trim: trim,
+        trimLeft: trimLeft,
+        trimRight: trimRight,
+
+        words: words,
+        lines: lines,
+
+        toUpper: toUpper,
+        toLower: toLower,
+
+        any: F2(any),
+        all: F2(all),
+
+        contains: F2(contains),
+        startsWith: F2(startsWith),
+        endsWith: F2(endsWith),
+        indexes: F2(indexes),
+
+        toInt: toInt,
+        toFloat: toFloat,
+        toList: toList,
+        fromList: fromList
+    };
+};
+ src/Native/Text.js view
@@ -0,0 +1,173 @@+Elm.Native.Text = {};
+Elm.Native.Text.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Text = elm.Native.Text || {};
+    if (elm.Native.Text.values) return elm.Native.Text.values;
+
+    var toCss = Elm.Native.Color.make(elm).toCss;
+    var Element = Elm.Graphics.Element.make(elm);
+    var NativeElement = Elm.Native.Graphics.Element.make(elm);
+    var List = Elm.Native.List.make(elm);
+    var Utils = Elm.Native.Utils.make(elm);
+
+    function makeSpaces(s) {
+        if (s.length == 0) { return s; }
+        var arr = s.split('');
+        if (arr[0] == ' ') { arr[0] = "&nbsp;" }      
+        for (var i = arr.length; --i; ) {
+            if (arr[i][0] == ' ' && arr[i-1] == ' ') {
+                arr[i-1] = arr[i-1] + arr[i];
+                arr[i] = '';
+            }
+        }
+        for (var i = arr.length; i--; ) {
+            if (arr[i].length > 1 && arr[i][0] == ' ') {
+                var spaces = arr[i].split('');
+                for (var j = spaces.length - 2; j >= 0; j -= 2) {
+                    spaces[j] = '&nbsp;';
+                }
+                arr[i] = spaces.join('');
+            }
+        }
+        arr = arr.join('');
+        if (arr[arr.length-1] === " ") {
+            return arr.slice(0,-1) + '&nbsp;';
+        }
+        return arr;
+    }
+
+    function properEscape(str) {
+        if (str.length == 0) return str;
+        str = str //.replace(/&/g,  "&#38;")
+            .replace(/"/g,  '&#34;')
+            .replace(/'/g,  "&#39;")
+            .replace(/</g,  "&#60;")
+            .replace(/>/g,  "&#62;")
+            .replace(/\n/g, "<br/>");
+        var arr = str.split('<br/>');
+        for (var i = arr.length; i--; ) {
+            arr[i] = makeSpaces(arr[i]);
+        }
+        return arr.join('<br/>');
+    }
+
+    function fromString(str) {
+        return Utils.txt(properEscape(str));
+    }
+
+    function append(xs, ys) {
+        return Utils.txt(Utils.makeText(xs) + Utils.makeText(ys));
+    }
+
+    // conversions from Elm values to CSS
+    function toTypefaces(list) {
+        var typefaces = List.toArray(list);
+        for (var i = typefaces.length; i--; ) {
+            var typeface = typefaces[i];
+            if (typeface.indexOf(' ') > -1) {
+                typefaces[i] = "'" + typeface + "'";
+            }
+        }
+        return typefaces.join(',');
+    }
+    function toLine(line) {
+        var ctor = line.ctor;
+        return ctor === 'Under' ? 'underline' :
+               ctor === 'Over'  ? 'overline'  : 'line-through';
+    }
+
+    // setting styles of Text
+    function style(style, text) {
+        var newText = '<span style="color:' + toCss(style.color) + ';'
+        if (style.typeface.ctor !== '[]') {
+            newText += 'font-family:' + toTypefaces(style.typeface) + ';'
+        }
+        if (style.height.ctor !== "Nothing") {
+            newText += 'font-size:' + style.height._0 + 'px;';
+        }
+        if (style.bold) {
+            newText += 'font-weight:bold;';
+        }
+        if (style.italic) {
+            newText += 'font-style:italic;';
+        }
+        if (style.line.ctor !== 'Nothing') {
+            newText += 'text-decoration:' + toLine(style.line._0) + ';';
+        }
+        newText += '">' + Utils.makeText(text) + '</span>'
+        return Utils.txt(newText);
+    }
+    function height(px, text) {
+        return { style: 'font-size:' + px + 'px;', text:text }
+    }
+    function typeface(names, text) {
+        return { style: 'font-family:' + toTypefaces(names) + ';', text:text }
+    }
+    function monospace(text) {
+        return { style: 'font-family:monospace;', text:text }
+    }
+    function italic(text) {
+        return { style: 'font-style:italic;', text:text }
+    }
+    function bold(text) {
+        return { style: 'font-weight:bold;', text:text }
+    }
+    function link(href, text) {
+        return { href: fromString(href), text:text };
+    }
+    function line(line, text) {
+        return { style: 'text-decoration:' + toLine(line) + ';', text:text };
+    }
+
+    function color(color, text) {
+        return { style: 'color:' + toCss(color) + ';', text:text };
+    }
+
+    function block(align) {
+        return function(text) {
+            var raw = {
+                ctor :'RawHtml',
+                html : Utils.makeText(text),
+                align: align,
+                guid : null
+            };
+            var pos = A2(NativeElement.htmlHeight, 0, raw);
+            return A3(Element.newElement, pos._0, pos._1, raw);
+        }
+    }
+
+    function markdown(text, guid) {
+        var raw = {
+            ctor:'RawHtml',
+            html: text,
+            align: null,
+            guid: guid
+        };
+        var pos = A2(NativeElement.htmlHeight, 0, raw);
+        return A3(Element.newElement, pos._0, pos._1, raw);
+    }
+
+    return elm.Native.Text.values = {
+        fromString: fromString,
+        append: F2(append),
+
+        height : F2(height),
+        italic : italic,
+        bold : bold,
+        line : F2(line),
+        monospace : monospace,
+        typeface : F2(typeface),
+        color : F2(color),
+        link : F2(link),
+        style : F2(style),
+
+        leftAligned  : block('left'),
+        rightAligned : block('right'),
+        centered     : block('center'),
+        justified    : block('justify'),
+        markdown     : markdown,
+
+        toTypefaces:toTypefaces,
+        toLine:toLine
+    };
+};
+ src/Native/Time.js view
@@ -0,0 +1,64 @@+Elm.Native.Time = {};
+Elm.Native.Time.make = function(elm) {
+
+  elm.Native = elm.Native || {};
+  elm.Native.Time = elm.Native.Time || {};
+  if (elm.Native.Time.values) return elm.Native.Time.values;
+
+  var Signal = Elm.Signal.make(elm);
+  var NS = Elm.Native.Signal.make(elm);
+  var Maybe = Elm.Maybe.make(elm);
+  var Utils = Elm.Native.Utils.make(elm);
+
+  function fpsWhen(desiredFPS, isOn) {
+    var msPerFrame = 1000 / desiredFPS;
+    var prev = elm.timer.now(), curr = prev, diff = 0, wasOn = true;
+    var ticker = NS.input(diff);
+    function tick(zero) {
+      return function() {
+        curr = elm.timer.now();
+        diff = zero ? 0 : curr - prev;
+        if (prev > curr) {
+          diff = 0;
+        }
+        prev = curr;
+        elm.notify(ticker.id, diff);
+      };
+    }
+    var timeoutID = 0;
+    function f(isOn, t) {
+      if (isOn) {
+        timeoutID = elm.setTimeout(tick(!wasOn && isOn), msPerFrame);
+      } else if (wasOn) {
+        clearTimeout(timeoutID);
+      }
+      wasOn = isOn;
+      return t;
+    }
+    return A3( Signal.map2, F2(f), isOn, ticker );
+  }
+
+  function every(t) {
+    var clock = NS.input(elm.timer.now());
+    function tellTime() {
+        elm.notify(clock.id, elm.timer.now());
+    }
+    setInterval(tellTime, t);
+    return clock;
+  }
+
+  function read(s) {
+      var t = Date.parse(s);
+      return isNaN(t) ? Maybe.Nothing : Maybe.Just(t);
+  }
+  return elm.Native.Time.values = {
+      fpsWhen : F2(fpsWhen),
+      fps : function(t) { return fpsWhen(t, Signal.constant(true)); },
+      every : every,
+      delay : NS.delay,
+      timestamp : NS.timestamp,
+      toDate : function(t) { return new window.Date(t); },
+      read   : read
+  };
+
+};
+ src/Native/Touch.js view
@@ -0,0 +1,171 @@+Elm.Native = Elm.Native || {};
+Elm.Native.Touch = {};
+Elm.Native.Touch.make = function(localRuntime) {
+
+    localRuntime.Native = localRuntime.Native || {};
+    localRuntime.Native.Touch = localRuntime.Native.Touch || {};
+    if (localRuntime.Native.Touch.values) {
+        return localRuntime.Native.Touch.values;
+    }
+
+    var Signal = Elm.Signal.make(localRuntime);
+    var List = Elm.Native.List.make(localRuntime);
+    var Utils = Elm.Native.Utils.make(localRuntime);
+
+    function Dict() {
+        this.keys = [];
+        this.values = [];
+
+        this.insert = function(key,value) {
+            this.keys.push(key);
+            this.values.push(value);
+        };
+        this.lookup = function(key) {
+            var i = this.keys.indexOf(key)
+            return i >= 0 ? this.values[i] : {x:0,y:0,t:0};
+        };
+        this.remove = function(key) {
+            var i = this.keys.indexOf(key);
+            if (i < 0) return;
+            var t = this.values[i];
+            this.keys.splice(i,1);
+            this.values.splice(i,1);
+            return t;
+        };
+        this.clear = function() {
+            this.keys = [];
+            this.values = [];
+        };
+    }
+    
+    var root = Signal.constant([]),
+    tapTime = 500,
+    hasTap = false,
+    tap = {_:{},x:0,y:0},
+    dict = new Dict();
+
+    function touch(t) {
+        var r = dict.lookup(t.identifier);
+        var point = Utils.getXY(t);
+        return {
+            _ : {},
+            id: t.identifier,
+            x : point._0,
+            y : point._1,
+            x0: r.x,
+            y0: r.y,
+            t0: r.t
+         };
+    }
+
+    var node = localRuntime.isFullscreen()
+        ? document
+        : localRuntime.node;
+
+    function start(e) {
+        var point = Utils.getXY(e);
+        dict.insert(e.identifier, {
+            x: point._0,
+            y: point._1,
+            t: localRuntime.timer.now()
+        });
+    }
+    function end(e) {
+        var t = dict.remove(e.identifier);
+        if (localRuntime.timer.now() - t.t < tapTime) {
+            hasTap = true;
+            tap = {
+                _: {},
+                x: t.x,
+                y: t.y
+            };
+        }
+    }
+
+    function listen(name, f) {
+        function update(e) {
+            for (var i = e.changedTouches.length; i--; ) {
+                f(e.changedTouches[i]);
+            }
+            var ts = new Array(e.touches.length);
+            for (var i = e.touches.length; i--; ) {
+                ts[i] = touch(e.touches[i]);
+            }
+            localRuntime.notify(root.id, ts);
+            e.preventDefault();
+        }
+        localRuntime.addListener([root.id], node, name, update);
+    }
+
+    listen("touchstart", start);
+    listen("touchmove", function(_){});
+    listen("touchend", end);
+    listen("touchcancel", end);
+    listen("touchleave", end);
+
+    var mouseID = -1;
+    function move(e) {
+        var point = Utils.getXY(e);
+        for (var i = root.value.length; i--; ) {
+            if (root.value[i].id === mouseID) {
+                root.value[i].x = point._0;
+                root.value[i].y = point._1;
+                localRuntime.notify(root.id, root.value);
+                break;
+            }
+        }
+    }
+    localRuntime.addListener([root.id], node, "mousedown", function down(e) {
+        node.addEventListener("mousemove", move);
+        e.identifier = mouseID;
+        start(e);
+        root.value.push(touch(e));
+        localRuntime.notify(root.id, root.value);
+    });
+    localRuntime.addListener([root.id], document, "mouseup", function up(e) {
+        node.removeEventListener("mousemove", move);
+        e.identifier = mouseID;
+        end(e);
+        for (var i = root.value.length; i--; ) {
+            if (root.value[i].id === mouseID) {
+                root.value.splice(i, 1);
+                --mouseID;
+                break;
+            }
+        }
+        localRuntime.notify(root.id, root.value);
+    });
+    localRuntime.addListener([root.id], node, "blur", function blur(e) {
+        node.removeEventListener("mousemove", move);
+        if (root.value.length > 0) {
+            localRuntime.notify(root.id, []);
+            --mouseID;
+        }
+        dict.clear();
+    });
+
+    function dependency(f) {
+        var sig = A2( Signal.map, f, root );
+        root.defaultNumberOfKids += 1;
+        sig.defaultNumberOfKids = 0;
+        return sig;
+    }
+
+    var touches = dependency(List.fromArray);
+
+    var taps = function() {
+        var sig = dependency(function(_) { return tap; });
+        sig.defaultNumberOfKids = 1;
+        function pred(_) {
+            var b = hasTap;
+            hasTap = false;
+            return b;
+        }
+        var sig2 = A3( Signal.keepIf, pred, {_:{},x:0,y:0}, sig);
+        sig2.defaultNumberOfKids = 0;
+        return sig2;
+    }();
+
+    return localRuntime.Native.Touch.values = { touches: touches, taps: taps };
+
+};
+ src/Native/Trampoline.js view
@@ -0,0 +1,24 @@+Elm.Native.Trampoline = {};
+Elm.Native.Trampoline.make = function(elm) {
+    elm.Native = elm.Native || {};
+    elm.Native.Trampoline = elm.Native.Trampoline || {};
+    if (elm.Native.Trampoline.values) return elm.Native.Trampoline.values;
+
+    // trampoline : Trampoline a -> a
+    function trampoline(t) {
+        var tramp = t;
+        while(true) {
+            switch(tramp.ctor) {
+            case "Done":
+                return tramp._0;
+            case "Continue":
+                tramp = tramp._0({ctor: "_Tuple0"});
+                continue;
+            }
+        }
+    }
+
+    return elm.Native.Trampoline.values = {
+        trampoline:trampoline
+    };
+};
+ src/Native/Transform2D.js view
@@ -0,0 +1,99 @@+Elm.Native.Transform2D = {};
+Elm.Native.Transform2D.make = function(elm) {
+
+ elm.Native = elm.Native || {};
+ elm.Native.Transform2D = elm.Native.Transform2D || {};
+ if (elm.Native.Transform2D.values) return elm.Native.Transform2D.values;
+
+ var A;
+ if (typeof Float32Array === 'undefined') {
+     A = function(arr) {
+         this.length = arr.length;
+         this[0] = arr[0];
+         this[1] = arr[1];
+         this[2] = arr[2];
+         this[3] = arr[3];
+         this[4] = arr[4];
+         this[5] = arr[5];
+     };
+ } else {
+     A = Float32Array;
+ }
+
+ // layout of matrix in an array is
+ //
+ //   | m11 m12 dx |
+ //   | m21 m22 dy |
+ //   |  0   0   1 |
+ //
+ //  new A([ m11, m12, dx, m21, m22, dy ])
+
+ var identity = new A([1,0,0,0,1,0]);
+ function matrix(m11, m12, m21, m22, dx, dy) {
+     return new A([m11, m12, dx, m21, m22, dy]);
+ }
+ function rotation(t) {
+     var c = Math.cos(t);
+     var s = Math.sin(t);
+     return new A([c, -s, 0, s, c, 0]);
+ }
+ function rotate(t,m) {
+     var c = Math.cos(t);
+     var s = Math.sin(t);
+     var m11 = m[0], m12 = m[1], m21 = m[3], m22 = m[4];
+     return new A([m11*c + m12*s, -m11*s + m12*c, m[2],
+                   m21*c + m22*s, -m21*s + m22*c, m[5]]);
+ }
+ /*
+ function move(xy,m) {
+     var x = xy._0;
+     var y = xy._1;
+     var m11 = m[0], m12 = m[1], m21 = m[3], m22 = m[4];
+     return new A([m11, m12, m11*x + m12*y + m[2],
+                   m21, m22, m21*x + m22*y + m[5]]);
+ }
+ function scale(s,m) { return new A([m[0]*s, m[1]*s, m[2], m[3]*s, m[4]*s, m[5]]); }
+ function scaleX(x,m) { return new A([m[0]*x, m[1], m[2], m[3]*x, m[4], m[5]]); }
+ function scaleY(y,m) { return new A([m[0], m[1]*y, m[2], m[3], m[4]*y, m[5]]); }
+ function reflectX(m) { return new A([-m[0], m[1], m[2], -m[3], m[4], m[5]]); }
+ function reflectY(m) { return new A([m[0], -m[1], m[2], m[3], -m[4], m[5]]); }
+
+ function transform(m11, m21, m12, m22, mdx, mdy, n) {
+     var n11 = n[0], n12 = n[1], n21 = n[3], n22 = n[4], ndx = n[2], ndy = n[5];
+     return new A([m11*n11 + m12*n21,
+                   m11*n12 + m12*n22,
+                   m11*ndx + m12*ndy + mdx,
+                   m21*n11 + m22*n21,
+                   m21*n12 + m22*n22,
+                   m21*ndx + m22*ndy + mdy]);
+ }
+ */
+ function multiply(m, n) {
+     var m11 = m[0], m12 = m[1], m21 = m[3], m22 = m[4], mdx = m[2], mdy = m[5];
+     var n11 = n[0], n12 = n[1], n21 = n[3], n22 = n[4], ndx = n[2], ndy = n[5];
+     return new A([m11*n11 + m12*n21,
+                   m11*n12 + m12*n22,
+                   m11*ndx + m12*ndy + mdx,
+                   m21*n11 + m22*n21,
+                   m21*n12 + m22*n22,
+                   m21*ndx + m22*ndy + mdy]);
+ }
+
+ return elm.Native.Transform2D.values = {
+     identity:identity,
+     matrix:F6(matrix),
+     rotation:rotation,
+     multiply:F2(multiply)
+     /*
+     transform:F7(transform),
+     rotate:F2(rotate),
+     move:F2(move),
+     scale:F2(scale),
+     scaleX:F2(scaleX),
+     scaleY:F2(scaleY),
+     reflectX:reflectX,
+     reflectY:reflectY
+     */
+ };
+
+};
+ src/Native/Utils.js view
@@ -0,0 +1,305 @@+Elm.Native = Elm.Native || {};
+Elm.Native.Utils = {};
+Elm.Native.Utils.make = function(localRuntime) {
+
+    localRuntime.Native = localRuntime.Native || {};
+    localRuntime.Native.Utils = localRuntime.Native.Utils || {};
+    if (localRuntime.Native.Utils.values) {
+        return localRuntime.Native.Utils.values;
+    }
+
+    function eq(l,r) {
+        var stack = [{'x': l, 'y': r}]
+        while (stack.length > 0) {
+            var front = stack.pop();
+            var x = front.x;
+            var y = front.y;
+            if (x === y) continue;
+            if (typeof x === "object") {
+                var c = 0;
+                for (var i in x) {
+                    ++c;
+                    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;
+                };
+            } else if (typeof x === 'function') {
+                throw new Error('Equality error: general function equality is ' +
+                                'undecidable, and therefore, unsupported');
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // code in Generate/JavaScript.hs depends on the particular
+    // integer values assigned to LT, EQ, and GT
+    var LT = -1, EQ = 0, GT = 1, ord = ['LT','EQ','GT'];
+    function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
+    function cmp(x,y) {
+        var ord;
+        if (typeof x !== 'object'){
+            return x === y ? EQ : x < y ? LT : GT;
+        }
+        else if (x.isChar){
+            var a = x.toString();
+            var b = y.toString();
+            return a === b ? EQ : a < b ? LT : GT;
+        }
+        else if (x.ctor === "::" || x.ctor === "[]") {
+            while (true) {
+                if (x.ctor === "[]" && y.ctor === "[]") return EQ;
+                if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
+                ord = cmp(x._0, y._0);
+                if (ord !== EQ) return ord;
+                x = x._1;
+                y = y._1;
+            }
+        }
+        else if (x.ctor.slice(0,6) === '_Tuple') {
+            var n = x.ctor.slice(6) - 0;
+            var err = 'cannot compare tuples with more than 6 elements.';
+            if (n === 0) return EQ;
+            if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord;
+            if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord;
+            if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord;
+            if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord;
+            if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord;
+            if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord;
+            if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
+            return EQ;
+        }
+        else {
+            throw new Error('Comparison error: comparison is only defined on ints, ' +
+                            'floats, times, chars, strings, lists of comparable values, ' +
+                            'and tuples of comparable values.');
+        }
+    }
+
+
+    var Tuple0 = { ctor: "_Tuple0" };
+    function Tuple2(x,y) {
+        return {
+            ctor: "_Tuple2",
+            _0: x,
+            _1: y
+        };
+    }
+
+    function chr(c) {
+        var x = new String(c);
+        x.isChar = true;
+        return x;
+    }
+
+    function txt(str) {
+        var t = new String(str);
+        t.text = true;
+        return t;
+    }
+
+    function makeText(text) {
+        var style = '';
+        var href = '';
+        while (true) {
+            if (text.style) {
+                style += text.style;
+                text = text.text;
+                continue;
+            }
+            if (text.href) {
+                href = text.href;
+                text = text.text;
+                continue;
+            }
+            if (href) {
+                text = '<a href="' + href + '">' + text + '</a>';
+            }
+            if (style) {
+                text = '<span style="' + style + '">' + text + '</span>';
+            }
+            return text;
+        }
+    }
+
+    var count = 0;
+    function guid(_) {
+        return count++
+    }
+
+    function copy(oldRecord) {
+        var newRecord = {};
+        for (var key in oldRecord) {
+            var value = key === '_'
+                ? copy(oldRecord._)
+                : oldRecord[key]
+                ;
+            newRecord[key] = value;
+        }
+        return newRecord;
+    }
+
+    function remove(key, oldRecord) {
+        var record = copy(oldRecord);
+        if (key in record._) {
+            record[key] = record._[key][0];
+            record._[key] = record._[key].slice(1);
+            if (record._[key].length === 0) {
+                delete record._[key];
+            }
+        } else {
+            delete record[key];
+        }
+        return record;
+    }
+
+    function replace(keyValuePairs, oldRecord) {
+        var record = copy(oldRecord);
+        for (var i = keyValuePairs.length; i--; ) {
+            var pair = keyValuePairs[i];
+            record[pair[0]] = pair[1];
+        }
+        return record;
+    }
+
+    function insert(key, value, oldRecord) {
+        var newRecord = copy(oldRecord);
+        if (key in newRecord) {
+            var values = newRecord._[key];
+            var copiedValues = values ? values.slice(0) : [];
+            newRecord._[key] = [newRecord[key]].concat(copiedValues);
+        }
+        newRecord[key] = value;
+        return newRecord;
+    }
+
+    function getXY(e) {
+        var posx = 0;
+        var posy = 0;
+        if (e.pageX || e.pageY) {
+            posx = e.pageX;
+            posy = e.pageY;
+        } else if (e.clientX || e.clientY) {
+            posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
+            posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
+        }
+
+        if (localRuntime.isEmbed()) {
+            var rect = localRuntime.node.getBoundingClientRect();
+            var relx = rect.left + document.body.scrollLeft + document.documentElement.scrollLeft;
+            var rely = rect.top + document.body.scrollTop + document.documentElement.scrollTop;
+            // TODO: figure out if there is a way to avoid rounding here
+            posx = posx - Math.round(relx) - localRuntime.node.clientLeft;
+            posy = posy - Math.round(rely) - localRuntime.node.clientTop;
+        }
+        return Tuple2(posx, posy);
+    }
+
+
+    //// LIST STUFF ////
+
+    var Nil = { ctor:'[]' };
+
+    function Cons(hd,tl) {
+        return {
+            ctor: "::",
+            _0: hd,
+            _1: tl
+        };
+    }
+
+    function append(xs,ys) {
+        // append Text
+        if (xs.text || ys.text) {
+            return txt(makeText(xs) + makeText(ys));
+        }
+
+        // append Strings
+        if (typeof xs === "string") {
+            return xs + ys;
+        }
+
+        // append Lists
+        if (xs.ctor === '[]') {
+            return ys;
+        }
+        var root = Cons(xs._0, Nil);
+        var curr = root;
+        xs = xs._1;
+        while (xs.ctor !== '[]') {
+            curr._1 = Cons(xs._0, Nil);
+            xs = xs._1;
+            curr = curr._1;
+        }
+        curr._1 = ys;
+        return root;
+    }
+
+    //// RUNTIME ERRORS ////
+
+    function indent(lines) {
+        return '\n' + lines.join('\n');
+    }
+
+    function badCase(moduleName, span) { 
+        var msg = indent([
+            'Non-exhaustive pattern match in case-expression.',
+            'Make sure your patterns cover every case!'
+        ]);
+        throw new Error('Runtime error in module ' + moduleName + ' (' + span + ')' + msg);
+    }
+
+    function badIf(moduleName, span) { 
+        var msg = indent([
+            'Non-exhaustive pattern match in multi-way-if expression.',
+            'It is best to use \'otherwise\' as the last branch of multi-way-if.'
+        ]);
+        throw new Error('Runtime error in module ' + moduleName + ' (' + span + ')' + msg);
+    }
+
+
+    function badPort(expected, received) { 
+        var msg = indent([
+            'Expecting ' + expected + ' but was given ',
+            JSON.stringify(received)
+        ]);
+        throw new Error('Runtime error when sending values through a port.' + msg);
+    }
+
+
+    return localRuntime.Native.Utils.values = {
+        eq:eq,
+        cmp:cmp,
+        compare:F2(compare),
+        Tuple0:Tuple0,
+        Tuple2:Tuple2,
+        chr:chr,
+        txt:txt,
+        makeText:makeText,
+        copy: copy,
+        remove: remove,
+        replace: replace,
+        insert: insert,
+        guid: guid,
+        getXY: getXY,
+
+        Nil: Nil,
+        Cons: Cons,
+        append: F2(append),
+
+        badCase: badCase,
+        badIf: badIf,
+        badPort: badPort
+    };
+};
+ src/Native/WebSocket.js view
@@ -0,0 +1,36 @@+Elm.Native.WebSocket = {};
+Elm.Native.WebSocket.make = function(elm) {
+
+  elm.Native = elm.Native || {};
+  elm.Native.WebSocket = elm.Native.WebSocket || {};
+  if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
+
+  var Signal = Elm.Signal.make(elm);
+  var List = Elm.Native.List.make(elm);
+
+  function open(url, outgoing) {
+    var incoming = Signal.constant("");
+    var ws = new WebSocket(url);
+
+    var pending = [];
+    var ready = false;
+    
+    ws.onopen = function(e) {
+      var len = pending.length;
+      for (var i = 0; i < len; ++i) { ws.send(pending[i]); }
+      ready = true;
+    };
+    ws.onmessage = function(event) {
+      elm.notify(incoming.id, event.data);
+    };
+    
+    function send(msg) {
+      ready ? ws.send(msg) : pending.push(msg);
+    }
+    
+    function take1(x,y) { return x }
+    return A3(Signal.map2, F2(take1), incoming, A2(Signal.map, send, outgoing));
+  }
+
+  return elm.Native.WebSocket.values = { connect: F2(open) };
+};
+ src/Native/Window.js view
@@ -0,0 +1,62 @@+Elm.Native = Elm.Native || {};
+Elm.Native.Window = {};
+Elm.Native.Window.make = function(localRuntime) {
+
+    localRuntime.Native = localRuntime.Native || {};
+    localRuntime.Native.Window = localRuntime.Native.Window || {};
+    if (localRuntime.Native.Window.values) {
+        return localRuntime.Native.Window.values;
+    }
+
+    var Signal = Elm.Signal.make(localRuntime);
+    var NS = Elm.Native.Signal.make(localRuntime);
+    var Tuple2 = Elm.Native.Utils.make(localRuntime).Tuple2;
+
+    function getWidth() {
+        return localRuntime.node.clientWidth;
+    }
+    function getHeight() {
+        if (localRuntime.isFullscreen()) {
+            return window.innerHeight;
+        }
+        return localRuntime.node.clientHeight;
+    }
+
+    var dimensions = NS.input(Tuple2(getWidth(), getHeight()));
+    dimensions.defaultNumberOfKids = 2;
+
+    // Do not move width and height into Elm. By setting the default number of kids,
+    // the resize listener can be detached.
+    var width  = A2(Signal.map, function(p){return p._0;}, dimensions);
+    width.defaultNumberOfKids = 0;
+
+    var height = A2(Signal.map, function(p){return p._1;}, dimensions);
+    height.defaultNumberOfKids = 0;
+
+    function resizeIfNeeded() {
+        // Do not trigger event if the dimensions have not changed.
+        // This should be most of the time.
+        var w = getWidth();
+        var h = getHeight();
+        if (dimensions.value._0 === w && dimensions.value._1 === h) return;
+
+        setTimeout(function () {
+            // Check again to see if the dimensions have changed.
+            // It is conceivable that the dimensions have changed
+            // again while some other event was being processed.
+            var w = getWidth();
+            var h = getHeight();
+            if (dimensions.value._0 === w && dimensions.value._1 === h) return;
+            localRuntime.notify(dimensions.id, Tuple2(w,h));
+        }, 0);
+    }
+    localRuntime.addListener([dimensions.id], window, 'resize', resizeIfNeeded);
+
+    return localRuntime.Native.Window.values = {
+        dimensions: dimensions,
+        width: width,
+        height: height,
+        resizeIfNeeded: resizeIfNeeded
+    };
+
+};
+ src/Random.elm view
@@ -0,0 +1,314 @@+module Random
+    ( Generator, Seed
+    , int, float
+    , list, pair
+    , minInt, maxInt
+    , generate, initialSeed
+    , customGenerator
+    )
+  where
+
+{-| This library helps you generate pseudo-random values.
+
+The general pattern is to define a `Generator` which can produce certain kinds
+of random values. You actually produce random values by feeding a fresh `Seed`
+to your `Generator`.
+
+Since you need a fresh `Seed` to produce more random values, you should
+probably store a `Seed` in your application's state. This will allow you to
+keep updating it as you generate random values and fresh seeds.
+
+The following example models a bunch of bad guys that randomly appear. The
+`possiblyAddBadGuy` function uses the random seed to see if we should add a bad
+guy, and if so, it places a bad guy at a randomly generated point.
+
+    type alias Model =
+        { badGuys : List (Float,Float)
+        , seed : Seed
+        }
+
+    possiblyAddBadGuy : Model -> Model
+    possiblyAddBadGuy model =
+        let (addProbability, seed') =
+              generate (float 0 1) model.seed
+        in
+            if addProbability < 0.9
+              then
+                { model |
+                    seed <- seed'
+                }
+              else
+                let (position, seed'') =
+                      generate (pair (float 0 100) (float 0 100)) seed'
+                in
+                    { model |
+                        badGuys <- position :: model.badGuys
+                        seed <- seed''
+                    }
+
+Details: This is an implemenation of the Portable Combined Generator of
+L'Ecuyer for 32-bit computers. It is almost a direct translation from the
+[System.Random](http://hackage.haskell.org/package/random-1.0.1.1/docs/System-Random.html)
+module. It has a period of roughly 2.30584e18.
+
+# Generators
+
+@docs int, float, pair, list
+
+# Running a Generator
+
+@docs generate, initialSeed
+
+# Constants
+
+@docs maxInt, minInt
+
+# Custom Generators
+
+@docs customGenerator
+
+-}
+
+import Basics (..)
+import List
+import List ((::))
+
+
+{-| Create a generator that produces 32-bit integers in a given range. This
+function *can* produce values outside of the range [minInt, maxInt] but
+sufficient randomness is not guaranteed.
+
+    int 0 10   -- an integer between zero and ten
+    int -5 5   -- an integer between -5 and 5
+
+    int minInt maxInt  -- an integer in the widest range feasible
+-}
+int : Int -> Int -> Generator Int
+int a b =
+  Generator <| \seed ->
+    let (lo,hi) = if a < b then (a,b) else (b,a)
+
+        k = hi - lo + 1
+        -- 2^31 - 87
+        base = 2147483561
+        n = iLogBase base k
+
+        f n acc state =
+            case n of
+              0 -> (acc, state)
+              _ -> let (x, state') = seed.next state
+                   in  f (n - 1) (x + acc * base) state'
+
+        (v, state') = f n 1 seed.state
+    in
+        (lo + v % k, { seed | state <- state' })
+
+
+iLogBase : Int -> Int -> Int       
+iLogBase b i =
+    if i < b then 1 else 1 + iLogBase b (i // b)
+
+
+{-| The maximum value for randomly generated 32-bit ints. -}
+maxInt : Int
+maxInt = 2147483647
+
+
+{-| The minimum value for randomly generated 32-bit ints. -}
+minInt : Int
+minInt = -2147483648
+
+
+{-| Create a generator that produces floats in a given range.
+
+    probability : Generator Float
+    probability =
+        float 0 1
+
+    -- generate probability seed0 ==> (0.51, seed1)
+    -- generate probability seed1 ==> (0.04, seed2)
+-}
+float : Float -> Float -> Generator Float
+float a b =
+  Generator <| \seed ->
+    let (lo, hi) = if a < b then (a,b) else (b,a)
+
+        (number, seed') =
+            generate (int minInt maxInt) seed
+
+        negativeOneToOne =
+            toFloat number / toFloat (maxInt - minInt)
+
+        scaled = (lo+hi)/2 + ((hi-lo) * negativeOneToOne)
+    in
+        (scaled, seed')
+
+
+-- DATA STRUCTURES
+
+{-| Create a pair of random values. A common use of this might be to generate
+a point in a certain 2D space. Imagine we have a collage that is 400 pixels
+wide and 200 pixels tall.
+
+    randomPoint : Generator (Int,Int)
+    randomPoint =
+        pair (int -200 200) (int -100 100)
+
+-}
+pair : Generator a -> Generator b -> Generator (a,b)
+pair (Generator genLeft) (Generator genRight) =
+  Generator <| \seed ->
+    let (left , seed' ) = genLeft seed
+        (right, seed'') = genRight seed'
+    in
+        ((left,right), seed'')
+
+
+{-| Create a list of random values.
+
+    floatList : Generator (List Float)
+    floatList =
+        list 10 (float 0 1)
+
+    intList : Generator (List Int)
+    intList =
+        list 5 (int 0 100)
+
+    intPairs : Generator (List (Int, Int))
+    intPairs =
+        list 10 (pair int int)
+-}
+list : Int -> Generator a -> Generator (List a)
+list n (Generator generate) =
+  Generator <| \seed ->
+    listHelp [] n generate seed
+
+
+listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed)
+listHelp list n generate seed =
+    if n < 1
+    then (List.reverse list, seed)
+    else
+        let (value, seed') = generate seed
+        in  listHelp (value :: list) (n-1) generate seed'
+
+
+{-| Create a custom generator. You provide a function that takes a seed, and
+returns a random value and a new seed. You can use this to create custom
+generators not covered by the basic functions in this library.
+
+    pairOf : Generator a -> Generator (a,a)
+    pairOf generator =
+      customGenerator <| \seed ->
+        let (left , seed' ) = generate generator seed
+            (right, seed'') = generate generator seed'
+        in
+            ((left,right), seed'')
+
+-}
+customGenerator : (Seed -> (a, Seed)) -> Generator a
+customGenerator generate =
+    Generator generate
+
+
+{-| A `Generator` is a function that takes a seed, and then returns a random
+value and a new seed. The new seed is used to generate new random values.
+-}
+type Generator a =
+    Generator (Seed -> (a, Seed))
+
+type State = State Int Int
+
+type alias Seed =
+    { state : State
+    , next  : State -> (Int, State)
+    , split : State -> (State, State)
+    , range : State -> (Int,Int)
+    }
+
+{-| Run a random value generator with a given seed. It will give you back a
+random value and a new seed.
+
+    seed0 = initialSeed 31415
+
+    -- generate (int 0 100) seed0 ==> (42, seed1)
+    -- generate (int 0 100) seed1 ==> (31, seed2)
+    -- generate (int 0 100) seed2 ==> (99, seed3)
+
+Notice that we use different seeds on each line. This is important! If you use
+the same seed, you get the same results.
+
+    -- generate (int 0 100) seed0 ==> (42, seed1)
+    -- generate (int 0 100) seed0 ==> (42, seed1)
+    -- generate (int 0 100) seed0 ==> (42, seed1)
+-}
+generate : Generator a -> Seed -> (a, Seed)
+generate (Generator generator) seed =
+    generator seed
+
+
+{-| Create a &ldquo;seed&rdquo; of randomness which makes it possible to
+generate random values. If you use the same seed many times, it will result
+in the same thing every time! A good way to get an unexpected seed is to use
+the current time.
+-}
+initialSeed : Int -> Seed
+initialSeed n =
+    Seed (initState n) next split range
+
+
+{-| Produce the initial generator state. Distinct arguments should be likely
+to produce distinct generator states.
+-}
+initState : Int -> State
+initState s' =
+    let s = max s' -s'
+        q  = s // (magicNum6-1)
+        s1 = s %  (magicNum6-1)
+        s2 = q %  (magicNum7-1)
+    in
+        State (s1+1) (s2+1)                         
+
+
+magicNum0 = 40014
+magicNum1 = 53668
+magicNum2 = 12211
+magicNum3 = 52774
+magicNum4 = 40692
+magicNum5 = 3791
+magicNum6 = 2147483563
+magicNum7 = 2137383399
+magicNum8 = 2147483562
+
+
+next : State -> (Int, State)
+next (State s1 s2) = 
+    -- Div always rounds down and so random numbers are biased
+    -- ideally we would use division that rounds towards zero so
+    -- that in the negative case it rounds up and in the positive case
+    -- it rounds down. Thus half the time it rounds up and half the time it
+    -- rounds down
+    let k = s1 // magicNum1 
+        s1' = magicNum0 * (s1 - k * magicNum1) - k * magicNum2
+        s1'' = if s1' < 0 then s1' + magicNum6 else s1' 
+        k' = s2 // magicNum3 
+        s2' = magicNum4 * (s2 - k' * magicNum3) - k' * magicNum5
+        s2'' = if s2' < 0 then s2' + magicNum7 else s2'
+        z = s1'' - s2''
+        z' = if z < 1 then z + magicNum8 else z
+    in
+        (z', State s1'' s2'')
+
+
+split : State -> (State, State)
+split (State s1 s2 as std) =
+    let new_s1 = if s1 == magicNum6-1 then 1 else s1 + 1
+        new_s2 = if s2 == 1 then magicNum7-1 else s2 - 1
+        (State t1 t2) = snd (next std)
+    in
+        (State new_s1 t2, State t1 new_s2)
+
+
+range : State -> (Int,Int)
+range _ =
+    (0, magicNum8)
+ src/Regex.elm view
@@ -0,0 +1,123 @@+module Regex where
+{-| A library for working with regular expressions. It uses [the
+same kind of regular expressions accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions).
+
+# Create
+@docs regex, escape, caseInsensitive
+
+# Helpful Data Structures
+
+These data structures are needed to help define functions like [`find`](#find)
+and [`replace`](#replace).
+
+@docs HowMany, Match
+
+# Use
+@docs contains, find, replace, split
+
+-}
+
+import Maybe (Maybe)
+import Native.Regex
+
+type Regex = Regex
+
+{-| Escape strings to be regular expressions, making all special characters
+safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series
+of `a`&rsquo;s that start at the beginning of the line.
+-}
+escape : String -> String
+escape = Native.Regex.escape
+
+{-| Create a Regex that matches patterns [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern).
+
+Be careful to escape backslashes properly! For example, `"\w"` is escaping the
+letter `w` which is probably not what you want. You probably want `"\\w"`
+instead, which escapes the backslash.
+-}
+regex : String -> Regex
+regex = Native.Regex.regex
+
+
+{-| Make a regex case insensitive -}
+caseInsensitive : Regex -> Regex
+caseInsensitive = Native.Regex.caseInsensitive
+
+{-| Check to see if a Regex is contained in a string.
+
+    contains (regex "123") "12345" == True
+    contains (regex "b+") "aabbcc" == True
+
+    contains (regex "789") "12345" == False
+    contains (regex "z+") "aabbcc" == False
+-}
+contains : Regex -> String -> Bool
+contains = Native.Regex.contains
+
+{-| A `Match` represents all of the details about a particular match in a string.
+Here are details on each field:
+
+  * `match` &mdash; the full string of the match.
+  * `submatches` &mdash; a regex might have [subpatterns, surrounded by
+    parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches).
+    If there are N subpatterns, there will be N elements in the `submatches` list.
+    Each submatch in this list is a `Maybe` because not all subpatterns may trigger.
+    For example, `(regex "(a+)|(b+)")` will either match many `a`&rsquo;s or
+    many `b`&rsquo;s, but never both.
+  * `index` &mdash; the index of the match in the original string.
+  * `number` &mdash; if you find many matches, you can think of each one
+    as being labeled with a `number` starting at one. So the first time you
+    find a match, that is match `number` one. Second time is match `number` two.
+    This is useful when paired with `replace All` if replacement is dependent on how
+    many times a pattern has appeared before.
+-}
+type alias Match =
+    { match : String
+    , submatches : List (Maybe String)
+    , index : Int
+    , number : Int
+    }
+
+{-| `HowMany` is used to specify how many matches you want to make. So
+`replace All` would replace every match, but `replace (AtMost 2)` would
+replace at most two matches (i.e. zero, one, two, but never three or more).
+-}
+type HowMany = All | AtMost Int
+
+{-| Find matches in a string:
+
+    findTwoCommas = find (AtMost 2) (regex ",")
+
+      -- map .index (findTwoCommas "a,b,c,d,e") == [1,3]
+      -- map .index (findTwoCommas "a b c d e") == []
+
+    places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake."
+
+      -- map .match places == ["on a boat", "in a lake"]
+      -- map .submatches places == [ [Just "boat"], [Just "lake"] ]
+-}
+find : HowMany -> Regex -> String -> List Match
+find = Native.Regex.find
+
+{-| Replace matches. The function from `Match` to `String` lets
+you use the details of a specific match when making replacements.
+
+    devowel = replace All (regex "[aeiou]") (\_ -> "")
+
+      -- devowel "The quick brown fox" == "Th qck brwn fx"
+
+    reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match)
+
+      -- reverseWords "deliver mined parts" == "reviled denim strap"
+-}
+replace : HowMany -> Regex -> (Match -> String) -> String -> String
+replace = Native.Regex.replace
+
+{-| Split a string, using the regex as the separator.
+
+    split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"]
+
+    split All (regex ",") "a,b,c,d" == ["a","b","c","d"]
+-}
+split : HowMany -> Regex -> String -> List String
+split = Native.Regex.split
+ src/Result.elm view
@@ -0,0 +1,128 @@+module Result where
+{-| A `Result` is the result of a computation that may fail. This is a great
+way to manage errors in Elm.
+
+# Type and Constructors
+@docs Result
+
+# Common Helpers
+@docs map, andThen
+
+# Formatting Errors
+@docs toMaybe, fromMaybe formatError
+-}
+
+import Maybe ( Maybe(Just, Nothing) )
+
+
+{-| A `Result` is either `Ok` meaning the computation succeeded, or it is an
+`Err` meaning that there was some failure.
+-}
+type Result error value = Ok value | Err error
+
+
+{-| Apply a function to a result. If the result is `Ok`, it will be converted.
+If the result is an `Err`, the same error value will propegate through.
+
+    map sqrt (Ok 4.0)          == Ok 2.0
+    map sqrt (Err "bad input") == Err "bad input"
+-}
+map : (a -> b) -> Result e a -> Result e b
+map f result =
+    case result of
+      Ok  v -> Ok (f v)
+      Err e -> Err e
+
+
+{-| Chain together a sequence of computations that may fail. It is helpful
+to see its definition:
+
+    andThen : Result e a -> (a -> Result e b) -> Result e b
+    andThen result callback =
+        case result of
+          Ok value -> callback value
+          Err msg -> Err msg
+
+This means we only continue with the callback if things are going well. For
+example, say you need to use (`toInt : String -> Result String Int`) to parse
+a month and make sure it is between 1 and 12:
+
+    toValidMonth : Int -> Result String Int
+    toValidMonth month =
+        if month >= 1 && month <= 12
+            then Ok month
+            else Err "months must be between 1 and 12"
+
+    toMonth : String -> Result String Int
+    toMonth rawString =
+        toInt rawString `andThen` toValidMonth
+
+    -- toMonth "4" == Ok 4
+    -- toMonth "9" == Ok 9
+    -- toMonth "a" == Err "cannot parse to an Int"
+    -- toMonth "0" == Err "months must be between 1 and 12"
+
+This allows us to come out of a chain of operations with quite a specific error
+message. It is often best to create a custom type that explicitly represents
+the exact ways your computation may fail. This way it is easy to handle in your
+code.
+-}
+andThen : Result e a -> (a -> Result e b) -> Result e b
+andThen result callback =
+    case result of
+      Ok value -> callback value
+      Err msg -> Err msg
+
+
+{-| Format the error value of a result. If the result is `Ok`, it stays exactly
+the same, but if the result is an `Err` we will format the error. For example,
+say the errors we get have too much information:
+
+    parseInt : String -> Result ParseError Int
+
+    type ParseError =
+        { message : String
+        , code : Int
+        , position : (Int,Int)
+        }
+
+    formatError .message (parseInt "123") == Ok 123
+    formatError .message (parseInt "abc") == Err "char 'a' is not a number"
+-}
+formatError : (error -> error') -> Result error a -> Result error' a
+formatError f result =
+    case result of
+      Ok  v -> Ok v
+      Err e -> Err (f e)
+
+
+{-| Convert to a simpler `Maybe` if the actual error message is not needed or
+you need to interact with some code that primarily uses maybes.
+
+    parseInt : String -> Result ParseError Int
+
+    maybeParseInt : String -> Maybe Int
+    maybeParseInt string =
+        toMaybe (parseInt string)
+-}
+toMaybe : Result e a -> Maybe a
+toMaybe result =
+    case result of
+      Ok  v -> Just v
+      Err _ -> Nothing
+
+
+{-| Convert from a simple `Maybe` to interact with some code that primarily
+uses `Results`.
+
+    parseInt : String -> Maybe Int
+
+    resultParseInt : String -> Result String Int
+    resultParseInt string =
+        fromMaybe ("error parsing string: " ++ show string) (parseInt string)
+-}
+fromMaybe : e -> Maybe a -> Result e a
+fromMaybe err maybe =
+    case maybe of
+      Just v  -> Ok v
+      Nothing -> Err err
+ src/Set.elm view
@@ -0,0 +1,101 @@+
+module Set
+    ( Set
+    , empty, singleton, insert, remove
+    , member
+    , foldl, foldr, map
+    , filter, partition
+    , union, intersect, diff
+    , toList, fromList
+    ) where
+
+{-| A set of unique values. The values can be any comparable type. This
+includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or lists
+of comparable types.
+
+Insert, remove, and query operations all take *O(log n)* time.
+
+# Build
+@docs empty, singleton, insert, remove
+
+# Query
+@docs member
+
+# Combine
+@docs union, intersect, diff
+
+# Lists
+@docs toList, fromList
+
+# Transform
+@docs map, foldl, foldr, filter, partition
+
+-}
+
+import Dict as Dict
+import List as List
+
+type alias Set t = Dict.Dict t ()
+
+{-| Create an empty set. -}
+empty : Set comparable
+empty = Dict.empty
+
+{-| Create a set with one value. -}
+singleton : comparable -> Set comparable
+singleton k = Dict.singleton k ()
+
+{-| Insert a value into a set. -}
+insert : comparable -> Set comparable -> Set comparable
+insert k = Dict.insert k ()
+
+{-| Remove a value from a set. If the value is not found, no changes are made.
+-}
+remove : comparable -> Set comparable -> Set comparable
+remove = Dict.remove
+
+{-| Determine if a value is in a set. -}
+member : comparable -> Set comparable -> Bool
+member = Dict.member
+
+{-| Get the union of two sets. Keep all values. -}
+union : Set comparable -> Set comparable -> Set comparable
+union = Dict.union
+
+{-| Get the intersection of two sets. Keeps values that appear in both sets. -}
+intersect : Set comparable -> Set comparable -> Set comparable
+intersect = Dict.intersect
+
+{-| Get the difference between the first set and the second. Keeps values
+that do not appear in the second set. -}
+diff : Set comparable -> Set comparable -> Set comparable
+diff = Dict.diff
+
+{-| Convert a set into a list. -}
+toList : Set comparable -> List comparable
+toList = Dict.keys
+
+{-| Convert a list into a set, removing any duplicates. -}
+fromList : List comparable -> Set comparable
+fromList xs = List.foldl insert empty xs
+
+{-| Fold over the values in a set, in order from lowest to highest. -}
+foldl : (comparable -> b -> b) -> b -> Set comparable -> b
+foldl f b s = Dict.foldl (\k _ b -> f k b) b s
+
+{-| Fold over the values in a set, in order from highest to lowest. -}
+foldr : (comparable -> b -> b) -> b -> Set comparable -> b
+foldr f b s = Dict.foldr (\k _ b -> f k b) b s
+
+{-| Map a function onto a set, creating a new set with no duplicates. -}
+map : (comparable -> comparable') -> Set comparable -> Set comparable'
+map f s = fromList (List.map f (toList s))
+
+{-| Create a new set consisting only of elements which satisfy a predicate. -}
+filter : (comparable -> Bool) -> Set comparable -> Set comparable
+filter p set = Dict.filter (\k _ -> p k) set
+
+{-| Create two new sets; the first consisting of elements which satisfy a
+predicate, the second consisting of elements which do not. -}
+partition : (comparable -> Bool) -> Set comparable -> (Set comparable, Set comparable)
+partition p set = Dict.partition (\k _ -> p k) set
+ src/Signal.elm view
@@ -0,0 +1,305 @@+module Signal where
+{-| The library for general signal manipulation. Includes mapping, merging,
+filters, past-dependence, and helpers for handling inputs from the UI.
+
+Some useful functions for working with time (e.g. setting FPS) and combining
+signals and time (e.g.  delaying updates, getting timestamps) can be found in
+the [`Time`](Time) library.
+
+# Merging
+@docs merge, mergeMany
+
+# Mapping
+@docs map, map2, map3, map4, map5
+
+# Fancy Mapping
+@docs (<~), (~)
+
+# Past-Dependence
+@docs foldp
+
+# Filters
+@docs keepIf, dropIf, keepWhen, dropWhen, dropRepeats, sampleOn
+
+# Channels
+@docs channel, send, subscribe
+
+# Constants
+@docs constant
+
+-}
+
+import Native.Signal
+import List
+import Basics (fst, snd, not)
+
+type Signal a = Signal
+
+{-| Create a constant signal that never changes. -}
+constant : a -> Signal a
+constant = Native.Signal.constant
+
+{-| Apply a function to the current value of a signal.
+
+    mouseIsUp : Signal Bool
+    mouseIsUp =
+        map not Mouse.isDown
+
+    main : Signal Element
+    main =
+        map toElement Mouse.position
+-}
+map : (a -> result) -> Signal a -> Signal result
+map = Native.Signal.map
+
+{-| Apply a function to the current value of two signals. In the following
+example, we figure out the `aspectRatio` of the window by combining the
+current width and height.
+
+    ratio : Int -> Int -> Float
+    ratio width height =
+        toFloat width / toFloat height
+
+    aspectRatio : Signal Float
+    aspectRatio =
+        map2 ratio Window.width Window.height
+-}
+map2 : (a -> b -> result) -> Signal a -> Signal b -> Signal result
+map2 = Native.Signal.map2
+
+map3 : (a -> b -> c -> result) -> Signal a -> Signal b -> Signal c -> Signal result
+map3 = Native.Signal.map3
+
+map4 : (a -> b -> c -> d -> result) -> Signal a -> Signal b -> Signal c -> Signal d -> Signal result
+map4 = Native.Signal.map4
+
+map5 : (a -> b -> c -> d -> e -> result) -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e -> Signal result
+map5 = Native.Signal.map5
+
+
+{-| Create a past-dependent signal. Each update from the incoming signals will
+be used to step the stat forward. The outgoing signal represents the current
+state.
+
+    clickCount : Signal Int
+    clickCount =
+        foldp (\click total -> total + 1) 0 Mouse.clicks
+
+    timeSoFar : Signal Time
+    timeSoFar =
+        foldp (+) 0 (fps 40)
+
+So `clickCount` updates on each mouse click, incrementing by one. `timeSoFar`
+is the time the program has been running, updated 40 times a second.
+-}
+foldp : (a -> state -> state) -> state -> Signal a -> Signal state
+foldp = Native.Signal.foldp
+
+
+{-| Merge two signals into one. This function is extremely useful for bringing
+together lots of different signals to feed into a `foldp`.
+
+    type Update = MouseMove (Int,Int) | TimeDelta Float
+
+    updates : Signal Update
+    updates =
+        merge
+            (map MouseMove Mouse.position)
+            (map TimeDelta (fps 40))
+
+If an update comes from either of the incoming signals, it updates the outgoing
+signal. If an update comes on both signals at the same time, the left update
+wins.
+-}
+merge : Signal a -> Signal a -> Signal a
+merge = Native.Signal.merge
+
+{-| Merge many signals into one. This is useful when you are merging more than
+two signals. When multiple updates come in at the same time, the left-most
+update wins, just like with `merge`.
+
+    type Update = MouseMove (Int,Int) | TimeDelta Float | Click
+
+    updates : Signal Update
+    updates =
+        mergeMany
+            [ map MouseMove Mouse.position
+            , map TimeDelta (fps 40)
+            , map (always Click) Mouse.clicks
+            ]
+-}
+mergeMany : List (Signal a) -> Signal a
+mergeMany signals =
+    List.foldr1 merge signals
+
+
+{-| Filter out some updates. The given function decides whether we should
+keep an update. If no updates ever flow through, we use the default value
+provided. The following example only keeps even numbers and has an initial
+value of zero.
+
+    numbers : Signal Int
+
+    isEven : Int -> Bool
+
+    evens : Signal Int
+    evens =
+        keepIf isEven 0 numbers
+-}
+keepIf : (a -> Bool) -> a -> Signal a -> Signal a
+keepIf =
+    Native.Signal.keepIf
+
+
+{-| Filter out some updates. The given function decides whether we should
+drop an update. If we drop all updates, we use the default value provided.
+The following example drops all even numbers and has an initial value of
+one.
+
+    numbers : Signal Int
+
+    isEven : Int -> Bool
+
+    odds : Signal Int
+    odds =
+        dropIf isEven 1 numbers
+-}
+dropIf : (a -> Bool) -> a -> Signal a -> Signal a
+dropIf =
+    Native.Signal.dropIf
+
+
+{-| Keep updates when the first signal is true. You provide a default value
+just in case that signal is *never* true and no updates make it through. For
+example, here is how you would capture mouse drags.
+
+    dragPosition : Signal (Int,Int)
+    dragPosition =
+        keepWhen Mouse.isDown (0,0) Mouse.position
+-}
+keepWhen : Signal Bool -> a -> Signal a -> Signal a
+keepWhen bs def sig = 
+    snd <~ (keepIf fst (False, def) ((,) <~ (sampleOn sig bs) ~ sig))
+
+{-| Drop events when the first signal is true. You provide a default value
+just in case that signal is *always* true and we drop all updates.
+-}
+dropWhen : Signal Bool -> a -> Signal a -> Signal a
+dropWhen bs = keepWhen (not <~ bs)
+
+
+{-| Drop updates that repeat the current value of the signal.
+
+    numbers : Signal Int
+
+    noDups : Signal Int
+    noDups =
+        dropRepeats numbers
+
+    --  numbers => 0 0 3 3 5 5 5 4 ...
+    --  noDups  => 0   3   5     4 ...
+-}
+dropRepeats : Signal a -> Signal a
+dropRepeats = Native.Signal.dropRepeats
+
+{-| Sample from the second input every time an event occurs on the first input.
+For example, `(sampleOn clicks (every second))` will give the approximate time
+of the latest click. -}
+sampleOn : Signal a -> Signal b -> Signal b
+sampleOn = Native.Signal.sampleOn
+
+
+{-| An alias for `map`. A prettier way to apply a function to the current value
+of a signal.
+-}
+(<~) : (a -> b) -> Signal a -> Signal b
+f <~ s = Native.Signal.map f s
+
+
+{-| Intended to be paired with the `(<~)` operator, this makes it possible for
+many signals to flow into a function. Think of it as a fancy alias for `mapN`.
+For example, the following declarations are equivalent:
+
+    main : Signal Element
+    main =
+      scene <~ Window.dimensions ~ Mouse.position
+
+    main : Signal ELement
+    main =
+      map2 scene Window.dimensions Mouse.position
+
+You can use this pattern for as many signals as you want by using `(~)` a bunch
+of times, so you can go higher than `map5` if you need to.
+-}
+(~) : Signal (a -> b) -> Signal a -> Signal b
+sf ~ s = Native.Signal.map2 (\f x -> f x) sf s
+
+infixl 4 <~
+infixl 4 ~
+
+
+---- INPUTS ----
+
+type Channel a = Channel -- Signal a
+
+type Message = Message -- () -> ()
+
+
+{-| Create a signal channel that you can `send` messages to. To receive these
+messages, `subscribe` to the channel and turn it into a normal signal. The
+primary use case is receiving updates from UI elements such as buttons and
+text fields. The argument is a default value for the custom signal.
+
+Note: This is an inherently impure function, so `(channel ())`
+and `(channel ())` produce two different signals.
+-}
+channel : a -> Channel a
+channel =
+    Native.Signal.input
+
+
+{-| Create a `Message` that can be sent to an `Channel` with a handler like
+`Html.onclick` or `Html.onblur`.
+
+    import Html
+
+    type Update = NoOp | Add Int | Remove Int
+
+    updates : Channel Update
+    updates = channel NoOp
+
+    addButton : Html.Html
+    addButton =
+        Html.button
+            [ onclick (send updates (Add 1)) ]
+            [ Html.text "Add 1" ]
+-}
+send : Channel a -> a -> Message
+send =
+    Native.Signal.send
+
+
+{-| Receive all the messages sent to an `Channel` as a `Signal`. The following
+example shows how you would set up a system that uses an `Channel`.
+
+    -- initialState : Model
+    -- type Update = NoOp | ...
+    -- step : Update -> Model -> Model
+    -- view : Channel Update -> Model -> Element
+
+    updates : Channel Update
+    updates = channel NoOp
+
+    main : Signal Element
+    main =
+      map
+        (view updates)
+        (foldp step initialState (subscribe updates))
+
+The `updates` channel appears twice in `main` because it serves as a bridge
+between your view and your signals. In the view you `send` to it, and in signal
+world you `subscribe` to it.
+-}
+subscribe : Channel a -> Signal a
+subscribe =
+    Native.Signal.subscribe
+ src/String.elm view
@@ -0,0 +1,345 @@+module String where
+{-| A built-in representation for efficient string manipulation. String literals
+are enclosed in `"double quotes"`. Strings are *not* lists of characters.
+
+# Basics
+@docs isEmpty, length, reverse, repeat
+
+# Building and Splitting
+@docs cons, uncons, fromChar, append, concat, split, join, words, lines
+
+# Get Substrings
+@docs slice, left, right, dropLeft, dropRight
+
+# Check for Substrings
+@docs contains, startsWith, endsWith, indexes, indices
+
+# Conversions
+@docs toInt, toFloat, toList, fromList
+
+# Formatting
+Cosmetic operations such as padding with extra characters or trimming whitespace.
+
+@docs toUpper, toLower,
+      pad, padLeft, padRight,
+      trim, trimLeft, trimRight
+
+# Higher-Order Functions
+@docs map, filter, foldl, foldr, any, all
+-}
+
+import Native.String
+import Char
+import Maybe (Maybe)
+import Result (Result)
+
+
+{-| Determine if a string is empty.
+
+    isEmpty "" == True
+    isEmpty "the world" == False
+-}
+isEmpty : String -> Bool
+isEmpty = Native.String.isEmpty
+
+{-| Add a character to the beginning of a string. -}
+cons : Char -> String -> String
+cons = Native.String.cons
+
+
+{-| Create a string from a given character.
+
+    fromChar 'a' == "a"
+-}
+fromChar : Char -> String
+fromChar char =
+    cons char ""
+
+
+{-| Split a non-empty string into its head and tail. This lets you
+pattern match on strings exactly as you would with lists.
+
+    uncons "abc" == Just ('a',"bc")
+    uncons ""    == Nothing
+-}
+uncons : String -> Maybe (Char, String)
+uncons = Native.String.uncons
+
+{-| Append two strings. You can also use [the `(++)` operator](Basics#++)
+to do this.
+
+    append "butter" "fly" == "butterfly"
+-}
+append : String -> String -> String
+append = Native.String.append
+
+{-| Concatenate many strings into one.
+
+    concat ["never","the","less"] == "nevertheless"
+-}
+concat : List String -> String
+concat = Native.String.concat
+
+{-| Get the length of a string.
+
+    length "innumerable" == 11
+    length "" == 0
+
+-}
+length : String -> Int
+length = Native.String.length
+
+{-| Transform every character in a string
+
+    map (\c -> if c == '/' then '.' else c) "a/b/c" == "a.b.c"
+-}
+map : (Char -> Char) -> String -> String
+map = Native.String.map
+
+{-| Keep only the characters that satisfy the predicate.
+
+    filter isDigit "R2-D2" == "22"
+-}
+filter : (Char -> Bool) -> String -> String
+filter = Native.String.filter
+
+{-| Reverse a string.
+
+    reverse "stressed" == "desserts"
+-}
+reverse : String -> String
+reverse = Native.String.reverse
+
+{-| Reduce a string from the left.
+
+    foldl cons "" "time" == "emit"
+-}
+foldl : (Char -> b -> b) -> b -> String -> b
+foldl = Native.String.foldl
+
+{-| Reduce a string from the right.
+
+    foldr cons "" "time" == "time"
+-}
+foldr : (Char -> b -> b) -> b -> String -> b
+foldr = Native.String.foldr
+
+{-| Split a string using a given separator.
+
+    split "," "cat,dog,cow"        == ["cat","dog","cow"]
+    split "/" "home/evan/Desktop/" == ["home","evan","Desktop", ""]
+
+Use `Regex.split` if you need something more flexible.
+-}
+split : String -> String -> List String
+split = Native.String.split
+
+{-| Put many strings together with a given separator.
+
+    join "a" ["H","w","ii","n"]        == "Hawaiian"
+    join " " ["cat","dog","cow"]       == "cat dog cow"
+    join "/" ["home","evan","Desktop"] == "home/evan/Desktop"
+-}
+join : String -> List String -> String
+join = Native.String.join
+
+{-| Repeat a string *n* times.
+
+    repeat 3 "ha" == "hahaha"
+-}
+repeat : Int -> String -> String
+repeat = Native.String.repeat
+
+{-| Take a substring given a start and end index. Negative indexes
+are taken starting from the *end* of the list.
+
+    slice  7  9 "snakes on a plane!" == "on"
+    slice  0  6 "snakes on a plane!" == "snakes"
+    slice  0 -7 "snakes on a plane!" == "snakes on a"
+    slice -6 -1 "snakes on a plane!" == "plane"
+-}
+slice : Int -> Int -> String -> String
+slice = Native.String.slice
+
+{-| Take *n* characters from the left side of a string. -}
+left : Int -> String -> String
+left = Native.String.left
+
+{-| Take *n* characters from the right side of a string. -}
+right : Int -> String -> String
+right = Native.String.right
+
+{-| Drop *n* characters from the left side of a string. -}
+dropLeft : Int -> String -> String
+dropLeft = Native.String.dropLeft
+
+{-| Drop *n* characters from the right side of a string. -}
+dropRight : Int -> String -> String
+dropRight = Native.String.dropRight
+
+{-| Pad a string on both sides until it has a given length.
+
+    pad 5 ' ' "1"   == "  1  "
+    pad 5 ' ' "11"  == "  11 "
+    pad 5 ' ' "121" == " 121 "
+-}
+pad : Int -> Char -> String -> String
+pad = Native.String.pad
+
+{-| Pad a string on the left until it has a given length.
+
+    padLeft 5 '.' "1"   == "....1"
+    padLeft 5 '.' "11"  == "...11"
+    padLeft 5 '.' "121" == "..121"
+-}
+padLeft : Int -> Char -> String -> String
+padLeft = Native.String.padLeft
+
+{-| Pad a string on the right until it has a given length.
+
+    padRight 5 '.' "1"   == "1...."
+    padRight 5 '.' "11"  == "11..."
+    padRight 5 '.' "121" == "121.."
+-}
+padRight : Int -> Char -> String -> String
+padRight = Native.String.padRight
+
+{-| Get rid of whitespace on both sides of a string.
+
+    trim "  hats  \n" == "hats"
+-}
+trim : String -> String
+trim = Native.String.trim
+
+{-| Get rid of whitespace on the left of a string.
+
+    trimLeft "  hats  \n" == "hats  \n"
+-}
+trimLeft : String -> String
+trimLeft = Native.String.trimLeft
+
+{-| Get rid of whitespace on the right of a string.
+
+    trimRight "  hats  \n" == "  hats"
+-}
+trimRight : String -> String
+trimRight = Native.String.trimRight
+
+{-| Break a string into words, splitting on chunks of whitespace.
+
+    words "How are \t you? \n Good?" == ["How","are","you?","Good?"]
+-}
+words : String -> List String
+words = Native.String.words
+
+{-| Break a string into lines, splitting on newlines.
+
+    lines "How are you?\nGood?" == ["How are you?", "Good?"]
+-}
+lines : String -> List String
+lines = Native.String.lines
+
+{-| Convert a string to all upper case. Useful for case insensitive comparisons
+and VIRTUAL YELLING.
+-}
+toUpper : String -> String
+toUpper = Native.String.toUpper
+
+{-| Convert a string to all lower case. Useful for case insensitive comparisons. -}
+toLower : String -> String
+toLower = Native.String.toLower
+
+{-| Determine whether *any* characters satisfy a predicate.
+
+    any isDigit "90210" == True
+    any isDigit "R2-D2" == True
+    any isDigit "heart" == False
+-}
+any : (Char -> Bool) -> String -> Bool
+any = Native.String.any
+
+{-| Determine whether *all* characters satisfy a predicate.
+
+    all isDigit "90210" == True
+    all isDigit "R2-D2" == False
+    all isDigit "heart" == False
+-}
+all : (Char -> Bool) -> String -> Bool
+all = Native.String.all
+
+{-| See if the second string contains the first one.
+
+    contains "the" "theory" == True
+    contains "hat" "theory" == False
+    contains "THE" "theory" == False
+
+Use `Regex.contains` if you need something more flexible.
+-}
+contains : String -> String -> Bool
+contains = Native.String.contains
+
+{-| See if the second string starts with the first one.
+
+    startsWith "the" "theory" == True
+    startsWith "ory" "theory" == False
+-}
+startsWith : String -> String -> Bool
+startsWith = Native.String.startsWith
+
+{-| See if the second string ends with the first one.
+
+    endsWith "the" "theory" == False
+    endsWith "ory" "theory" == True
+-}
+endsWith : String -> String -> Bool
+endsWith = Native.String.endsWith
+
+{-| Get all of the indexes for a substring in another string.
+
+    indexes "i" "Mississippi"   == [1,4,7,10]
+    indexes "ss" "Mississippi"  == [2,5]
+    indexes "needle" "haystack" == []
+-}
+indexes : String -> String -> List Int
+indexes = Native.String.indexes
+
+{-| Alias for `indexes` -}
+indices : String -> String -> List Int
+indices = Native.String.indexes
+
+
+{-| Try to convert a string into an int, failing on improperly formatted strings.
+
+    toInt "123" == Ok 123
+    toInt "-42" == Ok -42
+    toInt "3.1" == Err "could not convert string '3.1' to an Int"
+    toInt "31a" == Err "could not convert string '31a' to an Int"
+-}
+toInt : String -> Result String Int
+toInt = Native.String.toInt
+
+{-| Try to convert a string into a float, failing on improperly formatted strings.
+
+    toFloat "123" == Ok 123.0
+    toFloat "-42" == Ok -42.0
+    toFloat "3.1" == Ok 3.1
+    toFloat "31a" == Err "could not convert string '31a' to a Float"
+-}
+toFloat : String -> Result String Float
+toFloat = Native.String.toFloat
+
+{-| Convert a string to a list of characters.
+
+    toList "abc" == ['a','b','c']
+-}
+toList : String -> List Char
+toList = Native.String.toList
+
+{-| Convert a list of characters into a String. Can be useful if you
+want to create a string primarly by consing, perhaps for decoding
+something.
+
+    fromList ['a','b','c'] == "abc"
+-}
+fromList : List Char -> String
+fromList = Native.String.fromList
+ src/Text.elm view
@@ -0,0 +1,261 @@+module Text where
+{-| A library for styling and displaying text. Whlie the `String` library
+focuses on representing and manipulating strings of character strings, the
+`Text` library focuses on how those strings should look on screen. It lets
+you make text bold or italic, set the typeface, set the text size, etc.
+
+# Creating Text
+@docs fromString, empty, append, concat, join
+
+# Creating Elements
+
+Each of the following functions places `Text` into a box. The function you use
+determines the alignment of the text.
+
+@docs leftAligned, rightAligned, centered, justified
+
+# Links and Style
+@docs link, Style, style, defaultStyle, Line
+
+# Convenience Functions
+
+There are two convenience functions for creating an `Element` which can be
+useful when debugging or prototyping:
+
+@docs plainText, asText
+
+There are also a bunch of functions to set parts of a `Style` individually:
+
+@docs typeface, monospace, height, color, bold, italic, line
+
+-}
+
+import Basics (..)
+import Color (Color, black)
+import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
+import List
+import Maybe (Maybe(Nothing))
+import Native.Text
+
+type Text = Text
+
+{-| Styles for lines on text. This allows you to add an underline, an overline,
+or a strike out text:
+
+    line Under   (fromString "underline")
+    line Over    (fromString "overline")
+    line Through (fromString "strike out")
+-}
+type Line = Under | Over | Through
+
+{-| Represents all the ways you can style `Text`. If the `typeface` list is
+empty or the `height` is `Nothing`, the users will fall back on their browser's
+default settings. The following `Style` is black, 16 pixel tall, underlined, and
+Times New Roman (assuming that typeface is available on the user's computer):
+
+    { typeface = [ "Times New Roman", "serif" ]
+    , height   = Just 16
+    , color    = black
+    , bold     = False
+    , italic   = False
+    , line     = Just Under
+    }
+-}
+type alias Style =
+  { typeface : List String
+  , height   : Maybe Float
+  , color    : Color
+  , bold     : Bool
+  , italic   : Bool
+  , line     : Maybe Line
+  }
+
+{-| Plain black text. It uses the browsers default typeface and text height.
+No decorations are used.
+
+    { typeface = []
+    , height = Nothing
+    , color = black
+    , bold = False
+    , italic = False
+    , line = Nothing
+    }
+-}
+defaultStyle : Style
+defaultStyle =
+  { typeface = []
+  , height = Nothing
+  , color = black
+  , bold = False
+  , italic = False
+  , line = Nothing
+  }
+
+{-| Convert a string into text which can be styled and displayed. To show the
+string `"Hello World!"` on screen in italics, you could say:
+
+    main = leftAligned (italic (fromString "Hello World!"))
+-}
+fromString : String -> Text
+fromString = Native.Text.fromString
+
+
+{-| Text with nothing in it.
+
+    empty = fromString ""
+-}
+empty : Text
+empty =
+    fromString ""
+
+
+{-| Put two chunks of text together.
+
+    append (fromString "hello ") (fromString "world") == fromString "hello world"
+-}
+append : Text -> Text -> Text
+append =
+    Native.Text.append
+
+
+{-| Put many chunks of text together.
+
+    concat
+      [ fromString "type "
+      , bold (fromString "Maybe")
+      , fromString " = Just a | Nothing"
+      ]
+-}
+concat : List Text -> Text
+concat texts =
+    List.foldr append empty texts
+
+
+{-| Put many chunks of text together with a separator.
+
+    chunks : List Text
+    chunks = List.map fromString ["lions","tigers","bears"]
+
+    join (fromString ", ") chunks == fromString "lions, tigers, bears"
+-}
+join : Text -> List Text -> Text
+join seperator texts =
+    concat (List.intersperse seperator texts)
+
+
+{-| Set the style of some text. For example, if you design a `Style` called
+`footerStyle` that is specifically for the bottom of your page, you could apply
+it to text like this:
+
+    style footerStyle (fromString "the old prince / 2007")
+-}
+style : Style -> Text -> Text
+style = Native.Text.style
+
+{-| Provide a list of prefered typefaces for some text.
+
+    ["helvetica","arial","sans-serif"]
+
+Not every browser has access to the same typefaces, so rendering will use the
+first typeface in the list that is found on the user's computer. If there are
+no matches, it will use their default typeface. This works the same as the CSS
+font-family property.
+-}
+typeface : List String -> Text -> Text
+typeface = Native.Text.typeface
+
+{-| Switch to a monospace typeface. Good for code snippets.
+
+    monospace (fromString "foldl (+) 0 [1,2,3]")
+-}
+monospace : Text -> Text
+monospace = Native.Text.monospace
+
+{-| Create a link by providing a URL and the text of the link.
+
+    link "http://elm-lang.org" (fromString "Elm Website")
+-}
+link : String -> Text -> Text
+link = Native.Text.link
+
+{-| Set the height of some text.
+
+    height 40 (fromString "Title")
+-}
+height : Float -> Text -> Text
+height = Native.Text.height
+
+{-| Set the color of some text.
+
+    color red (fromString "Red")
+-}
+color : Color -> Text -> Text
+color = Native.Text.color
+
+{-| Make text bold.
+
+    fromString "sometimes you want " ++ bold (fromString "emphasis")
+-}
+bold : Text -> Text
+bold = Native.Text.bold
+
+{-| Make text italic.
+
+    fromString "make it " ++ italic (fromString "important")
+-}
+italic : Text -> Text
+italic = Native.Text.italic
+
+{-| Put lines on text.
+
+    line Under   (fromString "underlined")
+    line Over    (fromString "overlined")
+    line Through (fromString "strike out")
+-}
+line : Line -> Text -> Text
+line = Native.Text.line
+
+{-| Align text along the left side of the text block. This is sometimes known as
+*ragged right*.
+-}
+leftAligned : Text -> Element
+leftAligned = Native.Text.leftAligned
+
+{-| Align text along the right side of the text block. This is sometimes known
+as *ragged left*.
+-}
+rightAligned : Text -> Element
+rightAligned = Native.Text.rightAligned
+
+{-| Center text in the text block. There is equal spacing on either side of a
+line of text.
+-}
+centered : Text -> Element
+centered = Native.Text.centered
+
+{-| Align text along the left and right sides of the text block. Word spacing is
+adjusted to make this possible.
+-}
+justified : Text -> Element
+justified = Native.Text.justified
+
+{-| Display a string with no styling.
+
+    plainText string = leftAligned (fromString string)
+-}
+plainText : String -> Element
+plainText str =
+    leftAligned (fromString str)
+
+{-| for internal use only -}
+markdown : Element
+markdown = Native.Text.markdown
+
+{-| Convert anything to its textual representation and make it displayable in
+the browser. Excellent for debugging.
+
+    asText value = leftAligned (monospace (fromString (show value)))
+-}
+asText : a -> Element
+asText value =
+    leftAligned (monospace (fromString (toString value)))
+ src/Time.elm view
@@ -0,0 +1,105 @@+module Time where
+
+{-| Library for working with time.
+
+# Units
+@docs Time, millisecond, second, minute, hour,
+      inMilliseconds, inSeconds, inMinutes, inHours
+
+# Tickers
+@docs fps, fpsWhen, every
+
+# Timing
+@docs timestamp, delay, since
+
+-}
+
+import Basics (..)
+import Native.Time
+import Signal (Signal, map, merge, foldp)
+
+{-| Type alias to make it clearer when you are working with time values.
+Using the `Time` constants instead of raw numbers is very highly recommended.
+-}
+type alias Time = Float
+
+{-| Units of time, making it easier to specify things like a half-second
+`(500 * milliseconds)` without remembering Elm&rsquo;s underlying units of time.
+-}
+millisecond : Time
+millisecond = 1
+
+second : Time
+second = 1000 * millisecond
+
+minute : Time
+minute = 60 * second
+
+hour : Time
+hour = 60 * minute
+
+inMilliseconds : Time -> Float
+inMilliseconds t = t
+
+inSeconds : Time -> Float
+inSeconds t = t / second
+
+inMinutes : Time -> Float
+inMinutes t = t / minute
+
+inHours : Time -> Float
+inHours t = t / hour
+
+{-| Takes desired number of frames per second (fps). The resulting signal
+gives a sequence of time deltas as quickly as possible until it reaches
+the desired FPS. A time delta is the time between the last frame and the
+current frame.
+-}
+fps : number -> Signal Time
+fps = Native.Time.fps
+
+{-| Same as the fps function, but you can turn it on and off. Allows you
+to do brief animations based on user input without major inefficiencies.
+The first time delta after a pause is always zero, no matter how long
+the pause was. This way summing the deltas will actually give the amount
+of time that the output signal has been running.
+-}
+fpsWhen : number -> Signal Bool -> Signal Time
+fpsWhen = Native.Time.fpsWhen
+
+{-| Takes a time interval t. The resulting signal is the current time, updated
+every t.
+-}
+every : Time -> Signal Time
+every = Native.Time.every
+
+{-| Takes a time `t` and any signal. The resulting boolean signal is true for
+time `t` after every event on the input signal. So ``(second `since`
+Mouse.clicks)`` would result in a signal that is true for one second after
+each mouse click and false otherwise.
+-}
+since : Time -> Signal a -> Signal Bool
+since t s =
+    let
+        start = map (always 1) s
+        stop = map (always -1) (delay t s)
+        delaydiff = foldp (+) 0 (merge start stop)
+    in
+        map ((/=) 0) delaydiff
+
+{-| Add a timestamp to any signal. Timestamps increase monotonically. When you
+create `(timestamp Mouse.x)`, an initial timestamp is produced. The timestamp
+updates whenever `Mouse.x` updates.
+
+Timestamp updates are tied to individual events, so
+`(timestamp Mouse.x)` and `(timestamp Mouse.y)` will always have the same
+timestamp because they rely on the same underlying event (`Mouse.position`).
+-}
+timestamp : Signal a -> Signal (Time, a)
+timestamp = Native.Time.timestamp
+
+{-| Delay a signal by a certain amount of time. So `(delay second Mouse.clicks)`
+will update one second later than any mouse click.
+-}
+delay : Time -> Signal a -> Signal a
+delay = Native.Time.delay
+ src/Touch.elm view
@@ -0,0 +1,41 @@+module Touch where
+
+{-| This is an early version of the touch library. It will likely grow to
+include gestures that would be useful for both games and web-pages.
+
+# Touches
+@docs Touch, touches
+
+# Gestures
+@docs taps
+-}
+
+import Signal (Signal)
+import Native.Touch
+import Time (Time)
+
+{-| Every `Touch` has `xy` coordinates. It also has an identifier
+`id` to distinguish one touch from another.
+
+A touch also keeps info about the initial point and time of contact:
+`x0`, `y0`, and `t0`. This helps compute more complicated gestures
+like taps, drags, and swipes which need to know about timing or direction.
+-}
+type alias Touch =
+    { x:Int
+    , y:Int
+    , id:Int
+    , x0:Int
+    , y0:Int
+    , t0:Time
+    }
+
+{-| A list of ongoing touches. -}
+touches : Signal (List Touch)
+touches = Native.Touch.touches
+
+{-| The last position that was tapped. Default value is `{x=0,y=0}`.
+Updates whenever the user taps the screen.
+-}
+taps : Signal { x:Int, y:Int }
+taps = Native.Touch.taps
+ src/Trampoline.elm view
@@ -0,0 +1,51 @@+module Trampoline where
+{-| A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining)
+makes it possible to recursively call a function without growing the stack.
+
+Popular JavaScript implementations do not perform any tail-call elimination, so
+recursive functions can cause a stack overflow if they go too deep. Trampolines
+permit unbounded recursion despite limitations in JavaScript.
+
+This strategy may create many intermediate closures, which is very expensive in
+JavaScript, so use this library only when it is essential that you recurse deeply.
+
+# Trampolines
+@docs trampoline, Trampoline
+-}
+
+import Native.Trampoline
+
+{-| A way to build computations that may be deeply recursive. We will take an
+example of a tail-recursive function and rewrite it in a way that lets us use
+a trampoline:
+
+    length : List a -> Int
+    length list = length' 0 list
+
+    length' : Int -> List a -> Int
+    length' accum list =
+        case list of
+          []     -> accum
+          hd::tl -> length' (accum+1) tl
+
+This finds the length of a list, but if the list is too long, it may cause a
+stack overflow. We can rewrite it as follows:
+
+    length : List a -> Int
+    length list = trampoline (length' 0 list)
+
+    length' : Int -> List a -> Trampoline Int
+    length' accum list =
+        case list of
+          []     -> Done accum
+          hd::tl -> Continue (\() -> length' (accum+1) tl)
+
+Now it uses a trampoline and can recurse without growing the stack!
+-}
+type Trampoline a
+    = Done a
+    | Continue (() -> Trampoline a)
+
+{-| Evaluate a trampolined value in constant space. -}
+trampoline : Trampoline a -> a
+trampoline = Native.Trampoline.trampoline
+ src/Transform2D.elm view
@@ -0,0 +1,98 @@+module Transform2D ( Transform2D
+                   , identity, matrix, multiply
+                   , rotation, translation
+                   , scale, scaleX, scaleY
+                   ) where
+{-| A library for performing [2D matrix transformations][affine].
+It is used primarily with the `groupTransform` function from `Graphics.Collage` and
+allows you to do things like rotation, scaling, translation, shearing, and reflection.
+
+Note that all the matrices in this library are 3x3 matrices of homogeneous
+coordinates, used for [affine transformations][affine]. Since the bottom row as
+always `0 0 1` in these matrices, it is omitted in the diagrams below.
+
+ [affine]: http://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations
+
+# Transforms
+@docs identity, matrix, rotation, translation, scale, scaleX, scaleY
+
+# Multiplication
+@docs multiply
+-}
+
+import Native.Transform2D
+
+type Transform2D = Transform2D
+
+{-| Create an identity transform. Transforming by the identity does
+not change anything, but it can come in handy as a default or
+base case.
+
+        / 1 0 0 \
+        \ 0 1 0 /
+-}
+identity : Transform2D
+identity = Native.Transform2D.identity
+
+{-| Create a transformation matrix. This lets you create transforms
+such as scales, shears, reflections, and translations.
+
+    matrix a b c d x y
+
+        / a b x \
+        \ c d y /
+
+Note that `x` and `y` are the translation values.
+-}
+matrix : Float -> Float -> Float -> Float -> Float -> Float -> Transform2D
+matrix = Native.Transform2D.matrix
+
+{-| Create a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix).
+Given an angle t, it creates a counterclockwise rotation matrix:
+
+    rotation t
+
+        / cos t  -sin t  0 \
+        \ sin t   cos t  0 /
+-}
+rotation : Float -> Transform2D
+rotation = Native.Transform2D.rotation
+
+{-| Create a transformation matrix for translation.
+
+    translation x y
+
+        / 1 0 x \
+        \ 0 1 y /
+-}
+translation : Float -> Float -> Transform2D
+translation x y = matrix 1 0 0 1 x y
+
+{-| Creates a transformation matrix for scaling by a all directions.
+
+    scale s
+
+      / s 0 0 \
+      \ 0 s 0 /
+-}
+scale : Float -> Transform2D
+scale s = matrix s 0 0 s 0 0
+
+{-| Create a transformation for horizontal scaling. -}
+scaleX : Float -> Transform2D
+scaleX x = matrix x 0 0 1 0 0
+
+{-| Create a transformation for vertical scaling. -}
+scaleY : Float -> Transform2D
+scaleY y = matrix 1 0 0 y 0 0
+
+{-| Multiply two transforms together.
+
+    multiply m n
+
+        / ma mb mx \     / na nb nx \
+        | mc md my |  .  | nc nd ny |
+        \  0  0  1 /     \  0  0  1 /
+-}
+multiply : Transform2D -> Transform2D -> Transform2D
+multiply = Native.Transform2D.multiply
+ src/WebSocket.elm view
@@ -0,0 +1,21 @@+module WebSocket where
+{-| A library for low latency HTTP communication. See the HTTP library for
+standard requests like GET, POST, etc. The API of this library is likely to
+change to make it more flexible.
+
+# Open a Connection
+@docs connect
+-}
+
+import Signal (Signal)
+import Native.WebSocket
+
+{-| Create a web-socket. The first argument is the URL of the desired
+web-socket server. The input signal holds the outgoing messages,
+and the resulting signal contains the incoming ones.
+-}
+connect : String -> Signal String -> Signal String
+connect = Native.WebSocket.connect
+
+-- data Action = Open String | Close String | Send String String
+-- connections : Signal Action -> Signal String
+ src/Window.elm view
@@ -0,0 +1,27 @@+
+module Window where
+
+{-| Provides information about the container that your Elm program lives in.
+When you embed Elm in a `<div>` it gives the dimensions of the container, not
+the whole window.
+
+# Dimensions
+@docs dimensions, width, height
+
+-}
+
+import Signal (Signal)
+import Native.Window
+
+{-| The current width and height of the window (i.e. the area viewable to the
+user, not including scroll bars). -}
+dimensions : Signal (Int,Int)
+dimensions = Native.Window.dimensions
+
+{-| The current width of the window. -}
+width : Signal Int
+width = Native.Window.width
+
+{-| The current height of the window. -}
+height : Signal Int
+height = Native.Window.height