diff --git a/Elm.cabal b/Elm.cabal
--- a/Elm.cabal
+++ b/Elm.cabal
@@ -1,6 +1,6 @@
 
 Name:                Elm
-Version:             0.3.5
+Version:             0.3.6
 Synopsis:            The Elm language module.
 Description:         Elm aims to make client-side web-development more pleasant.
                      It is a statically/strongly typed, functional reactive
@@ -22,7 +22,7 @@
 Build-type:          Simple
 
 Extra-source-files:  changelog.txt
-Data-files:          elm-runtime-0.3.5.js
+Data-files:          elm-runtime-0.3.6.js
 Cabal-version:       >=1.8
 
 source-repository head
@@ -50,10 +50,10 @@
                        ParseModules,
                        ParseForeign,
                        Types,
-                       Constrain,
-                       Hints,
-                       Types,
-                       Unify
+                       Types.Constrain,
+                       Types.Hints,
+                       Types.Substitutions,
+                       Types.Unify
 
   Build-depends:       base >=4.2 && <5,
                        containers >= 0.3,
@@ -87,10 +87,10 @@
                        ParseModules,
                        ParseForeign,
                        Types,
-                       Constrain,
-                       Hints,
-                       Types,
-                       Unify
+                       Types.Constrain,
+                       Types.Hints,
+                       Types.Substitutions,
+                       Types.Unify
 
   Build-depends:       base >=4.2 && <5,
                        containers >= 0.3,
diff --git a/changelog.txt b/changelog.txt
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,4 +1,37 @@
 
+Release 0.3.6
+=============
+
+* Add JSON library.
+
+* Type-error messages improved. Gives better context for error, making them
+  easier to find. Better messages for runtime errors as well (errors that
+  the type checker cannot find yet).
+
+* Add Comparable super-type which allows the comparision of any values
+  of type {Int,Float,Char,String}. Now possible to make Set and Map libraries.
+
+* Parser now handles decimal numbers.
+
+* Added many new functions for manipulating numbers:
+  - truncate, round, floor, ceiling :: Float -> Int
+  - toFloat :: Int -> Float
+  - (^) :: Number -> Number -> Number
+  - e :: Float
+
+* Foreign import/export statements no longer have to preceed all other
+  variable and datatype definitions. They can be mixed in, making things
+  a bit more readable/natural.
+
+* Bug fixes:
+  - The `toText` function did not escape strings properly
+  - Correct `castJSTupleToTupleN` family of functions
+  - `foldr1` took the leftmost element as the base case instead of the rightmost
+  - Fix minor display issue in latest version of Chrome.
+  - Fix behavior of [ lo .. hi ] syntax (now [4..0] == [], not [0]).
+
+
+
 Release 0.3.5
 =============
 
