diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2012, Chris Done
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Chris Done nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/fay-jquery.cabal b/fay-jquery.cabal
new file mode 100644
--- /dev/null
+++ b/fay-jquery.cabal
@@ -0,0 +1,19 @@
+name:                fay-jquery
+version:             0.2.0.0
+synopsis:            jQuery binding.
+description:         jQuery binding.
+homepage:            https://github.com/faylang/fay-jquery
+bug-reports:         https://github.com/faylang/fay-jquery/issues
+license:             BSD3
+license-file:        LICENSE
+author:              Adam Bergmark, Brian Victor, Chris Done
+maintainer:          Chris Done <chrisdone@gmail.com>
+copyright:           Adam Bergmark, Brian Victor, Chris Done
+build-type:          Simple
+cabal-version:       >=1.8
+data-files: src/Language/Fay/JQuery.hs
+
+library
+  hs-source-dirs: src
+  exposed-modules: Language.Fay.JQuery
+  build-depends: fay-base >= 0.14.0.0
diff --git a/src/Language/Fay/JQuery.hs b/src/Language/Fay/JQuery.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Fay/JQuery.hs
@@ -0,0 +1,1066 @@
+{-# LANGUAGE EmptyDataDecls    #-}
+{-# LANGUAGE RankNTypes        #-}
+
+module Language.Fay.JQuery where
+
+{--
+Note that this is very much in flux. Function names, type signatures, and
+data types all subject to drastic change.
+--}
+
+import           FFI
+import           Prelude
+
+data JQuery
+
+data JQXHR
+
+type EventType = String
+
+type Selector = String
+
+
+-- Things that should go in fay or fay-dom
+data Element
+
+data Document
+
+data Window
+
+data Object
+
+emptyCallback :: a -> Fay ()
+emptyCallback = const $ return ()
+
+----
+---- Ajax
+----
+
+ajax :: String
+     -> (Automatic b -> Fay ())
+     -> (JQXHR -> Maybe String -> Maybe String -> Fay ())
+     -> Fay ()
+ajax ur succ err = ajax' $ defaultAjaxSettings
+  { success = Defined succ
+  , data' = Undefined :: Defined String -- hackety hack
+  , error' = Defined err
+  , url = Defined ur }
+
+-- | Serializes the given object to JSON and passes it as the request body without request parameters.
+--   The response is deserialized depending on its type.
+ajaxPost :: String
+         -> Automatic f
+         -> (Automatic g -> Fay ())
+         -> (JQXHR -> Maybe String -> Maybe String -> Fay ())
+         -> Fay ()
+ajaxPost ur dat succ err = ajax' $ defaultAjaxSettings
+  { success = Defined succ
+  , data' = Defined dat
+  , error' = Defined err
+  , url = Defined ur
+  , type' = Defined "POST"
+  , processData = Defined False
+  , contentType = Defined "text/json"
+  , dataType = Defined "json"
+  }
+
+-- | Same as ajaxPost but sends the data inside the given request parameter
+ajaxPostParam :: String
+              -> String
+              -> Automatic f
+              -> (Automatic g -> Fay ())
+              -> (JQXHR -> Maybe String -> Maybe String -> Fay ())
+              -> Fay ()
+ajaxPostParam ur rqparam dat succ err = ajax' $ defaultAjaxSettings
+  { success = Defined succ
+  , data' = Defined $ makeRqObj rqparam dat
+  , error' = Defined err
+  , url = Defined ur
+  , type' = Defined "POST"
+  , processData = Defined False
+  , contentType = Defined "text/json"
+  , dataType = Defined "json"
+  }
+
+makeRqObj :: String -> a -> Object
+makeRqObj = ffi "(function () { var o = {}; o[%1] = %2; return o; })()"
+
+data AjaxSettings a b = AjaxSettings
+  { accepts     :: Defined String
+  , async       :: Defined Bool
+  , beforeSend  :: Defined (JQXHR -> AjaxSettings a b -> Fay ())
+  , cache       :: Defined Bool
+  , complete    :: Defined (JQXHR -> String -> Fay ())
+  -- , contents :: Defined (Object RegExp) -- skipped
+  , contentType :: Defined String
+  -- , context :: Defined Object -- skipped
+  -- , converters :: Defined (Object Value) -- skipped
+  , crossDomain :: Defined Bool
+  , data'       :: Defined a
+  -- , dataFilter  :: Defined (Data -> Type -> Fay ()) -- skipped
+  , dataType    :: Defined String
+  , error'      :: Defined (JQXHR -> Maybe String -> Maybe String -> Fay ())
+  , global      :: Defined Bool
+  -- , headers :: Object String -- need generic objects
+  , ifModified  :: Defined Bool
+  , isLocal     :: Defined Bool
+  -- , jsonp -- skipped
+  -- , jsonpCallback -- skipped
+  , mimeType    :: Defined String
+  , password    :: Defined String
+  , processData :: Defined Bool
+  -- , scriptCharset -- skipped
+  -- , statusCode -- skipped
+  , success     :: Defined (b -> Fay ())
+  , timeout     :: Defined Double
+  -- , traditional -- skipped
+  , type'       :: Defined String
+  , url         :: Defined String
+  , username    :: Defined String
+  -- , xhr :: XHR -- XHR needs to be added to fay-dom
+  }
+
+defaultAjaxSettings :: AjaxSettings a b
+defaultAjaxSettings = AjaxSettings
+  { accepts     = Undefined
+  , async       = Undefined
+  , beforeSend  = Undefined
+  , cache       = Undefined
+  , complete    = Undefined
+  , contentType = Undefined
+  , crossDomain = Undefined
+  , data'       = Undefined
+  , dataType    = Undefined
+  , error'      = Undefined
+  , global      = Undefined
+  , ifModified  = Undefined
+  , isLocal     = Undefined
+  , mimeType    = Undefined
+  , password    = Undefined
+  , processData = Undefined
+  , success     = Undefined
+  , timeout     = Undefined
+  , type'       = Undefined
+  , url         = Undefined
+  , username    = Undefined
+  }
+
+ajax' :: AjaxSettings (Automatic a) (Automatic b) -> Fay ()
+ajax' = ffi "\
+  \ (function (o) { \
+    \ delete o['instance']; \
+    \ for (var p in o) { \
+      \ if (/\\$39\\$/.test(p)) { \
+        \ o[p.replace(/\\$39\\$/g, '')] = o[p]; \
+        \ delete o[p]; \
+      \ } \
+    \ } \
+    \ console.log(o); \
+    \ return jQuery.ajax(o); \
+  \ })(%1)"
+
+----
+---- Attributes
+----
+
+addClass :: String -> JQuery -> Fay JQuery
+addClass = ffi "%2['addClass'](%1)"
+
+-- FIXME: https://github.com/chrisdone/fay/issues/38
+addClassWith :: (Double -> String -> Fay String) -> JQuery -> Fay JQuery
+addClassWith = ffi "%2['addClass'](%1)"
+
+getAttr :: String -> JQuery -> Fay String
+getAttr = ffi "%2['attr'](%1)"
+
+setAttr :: String -> String -> JQuery -> Fay JQuery
+setAttr = ffi "%3['attr'](%1, %2)"
+
+-- TODO: setAttrs with map
+
+setAttrWith :: String -> (Double -> String -> Fay String) -> JQuery -> Fay JQuery
+setAttrWith = ffi "%3['attr'](%1, %2)"
+
+hasClass :: String -> JQuery -> Fay Bool
+hasClass = ffi "%2['hasClass'](%1)"
+
+getHtml :: JQuery -> Fay String
+getHtml = ffi "%1['html']()"
+
+setHtml :: String -> JQuery -> Fay JQuery
+setHtml = ffi "%2['html'](%1)"
+
+setHtmlWith :: (Double -> String -> Fay JQuery) -> JQuery -> Fay JQuery
+setHtmlWith = ffi "%2['html'](%1)"
+
+-- TODO: html with props
+
+getProp :: String -> JQuery -> Fay String
+getProp = ffi "%2['prop'](%1)"
+
+setProp :: String -> String -> JQuery -> Fay JQuery
+setProp = ffi "%3['prop'](%1, %2)"
+
+-- TODO: setProp with map
+
+setPropWith :: String -> (Double -> String -> Fay String) -> JQuery -> Fay JQuery
+setPropWith = ffi "%3['prop'](%1, %2)"
+
+removeAttr :: String -> JQuery -> Fay JQuery
+removeAttr = ffi "%2['removeAttr'](%1)"
+
+removeClass :: String -> JQuery -> Fay JQuery
+removeClass = ffi "%2['removeClass'](%1)"
+
+removeClassWith :: (Double -> String -> Fay JQuery) -> JQuery -> Fay JQuery
+removeClassWith = ffi "%2['removeClass'](%1)"
+
+removeProp :: String -> JQuery -> Fay JQuery
+removeProp = ffi "%2['removeProp'](%1)"
+
+toggleClass :: String -> JQuery -> Fay JQuery
+toggleClass = ffi "%2['toggleClass'](%1)"
+
+toggleClassBool :: String -> Bool -> JQuery -> Fay JQuery
+toggleClassBool = ffi "%3['toggleClass'](%1, %2)"
+
+toggleAllClasses :: Bool -> JQuery -> Fay JQuery
+toggleAllClasses = ffi "%2['toggleClass'](%1)"
+
+toggleClassWith :: (Double -> String -> Bool -> Fay JQuery) -> JQuery -> Fay JQuery
+toggleClassWith = ffi "%2['toggleClass'](%1)"
+
+toggleClassBoolWith :: (Double -> String -> Bool -> Fay JQuery) -> Bool -> JQuery -> Fay JQuery
+toggleClassBoolWith = ffi "%3['toggleClass'](%1, %2)"
+
+getVal :: JQuery -> Fay String
+getVal = ffi "%1['val']()"
+
+setVal :: String -> JQuery -> Fay JQuery
+setVal = ffi "%2['val'](%1)"
+
+setValWith :: (Double -> String -> Fay JQuery) -> JQuery -> Fay JQuery
+setValWith = ffi "%2['val'](%1)"
+
+setText :: String -> JQuery -> Fay JQuery
+setText = ffi "%2['text'](%1)"
+
+setTextWith :: (Double -> String -> Fay JQuery) -> JQuery -> Fay JQuery
+setTextWith = ffi "%2['text'](%1)"
+
+getText :: JQuery -> Fay String
+getText = ffi "%1['text']()"
+
+----
+---- Core
+----
+
+holdReady :: Bool -> Fay JQuery
+holdReady = ffi "jQuery['holdReady'](%1)"
+
+-- jQuery()
+selectElement :: Element -> Fay JQuery
+selectElement = ffi "jQuery(%1)"
+
+selectObject :: a -> Fay JQuery
+selectObject = ffi "jQuery(%1)"
+
+select :: String -> Fay JQuery
+select = ffi "jQuery(%1)"
+
+selectEmpty :: Fay JQuery
+selectEmpty = ffi "jQuery()"
+
+createJQuery :: String -> a -> Fay JQuery
+createJQuery = ffi "jQuery(%1, %2)"
+
+ready :: Fay () -> Fay ()
+ready = ffi "jQuery(%1)"
+-- end jQuery()
+
+-- is noConflict useful in the context of Fay?
+noConflict :: Fay JQuery
+noConflict = ffi "jQuery['noConflict']()"
+
+noConflictBool :: Bool -> Fay JQuery
+noConflictBool = ffi "jQuery['noConflict'](%1)"
+
+-- TODO: jQuery['sub']()
+
+-- TODO: jQuery['when'](): figure out Deferred first
+
+----
+---- CSS
+----
+
+getCss :: String -> JQuery -> Fay String
+getCss = ffi "%2['css'](%1)"
+
+setCss :: String -> String -> JQuery -> Fay JQuery
+setCss = ffi "%3['css'](%1, %2)"
+
+setCssWith :: String -> (Double -> String -> Fay String) -> JQuery -> Fay JQuery
+setCssWith = ffi "%3['css'](%1, %2)"
+
+getHeight :: JQuery -> Fay Double
+getHeight = ffi "%1['height']()"
+
+setHeight :: Double -> JQuery -> Fay JQuery
+setHeight = ffi "%2['height'](%1)"
+
+setHeightWith :: (Double -> Double -> Fay Double) -> JQuery -> Fay JQuery
+setHeightWith = ffi "%2['height'](%1)"
+
+getInnerHeight :: JQuery -> Fay Double
+getInnerHeight = ffi "%1['innerHeight']()"
+
+getInnerWidth :: JQuery -> Fay Double
+getInnerWidth = ffi "%1['innerWidth']()"
+
+-- TODO: figure out how to marshal coordinates
+--getOffset :: JQuery -> Fay
+--getOffset = ffi "%1['offset']()"
+
+--setOffset
+--setOffsetWith
+
+-- TODO: css with map
+
+-- TODO: cssHooks
+
+getOuterHeight :: JQuery -> Fay Double
+getOuterHeight = ffi "%1['outerHeight']()"
+
+-- FIXME: better name
+getOuterHeightBool :: Bool -> JQuery -> Fay Double
+getOuterHeightBool = ffi "%2['outerHeight'](%1)"
+
+getOuterWidth :: JQuery -> Fay Double
+getOuterWidth = ffi "%1['outerWidth']()"
+
+getOuterWidthBool :: Bool -> JQuery -> Fay Double
+getOuterWidthBool = ffi "%2['outerWidth'](%1)"
+
+-- TODO: marshal coordinates as in offset()
+-- getPosition
+
+getScrollLeft :: JQuery -> Fay Double
+getScrollLeft = ffi "%1['scrollLeft']()"
+
+setScrollLeft :: Double -> JQuery -> Fay JQuery
+setScrollLeft = ffi "%2['scrollLeft'](%1)"
+
+getScrollTop :: JQuery -> Fay Double
+getScrollTop = ffi "%1['scrollTop']()"
+
+setScrollTop :: Double -> JQuery -> Fay JQuery
+setScrollTop = ffi "%2['scrollTop'](%1)"
+
+getWidth :: JQuery -> Fay Double
+getWidth = ffi "%1['width']()"
+
+setWidth :: Double -> JQuery -> Fay JQuery
+setWidth = ffi "%2['width'](%1)"
+
+setWidthWith :: (Double -> Double -> Fay Double) -> JQuery -> Fay JQuery
+setWidthWith = ffi "%2['width'](%1)"
+
+
+----
+---- Data
+----
+
+----
+---- Deferred Object
+----
+
+----
+---- Effects
+----
+
+--
+-- Basics
+--
+
+data AnimationType = Show | Hide | Toggle | FadeIn | FadeOut | FadeToggle
+
+data Speed = Instantly | Slow | Fast | Speed Double
+
+data Animation = Animation
+  { _type :: AnimationType
+  , _speed :: Speed
+  , _nextAnimation :: Maybe Animation
+  , _element :: JQuery
+  }
+
+anim :: AnimationType -> JQuery -> Animation
+anim ty el = Animation ty Fast Nothing el
+
+speed :: Speed -> Animation -> Animation
+speed spd anim = anim { _speed = spd }
+
+chainAnim :: Animation -> Animation -> Animation
+chainAnim a1 a2 = a1 { _nextAnimation = Just a2 }
+
+chainAnims :: [Animation] -> Animation
+chainAnims [a] = a
+chainAnims (a:as) = a `chainAnim` chainAnims as
+
+runAnimation :: Animation -> Fay ()
+runAnimation a = do
+  animate (_type a) (_speed a) cb (_element a) >> return ()
+    where
+      cb = case _nextAnimation a of
+                Just a2 -> const (runAnimation a2)
+                Nothing -> const (return ())
+
+animate :: AnimationType -> Speed -> (JQuery -> Fay ()) -> JQuery -> Fay JQuery
+animate = ffi "%4[(function () { \
+      \ switch (%1['instance']) { \
+        \ case 'FadeIn': return 'fadeIn'; \
+        \ case 'FadeOut': return 'fadeOut'; \
+        \ case 'FadeToggle': return 'fadeToggle'; \
+        \ default: return %1['instance']['toLowerCase'](); \
+      \ } \
+    \ })()]((function () { \
+    \ if (%2['instance'] == 'Slow') { \
+      \ return 'slow'; \
+    \ } else if (%2['instance'] == 'Instantly') { \
+      \ return null; \
+    \ } else if (%2['instance'] == 'Fast') { \
+      \ return 'fast'; \
+    \ } else { \
+      \ return %2['slot1']; \
+    \ } \
+  \ })(), function() { \
+     \ %3(jQuery(this)); \
+  \ })"
+
+hide :: Speed -> JQuery -> Fay JQuery
+hide spd = animate Hide spd emptyCallback
+
+unhide :: JQuery -> Fay JQuery
+unhide = ffi "%1['show']()"
+
+jshow :: Speed -> JQuery -> Fay JQuery
+jshow spd = animate Show spd emptyCallback
+
+toggle :: Speed -> JQuery -> Fay JQuery
+toggle spd = animate Toggle spd emptyCallback
+
+--
+-- Fading
+--
+
+fadeIn :: Speed -> JQuery -> Fay JQuery
+fadeIn spd = animate FadeIn spd emptyCallback
+
+fadeOut :: Speed -> JQuery -> Fay JQuery
+fadeOut spd = animate FadeOut spd emptyCallback
+
+-- TODO fadeTo
+
+fadeToggle :: Speed -> JQuery -> Fay JQuery
+fadeToggle spd = animate FadeToggle spd emptyCallback
+
+----
+---- Events
+----
+
+--
+-- Browser Events
+--
+
+-- Skip error(), deprecated
+
+resize :: (Event -> Fay ()) -> JQuery -> Fay ()
+resize = ffi "%2['resize'](%1)"
+
+scroll :: (Event -> Fay ()) -> JQuery -> Fay ()
+scroll = ffi "%2['scroll'](%1)"
+
+--
+-- Document Loading
+--
+
+load :: (Event -> Fay()) -> JQuery -> Fay ()
+load = ffi "%2['load'](%1)"
+
+documentReady :: (Event -> Fay ()) -> Document -> Fay ()
+documentReady = ffi "jQuery(%2)['ready'](%1)"
+
+unload :: (Event -> Fay()) -> Window -> Fay ()
+unload = ffi "jQuery(%2)['unload'](%1)"
+
+--
+-- Mouse Events
+--
+
+click :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+click = ffi "%2['click'](%1)"
+
+dblclick :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+dblclick = ffi "%2['dblclick'](%1)"
+
+focusin :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+focusin = ffi "%2['focusin'](%1)"
+
+focusout :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+focusout = ffi "%2['focusout'](%1)"
+
+hover :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+hover = ffi "%2['hover'](%1)"
+
+mousedown :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mousedown = ffi "%2['mousedown'](%1)"
+
+mouseenter :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mouseenter = ffi "%2['mouseenter'](%1)"
+
+mouseleave :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mouseleave = ffi "%2['mouseleave'](%1)"
+
+mousemove :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mousemove = ffi "%2['mousemove'](%1)"
+
+mouseout :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mouseout = ffi "%2['mouseout'](%1)"
+
+mouseover :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mouseover = ffi "%2['mouseover'](%1)"
+
+mouseup :: (Event -> Fay ()) -> JQuery -> Fay JQuery
+mouseup = ffi "%2['mouseup'](%1)"
+
+-- Argument splat since an arbitrary number of events can be attached.
+-- `toggle` in jQuery but clashes with the `toggle` animation.
+toggleEvents :: [Event -> Fay ()] -> JQuery -> Fay ()
+toggleEvents = ffi "%2['toggle']['apply'](%2, %1)"
+
+
+--
+-- Event Handler Attachment
+--
+
+bind :: EventType -> (Event -> Fay ()) -> JQuery -> Fay ()
+bind = ffi "%3['bind'](%1, %2)"
+
+bindPreventBubble :: EventType -> (Event -> Fay ()) -> JQuery -> Fay ()
+bindPreventBubble = ffi "%3['bind'](%1,%2,false)"
+
+-- delegate() superceeded by on()
+-- die() deprecated
+-- live() deprecated
+-- off() TODO how should this be handled?
+
+on :: EventType -> (Event -> Fay ()) -> JQuery -> Fay ()
+on = ffi "%3['on'](%1, %2)"
+
+onDelegate :: EventType -> Selector -> (Event -> Fay()) -> JQuery -> Fay ()
+onDelegate = ffi "%4['on'](%1,%2,%3)"
+
+one :: EventType -> (Event -> Fay ()) -> JQuery -> Fay ()
+one = ffi "%3['one'](%1, %2)"
+
+trigger :: EventType -> JQuery -> Fay ()
+trigger = ffi "%2['trigger'](%1)"
+
+triggerHandler :: EventType -> JQuery -> Fay ()
+triggerHandler = ffi "%2['triggerHandler'](%1)"
+
+
+-- unbind() not useful in Fay?
+-- undelegate() not useful in Fay?
+
+--
+-- Event Object
+--
+
+-- event.data skipped
+
+data Event
+
+delegateTarget :: Event -> Fay Element
+delegateTarget = ffi "jQuery(%1['delegateTarget'])"
+
+isDefaultPrevented :: Event -> Fay Bool
+isDefaultPrevented = ffi "%1['isDefaultPrevented']()"
+
+isImmediatePropagationStopped :: Event -> Fay Bool
+isImmediatePropagationStopped = ffi "%1['isImmediatePropagationStopped']()"
+
+isPropagationStopped :: Event -> Fay Element
+isPropagationStopped = ffi "%1['isPropagationStopped']()"
+
+namespace :: Event -> Fay String
+namespace = ffi "%1['namespace']"
+
+pageX :: Event -> Fay Double
+pageX = ffi "%1['pageX']"
+
+pageY :: Event -> Fay Double
+pageY = ffi "%1['pageY']"
+
+preventDefault :: Event -> Fay ()
+preventDefault = ffi "%1['preventDefault']()"
+
+target :: Event -> Fay Element
+target = ffi "%1['target']"
+
+timeStamp :: Event -> Fay Double
+timeStamp = ffi "%1['timeStamp']"
+
+eventType :: Event -> Fay String
+eventType = ffi "%1['type']"
+
+which :: Event -> Fay Int
+which = ffi "%1['which']"
+
+--
+-- Form Events
+--
+
+blur :: (Event -> Fay ()) -> JQuery -> Fay ()
+blur = ffi "%2['blur'](%1)"
+
+change :: (Event -> Fay ()) -> JQuery -> Fay ()
+change = ffi "%2['change'](%1)"
+
+onFocus :: (Event -> Fay ()) -> JQuery -> Fay ()
+onFocus = ffi "%2['focus'](%1)"
+
+focus :: JQuery -> Fay JQuery
+focus = ffi "%1['focus']()"
+
+-- TODO `select` would clash with the other select definition, should it be renamed?
+onselect :: (Event -> Fay ()) -> JQuery -> Fay ()
+onselect = ffi "%2['select'](%1)"
+
+submit  :: (Event -> Fay ()) -> JQuery -> Fay ()
+submit = ffi "%2['submit'](%1)"
+
+--
+-- Keyboard Events
+--
+
+keydown :: (Event -> Fay ()) -> JQuery -> Fay ()
+keydown = ffi "%2['keydown'](%1)"
+
+keypress :: (Event -> Fay ()) -> JQuery -> Fay ()
+keypress = ffi "%2['keypress'](%1)"
+
+keyup :: (Event -> Fay ()) -> JQuery -> Fay ()
+keyup = ffi "%2['keyup'](%1)"
+
+----
+---- Forms
+----
+
+----
+---- Internals
+----
+
+----
+---- Manipulation
+----
+
+-- Is there a better way to constrain the type here?
+after :: a -> JQuery -> Fay JQuery
+after = ffi "%2['after'](%1)"
+
+afterWith :: (Double -> Fay JQuery) -> JQuery -> Fay JQuery
+afterWith = ffi "%2['after'](%1)"
+
+append :: a -> JQuery -> Fay JQuery
+append = ffi "%2['append'](%1)"
+
+appendJQuery :: JQuery -> JQuery -> Fay JQuery
+appendJQuery = ffi "%2['append'](%1)"
+
+
+appendWith :: (Double -> Fay JQuery) -> JQuery -> Fay JQuery
+appendWith = ffi "%2['append'](%1)"
+
+appendTo :: a -> JQuery -> Fay JQuery
+appendTo = ffi "%2['appendTo'](%1)"
+
+appendToJQuery :: JQuery -> JQuery -> Fay JQuery
+appendToJQuery = ffi "%2['appendTo'](%1)"
+
+
+
+before :: a -> JQuery -> Fay JQuery
+before = ffi "%2['before'](%1)"
+
+beforeWith :: (Double -> Fay JQuery) -> JQuery -> Fay JQuery
+beforeWith = ffi "%2['before'](%1)"
+
+data CloneType = WithoutDataAndEvents | WithDataAndEvents | DeepWithDataAndEvents
+
+clone :: CloneType -> JQuery -> Fay JQuery
+clone WithoutDataAndEvents  = ffi "%2['clone'](false)"
+clone WithDataAndEvents     = ffi "%2['clone'](true, false)"
+clone DeepWithDataAndEvents = ffi "%2['clone'](true, true)"
+
+detach :: JQuery -> Fay JQuery
+detach = ffi "%1['detach']()"
+
+detachSelector :: String -> JQuery -> Fay JQuery
+detachSelector = ffi "%2['detach'](%1)"
+
+empty :: JQuery -> Fay JQuery
+empty = ffi "%1['empty']()"
+
+insertAfter :: JQuery -> Fay JQuery
+insertAfter = ffi "%2['insertAfter'](%1)"
+
+insertBefore :: JQuery -> Fay JQuery
+insertBefore = ffi "%2['insertBefore'](%1)"
+
+prepend :: JQuery -> Fay JQuery
+prepend = ffi "%2['prepend'](%1)"
+
+prependWith :: (Double -> Fay JQuery) -> JQuery -> Fay JQuery
+prependWith = ffi "%2['prepend'](%1)"
+
+prependTo :: JQuery -> Fay JQuery
+prependTo = ffi "%2['prependTo'](%1)"
+
+remove :: JQuery -> Fay JQuery
+remove = ffi "%1['remove']()"
+
+removeSelector :: String -> JQuery -> Fay JQuery
+removeSelector = ffi "%2['remove'](%1)"
+
+replaceAll :: String -> JQuery -> Fay JQuery
+replaceAll = ffi "%2['replaceAll'](%1)"
+
+-- FIXME: create other forms of replaceWith
+replaceWith :: String -> JQuery -> Fay JQuery
+replaceWith = ffi "%2['replaceWith'](%1)"
+
+replaceWithJQuery :: JQuery -> JQuery -> Fay JQuery
+replaceWithJQuery = ffi "%2['replaceWith'](%1)"
+
+-- FIXME: this name matches convention, but it's kind of silly
+replaceWithWith :: (Fay JQuery) -> JQuery -> Fay JQuery
+replaceWithWith = ffi "%2['replaceWith'](%1)"
+
+unwrap :: JQuery -> Fay JQuery
+unwrap = ffi "%1['unwrap']()"
+
+-- FIXME: create other forms of wrap
+wrap :: String -> JQuery -> Fay JQuery
+wrap = ffi "%2['wrap'](%1)"
+
+wrapWith :: (Double -> Fay JQuery) -> JQuery -> Fay JQuery
+wrapWith = ffi "%2['wrap'](%1)"
+
+wrapAllHtml :: String -> JQuery -> Fay JQuery
+wrapAllHtml = ffi "%2['wrapAll'](%1)"
+
+wrapAllSelector :: String -> JQuery -> Fay JQuery
+wrapAllSelector = ffi "%2['wrapAll'](%1)"
+
+wrapAllElement :: Element -> JQuery -> Fay JQuery
+wrapAllElement = ffi "%2['wrapAll'](%1)"
+
+wrapInnerHtml :: String -> JQuery -> Fay JQuery
+wrapInnerHtml = ffi "%2['wrapInner'](%1)"
+
+wrapInnerSelector :: String -> JQuery -> Fay JQuery
+wrapInnerSelector = ffi "%2['wrapInner'](%1)"
+
+wrapInnerElement :: Element -> JQuery -> Fay JQuery
+wrapInnerElement = ffi "%2['wrapInner'](%1)"
+
+
+----
+---- Miscellaneous
+----
+
+----
+---- Offset
+----
+
+----
+---- Plugins
+----
+
+----
+---- Properties
+----
+
+----
+---- Selectors
+----
+
+----
+---- Traversing
+----
+
+-- TODO: unify these under a typeclass?
+addSelector :: String -> JQuery -> Fay JQuery
+addSelector = ffi "%2['add'](%1)"
+
+addElement :: Element -> JQuery -> Fay JQuery
+addElement = ffi "%2['add'](%1)"
+
+addHtml :: String -> JQuery -> Fay JQuery
+addHtml = ffi "%2['add'](%1)"
+
+add :: JQuery -> JQuery -> Fay JQuery
+add = ffi "%2['add'](%1)"
+
+addSelectorWithContext :: String -> JQuery -> JQuery -> Fay JQuery
+addSelectorWithContext = ffi "%3['add'](%1, %2)"
+
+andSelf :: JQuery -> Fay JQuery
+andSelf = ffi "%1['andSelf']()"
+
+children :: JQuery -> Fay JQuery
+children = ffi "%1['children']()"
+
+childrenMatching :: String -> JQuery -> Fay JQuery
+childrenMatching = ffi "%2['children'](%1)"
+
+closestSelector :: String -> JQuery -> Fay JQuery
+closestSelector = ffi "%2['closest'](%1)"
+
+-- TODO: is context really a string?
+closestWithContext :: String -> String -> JQuery -> Fay JQuery
+closestWithContext = ffi "%3['closest'](%1, %2)"
+
+closest :: JQuery -> JQuery -> Fay JQuery
+closest = ffi "%2['closest'](%1)"
+
+closestElement :: Element -> JQuery -> Fay JQuery
+closestElement = ffi "%2['closest'](%1)"
+
+-- TODO: include deprecated array-based signature?
+
+contents :: JQuery -> Fay JQuery
+contents = ffi "%1['contents']()"
+
+-- This just isn't cool[' Can']'t we all just use map?
+each :: (Double -> Element -> Fay Bool) -> JQuery -> Fay JQuery
+each = ffi "%2['each'](%1)"
+
+end :: JQuery -> Fay JQuery
+end = ffi "%1['end']()"
+
+eq :: Double -> JQuery -> Fay JQuery
+eq = ffi "%2['eq'](%1)"
+
+filter :: String -> JQuery -> Fay JQuery
+filter = ffi "%2['filter'](%1)"
+
+filterWith :: (Double -> Fay Bool) -> JQuery -> Fay JQuery
+filterWith = ffi "%2['filter'](%1)"
+
+filterElement :: Element -> JQuery -> Fay JQuery
+filterElement = ffi "%2['filter'](%1)"
+
+filterJQuery :: JQuery -> JQuery -> Fay JQuery
+filterJQuery = ffi "%2['filter'](%1)"
+
+-- FIXME: not called find because Fay doesn't seem to deal well with name conflicts yet
+findSelector :: String -> JQuery -> Fay JQuery
+findSelector = ffi "%2['find'](%1)"
+
+findJQuery :: JQuery -> JQuery -> Fay JQuery
+findJQuery = ffi "%2['find'](%1)"
+
+findElement :: Element -> JQuery -> Fay JQuery
+findElement = ffi "%2['find'](%1)"
+
+first :: JQuery -> Fay JQuery
+first = ffi "%1['first']()"
+
+has :: String -> JQuery -> Fay JQuery
+has = ffi "%2['has'](%1)"
+
+hasElement :: Element -> JQuery -> Fay JQuery
+hasElement = ffi "%2['has'](%1)"
+
+is :: String -> JQuery -> Fay JQuery
+is = ffi "%2['is'](%1)"
+
+isWith :: (Double -> Bool) -> JQuery -> Fay JQuery
+isWith = ffi "%2['is'](%1)"
+
+isJQuery :: JQuery -> JQuery -> Fay JQuery
+isJQuery = ffi "%2['is'](%1)"
+
+isElement :: Element -> JQuery -> Fay JQuery
+isElement = ffi "%2['is'](%1)"
+
+last :: JQuery -> Fay JQuery
+last = ffi "%1['last']()"
+
+-- FIXME: is the return value of the callback right?
+jQueryMap :: (Double -> Element -> Fay JQuery) -> JQuery -> Fay JQuery
+jQueryMap = ffi "%2['map'](%1)"
+
+next :: JQuery -> Fay JQuery
+next = ffi "%1['next']()"
+
+nextSelector :: String -> JQuery -> Fay JQuery
+nextSelector = ffi "%2['next'](%1)"
+
+nextAll :: JQuery -> Fay JQuery
+nextAll = ffi "%1['nextAll']()"
+
+nextAllSelector :: String -> JQuery -> Fay JQuery
+nextAllSelector = ffi "%2['nextAll'](%1)"
+
+nextUntil :: String -> JQuery -> Fay JQuery
+nextUntil = ffi "%2['nextUntil'](%1)"
+
+nextUntilFiltered :: String -> String -> JQuery -> Fay JQuery
+nextUntilFiltered = ffi "%3['nextUntil'](%1, %2)"
+
+nextUntilElement :: Element -> JQuery -> Fay JQuery
+nextUntilElement = ffi "%2['nextUntil'](%1)"
+
+nextUntilElementFiltered :: Element -> String -> JQuery -> Fay JQuery
+nextUntilElementFiltered = ffi "%3['nextUntil'](%1, %2)"
+
+not :: String -> JQuery -> Fay JQuery
+not = ffi "%2['not'](%1)"
+
+notElement :: Element -> JQuery -> Fay JQuery
+notElement = ffi "%2['not'](%1)"
+
+notElements :: [Element] -> JQuery -> Fay JQuery
+notElements = ffi "%2['not'](%1)"
+
+notWith :: (Double -> Bool) -> JQuery -> Fay JQuery
+notWith = ffi "%2['not'](%1)"
+
+notJQuery :: JQuery -> JQuery -> Fay JQuery
+notJQuery = ffi "%2['not'](%1)"
+
+offsetParent :: JQuery -> Fay JQuery
+offsetParent = ffi "%1['offsetParent']()"
+
+parent :: JQuery -> Fay JQuery
+parent = ffi "%1['parent']()"
+
+parentSelector :: String -> JQuery -> Fay JQuery
+parentSelector = ffi "%2['parent'](%1)"
+
+parents :: JQuery -> Fay JQuery
+parents = ffi "%1['parents']()"
+
+parentsSelector :: String -> JQuery -> Fay JQuery
+parentsSelector = ffi "%2['parents'](%1)"
+
+parentsUntil :: String -> JQuery -> Fay JQuery
+parentsUntil = ffi "%2['parentsUntil'](%1)"
+
+parentsUntilFiltered :: String -> String -> JQuery -> Fay JQuery
+parentsUntilFiltered = ffi "%3['parentsUntil'](%1, %2)"
+
+parentsUntilElement :: Element -> JQuery -> Fay JQuery
+parentsUntilElement = ffi "%2['parentsUntil'](%1)"
+
+parentsUntilElementFiltered :: Element -> String -> JQuery -> Fay JQuery
+parentsUntilElementFiltered = ffi "%3['parentsUntil'](%1, %2)"
+
+prev :: JQuery -> Fay JQuery
+prev = ffi "%1['prev']()"
+
+prevSelector :: String -> JQuery -> Fay JQuery
+prevSelector = ffi "%2['prev'](%1)"
+
+prevAll :: JQuery -> Fay JQuery
+prevAll = ffi "%1['prevAll']()"
+
+prevAllSelector :: String -> JQuery -> Fay JQuery
+prevAllSelector = ffi "%2['prevAll'](%1)"
+
+prevUntil :: String -> JQuery -> Fay JQuery
+prevUntil = ffi "%2['prevUntil'](%1)"
+
+prevUntilFiltered :: String -> String -> JQuery -> Fay JQuery
+prevUntilFiltered = ffi "%3['prevUntil'](%1, %2)"
+
+prevUntilElement :: Element -> JQuery -> Fay JQuery
+prevUntilElement = ffi "%2['prevUntil'](%1)"
+
+prevUntilElementFiltered :: Element -> String -> JQuery -> Fay JQuery
+prevUntilElementFiltered = ffi "%3['prevUntil'](%1, %2)"
+
+siblings :: JQuery -> Fay JQuery
+siblings = ffi "%1['siblings']()"
+
+siblingsSelector :: String -> JQuery -> Fay JQuery
+siblingsSelector = ffi "%2['siblings'](%1)"
+
+slice :: Double -> JQuery -> Fay JQuery
+slice = ffi "%2['slice'](%1)"
+
+sliceFromTo :: Double -> Double -> JQuery -> Fay JQuery
+sliceFromTo = ffi "%3['slice'](%1, %2)"
+
+data KeyCode = KeyUp
+             | KeyDown
+             | KeyLeft
+             | KeyRight
+             | KeyRet
+             | SomeKey Double
+  deriving (Show)
+
+onKeycode :: (KeyCode -> Fay Bool) -> JQuery -> Fay JQuery
+onKeycode callback el = do
+  _onKeycode (\code -> callback (case code of
+                                   38 -> KeyUp
+                                   40 -> KeyDown
+                                   37 -> KeyLeft
+                                   39 -> KeyRight
+                                   13 -> KeyRet
+                                   _  -> SomeKey code))
+             el
+
+_onKeycode :: (Double -> Fay Bool) -> JQuery -> Fay JQuery
+_onKeycode = ffi "%2['keycode'](%1)"
+
+unKeycode :: JQuery -> Fay JQuery
+unKeycode = ffi "%1['unkeycode']()"
+
+onClick :: (Event -> Fay Bool) -> JQuery -> Fay JQuery
+onClick = ffi "%2['click'](%1)"
+
+onChange :: (Fay ()) -> JQuery -> Fay JQuery
+onChange = ffi "%2['change'](%1)"
+
+onSubmit :: Fay Bool -> JQuery -> Fay JQuery
+onSubmit = ffi "%2['submit'](%1)"
+
+eventX :: Event -> JQuery -> Double
+eventX = ffi "%1['pageX'] - %2['get'](0)['offsetLeft']"
+
+eventY :: Event -> JQuery -> Double
+eventY = ffi "%1['pageY'] - %2['get'](0)['offsetTop']"
+
+onDblClick :: (Event -> Fay Bool) -> JQuery -> Fay JQuery
+onDblClick = ffi "%2['dblclick'](%1)"
+
+setDraggable :: JQuery -> Fay JQuery
+setDraggable = ffi "%1['draggable']()"
+
+validate :: JQuery -> Fay () -> Fay ()
+validate = ffi "%1['validate']({ \"submitHandler\": %2 })"
+
+onLivechange :: Fay () -> JQuery -> Fay JQuery
+onLivechange = ffi "%2['livechange'](50,%1)"
+
+-- vim implementation shortcut
+-- inoremap <F6> <ESC>:normal 0ywo<ESC>pa= ffi ""<ESC>F"i
+
+
+
+----
+---- Utilities
+----