diff --git a/elm-runtime-0.3.5.js b/elm-runtime-0.3.5.js
deleted file mode 100644
--- a/elm-runtime-0.3.5.js
+++ /dev/null
@@ -1,60 +0,0 @@
-var Guid=function(){var d=0;return{guid:function(){return d+=1}}}(),Foreign=function(){return{JavaScript:function(){function d(a){for(var b=["Nil"],c=a.length;c--;)b=["Cons",a[c],b];return b}function c(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b}function b(a){return a.slice(1)}function a(a){return a.unshift("Tuple"+a.length)}return{castJSBoolToBool:function(a){return a},castBoolToJSBool:function(a){return a},castJSNumberToFloat:function(a){return a},castFloatToJSNumber:function(a){return a},
-castJSNumberToInt:function(a){return~~a},castIntToJSNumber:function(a){return a},Experimental:{castJSElementToElement:function(a){return Element.jsElement(a)},castElementToJSElement:function(a){return a}},castJSArrayToList:d,castListToJSArray:c,castJSStringToString:d,castStringToJSString:function(a){return"string"===typeof a?a:c(a).join("")},castTupleToJSTuple2:b,castTupleToJSTuple3:b,castTupleToJSTuple4:b,castTupleToJSTuple5:b,castJSTupleToTuple2:a,castJSTupleToTuple3:a,castJSTupleToTuple4:a,castJSTupleToTuple5:a}}()}}(),
-Value=function(){var d=function(a,b){if("object"===typeof a){if(a===b)return!0;if(a.length!==b.length)return!1;for(var c=a.length;c--;)if(!d(a[c],b[c]))return!1;return!0}return a===b},c=function(a){a.replace('"',"&#34;");a.replace("&","&#38;");a.replace("'","&#39;");a.replace("<","&#60;");a.replace(">","&#62;");return a},b=function(a){if("boolean"===typeof a)return a?"True":"False";if("number"!==typeof a&&a[0]){if("Tuple"===a[0].substring(0,5)){for(var c="",i=a.length;--i;)c=","+b(a[i])+c;","===c[0]&&
-(c=c.substring(1));return"("+c+")"}if("Cons"===a[0])for(var i="string"===typeof a[1]?'"':"]",d="string"===typeof a[1]?"":",",c=("string"===typeof a[1]?'"':"[")+b(a[1]),a=a[2];;)if("Cons"===a[0])c+=d+b(a[1]),a=a[2];else return c+i;else{if("Nil"===a[0])return"[]";c="";for(i=a.length;--i;)c=" "+b(a[i])+c;c=a[0]+c;return 1<a.length?"("+c+")":c}}return a+""};return{eq:d,str:function(a){for(var b=["Nil"],c=a.length;c--;)b=["Cons",a[c],b];return b},show:function(a){return Text.monospace(c(b(a)))},Tuple:function(){var a=
-arguments.length,b=Array(a+1);for(b[0]="Tuple"+arguments.length;a--;)b[a+1]=arguments[a];return b},append:function(a,b){if("string"===typeof a&&"string"===typeof b)return a.concat(b);if("Nil"===a[0])return b;for(var c=["Cons",a[1],["Nil"]],d=c,a=a[2];"Cons"===a[0];)d[2]=["Cons",a[1],["Nil"]],a=a[2],d=d[2];d[2]=b;return c},listToArray:function(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b},toText:function(a){if("string"===typeof a)return a;for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];
-return c(b.join(""))},properEscape:c}}(),List=function(){function d(a){return function(f){if("Nil"===f[0])return f;"Cons"!==f[0]&&e("map");for(var b=["Cons",a(f[1]),["Nil"]],g=b,f=f[2];"Cons"===f[0];)g[2]=["Cons",a(f[1]),["Nil"]],f=f[2],g=g[2];return b}}function c(a){return function(f){return function(b){var g=f;if("Nil"===b[0])return g;for("Cons"!==b[0]&&e("foldl");"Cons"===b[0];)g=a(b[1])(g),b=b[2];return g}}}function b(a){return function(f){return function(b){var g=f;if("Nil"===b[0])return g;"Cons"!==
-b[0]&&e("foldr");for(var c=[];"Cons"===b[0];)c.push(b[1]),b=b[2];for(b=c.length;b--;)g=a(c[b])(g);return g}}}function a(a){return function(f){var b;"Cons"!==f[0]?b=void 0:(b=f[1],f=f[2],b=c(a)(b)(f));return b}}function h(a){return function(f){return function(b){if("Nil"===b[0])return["Cons",f,["Nil"]];"Cons"!==b[0]&&e("scanl");for(var g=[f];"Cons"===b[0];)f=a(b[1])(f),g.push(f),b=b[2];for(var b=["Nil"],c=g.length;c--;)b=["Cons",g[c],b];return b}}}function i(a){return function(b){return function(){for(var f=
-[function(a){return"Nil"!==a[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(b){if("Cons"===b[0]){var f=b[1],b=b[2];var g=i(a)(b);"Tuple2"!==g[0]?f=void 0:(b=g[1],g=g[2],f=a(f)?["Tuple2",["Cons",f,b],g]:["Tuple2",b,["Cons",f,g]]);return f}}],g=f.length;g--;){var c=f[g](b);if(void 0!==c)return c}}()}}function l(a){return function(){for(var b=[function(a){return"Nil"!==a[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(a){if("Cons"!==a[0])a=void 0;else if(a=["Tuple2",a[1],l(a[2])],"Tuple2"!==a[0]||"Tuple2"!==
-a[1][0])a=void 0;else var b=a[1][1],f=a[1][2],a="Tuple2"!==a[2][0]?void 0:["Tuple2",["Cons",b,a[2][1]],["Cons",f,a[2][2]]];return a}],f=b.length;f--;){var g=b[f](a);if(void 0!==g)return g}}()}function n(a){return function(b){return function(){for(var f=[function(a){return"Nil"!==a[0]?void 0:["Nil"]},function(a){if("Cons"===a[0]){var b=a[1];return"Nil"!==a[2][0]?void 0:["Cons",b,["Nil"]]}},function(b){if("Cons"===b[0]){var f=b[1];if("Cons"===b[2][0]){var g=b[2][1],b=b[2][2];return["Cons",f,["Cons",
-a,n(a)(["Cons",g,b])]]}}}],g=f.length;g--;){var c=f[g](b);if(void 0!==c)return c}}()}}function o(a){return function(b){return function(){for(var f=[function(a){return"Nil"!==a[0]?void 0:["Nil"]},function(a){if("Cons"===a[0]){var b=a[1];return"Nil"!==a[2][0]?void 0:b}},function(b){if("Cons"===b[0]){var f=b[1];if("Cons"===b[2][0]){var g=b[2][1],b=b[2][2];return Value.append(f,Value.append(a,o(a)(["Cons",g,b])))}}}],g=f.length;g--;){var c=f[g](b);if(void 0!==c)return c}}()}}var e=function(a){throw"Function '"+
-a+"' expecting a list!";},j=c(function(a){return function(b){return["Cons",a,b]}})(["Nil"]),k=b(function(a){return function(b){return Value.append(a,b)}})(["Nil"]),m=c(function(a){return function(b){return a&&b}})(!0),f=c(function(a){return function(b){return a||b}})(!1),g=c(function(a){return function(b){return a+b}})(0),t=c(function(a){return function(b){return a*b}})(1),q=a(function(a){return function(b){return Math.max(a,b)}}),s=a(function(a){return function(b){return Math.min(a,b)}});return{head:function(a){if("Cons"!==
-a[0])throw"Error: 'head' only accepts lists of length greater than one.";return a[1]},tail:function(a){if("Cons"!==a[0])throw"Error: 'tail' only accepts lists of length greater than one.";return a[2]},last:function(a){if("Cons"!==a[0])throw"Error: 'last' only accepts lists of length greater than one.";for(var b=a[1];"Cons"===a[0];)b=a[1],a=a[2];return b},map:d,foldl:c,foldr:b,foldl1:a,foldr1:function(a){return function(f){var g;"Cons"!==f[0]?g=void 0:(g=f[1],f=f[2],g=b(a)(g)(f));return g}},scanl:h,
-scanl1:function(a){return function(b){if("Cons"!==b[0])throw"Error: 'scanl1' requires a list of at least length 1.";return h(a)(b[1])(b[2])}},filter:function(a){return function(b){if("Nil"===b[0])return b;"Cons"!==b[0]&&e("filter");for(var f=[];"Cons"===b[0];)a(b[1])&&f.push(b[1]),b=b[2];for(var b=["Nil"],g=f.length;g--;)b=["Cons",f[g],b];return b}},length:function(a){for(var b=0;"Cons"===a[0];)b+=1,a=a[2];return b},reverse:j,concat:k,concatMap:function(a){return function(b){return k(d(a)(b))}},and:m,
-or:f,forall:function(a){return c(function(b){return function(f){return f&&a(b)}})(!0)},exists:function(a){return c(function(b){return function(f){return f||a(b)}})(!1)},sum:g,product:t,maximum:q,minimum:s,partition:i,zipWith:function(a){return function(b){return function(f){if("Nil"===b[0]||"Nil"===f[0])return["Nil"];("Cons"!==b[0]||"Cons"!==f[0])&&e("zipWith");for(var g=[];"Cons"===b[0]&&"Cons"===f[0];)g.push(a(b[1])(f[1])),b=b[2],f=f[2];for(var f=["Nil"],c=g.length;c--;)f=["Cons",g[c],f];return f}}},
-zip:function(a){return function(b){if("Nil"===a[0]||"Nil"===b[0])return["Nil"];("Cons"!==a[0]||"Cons"!==b[0])&&e("zip");for(var f=[];"Cons"===a[0]&&"Cons"===b[0];)f.push(["Tuple2",a[1],b[1]]),a=a[2],b=b[2];for(var b=["Nil"],g=f.length;g--;)b=["Cons",f[g],b];return b}},unzip:l,intersperse:n,intercalate:o,sort:function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&e("sort");for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];b.sort(function(a,b){return a-b});for(var a=["Nil"],f=b.length;f--;)a=["Cons",b[f],
-a];return a},take:function(a){return function(b){if(0>=a)return["Nil"];if("Nil"===b[0])return b;"Cons"!==b[0]&&e("take");var f=["Cons",b[1],["Nil"]],g=f,b=b[2];for(--a;"Cons"===b[0]&&0<a;)g[2]=["Cons",b[1],["Nil"]],g=g[2],b=b[2],--a;return f}},drop:function(a){return function(b){if("Nil"===b[0])return b;for("Cons"!==b[0]&&e("drop");"Cons"===b[0]&&0<a;)b=b[2],--a;return b}}}}(),Data=function(){var d=function(){return{fromCode:function(b){return String.fromCharCode(b)},toCode:function(b){return b.charCodeAt(0)},
-toUpper:function(b){return b.toUpperCase()},toLower:function(b){return b.toLowerCase()},toLocaleUpper:function(b){return b.toLocaleUpperCase()},toLocaleLower:function(b){return b.toLocaleLowerCase()}}}(),c=function(){function b(a){return function(b){return"Just"===a[0]?["Cons",a[1],b]:b}}function a(a){return function(b){return function(c){var d=a(b);return"Just"===d[0]?["Cons",d[1],c]:c}}}return{Just:function(a){return["Just",a]},Nothing:["Nothing"],catMaybes:List.foldr(b)(["Nil"]),isJust:function(a){return"Just"===
-a[0]},isNothing:function(a){return"Nothing"===a[0]},fromMaybe:function(a){return function(b){return"Just"===b[0]?b[1]:a}},consMaybe:b,mapMaybe:function(b){return List.foldr(a(b))(["Nil"])},maybe:function(a){return function(b){return function(c){return"Just"===c[0]?b(c[1]):a}}}}}();return{String:{toText:Value.toText,properEscape:Value.properEscape},Char:d,Maybe:c,List:List}}(),Color=function(){var d=function(c,b,a,d){return{r:c,g:b,b:a,a:d}};return{black:d(0,0,0,1),white:d(255,255,255,1),red:d(255,
-0,0,1),green:d(0,255,0,1),blue:d(0,0,255,1),gray:d(128,128,128,1),grey:d(128,128,128,1),yellow:d(255,255,0,1),cyan:d(0,255,255,1),magenta:d(255,0,255,1),rgba:function(c){return function(b){return function(a){return function(h){return d(c,b,a,h)}}}},rgb:function(c){return function(b){return function(a){return d(c,b,a,1)}}},Internal:{extract:function(c){return 1===c.a?"rgb("+c.r+","+c.g+","+c.b+")":"rgba("+c.r+","+c.g+","+c.b+","+c.a+")"}}}}(),Element=function(){var d=function(a){a=document.createElement(a);
-a.id=Guid.guid();a.style.padding="0";a.style.margin="0";return a},c=function(a){var b=d("div");b.appendChild(a);return b},b=function(a){return function(b){return function(c){var e=d("div");e.isElmLeaf=!0;e.isElmText=!0;e.innerHTML=c;e.style.textAlign=b;0<a&&(e.style.width=a+"px");return e}}},a=b(0)("left"),h=b(0)("justify"),i=b(0)("center"),l=b(0)("right"),n=function(a){return"DIV"===a.tagName?a:c(a)},o=function(a){a.style.styleFloat="left";a.style.cssFloat="left";return a},e=function(a){a.style.position=
-"absolute";return a},j=function(a,b,c){for(var e=d("div"),j=c.length;j--;){var k=b(c[j]);e.appendChild(k)}e.elmFlowDirection=a;return e},k=function(a){return function(b){for(var c=[];"Cons"===b[0];)c.push(b[1]),b=b[2];3<=a&&c.reverse();b=a%3;if(0==b)return j("Y",n,c);if(1==b)return j("X",o,c);if(2==b)return j("Z",e,c)}},m=function(a){return function(g){if("A"===g.tagName)return m(a)(g.firstChild),g;if(g.hasOwnProperty("isElmText")){var c=b(a)(g.style.textAlign)(g.innerHTML);g.style.height=c.style.height}g.style.width=
-a+"px";return g}};return{text:a,image:function(a){var b=d("img");b.isElmLeaf=!0;b.onload=function(){""===b.style.width&&0<this.width&&(b.style.width=b.width=this.width+"px");""===b.style.height&&0<this.height&&(b.style.height=b.height=this.height+"px");Dispatcher.adjust()};b.src=Data.String.toText(a);b.name=b.src;return b},fittedImage:function(a){return function(b){return function(c){var e=d("canvas");e.style.width=a+"px";e.style.height=b+"px";e.width=a;e.height=b;e.innerHTML="Your browser does not support the canvas element.";
-e.isElmLeaf=!0;var j=d("img");j.onload=function(){if(e.getContext){var c=e.getContext("2d"),d=0,k=0,m=this.width,i=this.height;a/b>this.width/this.height?(i=this.width*b/a,k=(this.height-i)/2):(m=this.height*a/b,d=(this.width-m)/2);c.drawImage(j,d,k,m,i,0,0,e.width,e.height)}};j.src=Data.String.toText(c);return e}}},video:function(a){var a=Data.String.toText(a),b=d("video");b.controls="controls";var c=d("source");c.src=a;c.type="video/"+a.substring(a.length-3,a.length);b.appendChild(c);b.isElmLeaf=
-!0;return b},audio:function(a){var a=Data.String.toString(a),b=d("video");b.controls="controls";var c=d("source");c.src=a;c.type="audio/"+a.substring(a.length-3,a.length);b.appendChild(c);b.isElmLeaf=!0;return b},collage:function(a){return function(b){return function(c){var e=d("canvas");e.style.width=a+"px";e.style.height=b+"px";e.width=a;e.height=b;if(e.getContext){var j=e.getContext("2d");for(j.clearRect(0,0,e.width,e.height);"Cons"===c[0];)j=c[1](j),c=c[2];return e}e.innerHTML="Your browser does not support the canvas element.";
-e.isElmLeaf=!0;return e}}},flow:k,layers:k(2),rectangle:function(a){return function(b){var c=d("div");c.isElmLeaf=!0;c.style.width=a+"px";c.style.height=b+"px";return c}},beside:function(a){return function(b){return k(4)(["Cons",a,["Cons",b,["Nil"]]])}},above:function(a){return function(b){return k(3)(["Cons",a,["Cons",b,["Nil"]]])}},below:function(a){return function(b){return k(0)(["Cons",a,["Cons",b,["Nil"]]])}},box:function(a){return function(b){b.style.position="absolute";b.style.margin="auto";
-var c=(a-1)%3,e=(a-1)/3;2>c&&(b.style.left=0);0<c&&(b.style.right=0);2>e&&(b.style.top=0);0<e&&(b.style.bottom=0);c=d("div");c.style.position="relative";c.appendChild(b);return c}},width:m,height:function(a){return function(b){("A"===b.tagName?b.firstChild:b).style.height=a+"px";return b}},size:function(a){return function(b){return function(c){var e="A"===c.tagName?c.firstChild:c;e.style.width=a+"px";e.style.height=b+"px";return c}}},color:function(a){return function(b){b.style.backgroundColor=Color.Internal.extract(a);
-return b}},opacity:function(a){return function(b){b.style.opacity=a;return b}},link:function(a){return function(b){var e=d("a");e.href=Text.fromString(a);e.appendChild(b);return c(e)}},asText:function(a){return b(0)("left")(Value.show(a))},plainText:function(a){return b(0)("left")(Data.String.toText(a))},justifiedText:h,centeredText:i,rightedText:l,up:0,left:1,inward:2,down:3,right:4,outward:5,correctTextSize:function(a){var b=a.style.width?a.style.width.slice(0,-2):0,c=d("div");c.innerHTML=a.innerHTML;
-c.style.textAlign=a.style.textAlign;0<b&&(c.style.width=b+"px");c.style.visibility="hidden";c.style.styleFloat="left";c.style.cssFloat="left";document.body.appendChild(c);var e=window.getComputedStyle(c);0>=b&&(a.style.width=e.getPropertyValue("width"));a.style.height=e.getPropertyValue("height");document.body.removeChild(c)},jsElement:function(a){return function(b){return function(c){var e=d("div");e.isElmLeaf=!0;e.style.width=a+"px";e.style.height=b+"px";e.appendChild(c);return e}}}}}(),Text=function(){var d=
-function(a){if("string"===typeof a)return a;for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return Data.String.properEscape(b.join(""))},c=function(a){return function(b){return"<"+a+' style="padding:0;margin:0">'+b+"</"+a+">"}},b=function(a,b){return function(c){return"<span style='"+a+":"+b+"'>"+c+"</span>"}},a=c("h1"),h=b("font-style","italic"),c=c("b"),i=b("text-decoration","underline"),l=b("text-decoration","overline"),n=b("text-decoration","line-through");return{fromString:d,toText:d,header:a,
-height:function(a){return b("font-size",a+"em")},italic:h,bold:c,underline:i,overline:l,strikeThrough:n,monospace:b("font-family","monospace"),color:function(a){return b("color",Color.Internal.extract(a))},link:function(a){return function(b){return"<a href='"+d(a)+"'>"+b+"</a>"}}}}(),Shape=function(){var d=function(b,a,c,d){return{center:b,points:a,theta:c,scale:d}},c=function(b){return function(a){return function(c){return function(d){d.save();d.translate(c.center[0],c.center[1]);d.rotate(c.theta);
-d.scale(c.scale,c.scale);d.beginPath();var l=c.points;d.moveTo(l[0][0],l[0][1]);for(var n=l.length;n--;)d.lineTo(l[n][0],l[n][1]);d.closePath();b?(d.fillStyle=Color.Internal.extract(a),d.fill()):(d.strokeStyle=Color.Internal.extract(a),d.stroke());d.restore();return d}}}};return{polygon:function(b){return function(a){for(var c=[];"Cons"===b[0];)c.push([b[1][1],b[1][2]]),b=b[2];a=[a[1],a[2]];return d(a,c,0,1)}},ngon:function(b){return function(a){return function(c){for(var i=[],l=b;l--;)i.push([a*
-Math.cos(2*Math.PI*l/b),a*Math.sin(2*Math.PI*l/b)]);c=[c[1],c[2]];return d(c,i,0,1)}}},rect:function(b){return function(a){return function(c){var i=[[-b/2,-a/2],[b/2,-a/2],[b/2,a/2],[-b/2,a/2]],c=[c[1],c[2]];return d(c,i,0,1)}}},oval:function(b){return function(a){return function(c){for(var i=[],l=2*Math.PI;0<l;l-=Math.PI/50)i.push([b/2*Math.cos(l),a/2*Math.sin(l)]);c=[c[1],c[2]];return d(c,i,0,1)}}},move:function(b){return function(a){return function(c){return d([b+c.center[0],a+c.center[1]],c.points,
-c.theta,c.scale)}}},rotate:function(b){return function(a){return d(a.center,a.points,a.theta+2*Math.PI*b,a.scale)}},scale:function(b){return function(a){return d(a.center,a.points,a.theta,a.scale*b)}},filled:c(!0),outlined:c(!1),customOutline:function(b){return function(a){return function(c){c.points.push(c.points[0]);return Line.customLine(b)(a)(c)}}}}}(),Line=function(){var d=function(c){return function(b){return function(a){if("string"===typeof c[0]){for(var d=[];"Cons"===c[0];)d.push(c[1]),c=
-c[2];c=d}0===c.length&&(c=[8,4]);return function(d){d.save();d.beginPath();d.translate(a.center[0],a.center[1]);d.rotate(a.theta);d.scale(a.scale,a.scale);var l=c,n=a.points,o=n.length-1,e=n[o][0],j=n[o][1],k=0,m=0,f=0,g=0,h=0,q=0,s=l.length,r=!0,p=l[0];for(d.moveTo(e,j);o--;){k=n[o][0];m=n[o][1];f=k-e;g=m-j;for(h=Math.sqrt(f*f+g*g);p<=h;)e+=f*p/h,j+=g*p/h,d[r?"lineTo":"moveTo"](e,j),f=k-e,g=m-j,h=Math.sqrt(f*f+g*g),r=!r,q=(q+1)%s,p=l[q];0<h&&(d[r?"lineTo":"moveTo"](k,m),p-=h);e=k;j=m}d.strokeStyle=
-Color.Internal.extract(b);d.stroke();d.restore();return d}}}};return{line:function(c){for(var b=[];"Cons"===c[0];)b.push([c[1][1],c[1][2]]),c=c[2];return{center:[0,0],points:b,theta:0,scale:1}},customLine:d,solid:function(c){return function(b){return function(a){a.save();a.beginPath();a.translate(b.center[0],b.center[1]);a.rotate(b.theta);a.scale(b.scale,b.scale);var d=b.points,i=d.length;for(a.moveTo(d[i-1][0],d[i-1][1]);i--;)a.lineTo(d[i][0],d[i][1]);a.strokeStyle=Color.Internal.extract(c);a.stroke();
-a.restore();return a}}},dashed:d([8,4]),dotted:d([3,3])}}(),Elm=function(){var d=function(a,b,c){for(var d=a.kids,m=d.length;m--;)d[m].recv(b,c,a.id)},c=function(a){this.id=Guid.guid();this.value=a;this.kids=[];this.recv=function(a,b,c){if(b=b===this.id)this.value=c;d(this,a,b)};Dispatcher.inputs.push(this)},b=function(a,b){this.id=Guid.guid();this.value=null;this.kids=[];this.inbox={};b.reverse();this.recalc=function(){for(var c=a,d=b.length;d--;)c=c(b[d].value);this.value=c};this.recalc();this.recv=
-function(a,c){this.inbox.hasOwnProperty(a)||(this.inbox[a]={changed:!1,count:0});var f=this.inbox[a];f.count+=1;c&&(f.changed=!0);f.count==b.length&&(f.changed&&this.recalc(),d(this,a,f.changed),delete this.inbox[a])};for(var c=b.length;c--;)b[c].kids.push(this)},a=function(a,b,c){this.id=Guid.guid();this.value=b;this.kids=[];this.recv=function(b,e){e&&(this.value=a(c.value)(this.value));d(this,b,e)};c.kids.push(this)},h=function(a,b,c){this.id=Guid.guid();this.value=a(c.value)?b:c.value;this.kids=
-[];this.recv=function(b,e){var f=e&&!a(c.value);f&&(this.value=c.value);d(this,b,f)};c.kids.push(this)},i=function(a){this.id=Guid.guid();this.value=a.value;this.kids=[];this.recv=function(b,c){var k=c&&!eq(this.value,a.value);k&&(this.value=a.value);d(this,b,k)};a.kids.push(this)},l=function(a){return function(c){return function(d){d=new b(function(a){return function(b){return[a,b]}},[a,d]);d=new h(function(a){return a[0]},[!0,c],d);return new b(function(a){return a[1]},[d])}}},n=function(a,b){this.id=
-Guid.guid();this.value=b.value;this.kids=[];this.inbox={};this.recv=function(c,k,m){if(k=k&&m===a.id)this.value=b.value;d(this,c,k)};a.kids.push(this);b.kids.push(this)};return{Input:function(a){return new c(a)},Lift:function(a,c){return new b(a,c)},Fold:function(b,c,d){return new a(b,c,d)},keepIf:function(a){return function(b){return function(c){return new h(function(b){return!a(b)},b,c)}}},dropIf:function(a){return function(b){return function(c){return new h(a,b,c)}}},keepWhen:function(a){return l(new b(function(a){return!a},
-[a]))},dropWhen:l,dropRepeats:function(a){return new i(a)},sampleOn:function(a){return function(b){return new n(a,b)}}}}(),Dispatcher=function(){var d=null,c=0,b=[],a=function(b){var c=b.childNodes,d=c.length;if(b.hasOwnProperty("isElmLeaf")){b.hasOwnProperty("isElmText")&&Element.correctTextSize(b);var c=""===b.style.width?0:b.style.width.slice(0,-2)-0,h=""===b.style.height?0:b.style.height.slice(0,-2)-0;return[c,h]}if(1===d){var e=a(c[0]);""!==b.style.width&&(e[0]=b.style.width.slice(0,-2)-0);""!==
-b.style.height&&(e[1]=b.style.height.slice(0,-2)-0);0!==e[0]&&(b.style.width=e[0]+"px");0!==e[1]&&(b.style.height=e[1]+"px");return e}for(var j=0,k=h=0,m=0,f=!0,g=!0;d--;)e=a(c[d]),j=Math.max(j,e[0]),h=Math.max(h,e[1]),k+=e[0],m+=e[1],f=f&&0<e[0],g=g&&0<e[1];c=j;d=b.elmFlowDirection;"X"===d&&(c=f?k:0);"Y"===d&&(h=g?m:0);0<c&&(b.style.width=c+"px");0<h&&(b.style.height=h+"px");return[c,h]},h=function(){var b=document.getElementById("content");a(b.children[0])};return{initialize:function(){d=ElmCode.main();
-d.hasOwnProperty("recv")||(d=Elm.Input(d));document.getElementById("content").appendChild(d.value);h();var a=document.getElementById("widthChecker").offsetWidth;a!==window.innerWidth&&Dispatcher.notify(Window.dimensions.id,Value.Tuple(a,window.innerHeight));d=Elm.Lift(function(a){var b=document.getElementById("content"),c=b.children[0];b.replaceChild(a,c);delete c;h();return a},[d])},notify:function(a,d){c+=1;for(var h=b.length;h--;)b[h].recv(c,a,d)},adjust:h,inputs:b}}(),Signal=function(){function d(a){for(var b=
-["Nil"],c=a.length;c--;)b=["Cons",a[c],b];return b}var c=function(){return document.addEventListener?function(a,b,c){a.addEventListener(b,c,!1)}:function(a,b,c){a.attachEvent("on"+b,c)}}(),b=function(){function a(b){var c=0,d=0;b||(b=window.event);if(b.pageX||b.pageY)c=b.pageX,d=b.pageY;else if(b.clientX||b.clientY)c=b.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,d=b.clientY+document.body.scrollTop+document.documentElement.scrollTop;return Value.Tuple(c,d)}var b=Elm.Input(Value.Tuple(0,
-0)),d=Elm.Input(!1),m=Elm.Input(!1),f=Elm.Input(Value.Tuple());c(document,"click",function(){Dispatcher.notify(m.id,!0);Dispatcher.notify(f.id,Value.Tuple());Dispatcher.notify(m.id,!1)});c(document,"mousedown",function(){Dispatcher.notify(d.id,!0)});c(document,"mouseup",function(){Dispatcher.notify(d.id,!1)});c(document,"mousemove",function(c){Dispatcher.notify(b.id,a(c))});return{position:b,x:Elm.Lift(function(a){return a[1]},[b]),y:Elm.Lift(function(a){return a[2]},[b]),isClicked:m,isDown:d,clicks:f}}(),
-a=function(){return{every:function(a){var a=1E3*a,b=Elm.Input(0),c=0;setInterval(function(){c+=a;Dispatcher.notify(b.id,c/1E3)},a);return b},after:function(a){var a=1E3*a,b=Elm.Input(!1);setTimeout(function(){Dispatcher.notify(b.id,!0)},a);return b},before:function(a){var a=1E3*a,b=Elm.Input(!0);setTimeout(function(){Dispatcher.notify(b.id,!1)},a);return b}}}(),h=function(){var a=Elm.Input(Value.Tuple(window.innerWidth,window.innerHeight));c(window,"resize",function(){var b=document.getElementById("widthChecker").offsetWidth;
-Dispatcher.notify(a.id,Value.Tuple(b,window.innerHeight))});return{dimensions:a,width:Elm.Lift(function(a){return a[1]},[a]),height:Elm.Lift(function(a){return a[2]},[a])}}(),i={Raw:function(){function a(b,c){return"Nil"===c[0]?c:c[1]===b?c[2]:["Cons",c[1],a(b,c[2])]}var b=Elm.Input(["Nil"]),d=Elm.Input(["Nothing"]);c(document,"keydown",function(a){var c;a:{for(c=b.value;"Nil"!==c[0];){if(c[1]===a.keyCode){c=!0;break a}c=c[2]}c=!1}c||Dispatcher.notify(b.id,["Cons",a.keyCode,b.value])});c(document,
-"keyup",function(c){c=a(c.keyCode,b.value);Dispatcher.notify(b.id,c)});c(window,"blur",function(){Dispatcher.notify(b.id,["Nil"])});c(document,"keypress",function(a){Dispatcher.notify(d.id,["Just",a.charCode||a.keyCode]);Dispatcher.notify(d.id,["Nothing"])});return{keysDown:b,charPressed:d}}()},l=function(){var a=function(a){return function(b){var c=Elm.Input(["Waiting"]),e={};window.XMLHttpRequest?e=new XMLHttpRequest:window.ActiveXObject&&(e=new ActiveXObject("Microsoft.XMLHTTP"));e.onreadystatechange=
-function(){4===e.readyState&&Dispatcher.notify(c.id,200===e.status?["Success",d(e.responseText)]:["Failure",e.status,d(e.statusText)])};e.open(a,Data.String.toText(b),!0);e.send(null);return c}},b=function(a){return function(b){var c=Elm.Input(["Nothing"]),b=Elm.Lift(function(b){if("Just"!==b[0]){try{Dispatcher.notify(c.id,["Nothing"])}catch(e){}return[]}try{Dispatcher.notify(c.id,["Just",["Waiting"]])}catch(m){c.value=["Just",["Waiting"]]}var j={};window.XMLHttpRequest?j=new XMLHttpRequest:window.ActiveXObject&&
-(j=new ActiveXObject("Microsoft.XMLHTTP"));j.onreadystatechange=function(){4===j.readyState&&Dispatcher.notify(c.id,["Just",200===j.status?["Success",d(j.responseText)]:["Failure",j.status,d(j.statusText)]])};j.open(a,Data.String.toText(b[1]),!0);j.send(null);return[]},[b]);return Elm.Lift(function(a){return function(){return a}},[c,b])}};return{get:a("GET"),post:a("POST"),gets:b("GET"),posts:b("POST")}}(),n=function(){return{inRange:function(a){return function(b){return Elm.Input(Math.floor(Math.random()*
-(b-a+1))+a)}},randomize:function(a){return function(b){return function(c){return Elm.Lift(function(){return Math.floor(Math.random()*(b-a+1))+a},[c])}}}}}(),o=function(){var a=function(a){a.isElmLeaf=!0;var b=Elm.Input(["Nil"]);c(a,"keyup",function(){Dispatcher.notify(b.id,d(a.value));a.focus()});return Value.Tuple(a,b)},b=function(a){a=document.createElement(a);a.id=Guid.guid();return a},h=function(a){for(var d=b("select"),e=[];"Cons"===a[0];){var h=b("option"),k=Text.toText(a[1][1]);h.value=k;h.innerHTML=
-k;d.appendChild(h);e.push(a[1][2]);a=a[2]}var i=Elm.Input(e[0]);c(d,"change",function(){Dispatcher.notify(i.id,e[d.selectedIndex])});return Value.Tuple(d,i)};return{textArea:function(c){return function(d){var g=b("textarea");g.rows=d;g.cols=c;return a(g,"")}},textField:function(c){var d=b("input");d.type="text";return a(d,c)},password:function(c){var d=b("input");d.type="password";return a(d,c)},checkbox:function(a){var d=b("input");d.type="checkbox";d.checked=a;var e=Elm.Input(a);c(d,"change",function(){Dispatcher.notify(e.id,
-d.checked)});return Value.Tuple(d,e)},dropDown:h,stringDropDown:function(a){return h(List.map(function(a){return Value.Tuple(a,a)})(a))},button:function(a){var d=b("input");d.type="button";d.value=Text.toText(a);var e=Elm.Input(!1);c(d,"click",function(){Dispatcher.notify(e.id,!0);Dispatcher.notify(e.id,!1)});return Value.Tuple(d,e)}}}();return{addListener:c,Mouse:b,Keyboard:i,Time:a,Window:h,HTTP:l,Random:n,Input:o,constant:function(a){return Elm.Input(a)},lift:function(a){return function(b){return Elm.Lift(a,
-[b])}},lift2:function(a){return function(b){return function(c){return Elm.Lift(a,[b,c])}}},lift3:function(a){return function(b){return function(c){return function(d){return Elm.Lift(a,[b,c,d])}}}},lift4:function(a){return function(b){return function(c){return function(d){return function(f){return Elm.Lift(a,[b,c,d,f])}}}}},foldp:function(a){return function(b){return function(c){return Elm.Fold(a,b,c)}}},count:function(a){return Elm.Fold(function(){return function(a){return a+1}},0,a)},keepIf:Elm.keepIf,
-dropIf:Elm.dropIf,keepWhen:Elm.keepWhen,dropWhen:Elm.dropWhen,dropRepeats:Elm.dropRepeats,sampleOn:Elm.sampleOn}}(),Prelude=function(){var d=function(c){return function(b){var a=c%b,a=0==c?0:0<b?0<=c?a:a+b:-d(-c)(-b);return a==b?0:a}};return{id:function(c){return c},not:function(c){return!c},fst:function(c){return c[1]},snd:function(c){return c[2]},rem:function(c){return function(b){return c%b}},sqrt:Math.sqrt,abs:Math.abs,pi:Math.PI,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,
-atan:Math.atan,mod:d,min:function(c){return function(b){return Math.min(c,b)}},max:function(c){return function(b){return Math.max(c,b)}},flip:function(c){return function(b){return function(a){return c(a)(b)}}},clamp:function(c){return function(b){return function(a){return Math.min(b,Math.max(c,a))}}},curry:function(c){return function(b){return function(a){return c(["Tuple2",b,a])}}},uncurry:function(c){return function(b){if("Tuple2"!==b[0])throw"Function was uncurry'd but was not given a pair.";return c(b[1])(b[2])}},
-logBase:function(c){return function(b){return Math.log(b)/Math.log(c)}},Just:Data.Maybe.Just,Nothing:Data.Maybe.Nothing,maybe:Data.Maybe.maybe,map:Data.List.map,filter:Data.List.filter,head:Data.List.head,tail:Data.List.tail,last:Data.List.last,length:Data.List.length,reverse:Data.List.reverse,foldr:Data.List.foldr,foldr1:Data.List.foldr1,foldl:Data.List.foldl,foldl1:Data.List.foldl1,and:Data.List.and,or:Data.List.or,forall:Data.List.forall,exists:Data.List.exists,sum:Data.List.sum,product:Data.List.product,
-concat:Data.List.concat,concatMap:Data.List.concatMap,maximum:Data.List.maximum,minimum:Data.List.minimum,scanl:Data.List.scanl,scanl1:Data.List.scanl1,take:Data.List.take,drop:Data.List.drop,lift:Signal.lift,lift2:Signal.lift2,lift3:Signal.lift3,lift4:Signal.lift4,foldp:Signal.foldp,constant:Signal.constant,count:Signal.count,keepIf:Signal.keepIf,dropIf:Signal.dropIf,keepWhen:Signal.keepWhen,dropWhen:Signal.dropWhen,dropRepeats:Signal.dropRepeats,sampleOn:Signal.sampleOn}}(),eq=Value.eq;
-Signal.addListener(document,"elm_log",function(d){console.log(d.value)});Signal.addListener(document,"elm_title",function(d){document.title=d.value});Signal.addListener(document,"elm_redirect",function(d){0<d.value.length&&(window.location=d.value)});var includeGlobal=this;
-(function(){var d=function(b){for(var a in b)if("Internal"!==a)try{includeGlobal[a]=b[a]}catch(c){"length"===a&&(includeGlobal.execScript("var length;"),length=b[a])}},c=function(b){return function(a){includeGlobal[b]=includeGlobal[b]||{};for(var c in a)"Internal"!==c&&(includeGlobal[b][c]=a[c])}};d(Element);d(Text);color=Element.color;height=Element.height;show=Value.show;d(Color);d(Shape);d(Line);c("Time")(Signal.Time);c("Mouse")(Signal.Mouse);c("Keyboard")(Signal.Keyboard);c("Window")(Signal.Window);
-c("HTTP")(Signal.HTTP);c("Input")(Signal.Input);c("Random")(Signal.Random)})();var ElmCode={};ElmCode.Data=Data;ElmCode.Signal=Signal;ElmCode.Data.List=List;ElmCode.Foreign=Foreign;ElmCode.Prelude=Prelude;
diff --git a/elm-runtime-0.3.6.js b/elm-runtime-0.3.6.js
new file mode 100644
--- /dev/null
+++ b/elm-runtime-0.3.6.js
@@ -0,0 +1,67 @@
+var Guid=function(){var d=0;return{guid:function(){return d+=1}}}(),Foreign=function(){var d=function(a){for(var c=["Nil"],b=a.length;b--;)c=["Cons",a[b],c];return c},b=function(a){for(var c=[];"Cons"===a[0];)c.push(a[1]),a=a[2];return c},c=function(a){return a.slice(1)},a=function(a){return["Tuple"+a.length].concat(a)};return{JavaScript:{castJSBoolToBool:function(a){return a},castBoolToJSBool:function(a){return a},castJSNumberToFloat:function(a){return a},castFloatToJSNumber:function(a){return a},
+castJSNumberToInt:function(a){return~~a},castIntToJSNumber:function(a){return a},Experimental:{castJSElementToElement:function(a){return Element.jsElement(a)},castElementToJSElement:function(a){return a}},castJSArrayToList:d,castListToJSArray:b,castJSStringToString:d,castStringToJSString:function(a){return"string"===typeof a?a:b(a).join("")},castTupleToJSTuple2:c,castTupleToJSTuple3:c,castTupleToJSTuple4:c,castTupleToJSTuple5:c,castJSTupleToTuple2:a,castJSTupleToTuple3:a,castJSTupleToTuple4:a,castJSTupleToTuple5:a}}}(),
+ElmJSON=function(){function d(a){return function(g){function b(a){switch(a[0]){case "JsonNull":return null;case "JsonString":return c.castStringToJSString(a[1]);case "JsonObject":var g={},a=a[1][1],d;for(d in a)g[d]=b(a[d]);return g;case "JsonArray":g=c.castListToJSArray(a[1]);for(d=g.length;d--;)g[d]=b(g[d]);return g;default:return a[1]}}return JSON.stringify(b(["JsonObject",g]),null,c.castStringToJSString(a))}}function b(a){function g(a){switch(typeof a){case "string":return["JsonString",c.castJSStringToString(a)];
+case "number":return["JsonNumber",c.castJSNumberToFloat(a)];case "boolean":return["JsonBool",c.castJSBoolToBool(a)];case "object":if(null===a)return["JsonNull"];for(var b in a)a[b]=g(a[b]);return a instanceof Array?["JsonArray",c.castJSArrayToList(a)]:["JsonObject",["JSON",a]]}}var a=JSON.parse(a),b;for(b in a)a[b]=g(a[b]);return["JSON",a]}var c=Foreign.JavaScript;return{empty:["JSON",{}],singleton:function(a){return function(g){var b={};b[c.castStringToJSString(a)]=g;return["JSON",b]}},insert:function(a){return function(g){return function(b){var b=
+b[1],d={},i;for(i in b)d[i]=b[i];d[c.castStringToJSString(a)]=g;return["JSON",d]}}},lookup:function(a){return function(b){var f=c.castStringToJSString(a);return b[1].hasOwnProperty(f)?Just(b[1][f]):Nothing}},findWithDefault:function(a){return function(b){return function(f){var d=c.castStringToJSString(b);return f[1].hasOwnProperty(d)?f[1][d]:a}}},remove:function(a){return function(b){var b=b[1],f={},d;for(d in b)f[d]=b[d];delete f[c.castStringToJSString(a)];return["JSON",f]}},toPrettyJSString:d,toJSString:d(""),
+fromJSString:b,toPrettyString:function(a){return function(b){return c.castJSStringToString(d(a)(b))}},toString:function(a){return c.castJSStringToString(d("")(a))},fromString:function(a){return b(c.castStringToJSString(a))},toList:function(a){var a=a[1],b=[],d;for(d in a)b.push(Value.Tuple(c.castJSStringToString(d),a[d]));return c.castJSArrayToList(b)},fromList:function(a){for(var a=c.castListToJSArray(a),b={},d=a.length;d--;)b[c.castStringToJSString(a[d][1])]=a[d][2];return["JSON",b]},JsonString:function(a){return["JsonString",
+a]},JsonNumber:function(a){return["JsonNumber",a]},JsonBool:function(a){return["JsonBool",a]},JsonNull:["JsonNull"],JsonArray:function(a){return["JsonArray",a]},JsonObject:function(a){return["JsonObject",a]}}}();Foreign.JavaScript.JSON=ElmJSON;
+var Value=function(){function d(a){if(0==a.length)return a;for(var a=a.replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;").replace(/>/g,"&#62;").replace(/\n/g,"<br/>"),a=a.split("<br/>"),c=a.length;c--;){var b=a,d=c,i;i=a[c].split("");" "==i[0]&&(i[0]="&nbsp;");for(var j=i.length;--j;)" "==i[j][0]&&" "==i[j-1]&&(i[j-1]+=i[j],i[j]="");for(j=i.length;j--;)if(1<i[j].length&&" "==i[j][0]){for(var h=i[j].split(""),m=h.length-2;0<=m;m-=2)h[m]="&nbsp;";i[j]=h.join("")}i=i.join("");b[d]=i}return a.join("<br/>")}
+var b=function(a,c){if("object"===typeof a){if(a===c)return!0;if(a.length!==c.length)return!1;for(var d=a.length;d--;)if(!b(a[d],c[d]))return!1;return!0}return a===c},c=function(a){if("boolean"===typeof a)return a?"True":"False";if("number"!==typeof a){if("string"===typeof a&&2>a.length)return"'"+a+"'";if(a[0]){if("Tuple"===a[0].substring(0,5)){for(var b="",d=a.length;--d;)b=","+c(a[d])+b;","===b[0]&&(b=b.substring(1));return"("+b+")"}if("Cons"===a[0])for(var d="string"===typeof a[1]?'"':"]",k="string"===
+typeof a[1]?"":",",i="string"===typeof a[1]?function(a){return a}:c,b=("string"===typeof a[1]?'"':"[")+i(a[1]),a=a[2];;)if("Cons"===a[0])b+=k+i(a[1]),a=a[2];else return b+d;else{if("Nil"===a[0])return"[]";if("JSON"===a[0])return"(JSON.fromList "+c(ElmJSON.toList(a))+")";b="";for(d=a.length;--d;)b=" "+c(a[d])+b;b=a[0]+b;return 1<a.length?"("+b+")":b}}}return a+""};return{eq:b,str:function(a){for(var b=["Nil"],c=a.length;c--;)b=["Cons",a[c],b];return b},show:function(a){return Text.monospace(d(c(a)))},
+Tuple:function(){var a=arguments.length,b=Array(a+1);for(b[0]="Tuple"+arguments.length;a--;)b[a+1]=arguments[a];return b},append:function(a,b){if("string"===typeof a&&"string"===typeof b)return a.concat(b);if("Nil"===a[0])return b;for(var c=["Cons",a[1],["Nil"]],d=c,a=a[2];"Cons"===a[0];)d[2]=["Cons",a[1],["Nil"]],a=a[2],d=d[2];d[2]=b;return c},listToArray:function(a){for(var b=[];"Cons"===a[0];)b.push(a[1]),a=a[2];return b},toText:function(a){if("string"===typeof a)return d(a);for(var b=[];"Cons"===
+a[0];)b.push(a[1]),a=a[2];return d(b.join(""))},properEscape:d}}(),List=function(){function d(a){return function(e){if("Nil"===e[0])return e;"Cons"!==e[0]&&h("map");for(var b=["Cons",a(e[1]),["Nil"]],c=b,e=e[2];"Cons"===e[0];)c[2]=["Cons",a(e[1]),["Nil"]],e=e[2],c=c[2];return b}}function b(a){return function(e){return function(b){var c=e;if("Nil"===b[0])return c;for("Cons"!==b[0]&&h("foldl");"Cons"===b[0];)c=a(b[1])(c),b=b[2];return c}}}function c(a){return function(e){return function(b){var c=e;
+if("Nil"===b[0])return c;"Cons"!==b[0]&&h("foldr");for(var d=[];"Cons"===b[0];)d.push(b[1]),b=b[2];for(b=d.length;b--;)c=a(d[b])(c);return c}}}function a(a){return function(e){var c;"Cons"!==e[0]?c=void 0:(c=e[1],e=e[2],c=b(a)(c)(e));return c}}function g(a){return function(e){return function(b){if("Nil"===b[0])return["Cons",e,["Nil"]];"Cons"!==b[0]&&h("scanl");for(var c=[e];"Cons"===b[0];)e=a(b[1])(e),c.push(e),b=b[2];for(var b=["Nil"],d=c.length;d--;)b=["Cons",c[d],b];return b}}}function f(a){return function(e){a:{for(var b=
+[function(a){return"Nil"!==a[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(e){if("Cons"===e[0]){var b=e[1],e=e[2];var c=f(a)(e);"Tuple2"!==c[0]?b=void 0:(e=c[1],c=c[2],b=a(b)?["Tuple2",["Cons",b,e],c]:["Tuple2",e,["Cons",b,c]]);return b}}],c=b.length;c--;){var d=b[c](e);if(void 0!==d){e=d;break a}}e=void 0}return e}}function k(a){a:{for(var e=[function(a){return"Nil"!==a[0]?void 0:["Tuple2",["Nil"],["Nil"]]},function(a){if("Cons"!==a[0])a=void 0;else if(a=["Tuple2",a[1],k(a[2])],"Tuple2"!==a[0]||
+"Tuple2"!==a[1][0])a=void 0;else var e=a[1][1],b=a[1][2],a="Tuple2"!==a[2][0]?void 0:["Tuple2",["Cons",e,a[2][1]],["Cons",b,a[2][2]]];return a}],b=e.length;b--;){var c=e[b](a);if(void 0!==c){a=c;break a}}a=void 0}return a}function i(a){return function(e){a:{for(var b=[function(a){return"Nil"!==a[0]?void 0:["Nil"]},function(a){if("Cons"===a[0]){var e=a[1];return"Nil"!==a[2][0]?void 0:["Cons",e,["Nil"]]}},function(e){if("Cons"===e[0]){var b=e[1];if("Cons"===e[2][0]){var c=e[2][1],e=e[2][2];return["Cons",
+b,["Cons",a,i(a)(["Cons",c,e])]]}}}],c=b.length;c--;){var d=b[c](e);if(void 0!==d){e=d;break a}}e=void 0}return e}}function j(a){return function(e){a:{for(var b=[function(a){return"Nil"!==a[0]?void 0:["Nil"]},function(a){if("Cons"===a[0]){var e=a[1];return"Nil"!==a[2][0]?void 0:e}},function(e){if("Cons"===e[0]){var b=e[1];if("Cons"===e[2][0]){var c=e[2][1],e=e[2][2];return Value.append(b,Value.append(a,j(a)(["Cons",c,e])))}}}],c=b.length;c--;){var d=b[c](e);if(void 0!==d){e=d;break a}}e=void 0}return e}}
+var h=function(a){throw"Function '"+a+"' expecting a list!";},m=b(function(a){return function(e){return["Cons",a,e]}})(["Nil"]),l=c(function(a){return function(e){return Value.append(a,e)}})(["Nil"]),o=b(function(a){return function(e){return a&&e}})(!0),p=b(function(a){return function(e){return a||e}})(!1),n=b(function(a){return function(e){return a+e}})(0),q=b(function(a){return function(e){return a*e}})(1),s=a(function(a){return function(e){return Math.max(a,e)}}),r=a(function(a){return function(e){return Math.min(a,
+e)}});return{head:function(a){if("Cons"!==a[0])throw"Error: 'head' only accepts lists of length greater than one.";return a[1]},tail:function(a){if("Cons"!==a[0])throw"Error: 'tail' only accepts lists of length greater than one.";return a[2]},last:function(a){if("Cons"!==a[0])throw"Error: 'last' only accepts lists of length greater than one.";for(var e=a[1];"Cons"===a[0];)e=a[1],a=a[2];return e},map:d,foldl:b,foldr:c,foldl1:a,foldr1:function(a){return function(e){if("Nil"===e[0])throw"'foldr1' requires an non-empty list.";
+"Cons"!==e[0]&&h("foldr1");for(var b=[];"Cons"===e[0];)b.push(e[1]),e=e[2];for(var e=b.pop(),c=b.length;c--;)e=a(b[c])(e);return e}},scanl:g,scanl1:function(a){return function(e){if("Cons"!==e[0])throw"Error: 'scanl1' requires a list of at least length 1.";return g(a)(e[1])(e[2])}},filter:function(a){return function(e){if("Nil"===e[0])return e;"Cons"!==e[0]&&h("filter");for(var b=[];"Cons"===e[0];)a(e[1])&&b.push(e[1]),e=e[2];for(var e=["Nil"],c=b.length;c--;)e=["Cons",b[c],e];return e}},length:function(a){for(var e=
+0;"Cons"===a[0];)e+=1,a=a[2];return e},reverse:m,concat:l,concatMap:function(a){return function(e){return l(d(a)(e))}},and:o,or:p,forall:function(a){return b(function(e){return function(b){return b&&a(e)}})(!0)},exists:function(a){return b(function(e){return function(b){return b||a(e)}})(!1)},sum:n,product:q,maximum:s,minimum:r,partition:f,zipWith:function(a){return function(e){return function(b){if("Nil"===e[0]||"Nil"===b[0])return["Nil"];("Cons"!==e[0]||"Cons"!==b[0])&&h("zipWith");for(var c=[];"Cons"===
+e[0]&&"Cons"===b[0];)c.push(a(e[1])(b[1])),e=e[2],b=b[2];for(var b=["Nil"],d=c.length;d--;)b=["Cons",c[d],b];return b}}},zip:function(a){return function(b){if("Nil"===a[0]||"Nil"===b[0])return["Nil"];("Cons"!==a[0]||"Cons"!==b[0])&&h("zip");for(var c=[];"Cons"===a[0]&&"Cons"===b[0];)c.push(["Tuple2",a[1],b[1]]),a=a[2],b=b[2];for(var b=["Nil"],d=c.length;d--;)b=["Cons",c[d],b];return b}},unzip:k,intersperse:i,intercalate:j,sort:function(a){if("Nil"===a[0])return a;"Cons"!==a[0]&&h("sort");for(var b=
+[];"Cons"===a[0];)b.push(a[1]),a=a[2];b.sort(function(a,b){return a-b});for(var a=["Nil"],c=b.length;c--;)a=["Cons",b[c],a];return a},take:function(a){return function(b){if(0>=a)return["Nil"];if("Nil"===b[0])return b;"Cons"!==b[0]&&h("take");var c=["Cons",b[1],["Nil"]],d=c,b=b[2];for(--a;"Cons"===b[0]&&0<a;)d[2]=["Cons",b[1],["Nil"]],d=d[2],b=b[2],--a;return c}},drop:function(a){return function(b){if("Nil"===b[0])return b;for("Cons"!==b[0]&&h("drop");"Cons"===b[0]&&0<a;)b=b[2],--a;return b}}}}(),
+Data=function(){var d;d=function(b){return function(a){return"Just"===b[0]?["Cons",b[1],a]:a}};var b=function(b){return function(a){return function(d){var f=b(a);return"Just"===f[0]?["Cons",f[1],d]:d}}};d={Just:function(b){return["Just",b]},Nothing:["Nothing"],catMaybes:List.foldr(d)(["Nil"]),isJust:function(b){return"Just"===b[0]},isNothing:function(b){return"Nothing"===b[0]},fromMaybe:function(b){return function(a){return"Just"===a[0]?a[1]:b}},consMaybe:d,mapMaybe:function(c){return List.foldr(b(c))(["Nil"])},
+maybe:function(b){return function(a){return function(d){return"Just"===d[0]?a(d[1]):b}}}};return{String:{toText:Value.toText,properEscape:Value.properEscape},Char:{fromCode:function(b){return String.fromCharCode(b)},toCode:function(b){return b.charCodeAt(0)},toUpper:function(b){return b.toUpperCase()},toLower:function(b){return b.toLowerCase()},toLocaleUpper:function(b){return b.toLocaleUpperCase()},toLocaleLower:function(b){return b.toLocaleLowerCase()}},Maybe:d,List:List}}(),Color=function(){var d=
+function(b,c,a,d){return{r:b,g:c,b:a,a:d}};return{black:d(0,0,0,1),white:d(255,255,255,1),red:d(255,0,0,1),green:d(0,255,0,1),blue:d(0,0,255,1),gray:d(128,128,128,1),grey:d(128,128,128,1),yellow:d(255,255,0,1),cyan:d(0,255,255,1),magenta:d(255,0,255,1),rgba:function(b){return function(c){return function(a){return function(g){return d(b,c,a,g)}}}},rgb:function(b){return function(c){return function(a){return d(b,c,a,1)}}},Internal:{extract:function(b){return 1===b.a?"rgb("+b.r+","+b.g+","+b.b+")":"rgba("+
+b.r+","+b.g+","+b.b+","+b.a+")"}}}}(),Element=function(){var d=function(a){a=document.createElement(a);a.id=Guid.guid();a.style.padding="0";a.style.margin="0";return a},b=function(a){var b=d("div");b.appendChild(a);return b},c=function(a){return function(b){return function(c){var f=d("div");f.isElmLeaf=!0;f.isElmText=!0;f.innerHTML=c;f.style.textAlign=b;0<a&&(f.style.width=a+"px");return f}}},a=c(0)("left"),g=c(0)("justify"),f=c(0)("center"),k=c(0)("right"),i=function(a){return"DIV"===a.tagName?a:
+b(a)},j=function(a){a.style.styleFloat="left";a.style.cssFloat="left";return a},h=function(a){a.style.position="absolute";return a},m=function(a,b,c){for(var f=d("div"),h=c.length;h--;){var g=b(c[h]);f.appendChild(g)}f.elmFlowDirection=a;return f},l=function(a){return function(b){for(var c=[];"Cons"===b[0];)c.push(b[1]),b=b[2];3<=a&&c.reverse();b=a%3;if(0==b)return m("Y",i,c);if(1==b)return m("X",j,c);if(2==b)return m("Z",h,c)}},o=function(a){return function(b){if("A"===b.tagName)return o(a)(b.firstChild),
+b;if(b.hasOwnProperty("isElmText")){var d=c(a)(b.style.textAlign)(b.innerHTML);b.style.height=d.style.height}b.style.width=a+"px";return b}};return{text:a,image:function(a){var b=d("img");b.isElmLeaf=!0;b.onload=function(){""===b.style.width&&0<this.width&&(b.style.width=b.width=this.width+"px");""===b.style.height&&0<this.height&&(b.style.height=b.height=this.height+"px");Dispatcher.adjust()};b.src=Value.toText(a);b.name=b.src;return b},fittedImage:function(a){return function(b){return function(c){var f=
+d("canvas");f.style.width=a+"px";f.style.height=b+"px";f.width=a;f.height=b;f.innerHTML="Your browser does not support the canvas element.";f.isElmLeaf=!0;var h=d("img");h.onload=function(){if(f.getContext){var c=f.getContext("2d"),e=0,d=0,g=this.width,j=this.height;a/b>this.width/this.height?(j=this.width*b/a,d=(this.height-j)/2):(g=this.height*a/b,e=(this.width-g)/2);c.drawImage(h,e,d,g,j,0,0,f.width,f.height)}};h.src=Value.toText(c);return f}}},video:function(a){var a=Value.toText(a),b=d("video");
+b.controls="controls";var c=d("source");c.src=a;c.type="video/"+a.substring(a.length-3,a.length);b.appendChild(c);b.isElmLeaf=!0;return b},audio:function(a){var a=Value.toText(a),b=d("video");b.controls="controls";var c=d("source");c.src=a;c.type="audio/"+a.substring(a.length-3,a.length);b.appendChild(c);b.isElmLeaf=!0;return b},collage:function(a){return function(b){return function(c){var f=d("canvas");f.style.width=a+"px";f.style.height=b+"px";f.width=a;f.height=b;if(f.getContext){var h=f.getContext("2d");
+for(h.clearRect(0,0,f.width,f.height);"Cons"===c[0];)h=c[1](h),c=c[2];return f}f.innerHTML="Your browser does not support the canvas element.";f.isElmLeaf=!0;return f}}},flow:l,layers:l(2),rectangle:function(a){return function(b){var c=d("div");c.isElmLeaf=!0;c.style.width=a+"px";c.style.height=b+"px";return c}},beside:function(a){return function(b){return l(4)(["Cons",a,["Cons",b,["Nil"]]])}},above:function(a){return function(b){return l(3)(["Cons",a,["Cons",b,["Nil"]]])}},below:function(a){return function(b){return l(0)(["Cons",
+a,["Cons",b,["Nil"]]])}},box:function(a){return function(b){b.style.position="absolute";b.style.margin="auto";var c=(a-1)%3,f=(a-1)/3;2>c&&(b.style.left=0);0<c&&(b.style.right=0);2>f&&(b.style.top=0);0<f&&(b.style.bottom=0);c=d("div");c.style.position="relative";c.appendChild(b);return c}},width:o,height:function(a){return function(b){("A"===b.tagName?b.firstChild:b).style.height=a+"px";return b}},size:function(a){return function(b){return function(c){var d="A"===c.tagName?c.firstChild:c;d.style.width=
+a+"px";d.style.height=b+"px";return c}}},color:function(a){return function(b){b.style.backgroundColor=Color.Internal.extract(a);return b}},opacity:function(a){return function(b){b.style.opacity=a;return b}},link:function(a){return function(c){var f=d("a");f.href=Text.fromString(a);f.appendChild(c);return b(f)}},asText:function(a){return c(0)("left")(Value.show(a))},plainText:function(a){return c(0)("left")(Value.toText(a))},justifiedText:g,centeredText:f,rightedText:k,up:0,left:1,inward:2,down:3,
+right:4,outward:5,correctTextSize:function(a){var b=a.style.width?a.style.width.slice(0,-2):0,c=d("div");c.innerHTML=a.innerHTML;c.style.textAlign=a.style.textAlign;0<b&&(c.style.width=b+"px");c.style.visibility="hidden";c.style.styleFloat="left";c.style.cssFloat="left";document.body.appendChild(c);var f=window.getComputedStyle(c);0>=b&&(a.style.width=f.getPropertyValue("width"));a.style.height=f.getPropertyValue("height");document.body.removeChild(c)},jsElement:function(a){return function(b){return function(c){var f=
+d("div");f.isElmLeaf=!0;f.style.width=a+"px";f.style.height=b+"px";f.appendChild(c);return f}}}}}(),Text=function(){function d(a){return Value.toText(a)}var b=function(a){return function(b){return"<"+a+' style="padding:0;margin:0">'+b+"</"+a+">"}},c=function(a,b){return function(c){return"<span style='"+a+":"+b+"'>"+c+"</span>"}},a=function(a){return c("font-family",a)},g=b("h1"),f=c("font-style","italic"),b=b("b"),k=c("text-decoration","underline"),i=c("text-decoration","overline"),j=c("text-decoration",
+"line-through");return{fromString:d,toText:d,header:g,height:function(a){return c("font-size",a+"em")},italic:f,bold:b,underline:k,overline:i,strikeThrough:j,monospace:a("monospace"),typeface:a,color:function(a){return c("color",Color.Internal.extract(a))},link:function(a){return function(b){return"<a href='"+d(a)+"'>"+b+"</a>"}}}}(),Shape=function(){var d=function(b,a,d,f){return{center:b,points:a,theta:d,scale:f}},b=function(b){return function(a){return function(d){return function(f){f.save();f.translate(d.center[0],
+d.center[1]);f.rotate(d.theta);f.scale(d.scale,d.scale);f.beginPath();var k=d.points;f.moveTo(k[0][0],k[0][1]);for(var i=k.length;i--;)f.lineTo(k[i][0],k[i][1]);f.closePath();b?(f.fillStyle=Color.Internal.extract(a),f.fill()):(f.strokeStyle=Color.Internal.extract(a),f.stroke());f.restore();return f}}}};return{polygon:function(b){return function(a){for(var g=[];"Cons"===b[0];)g.push([b[1][1],b[1][2]]),b=b[2];a=[a[1],a[2]];return d(a,g,0,1)}},ngon:function(b){return function(a){return function(g){for(var f=
+[],k=b;k--;)f.push([a*Math.cos(2*Math.PI*k/b),a*Math.sin(2*Math.PI*k/b)]);g=[g[1],g[2]];return d(g,f,0,1)}}},rect:function(b){return function(a){return function(g){var f=[[-b/2,-a/2],[b/2,-a/2],[b/2,a/2],[-b/2,a/2]],g=[g[1],g[2]];return d(g,f,0,1)}}},oval:function(b){return function(a){return function(g){for(var f=[],k=2*Math.PI;0<k;k-=Math.PI/50)f.push([b/2*Math.cos(k),a/2*Math.sin(k)]);g=[g[1],g[2]];return d(g,f,0,1)}}},move:function(b){return function(a){return function(g){return d([b+g.center[0],
+a+g.center[1]],g.points,g.theta,g.scale)}}},rotate:function(b){return function(a){return d(a.center,a.points,a.theta+2*Math.PI*b,a.scale)}},scale:function(b){return function(a){return d(a.center,a.points,a.theta,a.scale*b)}},filled:b(!0),outlined:b(!1),customOutline:function(b){return function(a){return function(d){d.points.push(d.points[0]);return Line.customLine(b)(a)(d)}}}}}(),Line=function(){var d=function(b){return function(c){return function(a){if("string"===typeof b[0]){for(var d=[];"Cons"===
+b[0];)d.push(b[1]),b=b[2];b=d}0===b.length&&(b=[8,4]);return function(d){d.save();d.beginPath();d.translate(a.center[0],a.center[1]);d.rotate(a.theta);d.scale(a.scale,a.scale);var g=b,i=a.points,j=i.length-1,h=i[j][0],m=i[j][1],l=0,o=0,p=0,n=0,q=0,s=0,r=g.length,t=!0,e=g[0];for(d.moveTo(h,m);j--;){l=i[j][0];o=i[j][1];p=l-h;n=o-m;for(q=Math.sqrt(p*p+n*n);e<=q;)h+=p*e/q,m+=n*e/q,d[t?"lineTo":"moveTo"](h,m),p=l-h,n=o-m,q=Math.sqrt(p*p+n*n),t=!t,s=(s+1)%r,e=g[s];0<q&&(d[t?"lineTo":"moveTo"](l,o),e-=q);
+h=l;m=o}d.strokeStyle=Color.Internal.extract(c);d.stroke();d.restore();return d}}}};return{line:function(b){for(var c=[];"Cons"===b[0];)c.push([b[1][1],b[1][2]]),b=b[2];return{center:[0,0],points:c,theta:0,scale:1}},customLine:d,solid:function(b){return function(c){return function(a){a.save();a.beginPath();a.translate(c.center[0],c.center[1]);a.rotate(c.theta);a.scale(c.scale,c.scale);var d=c.points,f=d.length;for(a.moveTo(d[f-1][0],d[f-1][1]);f--;)a.lineTo(d[f][0],d[f][1]);a.strokeStyle=Color.Internal.extract(b);
+a.stroke();a.restore();return a}}},dashed:d([8,4]),dotted:d([3,3])}}(),Elm=function(){var d=function(a,b,c){for(var d=a.kids,f=d.length;f--;)d[f].recv(b,c,a.id)},b=function(a){this.id=Guid.guid();this.value=a;this.kids=[];this.recv=function(a,b,c){if(b=b===this.id)this.value=c;d(this,a,b)};Dispatcher.inputs.push(this)},c=function(a,b){this.id=Guid.guid();this.value=null;this.kids=[];this.inbox={};b.reverse();this.recalc=function(){for(var c=a,d=b.length;d--;)c=c(b[d].value);this.value=c};this.recalc();
+this.recv=function(a,c){this.inbox.hasOwnProperty(a)||(this.inbox[a]={changed:!1,count:0});var f=this.inbox[a];f.count+=1;c&&(f.changed=!0);f.count==b.length&&(f.changed&&this.recalc(),d(this,a,f.changed),delete this.inbox[a])};for(var c=b.length;c--;)b[c].kids.push(this)},a=function(a,b,c){this.id=Guid.guid();this.value=b;this.kids=[];this.recv=function(b,f){f&&(this.value=a(c.value)(this.value));d(this,b,f)};c.kids.push(this)},g=function(a,b,c){this.id=Guid.guid();this.value=a(c.value)?b:c.value;
+this.kids=[];this.recv=function(b,f){var g=f&&!a(c.value);g&&(this.value=c.value);d(this,b,g)};c.kids.push(this)},f=function(a){this.id=Guid.guid();this.value=a.value;this.kids=[];this.recv=function(b,c){var f=c&&!eq(this.value,a.value);f&&(this.value=a.value);d(this,b,f)};a.kids.push(this)},k=function(a){return function(b){return function(d){d=new c(function(a){return function(b){return[a,b]}},[a,d]);d=new g(function(a){return a[0]},[!0,b],d);return new c(function(a){return a[1]},[d])}}},i=function(a,
+b){this.id=Guid.guid();this.value=b.value;this.kids=[];this.inbox={};this.recv=function(c,f,g){if(f=f&&g===a.id)this.value=b.value;d(this,c,f)};a.kids.push(this);b.kids.push(this)};return{Input:function(a){return new b(a)},Lift:function(a,b){return new c(a,b)},Fold:function(b,c,d){return new a(b,c,d)},keepIf:function(a){return function(b){return function(c){return new g(function(b){return!a(b)},b,c)}}},dropIf:function(a){return function(b){return function(c){return new g(a,b,c)}}},keepWhen:function(a){return k(new c(function(a){return!a},
+[a]))},dropWhen:k,dropRepeats:function(a){return new f(a)},sampleOn:function(a){return function(b){return new i(a,b)}}}}(),Dispatcher=function(){var d=null,b=0,c=[],a=function(b){var c=b.childNodes,d=c.length;if(b.hasOwnProperty("isElmLeaf")){b.hasOwnProperty("isElmText")&&Element.correctTextSize(b);var c=""===b.style.width?0:b.style.width.slice(0,-2)-0,g=""===b.style.height?0:b.style.height.slice(0,-2)-0;return[c,g]}if(1===d){var h=a(c[0]);b.style.hasOwnProperty("width")&&0<b.style.width.length&&
+(h[0]=b.style.width.slice(0,-2)-0);b.style.hasOwnProperty("height")&&0<b.style.height.length&&(h[1]=b.style.height.slice(0,-2)-0);0!==h[0]&&(b.style.width=h[0]+"px");0!==h[1]&&(b.style.height=h[1]+"px");return h}for(var m=0,l=g=0,o=0,p=!0,n=!0;d--;)h=a(c[d]),m=Math.max(m,h[0]),g=Math.max(g,h[1]),l+=h[0],o+=h[1],p=p&&0<h[0],n=n&&0<h[1];c=m;d=b.elmFlowDirection;"X"===d&&(c=p?l:0);"Y"===d&&(g=n?o:0);0<c&&(b.style.width=c+"px");0<g&&(b.style.height=g+"px");return[c,g]},g=function(){var b=document.getElementById("content");
+a(b.children[0])};return{initialize:function(){d=ElmCode.main();d.hasOwnProperty("recv")||(d=Elm.Input(d));document.getElementById("content").appendChild(d.value);g();var a=document.getElementById("widthChecker").offsetWidth;a!==window.innerWidth&&Dispatcher.notify(Window.dimensions.id,Value.Tuple(a,window.innerHeight));d=Elm.Lift(function(a){var b=document.getElementById("content"),c=b.children[0];b.replaceChild(a,c);delete c;g();return a},[d])},notify:function(a,d){b+=1;for(var g=c.length;g--;)c[g].recv(b,
+a,d)},adjust:g,inputs:c}}(),Signal=function(){function d(a){for(var b=["Nil"],c=a.length;c--;)b=["Cons",a[c],b];return b}var b;b=document.addEventListener?function(a,b,c){a.addEventListener(b,c,!1)}:function(a,b,c){a.attachEvent("on"+b,c)};var c,a=function(a){var b=0,c=0;a||(a=window.event);if(a.pageX||a.pageY)b=a.pageX,c=a.pageY;else if(a.clientX||a.clientY)b=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,c=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;
+return Value.Tuple(b,c)},g=Elm.Input(Value.Tuple(0,0)),f=Elm.Input(!1),k=Elm.Input(!1),i=Elm.Input(Value.Tuple());b(document,"click",function(){Dispatcher.notify(k.id,!0);Dispatcher.notify(i.id,Value.Tuple());Dispatcher.notify(k.id,!1)});b(document,"mousedown",function(){Dispatcher.notify(f.id,!0)});b(document,"mouseup",function(){Dispatcher.notify(f.id,!1)});b(document,"mousemove",function(b){Dispatcher.notify(g.id,a(b))});c={position:g,x:Elm.Lift(function(a){return a[1]},[g]),y:Elm.Lift(function(a){return a[2]},
+[g]),isClicked:k,isDown:f,clicks:i,isClickedOn:function(a){var c=Elm.Input(!1);b(a,"click",function(){Dispatcher.notify(c.id,!0);Dispatcher.notify(c.id,!1)});return Value.Tuple(a,c)}};var j,h=Elm.Input(Value.Tuple(window.innerWidth,window.innerHeight));b(window,"resize",function(){var a=document.getElementById("widthChecker").offsetWidth;Dispatcher.notify(h.id,Value.Tuple(a,window.innerHeight))});j={dimensions:h,width:Elm.Lift(function(a){return a[1]},[h]),height:Elm.Lift(function(a){return a[2]},
+[h])};var m=function(a,b){return"Nil"===b[0]?b:b[1]===a?b[2]:["Cons",b[1],m(a,b[2])]},l=Elm.Input(["Nil"]),o=Elm.Input(["Nothing"]);b(document,"keydown",function(a){var b;a:{for(b=l.value;"Nil"!==b[0];){if(b[1]===a.keyCode){b=!0;break a}b=b[2]}b=!1}b||Dispatcher.notify(l.id,["Cons",a.keyCode,l.value])});b(document,"keyup",function(a){a=m(a.keyCode,l.value);Dispatcher.notify(l.id,a)});b(window,"blur",function(){Dispatcher.notify(l.id,["Nil"])});b(document,"keypress",function(a){Dispatcher.notify(o.id,
+["Just",a.charCode||a.keyCode]);Dispatcher.notify(o.id,["Nothing"])});var p={Raw:{keysDown:l,charPressed:o}},n;n=function(a){return function(b){var c=Elm.Input(["Waiting"]),f={};window.XMLHttpRequest?f=new XMLHttpRequest:window.ActiveXObject&&(f=new ActiveXObject("Microsoft.XMLHTTP"));f.onreadystatechange=function(){4===f.readyState&&Dispatcher.notify(c.id,200===f.status?["Success",d(f.responseText)]:["Failure",f.status,d(f.statusText)])};f.open(a,Value.toText(b),!0);f.send(null);return c}};var q=
+function(a){return function(b){var c=Elm.Input(["Nothing"]),b=Elm.Lift(function(b){if("Just"!==b[0]){try{Dispatcher.notify(c.id,["Nothing"])}catch(f){}return[]}try{Dispatcher.notify(c.id,["Just",["Waiting"]])}catch(g){c.value=["Just",["Waiting"]]}var h={};window.XMLHttpRequest?h=new XMLHttpRequest:window.ActiveXObject&&(h=new ActiveXObject("Microsoft.XMLHTTP"));h.onreadystatechange=function(){4===h.readyState&&Dispatcher.notify(c.id,["Just",200===h.status?["Success",d(h.responseText)]:["Failure",
+h.status,d(h.statusText)]])};h.open(a,Value.toText(b[1]),!0);h.send(null);return[]},[b]);return Elm.Lift(function(a){return function(){return a}},[c,b])}};n={get:n("GET"),post:n("POST"),gets:q("GET"),posts:q("POST")};var s=function(a){a.isElmLeaf=!0;var c=Elm.Input(["Nil"]);b(a,"keyup",function(){Dispatcher.notify(c.id,d(a.value));a.focus()});return Value.Tuple(a,c)},r=function(a){a=document.createElement(a);a.id=Guid.guid();return a},t=function(a){for(var c=r("select"),d=[];"Cons"===a[0];){var f=
+r("option"),g=Text.toText(a[1][1]);f.value=g;f.innerHTML=g;c.appendChild(f);d.push(a[1][2]);a=a[2]}var h=Elm.Input(d[0]);b(c,"change",function(){Dispatcher.notify(h.id,d[c.selectedIndex])});return Value.Tuple(c,h)};return{addListener:b,Mouse:c,Keyboard:p,Time:{every:function(a){var a=1E3*a,b=Elm.Input(0),c=0;setInterval(function(){c+=a;Dispatcher.notify(b.id,c/1E3)},a);return b},after:function(a){var a=1E3*a,b=Elm.Input(!1);setTimeout(function(){Dispatcher.notify(b.id,!0)},a);return b},before:function(a){var a=
+1E3*a,b=Elm.Input(!0);setTimeout(function(){Dispatcher.notify(b.id,!1)},a);return b}},Window:j,HTTP:n,Random:{inRange:function(a){return function(b){return Elm.Input(Math.floor(Math.random()*(b-a+1))+a)}},randomize:function(a){return function(b){return function(c){return Elm.Lift(function(){return Math.floor(Math.random()*(b-a+1))+a},[c])}}}},Input:{textArea:function(a){return function(b){var c=r("textarea");c.rows=b;c.cols=a;return s(c,"")}},textField:function(a){var b=r("input");b.type="text";return s(b,
+a)},password:function(a){var b=r("input");b.type="password";return s(b,a)},checkbox:function(a){var c=r("input");c.type="checkbox";c.checked=a;var d=Elm.Input(a);b(c,"change",function(){Dispatcher.notify(d.id,c.checked)});return Value.Tuple(c,d)},dropDown:t,stringDropDown:function(a){return t(List.map(function(a){return Value.Tuple(a,a)})(a))},button:function(a){var c=r("input");c.type="button";c.value=Foreign.JavaScript.castStringToJSString(a);var d=Elm.Input(!1);b(c,"click",function(){Dispatcher.notify(d.id,
+!0);Dispatcher.notify(d.id,!1)});return Value.Tuple(c,d)}},constant:function(a){return Elm.Input(a)},lift:function(a){return function(b){return Elm.Lift(a,[b])}},lift2:function(a){return function(b){return function(c){return Elm.Lift(a,[b,c])}}},lift3:function(a){return function(b){return function(c){return function(d){return Elm.Lift(a,[b,c,d])}}}},lift4:function(a){return function(b){return function(c){return function(d){return function(f){return Elm.Lift(a,[b,c,d,f])}}}}},foldp:function(a){return function(b){return function(c){return Elm.Fold(a,
+b,c)}}},count:function(a){return Elm.Fold(function(){return function(a){return a+1}},0,a)},keepIf:Elm.keepIf,dropIf:Elm.dropIf,keepWhen:Elm.keepWhen,dropWhen:Elm.dropWhen,dropRepeats:Elm.dropRepeats,sampleOn:Elm.sampleOn}}(),Prelude=function(){var d=function(b){return function(c){var a=b%c,a=0==b?0:0<c?0<=b?a:a+c:-d(-b)(-c);return a==c?0:a}};return{id:function(b){return b},not:function(b){return!b},fst:function(b){return b[1]},snd:function(b){return b[2]},rem:function(b){return function(c){return b%
+c}},div:function(b){return function(c){return~~(b/c)}},compare:function(b){return function(c){b="object"===typeof b?toText(b):b;c="object"===typeof c?toText(c):c;return[b===c?"EQ":b<c?"LT":"GT"]}},toFloat:function(b){return b},round:function(b){return Math.round(b)},floor:function(b){return Math.floor(b)},ceiling:function(b){return Math.ceil(b)},truncate:function(b){return~~b},sqrt:Math.sqrt,abs:Math.abs,pi:Math.PI,e:Math.E,sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,
+mod:d,min:function(b){return function(c){return Math.min(b,c)}},max:function(b){return function(c){return Math.max(b,c)}},flip:function(b){return function(c){return function(a){return b(a)(c)}}},clamp:function(b){return function(c){return function(a){return Math.min(c,Math.max(b,a))}}},curry:function(b){return function(c){return function(a){return b(["Tuple2",c,a])}}},uncurry:function(b){return function(c){if("Tuple2"!==c[0])throw"Function was uncurry'd but was not given a pair.";return b(c[1])(c[2])}},
+logBase:function(b){return function(c){return Math.log(c)/Math.log(b)}},Just:Data.Maybe.Just,Nothing:Data.Maybe.Nothing,maybe:Data.Maybe.maybe,map:Data.List.map,filter:Data.List.filter,head:Data.List.head,tail:Data.List.tail,last:Data.List.last,length:Data.List.length,reverse:Data.List.reverse,foldr:Data.List.foldr,foldr1:Data.List.foldr1,foldl:Data.List.foldl,foldl1:Data.List.foldl1,and:Data.List.and,or:Data.List.or,forall:Data.List.forall,exists:Data.List.exists,sum:Data.List.sum,product:Data.List.product,
+concat:Data.List.concat,concatMap:Data.List.concatMap,maximum:Data.List.maximum,minimum:Data.List.minimum,scanl:Data.List.scanl,scanl1:Data.List.scanl1,take:Data.List.take,drop:Data.List.drop,lift:Signal.lift,lift2:Signal.lift2,lift3:Signal.lift3,lift4:Signal.lift4,foldp:Signal.foldp,constant:Signal.constant,count:Signal.count,keepIf:Signal.keepIf,dropIf:Signal.dropIf,keepWhen:Signal.keepWhen,dropWhen:Signal.dropWhen,dropRepeats:Signal.dropRepeats,sampleOn:Signal.sampleOn}}(),eq=Value.eq;
+Signal.addListener(document,"elm_log",function(d){console.log(d.value)});Signal.addListener(document,"elm_title",function(d){document.title=d.value});Signal.addListener(document,"elm_redirect",function(d){0<d.value.length&&(window.location=d.value)});var includeGlobal=this;
+(function(){var d=function(b){for(var a in b)if("Internal"!==a)try{includeGlobal[a]=b[a]}catch(d){"length"===a&&(includeGlobal.execScript("var length;"),length=b[a])}},b=function(b){return function(a){includeGlobal[b]=includeGlobal[b]||{};for(var d in a)"Internal"!==d&&(includeGlobal[b][d]=a[d])}};d(Element);d(Text);color=Element.color;height=Element.height;show=Value.show;d(Color);d(Shape);d(Line);b("Time")(Signal.Time);b("Mouse")(Signal.Mouse);b("Keyboard")(Signal.Keyboard);b("Window")(Signal.Window);
+b("HTTP")(Signal.HTTP);b("Input")(Signal.Input);b("Random")(Signal.Random)})();var ElmCode={};ElmCode.Data=Data;ElmCode.Signal=Signal;ElmCode.Data.List=List;ElmCode.Foreign=Foreign;ElmCode.Prelude=Prelude;
diff --git a/src/Ast.hs b/src/Ast.hs
--- a/src/Ast.hs
+++ b/src/Ast.hs
@@ -6,23 +6,19 @@
 import Types
 import Guid
 
-data Module = Module [String] Exports Imports Defs JSFFI
+data Module = Module [String] Exports Imports [Statement]
 
 type Exports = [String]
 
 type Imports = [(String, ImportMethod)]
 data ImportMethod = As String | Hiding [String] | Importing [String]
 
-type Defs = [(String,Expr)]
 
-type JSFFI = ( [(String, Expr, String, Type)]
-             , [(String, String, Type)] )
-
-
 data Pattern = PData String [Pattern] | PVar String | PAnything
                deriving (Eq)
 
-data Expr = Number Int
+data Expr = IntNum Int
+          | FloatNum Float
           | Chr Char
           | Str String
           | Boolean Bool
@@ -36,12 +32,21 @@
           | Fold Expr Expr Expr
           | Async Expr
           | Input String
-          | Let [(String,Expr)] Expr
+          | Let [Definition] Expr
           | Var String
           | Case Expr [(Pattern,Expr)]
           | Data String [Expr]
-            deriving (Show, Eq)
+            deriving (Eq)
 
+data Definition = Definition String [String] Expr
+                  deriving (Eq)
+
+data Statement = Def String [String] Expr
+               | Datatype String [X] [(String,[Type])]
+               | ImportEvent String Expr String Type
+               | ExportEvent String String Type
+                 deriving (Eq,Show)
+
 cons h t = Data "Cons" [h,t]
 nil      = Data "Nil" []
 list     = foldr cons nil
@@ -68,4 +73,52 @@
         if take 5 name == "Tuple" && all isDigit (drop 5 name) then
             parens . intercalate ", " $ map show ps
         else (if null ps then id else parens) $ unwords (name : map show ps)
-            where parens s = "(" ++ s ++ ")"
+            where parens s = "(" ++ s ++ ")"
+
+instance Show Expr where
+  show (IntNum n) = show n
+  show (FloatNum n) = show n
+  show (Chr c) = show c
+  show (Str s) = show s
+  show (Boolean b) = show b
+  show (Range e1 e2) = "[" ++ show e1 ++ ".." ++ show e2 ++ "]"
+  show (Access e x) = show' e ++ "." ++ x
+  show (Binop op e1 e2) = show' e1 ++ " " ++ op ++ " " ++ show' e2
+  show (Lambda x e) = let (xs,e') = getLambdas (Lambda x e) in
+                      concat [ "\\", intercalate " " xs, " -> ", show e' ]
+  show (App e1 e2) = show' e1 ++ " " ++ show' e2
+  show (If e1 e2 e3) = concat [ "if ", show e1, " then ", show e2, " else ", show e3 ]
+  show (Let defs e) = "let { " ++ intercalate " ; " (map show defs) ++ " } in " ++ show e
+  show (Var x) = x
+  show (Case e pats) = "case " ++ show e ++ " of { " ++ intercalate " ; " (map (\(p,e) -> show p ++ " -> " ++ show e) pats) ++ " }"
+  show (Data name es)
+      | name == "Cons" = ("["++) . (++"]") . intercalate "," . map show $ delist (Data "Cons" es)
+      | name == "Nil" = "[]"
+      | otherwise = name ++ " " ++ intercalate " " (map show' es)
+  show (Lift f es) = concat [ "lift", show $ length es, " ", show' f, " ", intercalate " " (map show' es) ]
+  show (Fold e1 e2 e3) = concat [ "foldp ", show' e1, " ", show' e2, " ", show' e3 ]
+  show (Async e) = "async " ++ show' e
+  show (Input i) = i
+
+
+instance Show Definition where
+  show (Definition v [] e) = v ++ " = " ++ show e
+  show (Definition f args e) = f ++ " " ++ intercalate " " args ++ " = " ++ show e
+
+getLambdas (Lambda x e) = (x:xs,e')
+    where (xs,e') = getLambdas e
+getLambdas e = ([],e)
+
+show' e = if needsParens e then "(" ++ show e ++ ")" else show e
+
+needsParens (Binop _ _ _) = True
+needsParens (Lambda _ _) = True
+needsParens (App _ _) = True
+needsParens (If _ _ _) = True
+needsParens (Let _ _) = True
+needsParens (Case _ _) = True
+needsParens (Data name (x:xs)) = name /= "Cons"
+needsParens (Lift _ _) = True
+needsParens (Fold _ _ _) = True
+needsParens (Async _) = True
+needsParens _ = False
diff --git a/src/Compiler.hs b/src/Compiler.hs
--- a/src/Compiler.hs
+++ b/src/Compiler.hs
@@ -32,14 +32,14 @@
           , separate_js = False &= help "Compile to separate HTML and JS files."
           , only_js = False &= help "Compile only to JavaScript."
           , import_js = [] &= typFile &= help "Include a JavaScript file before the body of the Elm program. Can be used many times. Files will be included in the given order."
-          , generate_noscript = False &= help "Add generated <noscript> tag to HTML output."
+          , generate_noscript = True &= help "Add generated <noscript> tag to HTML output."
           } &=
     help "Compile Elm programs to HTML, CSS, and JavaScript." &=
-    summary "The Elm Compiler v0.3.5, (c) Evan Czaplicki"
+    summary "The Elm Compiler v0.3.6, (c) Evan Czaplicki"
 
 main = do
   args <- cmdArgs elm
-  mini <- getDataFileName "elm-runtime-0.3.5.js"
+  mini <- getDataFileName "elm-runtime-0.3.6.js"
   compileArgs mini args
 
 compileArgs mini (ELM _ [] _ _ _ _ _) =
@@ -68,12 +68,12 @@
                   writeFile html . renderHtml $ linkedHtml rtLoc js ms
                   writeFile js $ jss ++ concatMap jsModule ms
 
-getModules :: [String] -> FilePath -> IO (Either String [Module])
+getModules :: [String] -> FilePath -> IO (Either String [([String],Module)])
 getModules uses file = do
   code <- readFile file
   case initialize code of
     Left err -> return . Left $ "Error in " ++ file ++ ":\n" ++ err
-    Right modul@(Module _ _ imports _ _) ->
+    Right (escs, modul@(Module _ _ imports _)) ->
         let imps = filter (`notElem` builtInModules) $ map fst imports in
         case intersect uses imps of
           x:_ -> return . Left $ "Error: Cyclic dependency. Module " ++
@@ -81,10 +81,10 @@
           [] -> do
             ems <- mapM (getModules (uses ++ imps) . toFilePath) imps
             return $ case lefts ems of
-              [] -> Right $ concat (rights ems) ++ [modul]
+              [] -> Right $ concat (rights ems) ++ [(escs,modul)]
               errs -> Left $ intercalate "\n" errs
 
-getModule :: FilePath -> IO (Either String [Module])
+getModule :: FilePath -> IO (Either String [([String],Module)])
 getModule file = do
   code <- readFile file
   return . fmap (:[]) $ initialize code
diff --git a/src/Gen/CompileToJS.hs b/src/Gen/CompileToJS.hs
--- a/src/Gen/CompileToJS.hs
+++ b/src/Gen/CompileToJS.hs
@@ -2,6 +2,7 @@
 module CompileToJS (showErr, jsModule) where
 
 import Ast
+import Control.Arrow (first)
 import Control.Monad (liftM,(<=<),join)
 import Data.Char (isAlpha,isDigit)
 import Data.List (intercalate,sortBy,inits)
@@ -9,6 +10,7 @@
 import Data.Maybe (mapMaybe)
 
 import Initialize
+import Rename (derename)
 
 showErr :: String -> String
 showErr err = mainEquals $ "text(monospace(" ++ msg ++ "))"
@@ -25,53 +27,48 @@
 mainEquals s = globalAssign "ElmCode.main" (jsFunc "" (ret s))
 globalAssign m s = "\n" ++ m ++ "=" ++ s ++ ";"
 
-tryBlock names e = 
+tryBlock escapees names e = 
     concat [ "\ntry{\n" ++ e ++ "\n\n} catch (e) {"
            , "ElmCode.main=function() {"
-	   , "var msg = ('<br><h2>Your browser may not be supported. " ++
+	   , "var msg = ('<br/><h2>Your browser may not be supported. " ++
              "Are you using a modern browser?</h2>' +" ++
-             " '<br><span style=\"color:grey\">Runtime Error in " ++
-             intercalate "." names ++ " module:<br>' + e + '</span>');"
+             " '<br/><span style=\"color:grey\">Runtime Error in " ++
+             intercalate "." names ++ " module:<br/>' + e + '" ++ msg ++ "</span>');"
 	   , "document.body.innerHTML = Text.monospace(msg);"
            , "throw e;"
            , "};}"
            ]
-
+    where msg | escapees /= [] = concat [ "<br/><br/>The problem may stem from an improper usage of:<br/>"
+                                        ,  intercalate ", " escapees ]
+              | otherwise = ""
 
-jsModule (Module names exports imports defs foreigns) =
-    tryBlock (tail modNames) $ concat
+jsModule (escapees, Module names exports imports stmts) =
+    tryBlock escapees (tail modNames) $ concat
            [ concatMap (\n -> globalAssign n $ n ++ " || {}") .
              map (intercalate ".") . drop 2 . inits $
              take (length modNames - 1) modNames
            , "\nif (" ++ modName ++ ") throw \"Module name collision, '" ++
              intercalate "." (tail modNames) ++ "' is already defined.\"; "
-           , globalAssign modName $ jsFunc "" (includes++ims++body++exs++export)++"()"
+           , globalAssign modName $ jsFunc "" (includes ++body++ export) ++ "()"
            , mainEquals $ modName ++ ".main" ]
-        where modNames = if null names then ["ElmCode", "Main"] else "ElmCode" : names
+        where modNames = if null names then ["ElmCode", "Main"]
+                                       else  "ElmCode" : names
               modName  = intercalate "." modNames
-              includes = concatMap jsImport $
-                         map (\(x,y) -> ("ElmCode." ++ x,y)) imports
-              body = jsDefs defs
-              export = ret . braces . intercalate "," $ mapMaybe getNames defs
+              includes = concatMap jsImport $ map (first ("ElmCode."++)) imports
+              body = stmtsToJS stmts
+              export = getExports exps stmts
               exps = if null exports then ["main"] else exports
-              getNames (x,_) =
-                  let y = reverse . tail . dropWhile isDigit $ reverse x in
-                  if y `elem` exps then Just $ y ++ ":" ++ x else Nothing
-              (ims,exs) = let (i,e) = foreigns in
-                          (concatMap importEvent i, concatMap exportEvent e)
 
-importEvent (js,base,elm,_) =
-    concat [ "\nvar " ++ elm ++ " = Elm.Input(" ++ toJS base ++ ");"
-           , "\nSignal.addListener(document, '" ++ js
-           , "', function(e) { Dispatcher.notify(" ++ elm
-           , ".id, e.value); });" ]
-exportEvent (js,elm,_) =
-    concat [ "\nlift(function(v) { var e = document.createEvent('Event');"
-           , "e.initEvent('" ++ js ++ "', true, true);"
-           , "e.value = v;"
-           , "document.dispatchEvent(e); return v; })(" ++ elm ++ ");"
-           ]
+getExports names stmts = ret . braces $ intercalate "," pairs
+    where pairs = mapMaybe pair $ concatMap get stmts
+          pair x = if y `elem` names then Just $ y ++ ":" ++ x else Nothing
+              where y = derename x
+          get s = case s of Def x _ _           -> [x]
+                            Datatype _ _ tcs    -> map fst tcs
+                            ImportEvent _ _ x _ -> [x]
+                            ExportEvent _ _ _   -> []
 
+
 jsImport (modul, how) =
   concat [ "\ntry{" ++ modul ++ " instanceof Object} catch(e) {throw \"Module '"
          , drop 1 (dropWhile (/='.') modul)
@@ -90,10 +87,41 @@
            , globalAssign "this[i]" $ modul ++ "[i]"
            , "}" ]
 
+stmtsToJS :: [Statement] -> String
+stmtsToJS stmts = concatMap stmtToJS (sortBy cmpStmt stmts)
+    where cmpStmt s1 s2 = compare (valueOf s1) (valueOf s2)
+          valueOf s = case s of Datatype _ _ _      -> 1
+                                ImportEvent _ _ _ _ -> 3
+                                Def _ [] _          -> 3
+                                Def _ _ _           -> 4
+                                ExportEvent _ _ _   -> 5
 
+stmtToJS :: Statement -> String
+stmtToJS (Def name [] e) = assign name (toJS e)
+stmtToJS (Def name (a:as) e) = "\nfunction " ++ name ++ parens a ++
+                               braces (ret . toJS $ foldr Lambda e as) ++ ";"
+stmtToJS (Datatype _ _ tcs) = concatMap (stmtToJS . toDef) tcs
+    where toDef (name,args) = Def name vars $ Data (derename name) (map Var vars)
+              where vars = map (('a':) . show) [1..length args]
+stmtToJS (ImportEvent js base elm _) =
+    concat [ "\nvar " ++ elm ++ " = Elm.Input(" ++ toJS base ++ ");"
+           , "\nSignal.addListener(document, '" ++ js
+           , "', function(e) { Dispatcher.notify(" ++ elm
+           , ".id, e.value); });" ]
+stmtToJS (ExportEvent js elm _) =
+    concat [ "\nlift(function(v) { var e = document.createEvent('Event');"
+           , "e.initEvent('" ++ js ++ "', true, true);"
+           , "e.value = v;"
+           , "document.dispatchEvent(e); return v; })(" ++ elm ++ ");"
+           ]
+
+
+
+toJS :: Expr -> String
 toJS expr =
     case expr of
-      Number n -> show n
+      IntNum n -> show n
+      FloatNum n -> show n
       Var x -> x
       Chr c -> show c
       Str s -> "Value.str" ++ parens (show s)
@@ -103,7 +131,7 @@
       Binop op e1 e2 -> binop op (toJS e1) (toJS e2)
       If eb et ef -> parens $ iff (toJS eb) (toJS et) (toJS ef)
       Lambda v e -> jsFunc v $ ret (toJS e)
-      App (Var "toText") (Str s) -> show s
+      App (Var "toText") (Str s) -> "toText" ++ parens (show s)
       App (Var "link") (Str s) -> "link(" ++ show s ++ ")"
       App (Var "plainText") (Str s) -> "plainText(" ++ show s ++ ")"
       App e1 e2 -> toJS e1 ++ parens (toJS e2)
@@ -114,12 +142,11 @@
 jsLet defs e' = jsFunc "" (jsDefs defs ++ ret (toJS e')) ++ "()"
 
 jsDefs defs = concatMap toDef $ sortBy f defs
-    where f a b = compare (isLambda a) (isLambda b)
-          isLambda (_, Lambda _ _) = 1
-          isLambda _ = 0
-          toDef (f, Lambda x e) =
-              "\nfunction " ++ f ++ parens x ++ braces (ret $ toJS e) ++ ";"
-          toDef (x, e) = assign x (toJS e)
+    where f a b = compare (valueOf a) (valueOf b)
+          valueOf (Definition _ args _) = min 1 (length args)
+          toDef (Definition x [] e) = assign x (toJS e)
+          toDef (Definition f (a:as) e) = 
+              "\nfunction " ++ f ++ parens a ++ braces (ret . toJS $ foldr Lambda e as) ++ ";"
 
 jsCase e  [c]  = jsMatch c ++ parens (toJS e)
 jsCase e cases = "(function(){" ++
@@ -146,18 +173,23 @@
 jsCons  e1 e2 = jsList [ show "Cons", e1, e2 ]
 jsRange e1 e2 = (++"()") . jsFunc "" $
                 assign "lo" e1 ++ assign "hi" e2 ++ assign "lst" jsNil ++
-                "do{" ++ assign "lst" (jsCons "hi" "lst") ++ "}while(hi-->lo)" ++
+                "if(lo<=hi){do{" ++ assign "lst" (jsCons "hi" "lst") ++ "}while(hi-->lo)}" ++
                 ret "lst"
 
 binop (o:p) e1 e2
     | isAlpha o || '_' == o = (o:p) ++ parens e1 ++ parens e2
     | otherwise = case o:p of
-                    ":" -> jsCons e1 e2
+                    ":"  -> jsCons e1 e2
                     "++" -> append e1 e2
-                    "$" -> e1 ++ parens e2
-                    "." -> jsFunc "x" . ret $ e1 ++ parens (e2 ++ parens "x")
+                    "$"  -> e1 ++ parens e2
+                    "."  -> jsFunc "x" . ret $ e1 ++ parens (e2 ++ parens "x")
+                    "^"  -> "Math.pow(" ++ e1 ++ "," ++ e2 ++ ")"
                     "==" -> "eq(" ++ e1 ++ "," ++ e2 ++ ")"
                     "/=" -> "not(eq(" ++ e1 ++ "," ++ e2 ++ "))"
-                    _ -> parens (e1 ++ (o:p) ++ e2)
+                    "<"  -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'LT')"
+                    ">"  -> "(compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0] === 'GT')"
+                    "<=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0]; return ord === 'LT' || ord === 'EQ'; }()"
+                    ">=" -> "function() { var ord = compare(" ++ e1 ++ ")(" ++ e2 ++ ")[0]; return ord === 'GT' || ord === 'EQ'; }()"
+                    _    -> parens (e1 ++ (o:p) ++ e2)
 
 append e1 e2 = "Value.append" ++ parens (e1 ++ "," ++ e2)
diff --git a/src/Gen/ExtractNoscript.hs b/src/Gen/ExtractNoscript.hs
--- a/src/Gen/ExtractNoscript.hs
+++ b/src/Gen/ExtractNoscript.hs
@@ -3,8 +3,10 @@
 
 import Ast
 
-extract (Module _ _ _ defs _) =
-    concatMap (\s -> "<p>" ++ s ++ "</p>") $ concatMap (extract' . snd) defs
+extract (Module _ _ _ stmts) =
+    concatMap (\s -> "<p>" ++ s ++ "</p>") (concatMap stmtExtract stmts)
+        where stmtExtract (Def _ _ e) = extract' e
+              stmtExtract _ = []
 
 extract' expr =
     let f = extract' in
@@ -24,12 +26,10 @@
       App (Var "monospace") e -> tag "code" e
       App e1 e2 -> f e1 ++ f e2
       If eb et ef -> f et ++ f ef
-      Let defs e -> concatMap (f . snd) defs ++ f e
+      Let defs e -> concatMap (\(Definition _ _ d) -> f d) defs ++ f e
       Var _ -> []
       Case e cases -> concatMap (f . snd) cases
       Data _ es -> concatMap f es
       _ -> []
 
-tag t e = case extract' e of
-            [s] -> [ concat [ "<", t, ">", s, "</", t, ">" ] ]
-            ss  -> ss
+tag t e = map (\s -> concat [ "<", t, ">", s, "</", t, ">" ]) (extract' e)
diff --git a/src/Gen/GenerateHtml.hs b/src/Gen/GenerateHtml.hs
--- a/src/Gen/GenerateHtml.hs
+++ b/src/Gen/GenerateHtml.hs
@@ -46,21 +46,22 @@
 generateHtml libLoc title source =
     case initialize source of
       Left err -> createHtml libLoc title (Right $ showErr err) (H.noscript "")
-      Right modul -> modulesToHtml title libLoc [] False [modul]
+      Right (escs, modul) -> modulesToHtml title libLoc [] True [(escs,modul)]
 
 
-modulesToHtml title libLoc jss nscrpt modules = createHtml libLoc title' js noscript
-    where js = Right $ jss ++ concatMap jsModule modules
+modulesToHtml title libLoc jss nscrpt pairs = createHtml libLoc title' js noscript
+    where modules = map snd pairs
+          js = Right $ jss ++ concatMap jsModule pairs
           noscript = if nscrpt then extract $ last modules else ""
           title' = if null title then altTitle else title
-          altTitle = (\(Module names _ _ _ _) -> intercalate "." names) $
+          altTitle = (\(Module names _ _ _) -> intercalate "." names) $
                      last modules
                   
 
 linkedHtml rtLoc jsLoc modules =
     createHtml rtLoc title (Left jsLoc) (H.noscript "")
-    where title = (\(Module names _ _ _ _) -> intercalate "." names) $
-                  last modules
+    where title = (\(Module names _ _ _) -> intercalate "." names) $
+                  snd (last modules)
 
 
 createHtml libLoc title js noscript =
diff --git a/src/Initialize.hs b/src/Initialize.hs
--- a/src/Initialize.hs
+++ b/src/Initialize.hs
@@ -1,32 +1,23 @@
 module Initialize (initialize) where
 
+import Control.Applicative ((<$>))
 import Control.Monad.Error
 import Data.List (lookup)
 
 import Ast
 import Parser (parseProgram)
-import Hints
-import Unify
 import Rename
+import Types ((-:))
+import Types.Hints (hints)
+import Types.Unify
 import Optimize
 
 
-initialize str = do
-  (Module name ex im defs (ims,exs), tipes) <- parseProgram str
-  let (Let ds _) = rename . Let defs $ Var "_"
-  let dict n = maybe n id . lookup n $ zip (map fst defs) (map fst ds)
-  let allHints = liftM2 (\a b -> a ++ b ++ ffiHints (ims,exs)) hints tipes
-  subs <- unify allHints . Let ds $ checkFFI dict ims exs
-  let Let defs' _ = optimize (Let ds $ Var "_")
-  let im' = if any ((=="Prelude") . fst) im then im else
-                ("Prelude", Importing []):im
-  let exs' = map (\(js,n,t) -> (js,dict n,t)) exs
-  return (subs `seq` Module name ex im' defs' (ims,exs'))
-
-
-ffiHints (ims,exs) =
-    map (\(_,_,n,t) -> (n,t)) ims ++ map (\(_,n,t) -> (n,t)) exs
-
-checkFFI dict ims exs = list $ ims' ++ exs'
-  where ims' = map (\(_,b,n,_)-> Binop "==" (Var n) (App (Var "constant") b)) ims
-        exs' = map (\(_,n,_)  -> Binop "==" (Var n) (Var $ dict n)) exs
+initialize str =
+    let nameOf (Definition n _ _) = n in
+    do modul@(Module name ex im stmts) <- parseProgram str
+       (escapees, subs) <- unify hints modul
+       let modul' = optimize . rename $ Module name ex im' stmts
+               where im' | any ((=="Prelude") . fst) im = im
+                         | otherwise = ("Prelude", Importing []) : im
+       subs `seq` return (escapees, modul')
diff --git a/src/Language/Elm.hs b/src/Language/Elm.hs
--- a/src/Language/Elm.hs
+++ b/src/Language/Elm.hs
@@ -71,4 +71,4 @@
 toPartsHelper source = (html, css, js)
   where modul = initialize source
         js = either showErr jsModule modul
-        html = widgetBody $ either id extract modul
+        html = widgetBody $ either id (extract . snd) modul
diff --git a/src/Optimize.hs b/src/Optimize.hs
--- a/src/Optimize.hs
+++ b/src/Optimize.hs
@@ -5,9 +5,16 @@
 import Data.Char (isAlpha)
 
 
-optimize exp = if exp == exp' then exp' else optimize exp'
-    where exp' = simp exp
+optimize (Module name ims exs stmts) =
+    Module name ims exs (map optimizeStmt stmts)
 
+optimizeStmt stmt = if stmt == stmt' then stmt' else optimizeStmt stmt'
+    where stmt' = simpStmt stmt
+          simpStmt (Def name args e) = Def name args (simp e)
+          simpStmt (ImportEvent js b elm t) = ImportEvent js (simp b) elm t
+          simpStmt stmt = stmt
+
+simp :: Expr -> Expr
 simp expr =
     let f = simp in
     case expr of
@@ -16,7 +23,8 @@
       Lambda x e -> Lambda x (f e)
       App e1 e2 -> App (f e1) (f e2)
       If e1 e2 e3 -> simp_if (f e1) (f e2) (f e3)
-      Let defs e -> Let (map (second f) defs) (f e)
+      Let defs e -> Let (map simpDef defs) (f e)
+              where simpDef (Definition func args e) = Definition func args (f e)
       Data name es -> Data name (map f es)
       Case e cases -> Case (f e) (map (second f) cases)
       _ -> expr
@@ -24,39 +32,38 @@
 simp_if (Boolean b) e2 e3 = if b then e2 else e3
 simp_if a b c = If a b c
 
-simp_binop "mod" (Number n) (Number m) = Number (mod n m)
-simp_binop "mod" e1 e2 = Binop "mod" e1 e2
-simp_binop str e1 e2
-    | isAlpha (head str) || '_' == head str = App (App (Var str) e1) e2
-    | otherwise = binop str e1 e2
+simp_binop = binop
 
-binop op (Number n) (Number m) = f n m
+binop op (IntNum n) (IntNum m) = f n m
     where f a b = case op of
-                    { "+" -> Number $ (+) a b
-                    ; "-" -> Number $ (-) a b
-                    ; "*" -> Number $ (*) a b
-                    --; "/" -> Number $ div a b
+                    { "+" -> IntNum $ (+) a b
+                    ; "-" -> IntNum $ (-) a b
+                    ; "*" -> IntNum $ (*) a b
+                    ; "div" -> IntNum $ div a b
+                    ; "mod" -> IntNum $ mod a b
                     ; "<" -> Boolean $ a < b
                     ; ">" -> Boolean $ a < b
                     ; "<=" -> Boolean $ a <= b
                     ; ">=" -> Boolean $ a >= b
                     ; "==" -> Boolean $ a == b
                     ; "/=" -> Boolean $ a /= b
-                    ;  _  -> Binop op (Number n) (Number m) }
+                    ;  _  -> Binop op (IntNum n) (IntNum m) }
 
-binop "-" e (Number 0) = e
-binop "+" (Number 0) e = e
-binop "+" (Number n) (Binop "+" (Number m) e) = binop "+" (Number (n+m)) e
-binop "+" (Number n) (Binop "+" e (Number m)) = binop "+" (Number (n+m)) e
+binop "-" e (IntNum 0) = e
+binop "+" (IntNum 0) e = e
+binop "+" e (IntNum 0) = e
+binop "+" (IntNum n) (Binop "+" (IntNum m) e) = binop "+" (IntNum (n+m)) e
+binop "+" (IntNum n) (Binop "+" e (IntNum m)) = binop "+" (IntNum (n+m)) e
 
-binop "/" e (Number 1) = e
-binop "*" (Number 0) e = Number 0
-binop "*" (Number 1) e = e
-binop "*" (Number n) (Binop "*" (Number m) e) = binop "*" (Number (n*m)) e
-binop "*" (Number n) (Binop "*" e (Number m)) = binop "*" (Number (n*m)) e
+binop "/" e (IntNum 1) = e
+binop "div" e (IntNum 1) = e
+binop "*" (IntNum 0) e = IntNum 0
+binop "*" (IntNum 1) e = e
+binop "*" (IntNum n) (Binop "*" (IntNum m) e) = binop "*" (IntNum (n*m)) e
+binop "*" (IntNum n) (Binop "*" e (IntNum m)) = binop "*" (IntNum (n*m)) e
 
-binop "+" e (Number n) = binop "+" (Number n) e
-binop "*" e (Number n) = binop "*" (Number n) e
+binop "+" e (IntNum n) = binop "+" (IntNum n) e
+binop "*" e (IntNum n) = binop "*" (IntNum n) e
 
 binop op (Boolean n) (Boolean m) = f n m
     where f a b = case op of { "&&" -> Boolean $ (&&) n m
@@ -68,7 +75,8 @@
 binop "||" (Boolean  True) e = Boolean True
 binop "||" (Boolean False) e = e
 
-binop op e (Boolean n) = binop op (Boolean n) e
+binop "&&" e (Boolean n) = binop "&&" (Boolean n) e
+binop "||" e (Boolean n) = binop "||" (Boolean n) e
 
 binop ":" h t = cons h t
 binop "++" (Str s1) (Str s2) = Str $ s1 ++ s2
@@ -80,5 +88,6 @@
 
 binop "$" e1 e2 = App e1 e2
 
-binop op e1 e2 = Binop op e1 e2
---}
+binop op e1 e2
+    | isAlpha (head op) || '_' == head op = App (App (Var op) e1) e2
+    | otherwise = Binop op e1 e2
diff --git a/src/Parse/Binops.hs b/src/Parse/Binops.hs
--- a/src/Parse/Binops.hs
+++ b/src/Parse/Binops.hs
@@ -13,7 +13,8 @@
 data Assoc = L | N | R deriving (Eq,Show)
 
 table = [ (9, R, ".")
-        , (7, L, "*"), (7, L, "/"), (7, L, "mod")
+        , (8, R, "^")
+        , (7, L, "*"), (7, L, "/"), (7, L, "mod"), (7, L, "div"), (7, L, "rem")
         , (6, L, "+"), (6, L, "-")
         , (5, R, ":" ), (5, R, "++")
         , (4, N, "<="), (4, N, ">="), (4, N, "<")
diff --git a/src/Parse/ParseExpr.hs b/src/Parse/ParseExpr.hs
--- a/src/Parse/ParseExpr.hs
+++ b/src/Parse/ParseExpr.hs
@@ -12,13 +12,19 @@
 import Binops
 
 import Guid
-import Types (Type (VarT))
+import Types (Type (VarT), Scheme (Forall))
 
 
 --------  Basic Terms  --------
 
 numTerm :: (Monad m) => ParsecT [Char] u m Expr
-numTerm = liftM (Number . read) (many1 digit) <?> "number"
+numTerm = toExpr <$> (preNum <?> "number")
+    where toExpr n | '.' `elem` n = FloatNum (read n)
+                   | otherwise = IntNum (read n)
+          preNum  = (++) <$> many1 digit <*> option "" postNum
+          postNum = do try $ lookAhead (string "." >> digit)
+                       string "."
+                       ('.':) <$> many1 digit
 
 strTerm :: (Monad m) => ParsecT [Char] u m Expr
 strTerm = liftM Str . expecting "string" . betwixt '"' '"' . many $
@@ -74,10 +80,10 @@
 
 lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
                 whitespace
-                args <- spaceSep1 patternTerm
+                pats <- spaceSep1 patternTerm
                 whitespace ; arrow ; whitespace
                 e <- expr
-                return $ makeFunction args e
+                return $ makeLambda pats e
 
 letExpr = do
   reserved "let"
@@ -111,9 +117,8 @@
   whitespace; string "="; whitespace; exp <- expr
   flattenPatterns patterns exp
 
+def = map (\(Definition n as e) -> Def n as e) <$> assignExpr
 
-def = do (fs,es) <- unzip <$> assignExpr
-         return (fs, es, mapM (\_ -> liftM VarT guid) fs)
 
 parseDef str =
     case parse def "" str of
diff --git a/src/Parse/ParseForeign.hs b/src/Parse/ParseForeign.hs
--- a/src/Parse/ParseForeign.hs
+++ b/src/Parse/ParseForeign.hs
@@ -1,5 +1,5 @@
 
-module ParseForeign (foreignDefs) where
+module ParseForeign (foreignDef) where
 
 import Control.Applicative ((<$>), (<*>))
 import Data.Either (partitionEithers)
@@ -12,14 +12,8 @@
 import Types (signalOf)
 
 
-foreignDefs = do
-  f  <- foreign --commitIf (reserved "foreign") foreign
-  fs <- many (commitIf (freshLine >> reserved "foreign") (freshLine >> foreign))
-  return . partitionEithers $ f:fs
-
-
-foreign = do try (reserved "foreign") ; whitespace
-             Left <$> importEvent <|> Right <$> exportEvent
+foreignDef = do try (reserved "foreign") ; whitespace
+                importEvent <|> exportEvent
 
 exportEvent = do
   try (reserved "export" >> whitespace >> reserved "jsevent" >> whitespace)
@@ -29,7 +23,7 @@
   tipe <- typeExpr
   case tipe of
     ADTPT "Signal" [pt] ->
-        either fail (return . (,,) js elm . signalOf) (toForeignType pt)
+        either fail (return . ExportEvent js elm . signalOf) (toForeignType pt)
     _ -> fail "When exporting events, the exported value must be a Signal."
 
 importEvent = do
@@ -42,7 +36,7 @@
   tipe <- typeExpr
   case tipe of
     ADTPT "Signal" [pt] ->
-        either fail (return . (,,,) js base elm . signalOf) (toForeignType pt)
+        either fail (return . ImportEvent js base elm . signalOf) (toForeignType pt)
     _ -> fail "When importing events, the imported value must be a Signal."
 
 
diff --git a/src/Parse/ParseTypes.hs b/src/Parse/ParseTypes.hs
--- a/src/Parse/ParseTypes.hs
+++ b/src/Parse/ParseTypes.hs
@@ -2,7 +2,7 @@
 
 import Ast
 import Control.Applicative ((<$>),(<*>))
-import Control.Monad (liftM)
+import Control.Monad (liftM,mapM)
 import Data.Char (isUpper,isLower)
 import Data.Maybe (fromMaybe)
 import Data.List (lookup)
@@ -52,35 +52,32 @@
 typeConstructor :: (Monad m) => ParsecT [Char] u m (String, [ParseType])
 typeConstructor = (,) <$> (capVar <?> "another type constructor") <*> spacePrefix (typeSimple <|> typeUnambiguous)
 
-datatype :: (Monad m) => ParsecT [Char] u m ([String], [Expr], GuidCounter [Type])
+datatype :: (Monad m) => ParsecT [Char] u m Statement
 datatype = do
   reserved "data" <?> "datatype definition (data T = A | B | ...)"
   forcedWS ; name <- capVar <?> "name of data-type" ; args <- spacePrefix lowVar
   whitespace ; string "=" ; whitespace
   tcs <- pipeSep1 typeConstructor
-  return $ (map fst tcs , map toFunc tcs , toTypes name args tcs)
+  case toDatatype name args tcs of
+    Right dt -> return dt
+    Left msg -> fail msg
 
 beta = liftM VarT guid
 
-toFunc (name,args) = foldr Lambda (Data name $ map Var argNames) argNames
-    where argNames = map (("a"++) . show) [1..length args]
-
-toTypes name args constructors = do
-  pairs <- mapM (\x -> (,) x `liftM` guid) args
-  return $ map (toType pairs . ADT name $ map (VarT . snd) pairs) constructors
-
-toType pairs outType (name,args) =
-    foldr (==>) outType (map toT args)
-    where toT (LambdaPT t1 t2)  = toT t1 ==> toT t2
-          toT (ADTPT name args) = ADT name $ map toT args
+toDatatype name args tcs = Datatype name [1..n] <$> mapM toC tcs
+    where n = length args
+          tvarDict = zip args [1..n]
+          toC (name,pt) = (,) name <$> mapM toT pt
+          toT (LambdaPT t1 t2)  = (==>) <$> toT t1 <*> toT t2
+          toT (ADTPT name args) = ADT name <$> mapM toT args
           toT (VarPT x@(c:_))
-              | isLower c = VarT . fromMaybe (-1) $ lookup x pairs
-              | otherwise = case x of "Int" -> IntT
-                                      "Number" -> IntT
-                                      "String" -> StringT
-                                      "Char" -> CharT
-                                      "Bool" -> BoolT
-                                      _ -> ADT x []
+              | isLower c = VarT <$> case lookup x tvarDict of
+                                       Just v -> Right v
+                                       Nothing -> Left $ msg x
+              | otherwise = return $ ADT x []
+          msg x = "Type variable '" ++ x ++
+                  "' is unbound in type constructor '" ++ name ++ "'."
+
 
 toForeignType (LambdaPT t1 t2) =
     fail $ "Elm's JavaScript event interface does not yet handle functions. " ++
diff --git a/src/Parse/Parser.hs b/src/Parse/Parser.hs
--- a/src/Parse/Parser.hs
+++ b/src/Parse/Parser.hs
@@ -14,26 +14,26 @@
 import ParseForeign
 
 
+statement =  (:[]) <$> foreignDef
+         <|> (:[]) <$> datatype
+         <|> def
+         <?> "datatype or variable definition"
+
 freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do
              freshLine
-             datatype <|> def <?> "another datatype or variable definition"
-
-defs1 = do d <- datatype <|> def <?> "at least one datatype or variable definition"
-           (d:) <$> many freshDef
+             statement <?> "another datatype or variable definition"
 
-defs = do
-  (fss,ess,tss) <- unzip3 <$> defs1
-  return (concat fss, concat ess, concat `liftM` sequence tss)
+defs1 = do d <- statement <?> "at least one datatype or variable definition"
+           concat <$> (d:) <$> many freshDef
 
 program = do
   optional freshLine
   (names,exports) <- option (["Main"],[]) (moduleDef `followedBy` freshLine)
   is <- (do try (lookAhead $ reserved "import")
             imports `followedBy` freshLine) <|> return []
-  jsffi <- foreignDefs `followedBy` freshLine <|> return ([],[])
-  (vs,es,ts) <- defs
+  statements <- defs1
   optional freshLine ; optional spaces ; eof
-  return (Module names exports is (zip vs es) jsffi, zip vs `liftM` ts)
+  return $ Module names exports is statements
 
 parseProgram source = 
     case parse program "" source of
diff --git a/src/Parse/Patterns.hs b/src/Parse/Patterns.hs
--- a/src/Parse/Patterns.hs
+++ b/src/Parse/Patterns.hs
@@ -1,4 +1,4 @@
-module Patterns (patternTerm, patternExpr, makeFunction, flattenPatterns) where
+module Patterns (patternTerm, patternExpr, makeLambda, flattenPatterns) where
 
 import Ast
 import Data.Char (isUpper)
@@ -29,25 +29,28 @@
 patternExpr = foldl1 pcons <$> consSep1 patternTerm <?> "pattern"
 
 
+makeLambda pats body = foldr Lambda (makeBody pats body) (map getName pats)
 
-makeFunction args body = foldr func body args
-    where func PAnything e = Lambda "_" e
-          func (PVar x)  e = Lambda x e
-          func p e = "t" `Lambda` Case (Var "t") [(p,e)]
+makeBody pats body = foldr func body pats
+    where func PAnything e = e
+          func (PVar x)  e = e
+          func p e = Case (Var $ getName p) [(p,e)]
 
-flattenPatterns (PVar f : args) exp = return [(f, makeFunction args exp)]
+flattenPatterns (PVar f : args) exp =
+    return [ Definition f (map getName args) (makeBody args exp) ]
 flattenPatterns [p] exp = return $ matchSingle p exp p
 flattenPatterns ps _ = 
     fail $ "Pattern (" ++ unwords (map show ps) ++
            ") cannot be used on the left-hand side of an assign statement."
 
 matchSingle pat exp p@(PData _ ps) =
-    (v, exp) : concatMap (matchSingle p $ Var v) ps
-        where v = "'" ++ getName p
-matchSingle pat exp (PVar x)  = [ (x, Case exp [(pat,Var x)]) ]
+    (Definition v [] exp) : concatMap (matchSingle p $ Var v) ps
+        where v = getName p
+matchSingle pat exp (PVar x)  = [ Definition x [] (Case exp [(pat,Var x)]) ]
 matchSingle pat exp PAnything = []
 
-getName (PData n ps) = n ++ concatMap getName ps
-getName (PAnything)  = "_"
-getName (PVar x)     = x
+getName p = f p
+    where f (PData n ps) = n ++ "$" ++ concatMap getName ps
+          f (PAnything)  = "_"
+          f (PVar x)     = x
 
diff --git a/src/Rename.hs b/src/Rename.hs
--- a/src/Rename.hs
+++ b/src/Rename.hs
@@ -1,16 +1,38 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-module Rename (rename) where
+module Rename (rename, derename) where
 
 import Ast
 import Control.Arrow (first)
-import Control.Monad (ap, liftM, foldM, mapM, Monad)
+import Control.Monad (ap, liftM, foldM, mapM, Monad, zipWithM)
 import Control.Monad.State (evalState, State, get, put)
-import Data.Char (isLower)
+import Data.Char (isLower,isDigit)
 import Guid
 
-rename :: Expr -> Expr
-rename = run . rename' id
+derename var
+    | isDigit (last var) = reverse . tail . dropWhile isDigit $ reverse var
+    | otherwise = var
 
+rename :: Module -> Module
+rename (Module name ex im stmts) =
+    Module name ex im . run $ renameStatements id stmts
+
+renameStatements env stmts = do env' <- extends env $ concatMap getNames stmts
+                                mapM (renameStmt env') stmts
+    where getNames stmt = case stmt of Def n _ _ -> [n]
+                                       Datatype _ _ tcs -> map fst tcs
+                                       ImportEvent _ _ n _ -> [n]
+                                       ExportEvent _ _ _ -> []
+          renameStmt env (Def name args e) =
+              do env' <- extends env args
+                 Def (env name) (map env' args) `liftM` rename' env' e
+          renameStmt env (Datatype name args tcs) =
+              return $ Datatype name args $ map (first env) tcs
+          renameStmt env (ImportEvent js base elm tipe) =
+              do base' <- rename' env base
+                 return $ ImportEvent js base' (env elm) tipe
+          renameStmt env (ExportEvent js elm tipe) =
+                 return $ ExportEvent js (env elm) tipe
+
 rename' :: (String -> String) -> Expr -> GuidCounter Expr
 rename' env expr =
     case expr of
@@ -48,11 +70,7 @@
 
       Async e -> Async `liftM` rnm e
 
-      Let defs e -> do
-                let (vs,es) = unzip defs
-                env' <- foldM (\acc x -> snd `liftM` extend acc x) env vs
-                es' <- mapM (rename' env') es; re <- rename' env' e
-                return $ Let (zip (map env' vs) es') re
+      Let defs e -> renameLet env defs e
 
       Var x -> return . Var $ env x
 
@@ -71,6 +89,9 @@
   let rx = map (\c -> if c == '\'' then '_' else c) $ x ++ "_" ++ show n
   return (rx, \y -> if y == x then rx else env y)
 
+extends :: (String -> String) -> [String] -> GuidCounter (String -> String)
+extends env xs = foldM (\e x -> liftM snd $ extend e x) env xs
+
 patternExtend :: Pattern -> (String -> String) -> GuidCounter (Pattern, String -> String)
 patternExtend pattern env =
     case pattern of
@@ -86,3 +107,11 @@
   (rp,env') <- patternExtend p env
   re <- rename' env' e
   return (rp,re)
+
+renameLet env defs e = do env' <- extends env $ map getNames defs
+                          defs' <- mapM (renameDef env') defs
+                          Let defs' `liftM` rename' env' e
+    where getNames (Definition n _ _) = n
+          renameDef env (Definition name args e) =
+              do env' <- extends env args
+                 Definition (env name) (map env' args) `liftM` rename' env' e
diff --git a/src/Types/Constrain.hs b/src/Types/Constrain.hs
--- a/src/Types/Constrain.hs
+++ b/src/Types/Constrain.hs
@@ -1,77 +1,180 @@
 
-module Constrain where
+module Types.Constrain (constrain) where
 
 import Ast
 import Types
 import Data.List (foldl')
 import qualified Data.Set as Set
 import qualified Data.Map as Map
-import Control.Monad (liftM,mapM)
+import Control.Arrow (second)
+import Control.Monad (liftM,mapM,zipWithM,foldM)
 import Control.Monad.State (evalState)
 import Guid
+import Types.Substitutions
 
-data Constraint = Type :=: Type
-                | Type :<: Type
-                | Type :<<: Scheme
-                  deriving (Eq, Ord, Show)
+--import System.IO.Unsafe
 
+prints xs v = v --} unsafePerformIO (putStrLn "~~~~~~~~~~" >> mapM print xs) `seq` v
+
 beta = VarT `liftM` guid
 unionA = Map.unionWith (++)
 unionsA = Map.unionsWith (++)
 
-constrain hints expr = do
-    (as,cs,t) <- inference expr
-    hs <- hints
-    let cMap = Map.intersectionWith (\t -> map (:<: t)) (Map.fromList hs) as
-    return $ Set.toList cs ++ (concat . map snd $ Map.toList cMap)
+constrain hints (Module _ _ _ stmts) = do
+    (ass,css,schemess) <- unzip3 `liftM` mapM stmtGen stmts
+    allHints <-  liftM (Map.fromList . (++ concat schemess)) hints
+    let insert as n = do v <- guid; return $ Map.insertWith' (\_ x -> x) n [v] as
+    assumptions <- foldM insert (unionsA ass) $ map fst (concat schemess)
+    let cs = let f k s vs = map (\v -> Context k $ v :<<: s) vs in
+             concat . Map.elems $ Map.intersectionWithKey f allHints assumptions
+    let escapees = Map.keys $ Map.difference assumptions allHints
+    return . (,) escapees $ cs ++ Set.toList (Set.unions css)
 
-inference (Var x) =
-    do b <- beta
-       return (Map.singleton x [b], Set.empty, b)
-inference (App e1 e2) =
-    do (a1,c1,t1) <- inference e1
-       (a2,c2,t2) <- inference e2
+gen :: Expr -> GuidCounter (Map.Map String [X], Set.Set (Context String Constraint), Type)
+
+gen (Var x) =
+    do b <- guid
+       return (Map.singleton x [b], Set.empty, VarT b)
+
+gen e@(App e1 e2) =
+    do (a1,c1,t1) <- gen e1
+       (a2,c2,t2) <- gen e2
        b <- beta
        return ( unionA a1 a2
-              , Set.unions [c1,c2,Set.singleton $ t1 :=: (LambdaT t2 b)]
+              , Set.unions [c1,c2,Set.singleton . ctx e $ t1 :=: (LambdaT t2 b)]
               , b )
-inference (Lambda x e) =
-    do (a,c,t) <- inference e
+gen (Lambda x e) =
+    do (a,c,t) <- gen e
        b <- beta
+       v <- guid
        return ( Map.delete x a
-              , Set.union c . Set.fromList . map (:=: b) $
-                          Map.findWithDefault [] x a
+              , Set.union c . Set.fromList . map (\x -> ctx e $ VarT x :=: b) $
+                          Map.findWithDefault [v] x a
               , LambdaT b t )
-inference (Let defs e) =
-    do (a,c,t) <- inference e
-       let (xs,es) = unzip defs
-       (as,cs,ts) <- unzip3 `liftM` mapM inference es
-       let assumptions = unionsA (a:as)
-       let f x t = map (:<: t) $ Map.findWithDefault [] x assumptions
-       let constraints = Set.fromList . concat $ zipWith f xs ts
-       return ( foldr Map.delete assumptions xs
-              , Set.unions $ c:constraints:cs
+gen (Let defs e) =
+    do (as,cs,t) <- gen e
+       (ass, schemes) <- liftM unzip (mapM defScheme defs)
+       let assumptions = unionsA (as:ass)
+       let names = map (\(Definition x _ _) -> x) defs
+       let genCs name s = do
+             v <- guid
+             let vs = Map.findWithDefault [v] name assumptions
+             return $ map (\x -> ctx (Var name) $ x :<<: s) vs
+       cs' <- zipWithM genCs names schemes
+       return ( foldr Map.delete assumptions names
+              , Set.union (Set.fromList . concat $ cs') cs
               , t )
 
-inference (If e1 e2 e3) =
-    do (a1,c1,t1) <- inference e1
-       (a2,c2,t2) <- inference e2
-       (a3,c3,t3) <- inference e3
+gen ce@(Case e cases) =
+    do (as,cs,t) <- gen e
+       (ass,css,ts) <- liftM unzip3 $ mapM (caseGen t) cases
+       return ( unionsA $ as:ass
+              , let combine t1 t2 = ctx ce (t1 :=: t2) in
+                Set.unions $ Set.fromList (zipWith combine ts $ tail ts) : cs : css
+              , head ts)
+
+gen e@(If e1 e2 e3) =
+    do (a1,c1,t1) <- gen e1
+       (a2,c2,t2) <- gen e2
+       (a3,c3,t3) <- gen e3
        return ( unionsA [a1,a2,a3]
-              , Set.unions [c1,c2,c3, Set.fromList [ t1 :=: BoolT, t2 :=: t3 ] ]
+              , Set.unions [c1,c2,c3, Set.fromList [ ctx e1 (t1 :=: bool), ctx e (t2 :=: t3) ] ]
               , t2 )
 
-inference (Data name es) = inference $ foldl' App (Var name) es
-inference (Binop op e1 e2) = inference (Var op `App` e1 `App` e2)
-inference (Access (Var x) y) = inference . Var $ x ++ "." ++ y
-inference (Range e1 e2) = inference (Var "elmRange" `App` e1 `App` e2)
+gen (Data name es) = gen $ foldl' App (Var name) es
+gen (Binop op e1 e2) = gen (Var op `App` e1 `App` e2)
+gen (Access (Var x) y) = gen . Var $ x ++ "." ++ y
+gen (Range e1 e2) = gen (Var "elmRange" `App` e1 `App` e2)
 
-inference other =
+gen other =
     case other of
-      Number _ -> primitive IntT
-      Chr _ -> primitive CharT
+      IntNum _ -> do t <- beta
+                     return (Map.empty, Set.singleton (ctx other $ t :<: number), t)
+      FloatNum _ -> primitive float
+      Chr _ -> primitive char
       Str _ -> primitive string
-      Boolean _ -> primitive BoolT
+      Boolean _ -> primitive bool
       _ -> beta >>= primitive 
 
 primitive t = return (Map.empty, Set.empty, t)
+
+caseGen tipe (p,e) = do
+  (as ,cs , t  ) <- gen e
+  (as',cs',[t']) <- patternGen (as,cs,[]) p
+  let cs'' = Set.union cs' . Set.singleton . ctx p $ t' :=: tipe
+  return ( as', cs'', t )
+
+patternGen (as,cs,ts) PAnything = ((,,) as cs . (\t -> ts++[t])) `liftM` beta
+patternGen (as,cs,ts) (PVar v) = do
+  b <- beta
+  let cs' = map (\x -> ctx (Var v) $ VarT x :=: b) $ Map.findWithDefault [] v as
+  return ( Map.delete v as, Set.union cs $ Set.fromList cs', ts ++ [b] )
+patternGen (as,cs,ts) p@(PData name ps) = do
+  constr <- guid
+  output <- beta
+  (as',cs',ts') <- foldM patternGen (as,cs,[]) ps
+  let t = foldr (==>) output ts'
+  let getC | isTupleString name = do
+        vs <- mapM (\_ -> beta) ps
+        return . Set.singleton . ctx p $ output :=: ADT name vs
+           | otherwise = return Set.empty
+  cs'' <- getC
+  return ( unionA as' (Map.singleton name [constr])
+         , Set.unions [cs',cs'', Set.singleton . ctx p $ VarT constr :=: t]
+         , ts ++ [output] )
+
+
+defScheme :: Definition -> GuidCounter (Map.Map String [X], Scheme)
+defScheme (Definition name args e) = do
+  (as,cs,hint) <- defGen name args e
+  return ( as, snd hint )
+
+defGen name args e = do
+  argDict <- mapM (\a -> liftM ((,) a) guid) args 
+  (as,cs,t) <- gen e
+  let genCs (arg,x) = do
+        v <- guid
+        return . map (\y -> Context arg $ VarT x :=: VarT y) $ Map.findWithDefault [v] arg as
+  cs' <- concat `liftM` mapM genCs argDict
+  let as' = foldr Map.delete as args
+  let tipe = foldr (==>) t $ map (VarT . snd) argDict
+  scheme <- generalize (concat $ Map.elems as') $
+            Forall (map snd argDict) (cs' ++ Set.toList cs) tipe
+  return ( as', Set.empty, (name, scheme) )
+
+stmtGen (Def name args e) = do (as,cs,hint) <- defGen name args e
+                               return ( as, cs, [hint] )
+
+stmtGen (Datatype name xs tcs) = do schemes <- mapM gen' tcs'
+                                    return (Map.empty, Set.empty, schemes)
+    where names = map (+ (length xs)) [1..5]
+          tcs' = map (second . map $ rnm names) tcs
+          supers t = map (Context name) $ zipWith (:<:) (map VarT names)
+                     [ number, time, appendable t, comparable, transformable ]
+          gen' (n,ts) = do t <- beta
+                           let s = Forall (xs ++ names) (supers t) $
+                                   foldr (==>) (ADT name $ map VarT xs) ts
+                           (,) n `liftM` generalize [] s
+          rnm [a,b,c,d,e] (ADT n []) | n == "Number" = VarT a
+                                     | n == "Time"  = VarT b
+                                     | n == "Appendable"  = VarT c
+                                     | n == "Comparable"  = VarT d
+                                     | n == "Transformable"  = VarT e
+          rnm _ t = t
+
+stmtGen (ExportEvent js elm tipe) = do
+  x <- guid
+  return ( Map.singleton elm [x]
+         , Set.singleton . ctx (Var elm) $ VarT x :=: tipe
+         , [] )
+
+stmtGen (ImportEvent js base elm tipe) = do
+  (as,cs,t) <- gen base
+  return ( as
+         , Set.insert (ctx base (signalOf t :=: tipe)) cs
+         , [ (elm, Forall [] [] tipe) ] )
+
+getDatatypeInfo (Datatype name args tcs) =
+    Just (name, args, tcs)
+getDatatypeInfo _ = Nothing
+
diff --git a/src/Types/Hints.hs b/src/Types/Hints.hs
--- a/src/Types/Hints.hs
+++ b/src/Types/Hints.hs
@@ -1,10 +1,10 @@
 
-module Hints (hints) where
+module Types.Hints (hints) where
 
 import Control.Monad (liftM,mapM)
 import Control.Arrow (first)
 import Types
-import Guid
+import Types.Substitutions (rescheme)
 
 
 --------  Text and Elements  --------
@@ -16,190 +16,242 @@
 
 textAttrs = [ "toText" -: string ==> text
             , "link"   -: string ==> text ==> text
-            , "Text.height" -: IntT ==> text ==> text
+            , numScheme (\t -> t ==> text ==> text) "Text.height"
             ] ++ hasType (text ==> text) textToText
 
-elements = let iee = IntT ==> element ==> element in
+elements = let iee = int ==> element ==> element in
            [ "flow"    -: direction ==> listOf element ==> element
            , "layers"  -: listOf element ==> element
            , "text"    -: text ==> element
-           , "opacity" -: iee
+           , "opacity" -: float ==> element ==> element
            , "width"   -: iee
            , "height"  -: iee
-           , "size"    -: IntT ==> iee
+           , "size"    -: int ==> iee
+           , "color"   -: color ==> element ==> element
            , "box"     -: iee
+           , "rectangle" -: int ==> int ==> element
+           , "rightedText"  -: text ==> element
            , "centeredText"  -: text ==> element
            , "justifiedText" -: text ==> element
-           , "collage" -: IntT ==> IntT ==> listOf form ==> element
+           , "asText" -:: a ==> element 
+           , "show" -:: a ==> text
+           , "collage" -: int ==> int ==> listOf form ==> element
            ]
 
 directions = hasType direction ["up","down","left","right","inward","outward"]
-colors = [ "rgb"  -: IntT ==> IntT ==> IntT ==> color
-         , "rgba" -: IntT ==> IntT ==> IntT ==> IntT ==> color
-         ] ++ hasType color ["red","green","blue","black","white"]
+colors = [ numScheme (\n -> n ==> n ==> n ==> color) "rgb"
+         , numScheme (\n -> n ==> n ==> n ==> n ==> color) "rgba"
+         ] ++ hasType color ["red","green","blue","black","white"
+                            ,"yellow","cyan","magenta","grey","gray"]
 
-lineTypes = [ "line"       -: listOf point ==> line
-            , "customLine" -: listOf IntT ==> color ==> line ==> form
+lineTypes = [ numScheme (\n -> listOf (pairOf n) ==> line) "line"
+            , "customLine" -: listOf int ==> color ==> line ==> form
             ] ++ hasType (color ==> line ==> form) ["solid","dashed","dotted"]
 
-shapes = [ "polygon"       -: listOf point ==> point ==> shape
+shapes = [ twoNums (\n m -> listOf (pairOf n) ==> pairOf m ==> shape) "polygon"
          , "filled"        -: color ==> shape ==> form
          , "outlined"      -: color ==> shape ==> form
-         , "customOutline" -: listOf IntT ==> color ==> shape ==> form
-         ] ++ hasType (IntT ==> IntT ==> point ==> shape) ["ngon","rect","oval"]
+         , "customOutline" -: listOf int ==> color ==> shape ==> form
+         , scheme2 number transformable (\n t -> n ==> n ==> t ==> t) "move"
+         , scheme2 number transformable (\n t -> n ==> t ==> t) "rotate"
+         , scheme2 number transformable (\n t -> n ==> t ==> t) "scale"
+         ] ++ map (twoNums (\n m -> n ==> n ==> pairOf m ==> shape)) [ "ngon"
+                                                                     , "rect"
+                                                                     , "oval" ]
 
 
 --------  Foreign  --------
 
 casts =
-  [ "castJSBoolToBool"       -: jsBool ==> BoolT
-  , "castBoolToJSBool"       -: BoolT ==> jsBool
-  , "castJSNumberToInt"      -: jsNumber ==> IntT
-  , "castIntToJSNumber"      -: IntT ==> jsNumber
-  , "castJSElementToElement" -: IntT ==> IntT ==> jsElement ==> element
+  [ "castJSBoolToBool"       -: jsBool ==> bool
+  , "castBoolToJSBool"       -: bool ==> jsBool
+  , "castJSNumberToInt"      -: jsNumber ==> int
+  , "castIntToJSNumber"      -: int ==> jsNumber
+  , "castJSElementToElement" -: int ==> int ==> jsElement ==> element
   , "castElementToJSElement" -: element ==> jsElement
   , "castJSStringToString"   -: jsString ==> string
   , "castStringToJSString"   -: string ==> jsString
-  --  , "castJSNumberToFloat -: 
-  --  , "castFloatToJSNumber -:
+  , "castJSNumberToFloat"    -: jsNumber ==> float 
+  , "castFloatToJSNumber"    -: float ==> jsNumber
   ]
 
-polyCasts = sequence
-  [ do a <- var     ; "castJSArrayToList"   -:: jsArray a ==> listOf a
-  , do a <- var     ; "castListToJSArray"   -:: listOf a ==> jsArray a
-  , do vs <- vars 2 ; "castTupleToJSTuple2" -:: tupleOf vs ==> jsTuple vs
-  , do vs <- vars 3 ; "castTupleToJSTuple3" -:: tupleOf vs ==> jsTuple vs
-  , do vs <- vars 4 ; "castTupleToJSTuple4" -:: tupleOf vs ==> jsTuple vs
-  , do vs <- vars 5 ; "castTupleToJSTuple5" -:: tupleOf vs ==> jsTuple vs
-  , do vs <- vars 2 ; "castJSTupleToTuple2" -:: jsTuple vs ==> tupleOf vs
-  , do vs <- vars 3 ; "castJSTupleToTuple3" -:: jsTuple vs ==> tupleOf vs
-  , do vs <- vars 4 ; "castJSTupleToTuple4" -:: jsTuple vs ==> tupleOf vs
-  , do vs <- vars 5 ; "castJSTupleToTuple5" -:: jsTuple vs ==> tupleOf vs
+castToTuple n = (,) name $ Forall [1..n] [] (jsTuple vs ==> tupleOf vs)
+    where vs = map VarT [1..n]
+          name = "castJSTupleToTuple" ++ show n
+castToJSTuple n = (,) name $ Forall [1..n] [] (tupleOf vs ==> jsTuple vs)
+    where vs = map VarT [1..n]
+          name = "castTupleToJSTuple" ++ show n
+
+polyCasts =
+  map castToTuple [2..5] ++ map castToJSTuple [2..5] ++
+  [ "castJSArrayToList"   -:: jsArray a ==> listOf a
+  , "castListToJSArray"   -:: listOf a ==> jsArray a
   ]
 
+json =
+  [ "JsonString" -: string ==> jsonValue
+  , "JsonBool"   -: bool   ==> jsonValue
+  , "JsonNull"   -: jsonValue
+  , "JsonArray"  -: listOf jsonValue ==> jsonValue
+  , "JsonObject" -: jsonObject ==> jsonValue
+  , numScheme (\n -> n ==> jsonValue) "JsonNumber"
+  , "toPrettyString" -: string ==> jsonObject ==> string
+  , "toPrettyJSString" -: string ==> jsonObject ==> jsString
+  , "toJSString" -: jsonObject ==> jsString
+  ]
 
+
 --------  Signals  --------
 
-sig ts = fn ts ==> fn (map signalOf ts)
+sig n name = (,) name $ Forall [1..n] [] (fn ts ==> fn (map signalOf ts))
     where fn = foldr1 (==>)
+          ts = map VarT [1..n]
 
-signals = sequence
-    [ do ts <- vars 1 ; "constant" -:: sig ts
-    , do ts <- vars 2 ; "lift"     -:: sig ts
-    , do ts <- vars 3 ; "lift2"    -:: sig ts
-    , do ts <- vars 4 ; "lift3"    -:: sig ts
-    , do ts <- vars 5 ; "lift4"    -:: sig ts
-    , do [a,b] <- vars 2 
-         "foldp" -:: (a ==> b ==> b) ==> b ==> signalOf a ==> signalOf b
-    , do a <- var ; "randomize" -:: IntT ==> IntT ==> signalOf a ==> signalOf IntT
-    , do a <- var ; "count"     -:: signalOf a ==> signalOf IntT
-    , do a <- var ; "keepIf"    -:: (a==>BoolT) ==> a ==> signalOf a ==> signalOf a
-    , do a <- var ; "dropIf"    -:: (a==>BoolT) ==> a ==> signalOf a ==> signalOf a
-    , do a <- var ; "keepWhen"  -:: signalOf BoolT ==>a==> signalOf a ==> signalOf a
-    , do a <- var ; "dropWhen"  -:: signalOf BoolT ==>a==> signalOf a ==> signalOf a
-    , do a <- var ; "dropRepeats" -:: signalOf a ==> signalOf a
-    , do [a,b] <- vars 2 ; "sampleOn" -:: signalOf a ==> signalOf b ==> signalOf b
+signals =
+    [ sig 1 "constant"
+    , sig 2 "lift" 
+    , sig 3 "lift2"
+    , sig 4 "lift3"
+    , sig 5 "lift4"
+    , "foldp" -:: (a ==> b ==> b) ==> b ==> signalOf a ==> signalOf b
+    , "randomize" -:: int ==> int ==> signalOf a ==> signalOf int
+    , "count"     -:: signalOf a ==> signalOf int
+    , "keepIf"    -:: (a==>bool) ==> a ==> signalOf a ==> signalOf a
+    , "dropIf"    -:: (a==>bool) ==> a ==> signalOf a ==> signalOf a
+    , "keepWhen"  -:: signalOf bool ==>a==> signalOf a ==> signalOf a
+    , "dropWhen"  -:: signalOf bool ==>a==> signalOf a ==> signalOf a
+    , "dropRepeats" -:: signalOf a ==> signalOf a
+    , "sampleOn" -:: signalOf a ==> signalOf b ==> signalOf b
     ]
 
 concreteSignals = 
-  [ "keysDown"    -: signalOf (listOf IntT)
-  , "charPressed" -: signalOf (maybeOf IntT)
-  , "inRange"     -: IntT ==> IntT ==> signalOf IntT
-  , "every"       -: time ==> signalOf time
-  , "before"      -: time ==> signalOf BoolT
-  , "after"       -: time ==> signalOf BoolT
+  [ "keysDown"    -: signalOf (listOf int)
+  , "charPressed" -: signalOf (maybeOf int)
+  , "inRange"     -: int ==> int ==> signalOf int
+  , timeScheme "every"  (\t -> t ==> signalOf t)
+  , timeScheme "before" (\t -> t ==> signalOf bool)
+  , timeScheme "after"  (\t -> t ==> signalOf bool)
   , "dimensions"  -: signalOf point
   , "position"    -: signalOf point
-  , "x"           -: signalOf IntT
-  , "y"           -: signalOf IntT
-  , "isDown"      -: signalOf BoolT
-  , "isClicked"   -: signalOf BoolT
+  , "x"           -: signalOf int
+  , "y"           -: signalOf int
+  , "isDown"      -: signalOf bool
+  , "isClicked"   -: signalOf bool
   , "textField"   -: string ==> tupleOf [element, signalOf string]
   , "password"    -: string ==> tupleOf [element, signalOf string]
-  , "textArea"    -: IntT ==> IntT ==> tupleOf [element, signalOf string]
-  , "checkBox"    -: BoolT ==> tupleOf [element, signalOf BoolT]
-  , "button"      -: string ==> tupleOf [element, signalOf BoolT]
+  , "textArea"    -: int ==> int ==> tupleOf [element, signalOf string]
+  , "checkBox"    -: bool ==> tupleOf [element, signalOf bool]
+  , "button"      -: string ==> tupleOf [element, signalOf bool]
   , "stringDropDown" -: listOf string ==> tupleOf [element, signalOf string]
   ]
 
 --------  Math and Binops  --------
 
-iii = IntT ==> IntT ==> IntT
-xxb x = x ==> x ==> BoolT
+binop t = t ==> t ==> t
+scheme1 super t name =
+    (name, Forall [0] [ Context ("`" ++ name ++ "'") $ VarT 0 :<: super
+                      ] (t (VarT 0)))
+scheme2 s1 s2 t name =
+    (name, Forall [0,1] [ Context ("`" ++ name ++ "'") $ VarT 0 :<: s1
+                        , Context ("`" ++ name ++ "'") $ VarT 1 :<: s2
+                        ] (t (VarT 0) (VarT 1)))
+numScheme t name = scheme1 number t name
+timeScheme name t = scheme1 time t name
+twoNums f name = scheme2 number number f name
 
 math =
-  hasType (IntT ==> iii) ["clamp"] ++
-  hasType iii ["+", "-", "*", "/","rem","mod","logBase","max","min"] ++
-  hasType (IntT ==> IntT) ["sin","cos","tan","asin","acos","atan","sqrt","abs"]
-
-bool =
-  [ "not" -: BoolT ==> BoolT ] ++
-  hasType (xxb BoolT) ["&&","||"] ++
-  hasType (xxb IntT)  ["<",">","<=",">="]
+  map (numScheme (\t -> t ==> binop t)) ["clamp"] ++
+  map (numScheme (\t -> binop t)) ["+","-","*","max","min"] ++
+  [ numScheme (\t -> t ==> t) "abs" ] ++
+  hasType (binop float) [ "/", "logBase" ] ++
+  hasType (binop int) ["rem","div","mod"] ++
+  hasType (float ==> float) ["sin","cos","tan","asin","acos","atan","sqrt"] ++
+  hasType float ["pi","e"] ++
+  hasType (int ==> float) ["toFloat","castIntToFloat"] ++
+  hasType (float ==> int) ["round","floor","ceiling","truncate"]
 
+bools =
+  [ "not" -: bool ==> bool ] ++
+  hasType (binop bool) ["&&","||"] ++
+  map (scheme1 comparable (\t -> t ==> t ==> bool))  ["<",">","<=",">="] ++
+  [ ( "compare"
+    , Forall [0,1] [ Context "`compare'" $ VarT 0 :<: comparable ] (VarT 0 ==> VarT 0 ==> VarT 1) )
+  ]
 
 --------  Polymorphic Functions  --------
 
-var = VarT `liftM` guid
-vars n = mapM (const var) [1..n]
+[a,b,c] = map VarT [1,2,3]
 
 infix 8 -::
-name -:: tipe = return $ name -: tipe
+name -:: tipe = (name, Forall [1,2,3] [] tipe)
 
-funcs = sequence
-    [ do a <- var          ; "id"   -:: a ==> a
-    , do a <- var          ; "=="   -:: a ==> a ==> BoolT
-    , do a <- var          ; "/="   -:: a ==> a ==> BoolT
-    , do [a,b,c] <- vars 3 ; "flip" -:: (a ==> b ==> c) ==> (b ==> a ==> c)
-    , do [a,b,c] <- vars 3 ; "."    -:: (b ==> c) ==> (a ==> b) ==> (a ==> c)
-    , do [a,b] <- vars 2   ; "$"    -:: (a ==> b) ==> a ==> b
-    , do a <- var ; ":"       -:: a ==> listOf a ==> listOf a
-    , do a <- var ; "++"      -:: a ==> a ==> a
-    , do a <- var ; "Cons"    -:: a ==> listOf a ==> listOf a 
-    , do a <- var ; "Nil"     -:: listOf a
-    , do a <- var ; "Just"    -:: a ==> ADT "Maybe" [a]
-    , do a <- var ; "Nothing" -:: ADT "Maybe" [a]
-    , "elmRange" -:: IntT ==> IntT ==> listOf IntT
-    ]
+funcs =
+    [ "id"   -:: a ==> a
+    , "=="   -:: a ==> a ==> bool
+    , "/="   -:: a ==> a ==> bool
+    , "flip" -:: (a ==> b ==> c) ==> (b ==> a ==> c)
+    , "."    -:: (b ==> c) ==> (a ==> b) ==> (a ==> c)
+    , "$"    -:: (a ==> b) ==> a ==> b
+    , ":"       -:: a ==> listOf a ==> listOf a
+    , (,) "++" . Forall [0,1] [ Context "`++'" $ VarT 0 :<: appendable (VarT 1) ] $ VarT 0 ==> VarT 0 ==> VarT 0
+    , "Cons"    -:: a ==> listOf a ==> listOf a 
+    , "Nil"     -:: listOf a
+    , "Just"    -:: a ==> maybeOf a
+    , "Nothing" -:: maybeOf a
+    , "curry"   -:: (tupleOf [a,b] ==> c) ==> a ==> b ==> c
+    , "uncurry" -:: (a ==> b ==> c) ==> tupleOf [a,b] ==> c
+    ] ++ map tuple [0..8]
 
-ints = map (-: (listOf IntT ==> IntT)) [ "sum","product","maximum","minimum" ]
+tuple n = ("Tuple" ++ show n, Forall [1..n] [] $ foldr (==>) (tupleOf vs) vs)
+    where vs = map VarT [1..n]
 
-lists = liftM (++ints) . sequence $
-    [ "and"  -:: listOf BoolT ==> BoolT
-    , "or"   -:: listOf BoolT ==> BoolT
-    , "sort" -:: listOf IntT ==> listOf IntT
-    , do a <- var ; "head"    -:: listOf a ==> a
-    , do a <- var ; "tail"    -:: listOf a ==> listOf a
-    , do a <- var ; "length"  -:: listOf a ==> IntT
-    , do a <- var ; "filter"  -:: (a ==> BoolT) ==> listOf a ==> listOf a
-    , do a <- var ; "foldr1"  -:: (a ==> a ==> a) ==> listOf a ==> a
-    , do a <- var ; "foldl1"  -:: (a ==> a ==> a) ==> listOf a ==> a
-    , do a <- var ; "scanl1"  -:: (a ==> a ==> a) ==> listOf a ==> a
-    , do a <- var ; "forall"  -:: (a ==> BoolT) ==> listOf a ==> BoolT
-    , do a <- var ; "exists"  -:: (a ==> BoolT) ==> listOf a ==> BoolT
-    , do a <- var ; "concat"  -:: listOf (listOf a) ==> listOf a
-    , do a <- var ; "reverse" -:: listOf a ==> listOf a
-    , do a <- var ; "take"    -:: IntT ==> listOf a ==> listOf a
-    , do a <- var ; "drop"    -:: IntT ==> listOf a ==> listOf a
-    , do a <- var ; "partition"    -:: (a==>BoolT)==>listOf a==>tupleOf [listOf a,listOf a]
-    , do a <- var ; "intersperse"  -:: a ==> listOf a ==> listOf a
-    , do a <- var ; "intercalate"  -:: listOf a ==> listOf(listOf a) ==> listOf a
-    , do [a,b] <- vars 2 ; "zip"   -:: listOf a ==>listOf b ==>listOf(tupleOf [a,b])
-    , do [a,b] <- vars 2 ; "map"   -:: (a ==> b) ==> listOf a ==> listOf b
-    , do [a,b] <- vars 2 ; "foldr" -:: (a ==> b ==> b) ==> b ==> listOf a ==> b
-    , do [a,b] <- vars 2 ; "foldl" -:: (a ==> b ==> b) ==> b ==> listOf a ==> b
-    , do [a,b] <- vars 2 ; "scanl" -:: (a==>b==>b)==>b==>listOf a==>listOf b
-    , do [a,b] <- vars 2 ; "concatMap" -:: (a==>listOf b)==>listOf a ==> listOf b
-    , do [a,b,c] <- vars 3
-         "zipWith" -:: (a ==> b ==> c) ==> listOf a ==> listOf b ==> listOf c
-    ]
+lists =
+  [ "and"  -:: listOf bool ==> bool
+  , "or"   -:: listOf bool ==> bool
+  , numScheme (\n -> listOf n ==> listOf n) "sort"
+  , "head"    -:: listOf a ==> a
+  , "tail"    -:: listOf a ==> listOf a
+  , "length"  -:: listOf a ==> int
+  , "filter"  -:: (a ==> bool) ==> listOf a ==> listOf a
+  , "foldr1"  -:: (a ==> a ==> a) ==> listOf a ==> a
+  , "foldl1"  -:: (a ==> a ==> a) ==> listOf a ==> a
+  , "scanl1"  -:: (a ==> a ==> a) ==> listOf a ==> a
+  , "forall"  -:: (a ==> bool) ==> listOf a ==> bool
+  , "exists"  -:: (a ==> bool) ==> listOf a ==> bool
+  , "reverse" -:: listOf a ==> listOf a
+  , "take"    -:: int ==> listOf a ==> listOf a
+  , "drop"    -:: int ==> listOf a ==> listOf a
+  , "partition"    -:: (a ==> bool) ==> listOf a ==> tupleOf [listOf a,listOf a]
+  , "intersperse"  -:: a ==> listOf a ==> listOf a
+  , "zip"   -:: listOf a ==>listOf b ==>listOf(tupleOf [a,b])
+  , "map"   -:: (a ==> b) ==> listOf a ==> listOf b
+  , "foldr" -:: (a ==> b ==> b) ==> b ==> listOf a ==> b
+  , "foldl" -:: (a ==> b ==> b) ==> b ==> listOf a ==> b
+  , "scanl" -:: (a ==> b ==> b) ==> b ==> listOf a ==> listOf b
+  , (,) "concat"      . Forall [0,1]   [ Context "`concat'" $ VarT 0 :<: appendable (VarT 1) ] $
+        listOf (VarT 0) ==> VarT 0
+  , (,) "concatMap"   . Forall [0,1,2] [ Context "`concatMap'" $ VarT 0 :<: appendable (VarT 1) ] $
+        (VarT 2 ==> VarT 0) ==> listOf (VarT 2) ==> VarT 0
+  , (,) "intercalate" . Forall [0,1]   [ Context "`intercalate'" $ VarT 0 :<: appendable (VarT 1) ] $
+        VarT 0 ==> listOf (VarT 0) ==> VarT 0
+  , "zipWith" -:: (a ==> b ==> c) ==> listOf a ==> listOf b ==> listOf c
+  ] ++ map (numScheme (\n -> listOf n ==> n)) [ "sum", "product"
+                                              , "maximum", "minimum" ]
 
+maybeFuncs =
+  [ "maybe" -:: b ==> (a ==> b) ==> maybeOf a ==> b
+  , "isJust" -:: maybeOf a ==> bool
+  , "isNothing" -:: maybeOf a ==> bool
+  , "fromMaybe" -:: a ==> maybeOf a ==> a
+  , "consMaybe" -:: maybeOf a ==> listOf a ==> listOf a
+  , "catMaybes" -:: listOf (maybeOf a) ==> listOf a
+  , "catMaybes" -:: (a ==> maybeOf b) ==> listOf a ==> listOf b
+  ]
 
 --------  Everything  --------
 
-hints = do
-  fs <- funcs ; ls <- lists ; ss <- signals ; pcasts <- polyCasts
-  return $ concat [ fs, ls, ss, math, bool, str2elem, textAttrs
-                  , elements, directions, colors, lineTypes, shapes
-                  , concreteSignals, casts, pcasts
-                  ]
+hints = mapM (\(n,s) -> (,) n `liftM` rescheme s) hs
+    where hs = concat [ funcs, lists, signals, math, bools, str2elem, textAttrs
+                      , elements, directions, colors, lineTypes, shapes
+                      , concreteSignals, casts, polyCasts, json, maybeFuncs
+                      ]
diff --git a/src/Types/Substitutions.hs b/src/Types/Substitutions.hs
new file mode 100644
--- /dev/null
+++ b/src/Types/Substitutions.hs
@@ -0,0 +1,98 @@
+
+module Types.Substitutions (cSub
+                           ,tSub
+                           ,cSubNoContext
+                           ,cFreeVars
+                           ,schemeSub
+                           ,concretize
+                           ,rescheme
+                           ,generalize) where
+
+import Control.DeepSeq (NFData (..), deepseq)
+import Control.Monad (liftM)
+import Data.List (foldl')
+import qualified Data.Set as Set
+import Guid
+import Types
+
+force x = x `deepseq` x
+
+instance (NFData a) => NFData (Context c a) where
+  rnf (Context _ a) = a `deepseq` ()
+
+instance NFData Constraint where
+  rnf (t1 :=: t2) = t1 `deepseq` t2 `deepseq` ()
+  rnf (t :<: _)   = t `deepseq` ()
+  rnf (t :<<: _)  = t `deepseq` ()
+
+instance NFData Type where
+  rnf (LambdaT t1 t2) = t1 `deepseq` t2 `deepseq` ()
+  rnf (ADT _ ts) =  foldl' (\acc x -> x `deepseq` acc) () ts
+  rnf t = t `seq` ()
+
+tSub k v t@(VarT x) = if k == x then v else t
+tSub k v (LambdaT t1 t2) = force $ LambdaT (tSub k v t1) (tSub k v t2)
+tSub k v (ADT name ts) = ADT name (map (force . tSub k v) ts)
+tSub k v (Super ts) = Super ts
+
+schemeSubHelp k s c t1 t2 relation = do
+  (t1',cs1) <- f1 ; (t2',cs2) <- f2
+  return (Context c (relation t1' t2') : cs1 ++ cs2)
+    where f1 | hasVar k t1 = do (v, cs) <- concretize s; return (tSub k v t1, cs)
+             | otherwise = return (t1, [])
+          f2 | hasVar k t2 = do (v, cs) <- concretize s; return (tSub k v t2, cs)
+             | otherwise = return (t2, [])
+
+schemeSub k s (Context ctx (t1 :=: t2)) = schemeSubHelp k s ctx t1 t2 (:=:)
+schemeSub k s (Context ctx (t1 :<: t2)) = schemeSubHelp k s ctx t1 t2 (:<:)
+schemeSub k s (Context ctx c@(x :<<: Forall cxs ccs ctipe))
+    | k `elem` cxs || k `notElem` cFreeVars c = return [Context ctx c]
+    | otherwise = do
+          Forall xs cs tipe <- rescheme s
+          let constraints = (map (cSub k tipe) $ cs ++ ccs)
+          let c' = x :<<: Forall (cxs ++ xs) constraints (tSub k tipe ctipe)
+          return [ Context ctx c' ]
+
+hasVar v (VarT x) = v == x
+hasVar v (LambdaT t1 t2) = hasVar v t1 || hasVar v t2
+hasVar v (ADT _ ts) = any (hasVar v) ts
+hasVar v (Super _ ) = False
+
+cSub k v (Context ctx c) = Context ctx (cSubNoContext k v c)
+
+cSubNoContext k v (t1 :=: t2) = force $ tSub k v t1 :=: tSub k v t2
+cSubNoContext k v (t :<: super) = force $ tSub k v t :<: super
+cSubNoContext k v (x :<<: poly@(Forall vs cs tipe)) = force $ x :<<: poly'
+    where poly' | k `elem` vs = poly
+                | otherwise = let cs' = map (cSub k v) cs in
+                              Forall vs cs' (tSub k v tipe)
+
+concretize (Forall xs cs t) = do
+  pairs <- mapM (\x -> liftM ((,) x) guid) xs
+  return ( foldl' (\t'  (k,v) -> tSub k (VarT v) t') t pairs
+         , foldl' (\cs' (k,v) -> map (cSub k $ VarT v) cs') cs pairs )
+
+rescheme :: Scheme -> GuidCounter Scheme
+rescheme (Forall xs cs t) = do
+  pairs <- mapM (\x -> liftM ((,) x) guid) xs
+  let tipe = foldl' (\t'  (k,v) -> tSub k (VarT v) t') t pairs
+  let cs'  = foldl' (\cs' (k,v) -> map (cSub k $ VarT v) cs') cs pairs
+  return $ Forall (map snd pairs) cs' tipe
+
+freeVars (VarT v) = [v]
+freeVars (LambdaT t1 t2) = freeVars t1 ++ freeVars t2
+freeVars (ADT _ ts) = concatMap freeVars ts
+freeVars (Super _ ) = []
+
+cFreeVars (t1 :=: t2) = freeVars t1 ++ freeVars t2
+cFreeVars (t1 :<: t2) = freeVars t1 ++ freeVars t2
+cFreeVars (x :<<: Forall xs cs t) = filter (`notElem` xs) frees
+    where frees = concatMap (\(Context _ c) -> cFreeVars c) cs ++ freeVars t
+
+decontext (Context _ c) = c
+
+generalize :: [X] -> Scheme -> GuidCounter Scheme
+generalize exceptions (Forall xs cs t) = rescheme (Forall (xs ++ frees) cs t)
+    where allFrees = Set.fromList $ freeVars t ++ concatMap (cFreeVars . decontext) cs
+          frees = Set.toList $ Set.difference allFrees (Set.fromList exceptions)
+
diff --git a/src/Types/Types.hs b/src/Types/Types.hs
--- a/src/Types/Types.hs
+++ b/src/Types/Types.hs
@@ -1,51 +1,80 @@
 
 module Types where
 
-import Data.List (intercalate)
+import Data.Char (isDigit)
+import Data.List (intercalate,isPrefixOf)
 import qualified Data.Set as Set
 
 type X = Int
 
-data Type = IntT
-          | StringT
-          | CharT
-          | BoolT
-          | LambdaT Type Type
+data Type = LambdaT Type Type
           | VarT X
           | ADT String [Type]
+          | Super (Set.Set Type)
             deriving (Eq, Ord)
 
-data Scheme = Forall (Set.Set X) Type deriving (Eq, Ord, Show)
+data Scheme = Forall [X] [Context String Constraint] Type deriving (Eq, Ord)
 
-element   = ADT "Element" []
-direction = ADT "Direction" []
+data Constraint = Type :=: Type
+                | Type :<: Type
+                | X :<<: Scheme
+                  deriving (Eq, Ord, Show)
 
-form  = ADT "Form" []
-line  = ADT "Line" []
-shape = ADT "Shape" []
-color = ADT "Color" []
-text  = ADT "List" [ADT "Text" []]
-point = tupleOf [IntT,IntT]
+data Context c v = Context c v deriving (Eq, Show)
 
+ctx c = Context ("`" ++ show c ++ "'")
+extendCtx ctx2 (Context ctx1 c) = Context (ctx1 ++ " in " ++ ctx2) c
+
+instance (Ord a, Eq c) => Ord (Context c a) where
+    compare (Context _ x) (Context _ y) = compare x y
+
+
+tipe t = ADT t []
+
+
+int = tipe "Int"
+float = tipe "Float"
+number = Super (Set.fromList [ int, float ])
+
+char = tipe "Char"
+bool = tipe "Bool"
+
+string = listOf char -- tipe "String"
+text  = tipe "Text"
+
+time = Super (Set.fromList [ int, float ])
+
+element   = tipe "Element"
+direction = tipe "Direction"
+form  = tipe "Form"
+line  = tipe "Line"
+shape = tipe "Shape"
+color = tipe "Color"
+
 listOf t   = ADT "List" [t]
 signalOf t = ADT "Signal" [t]
 tupleOf ts = ADT ("Tuple" ++ show (length ts)) ts
 maybeOf t  = ADT "Maybe" [t]
-string     = listOf CharT
-time       = IntT
+pairOf t = tupleOf [t,t]
+point = pairOf int
+appendable t = Super (Set.fromList [ string, text, listOf t ])
+comparable = Super (Set.fromList [ int, float, char, string ])
+transformable = Super (Set.fromList [ shape, line ])
 
-jsBool     = ADT "JSBool" []
-jsNumber   = ADT "JSNumber" []
-jsString   = ADT "JSString" []
-jsElement  = ADT "JSElement" []
+jsBool     = tipe "JSBool"
+jsNumber   = tipe "JSNumber"
+jsString   = tipe "JSString"
+jsElement  = tipe "JSElement"
 jsArray t  = ADT "JSArray" [t]
 jsTuple ts = ADT ("JSTuple" ++ show (length ts)) ts
+jsonValue = tipe "JsonValue"
+jsonObject = tipe "JsonObject"
 
 infixr ==>
 t1 ==> t2 = LambdaT t1 t2
 
 infix 8 -:
-name -: tipe = (,) name tipe
+name -: tipe = (,) name $ Forall [] [] tipe
 
 hasType t = map (-: t)
 
@@ -54,14 +83,21 @@
 instance Show Type where
   show t =
       case t of
-        { IntT -> "Int"
-        ; StringT -> "String"
-        ; CharT -> "Char"
-        ; BoolT -> "Bool"
-        ; LambdaT t1@(LambdaT _ _) t2 -> parens (show t1) ++ " -> " ++ show t2
+        { LambdaT t1@(LambdaT _ _) t2 -> parens (show t1) ++ " -> " ++ show t2
         ; LambdaT t1 t2 -> show t1 ++ " -> " ++ show t2
-        ; VarT x -> show x
+        ; VarT x -> 't' : show x
+        ; ADT "List" [ADT "Char" []] -> "String"
         ; ADT "List" [tipe] -> "[" ++ show tipe ++ "]"
-        ; ADT name [] -> name
-        ; ADT name cs -> parens $ name ++ " " ++ unwords (map show cs)
+        ; ADT name cs ->
+            if isTupleString name
+                then parens . intercalate "," $ map show cs
+                else case cs of [] -> name
+                                _ -> parens $ name ++ " " ++ unwords (map show cs)
+        ; Super ts -> "{" ++ (intercalate "," . map show $ Set.toList ts) ++ "}"
         }
+
+instance Show Scheme where
+  show (Forall xs cs t) = "Forall " ++ show xs ++ cs' ++ "\n  " ++ show t
+      where cs' = concatMap (concatMap ("\n  "++) . lines . show) cs
+
+isTupleString str = "Tuple" `isPrefixOf` str && all isDigit (drop 5 str)
diff --git a/src/Types/Unify.hs b/src/Types/Unify.hs
--- a/src/Types/Unify.hs
+++ b/src/Types/Unify.hs
@@ -1,71 +1,111 @@
 
-module Unify where
+module Types.Unify (unify) where
 
-import Constrain
 import Control.Arrow (second)
 import Control.Monad (liftM)
 import Data.List (foldl')
 import qualified Data.Set as Set
+import qualified Data.Map as Map
 import Guid
 import Types
+import Types.Constrain
+import Types.Substitutions
 
-import Control.DeepSeq (NFData (..), deepseq)
+--import System.IO.Unsafe
 
-unify hints expr = run $ do
-  cs <- constrain hints expr
-  solver cs []
+prints xs v = v --} unsafePerformIO (putStrLn "----------" >> mapM print xs) `seq` v
 
-solver [] subs = return $ Right subs
+unify hints modul = run $ do
+  (escapees, cs) <- constrain hints modul
+  subs <- solver cs Map.empty
+  prints cs $ return ((,) escapees `liftM` subs)
 
+eq ctx t1 t2 = Context ctx (t1 :=: t2)
+
+solver [] subs = prints (Map.toList subs) $ return $ Right subs
+
 --------  Destruct Type-constructors  --------
 
-solver ((t1@(ADT n1 ts1) :=: t2@(ADT n2 ts2)) : cs) subs =
-    if n1 /= n2 then uniError t1 t2 else
-        solver (zipWith (:=:) ts1 ts2 ++ cs) subs
-solver ((LambdaT t1 t2 :=: LambdaT t1' t2') : cs) subs =
-    solver ([ t1 :=: t1', t2 :=: t2' ] ++ cs) subs
+solver ((Context ctx (t1@(ADT n1 ts1) :=: t2@(ADT n2 ts2))) : cs) subs =
+    if n1 /= n2 then uniError ctx t1 t2 else
+        solver (zipWith (eq ctx) ts1 ts2 ++ cs) subs
+solver ((Context ctx (LambdaT t1 t2 :=: LambdaT t1' t2')) : cs) subs =
+    solver ([ eq ctx t1 t1', eq ctx t2 t2' ] ++ cs) subs
 
 --------  Type-equality  --------
 
-solver ((VarT x :=: t) : cs) subs =
-    solver (map (cSub x t) cs) . map (second $ tSub x t) $ (x,t):subs
-solver ((t :=: VarT x) : cs) subs =
-    solver (map (cSub x t) cs) . map (second $ tSub x t) $ (x,t):subs
-solver ((t1 :=: t2) : cs) subs =
-    if t1 /= t2 then uniError t1 t2 else solver cs subs
+solver (Context ctx (VarT x :=: VarT y) : cs) subs
+    | x == y    = solver cs subs
+    | otherwise =
+        case (Map.lookup x subs, Map.lookup y subs) of
+          (Just (Super xts), Just (Super yts)) ->
+             let ts = Set.intersection xts yts
+                 setXY t = Map.insert x t . Map.insert y t
+             in  case Set.toList ts of
+                   []  -> unionError ctx xts yts
+                   [t] -> solver (map (cSub x t . cSub y t) cs) $ setXY t subs
+                   _   -> solver cs $ setXY (Super ts) subs
+          (Just (Super xts), _) ->
+              solver (map (cSub y (VarT x)) cs) $ Map.insert y (VarT x) subs
+          (_, _) ->
+              solver (map (cSub x (VarT y)) cs) $ Map.insert x (VarT y) subs
+solver (Context ctx (VarT x :=: t) : cs) subs =
+    case Map.lookup x subs of
+      Nothing -> solver (map (cSub x t) cs) . Map.map (tSub x t) $ Map.insert x t subs
+      Just (Super ts) ->
+          let ts' = Set.intersection ts (Set.singleton t) in
+          case Set.toList ts' of
+            []   -> solver (Context ctx (t :<: Super ts) : cs) subs
+            [t'] -> solver (map (cSub x t') cs) $ Map.insert x t' subs
+            _    -> solver cs $ Map.insert x (Super ts') subs
+      Just t' -> solver (Context ctx (t' :=: t) : cs) subs
+solver ((Context ctx (t :=: VarT x)) : cs) subs =
+    solver ((Context ctx (VarT x :=: t)) : cs) subs
+solver ((Context ctx (t1 :=: t2)) : cs) subs
+    | t1 == t2  = solver cs subs
+    | otherwise = uniError ctx t1 t2
 
+
 --------  subtypes  --------
 
-solver ((t1 :<: t2) : cs) subs = do
-  let f x = do y <- guid ; return (x,VarT y)
-  pairs <- mapM f . Set.toList $ getVars t2
-  let t2' = foldr (uncurry tSub) t2 pairs
-  solver ((t1 :=: t2') : cs) subs
+solver (Context ctx (VarT x :<: Super ts) : cs) subs =
+    case Map.lookup x subs of
+      Nothing -> solver cs $ Map.insert x (Super ts) subs
+      Just (Super ts') ->
+          case Set.toList $ Set.intersection ts ts' of
+            []   -> unionError ctx ts ts'
+            [t]  -> solver (map (cSub x t) cs) $ Map.insert x t subs
+            ts'' -> solver cs $ Map.insert x (Super $ Set.fromList ts'') subs
 
+solver (Context ctx (ADT "List" [t] :<: Super ts) : cs) subs
+    | any f (Set.toList ts) = solver cs subs
+    | otherwise = subtypeError ("aoeu" ++ ctx) (ADT "List" [t]) (Super ts)
+        where f (ADT "List" [VarT _]) = True
+              f (ADT "List" [t']) = t == t'
+              f _ = False
 
-cSub k v (t1 :=: t2) = force $ tSub k v t1 :=: tSub k v t2
-cSub k v (t1 :<: t2) = force $ tSub k v t1 :<: tSub k v t2
+solver (Context ctx (t :<: Super ts) : cs) subs
+    | Set.member t ts = solver cs subs
+    | otherwise = subtypeError ("htns" ++ ctx) t (Super ts)
 
-tSub k v t@(VarT x) = if k == x then v else t
-tSub k v (LambdaT t1 t2) = force $ LambdaT (tSub k v t1) (tSub k v t2)
-tSub k v (ADT name ts) = ADT name (map (force . tSub k v) ts)
-tSub _ _ t = t
+solver (Context ctx (x :<<: s) : cs) subs
+    | any (\(Context _ c) -> x `elem` cFreeVars c) cs =
+        do cs' <- concat `liftM` mapM (schemeSub x s) cs
+           prints cs' $ solver cs' subs
+    | otherwise =
+        do (t,cs') <- concretize s
+           let cs'' = (cs ++ Context ctx (VarT x :=: t) : map (extendCtx ctx) cs')
+           prints cs'' $ solver cs'' subs
 
-getVars (VarT x)        = Set.singleton x
-getVars (LambdaT t1 t2) = Set.union (getVars t1) (getVars t2)
-getVars (ADT name ts)   = Set.unions $ map getVars ts
-getVars _               = Set.empty
 
-uniError t1 t2 =
-    return . Left $ "Type error: " ++ show t1 ++ " is not equal to " ++ show t2
-
-force x = x `deepseq` x
-
-instance NFData Constraint where
-  rnf (t1 :=: t2) = t1 `deepseq` t2 `deepseq` ()
-  rnf (t1 :<: t2) = t1 `deepseq` t2 `deepseq` ()
-
-instance NFData Type where
-  rnf (LambdaT t1 t2) = t1 `deepseq` t2 `deepseq` ()
-  rnf (ADT _ ts) =  foldl' (\acc x -> x `deepseq` acc) () ts
-  rnf t = t `seq` ()
+uniError ctx t1 t2 =
+    return . Left $ "Type error: " ++ show t1 ++
+                    " is not equal to " ++ show t2 ++
+                    " in context " ++ ctx
+unionError ctx ts ts' =
+    return . Left $ concat [ "Type error: There are no types in both "
+                           , show (Super ts), " and ", show (Super ts')
+                           , " in context ", ctx ]
+subtypeError ctx t s =
+    return . Left $ concat [ "Type error: ", show t, " is not a ", show s
+                           , " in context ", ctx ]
