diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,85 @@
 ## Changelog for the `threepenny-gui` package
 
+**0.9.4.2** – Maintenance and snapshot release
+
+* Bump dependencies for compatibility with GHC-9.12.
+
+**0.9.4.1** – Maintenance and snapshot release
+
+* Bump dependencies for compatibility with GHC-9.8.
+
+**0.9.4.0** – Maintenance and snapshot release
+
+* Fix support for SSL: Export `ConfigSSL` constructor.
+
+**0.9.2.0** – Maintenance and snapshot release
+
+* Add support for SSL.
+
+  To start the server as an HTTPS server, use the `jsUseSSL` field with appropriate parameters. For security reasons, no information is read from the environment in this case.
+
+* Bump dependencies for compatibility with GHC-9.4.
+* Bump dependencies for compatibility with GHC-9.2.
+
+**0.9.1.0** – Maintenance and snapshot release
+
+* Add support for websockets over SSL.
+* Bump dependencies for compatibility with GHC-9.0.
+
+**0.9.0.0** – Maintenance and snapshot release
+
+* The events `contextmenu`, `mousedown`, `mousemove` and `mouseup` now return
+  `Double` coordinates instead of `Int`s. This change reflects updates to the
+  underlying browser APIs and the jQuery library. [#238][]
+
+  Users who prefer to keep working with `Int` coordinates may use the added
+  `roundCoordinates` compatibility function.
+
+* Bump dependencies to allow `aeson` 1.5.
+
+[#238]: https://github.com/HeinrichApfelmus/threepenny-gui/issues/238
+
+**0.8.3.2** – Maintenance release
+
+* Bump dependencies for compatibility with GHC-8.10.
+
+**0.8.3.1** – Maintenance release
+
+* Bump dependencies for compatibility with GHC-8.8.
+* Bump dependencies to allow `hashable` 1.3.0.0.
+* Remove support for GHC 7.6 and 7.8.
+
+**0.8.3.0** – Maintenance and snapshot release
+
+* Export `keypress` event.
+* Fix the spelling of the `refX` and `refY` SVG attributes.
+  `refX` and `refY` are added to `Graphics.UI.Threepenny.SVG.Attributes`,
+  the old lowercase versions are deprecated.
+* Invoke compatibility mode of IE11 for jQuery v3.2.1.
+* Compatibility with GHC-8.6.1
+
+**0.8.2.4** – Maintenance release
+
+* Remove redundant dependencies on `network-uri` and `network`
+* Bump dependencies to allow `aeson` 1.4.0.0
+* Exclude `websockets` 0.12.5.0 from dependencies.
+
+**0.8.2.3** – Maintenance release
+
+* Compatibility with GHC-8.4.1
+* Bump dependencies to allow `aeson` 1.3.0.0
+* Bump dependencies to allow `exceptions` 0.10.0
+* Bump dependencies to allow `snap-server` 1.1.0.0
+
+**0.8.2.2** – Maintenance release
+
+* Bump dependencies to allow `exceptions` 0.9.0
+
+**0.8.2.1** — Maintenance release
+
+* Bump dependencies to allow `async` 2.2
+* Fix a compatibility issue with Cabal-2.0
+
 **0.8.2.0** — Snapshot release
 
 * Add `getCookies` function that retrieves the cookies sent with the HTTP request when the browser window connects (to the websocket). [#137][]
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
-[![Travis Build Status](https://travis-ci.org/HeinrichApfelmus/threepenny-gui.svg)](https://travis-ci.org/HeinrichApfelmus/threepenny-gui)
 [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/HeinrichApfelmus/threepenny-gui?svg=true)](https://ci.appveyor.com/project/HeinrichApfelmus/threepenny-gui)
 [![Hackage](https://img.shields.io/hackage/v/threepenny-gui.svg)](https://hackage.haskell.org/package/threepenny-gui)
 [![Stackage LTS](http://stackage.org/package/threepenny-gui/badge/lts)](http://stackage.org/lts/package/threepenny-gui)
@@ -10,7 +9,7 @@
 
 Threepenny is a GUI framework written in Haskell that uses the web browser as a display. It's very easy to install. See the
 
-  [**Project homepage**](http://wiki.haskell.org/Threepenny-gui)
+  [**Project homepage**](https://heinrichapfelmus.github.io/threepenny-gui/)
 
 for more information on what it does and can do for you as a library user.
 
@@ -40,7 +39,7 @@
 shading language](http://en.wikipedia.org/wiki/Shading_language).
 You can import any JavaScript library and use it from the JavaScript FFI.
 
-If you don't want to write JavaScript, then you could choose a Haskell-like language like [PureScript](http://www.purescript.org), [Fay](https://github.com/faylang/fay/wiki). You can also directly compile JavaScript to Haskell with [Haste](https://github.com/valderman/haste-compiler) or [GHCJS](https://github.com/ghcjs/ghcjs).
+If you don't want to write JavaScript, then you could choose a Haskell-like language like [PureScript](http://www.purescript.org), [Fay](https://github.com/faylang/fay/wiki). You can also directly compile Haskell to JavaScript with [Haste](https://github.com/valderman/haste-compiler) or [GHCJS](https://github.com/ghcjs/ghcjs).
 
 # Future ideas
 
diff --git a/js/comm.js b/js/comm.js
--- a/js/comm.js
+++ b/js/comm.js
@@ -15,7 +15,10 @@
 Haskell.createWebSocket = function (url0, receive) {
   var that = {};
   var optReloadOnDisconnect = false;
-  var url  = 'ws:' + url0.slice(5) + '/websocket/';
+  var url  = new URL(url0);
+  if (url.protocol === 'http:')  { url.protocol = 'ws:'  }
+  if (url.protocol === 'https:') { url.protocol = 'wss:' }
+  url.href = url.href + 'websocket/';
   var ws   = new WebSocket(url);
   
   // Close WebSocket when the browser window is closed.
diff --git a/js/index.html b/js/index.html
--- a/js/index.html
+++ b/js/index.html
@@ -1,6 +1,8 @@
 <!doctype html>
 <head>
   <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+
   <title></title>
   <link rel="stylesheet" type="text/css" href="haskell.css"/>
 
diff --git a/samples/CRUD.hs b/samples/CRUD.hs
--- a/samples/CRUD.hs
+++ b/samples/CRUD.hs
@@ -12,10 +12,7 @@
 import Prelude hiding (lookup)
 import Control.Monad  (void)
 import Data.List      (isPrefixOf)
-import Data.Maybe
-import Data.Monoid
 import qualified Data.Map as Map
-import qualified Data.Set as Set
 
 import qualified Graphics.UI.Threepenny as UI
 import Graphics.UI.Threepenny.Core hiding (delete)
diff --git a/samples/Chat.hs b/samples/Chat.hs
--- a/samples/Chat.hs
+++ b/samples/Chat.hs
@@ -1,8 +1,6 @@
 import Control.Concurrent
 import qualified Control.Concurrent.Chan as Chan
-import Control.Exception
 import Control.Monad
-import Data.Functor
 import Data.List.Extra
 import Data.Time
 import Data.IORef
diff --git a/samples/CurrencyConverter.hs b/samples/CurrencyConverter.hs
--- a/samples/CurrencyConverter.hs
+++ b/samples/CurrencyConverter.hs
@@ -1,5 +1,4 @@
 import Control.Monad (void)
-import Data.Maybe
 import Text.Printf
 import Safe          (readMay)
 
diff --git a/samples/Data/List/Extra.hs b/samples/Data/List/Extra.hs
--- a/samples/Data/List/Extra.hs
+++ b/samples/Data/List/Extra.hs
@@ -1,8 +1,8 @@
 module Data.List.Extra where
-                  
-import Data.List
+
 import Data.Char
-import Data.Maybe
+    ( isSpace
+    )
 
 trim :: String -> String
 trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
diff --git a/samples/DragNDropExample.hs b/samples/DragNDropExample.hs
--- a/samples/DragNDropExample.hs
+++ b/samples/DragNDropExample.hs
@@ -1,7 +1,5 @@
-import Control.Applicative
 import Control.Monad
 import Data.IORef
-import Data.Maybe
 
 import Paths
 
diff --git a/samples/DrumMachine.hs b/samples/DrumMachine.hs
--- a/samples/DrumMachine.hs
+++ b/samples/DrumMachine.hs
@@ -1,9 +1,6 @@
 import Control.Monad
-import Data.IORef
-import Data.Functor
 
 import Paths
-import System.FilePath
 
 import qualified Graphics.UI.Threepenny as UI
 import Graphics.UI.Threepenny.Core
@@ -11,12 +8,13 @@
 {-----------------------------------------------------------------------------
     Configuration
 ------------------------------------------------------------------------------}
+bars, beats, defaultBpm :: Int
 bars  = 4
 beats = 4
 defaultBpm = 120
 
 bpm2ms :: Int -> Int
-bpm2ms bpm = ceiling $ 1000*60 / fromIntegral bpm
+bpm2ms bpm = ceiling $ 1000*60 / (fromIntegral bpm :: Double)
 
 -- NOTE: Samples taken from "conductive-examples"
 
@@ -42,7 +40,7 @@
     let status = grid [[UI.string "BPM:" , element elBpm]
                       ,[UI.string "Beat:", element elTick]]
     getBody w #+ [UI.div #. "wrap" #+ (status : map element elInstruments)]
-    
+
     timer <- UI.timer # set UI.interval (bpm2ms defaultBpm)
     eBeat <- accumE (0::Int) $
         (\beat -> (beat + 1) `mod` (beats * bars)) <$ UI.tick timer
@@ -51,12 +49,12 @@
         element elTick # set text (show $ beat + 1)
         -- play corresponding sounds
         sequence_ $ map (!! beat) kit
-    
+
     -- allow user to set BPM
     on UI.keydown elBpm $ \keycode -> when (keycode == 13) $ void $ do
         bpm <- read <$> get value elBpm
         return timer # set UI.interval (bpm2ms bpm)
-    
+
     -- start the timer
     UI.start timer
 
@@ -82,13 +80,13 @@
             checked <- get UI.checked box
             when checked $ do
                 runFunction $ ffi "%1.pause()" elAudio
-                runFunction $ ffi "%1.currentTime = 0" elAudio 
+                runFunction $ ffi "%1.currentTime = 0" elAudio
                 runFunction $ ffi "%1.play()" elAudio
         beats    = map play . concat $ elCheckboxes
         elGroups = [UI.span #. "bar" #+ map element bar | bar <- elCheckboxes]
-    
+
     elInstrument <- UI.div #. "instrument"
         #+ (element elAudio : UI.string name : elGroups)
-    
+
     return (beats, elInstrument)
 
diff --git a/samples/Paths.hs b/samples/Paths.hs
--- a/samples/Paths.hs
+++ b/samples/Paths.hs
@@ -11,11 +11,6 @@
 getStaticDir :: IO FilePath
 getStaticDir = (</> "samples/static") `liftM` Paths_threepenny_gui.getDataDir
 
-#elif defined(FPCOMPLETE)
-
-getStaticDir :: IO FilePath
-getStaticDir = return "samples/static"
-
 #else
 -- using GHCi
 
diff --git a/src/Foreign/JavaScript.hs b/src/Foreign/JavaScript.hs
--- a/src/Foreign/JavaScript.hs
+++ b/src/Foreign/JavaScript.hs
@@ -16,7 +16,9 @@
     serve, defaultConfig, Config(
           jsPort, jsAddr
         , jsCustomHTML, jsStatic, jsLog
-        , jsWindowReloadOnDisconnect, jsCallBufferMode),
+        , jsWindowReloadOnDisconnect, jsCallBufferMode
+        , jsUseSSL),
+    ConfigSSL (..),
     Server, MimeType, URI, loadFile, loadDirectory,
     Window, getServer, getCookies, root,
 
@@ -29,9 +31,6 @@
     debug, timestamp,
     ) where
 
-import           Control.Concurrent.STM       as STM
-import           Control.Monad                           (unless)
-import qualified Data.Aeson                   as JSON
 import           Foreign.JavaScript.CallBuffer
 import           Foreign.JavaScript.EventLoop
 import           Foreign.JavaScript.Marshal
@@ -47,12 +46,12 @@
     :: Config               -- ^ Configuration options.
     -> (Window -> IO ())    -- ^ Initialization whenever a client connects.
     -> IO ()
-serve config init = httpComm config $ eventLoop $ \w -> do
+serve config initialize = httpComm config $ eventLoop $ \w -> do
     setCallBufferMode w (jsCallBufferMode config)
     runFunction w $
         ffi "connection.setReloadOnDisconnect(%1)" $ jsWindowReloadOnDisconnect config
     flushCallBuffer w   -- make sure that all `runEval` commands are executed
-    init w
+    initialize w
     flushCallBuffer w   -- make sure that all `runEval` commands are executed
 
 {-----------------------------------------------------------------------------
@@ -76,7 +75,9 @@
 unsafeCreateJSObject w f = do
     g <- wrapImposeStablePtr w f
     bufferRunEval w =<< toCode g
-    marshalResult g w JSON.Null
+    marshalResult g w err
+    where
+    err = error "unsafeCreateJSObject: marshal does not take arguments"
 
 -- | Call a JavaScript function and wait for the result.
 callFunction :: Window -> JSFunction a -> IO a
diff --git a/src/Foreign/JavaScript/CallBuffer.hs b/src/Foreign/JavaScript/CallBuffer.hs
--- a/src/Foreign/JavaScript/CallBuffer.hs
+++ b/src/Foreign/JavaScript/CallBuffer.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE RecordWildCards #-}
 module Foreign.JavaScript.CallBuffer where
 
-import Control.Concurrent
 import Control.Concurrent.STM as STM
 import Control.Monad
 
@@ -12,39 +11,43 @@
 ------------------------------------------------------------------------------}
 -- | Set the call buffering mode for the given browser window.
 setCallBufferMode :: Window -> CallBufferMode -> IO ()
-setCallBufferMode w@Window{..} new = do
-    flushCallBuffer w
-    atomically $ writeTVar wCallBufferMode new
+setCallBufferMode w new =
+    flushCallBufferWithAtomic w $ writeTVar (wCallBufferMode w) new
 
 -- | Get the call buffering mode for the given browser window.
 getCallBufferMode :: Window -> IO CallBufferMode
-getCallBufferMode w@Window{..} = atomically $ readTVar wCallBufferMode
+getCallBufferMode Window{..} = atomically $ readTVar wCallBufferMode
 
 -- | Flush the call buffer,
 -- i.e. send all outstanding JavaScript to the client in one single message.
 flushCallBuffer :: Window -> IO ()
-flushCallBuffer w@Window{..} = do
-    code' <- atomically $ do
-        code <- readTVar wCallBuffer
-        writeTVar wCallBuffer id
-        return code
+flushCallBuffer w = flushCallBufferWithAtomic w $ return ()
+
+-- | Flush the call buffer, and atomically perform an additional action
+flushCallBufferWithAtomic :: Window -> STM a -> IO a
+flushCallBufferWithAtomic Window{..} action = do
+    -- by taking the call buffer, we ensure that no further code
+    -- is added to the buffer while we execute the current buffer's code.
+    code' <- atomically $ takeTMVar wCallBuffer
     let code = code' ""
-    unless (null code) $
-        runEval code
+    unless (null code) $ runEval code
+    atomically $ do
+        putTMVar wCallBuffer id
+        action
 
--- Schedule a piece of JavaScript code to be run with `runEval`,
+-- | Schedule a piece of JavaScript code to be run with `runEval`,
 -- depending on the buffering mode
 bufferRunEval :: Window -> String -> IO ()
-bufferRunEval w@Window{..} code = do
+bufferRunEval Window{..} code = do
     action <- atomically $ do
         mode <- readTVar wCallBufferMode
         case mode of
             NoBuffering -> do
                 return $ Just code
             _ -> do
-                msg <- readTVar wCallBuffer
-                writeTVar wCallBuffer (msg . (\s -> ";" ++ code ++ s))
+                msg <- takeTMVar wCallBuffer
+                putTMVar wCallBuffer (msg . (\s -> ";" ++ code ++ s))
                 return Nothing
     case action of
-        Nothing   -> return ()
-        Just code -> runEval code
+        Nothing    -> return ()
+        Just code1 -> runEval code1
diff --git a/src/Foreign/JavaScript/EventLoop.hs b/src/Foreign/JavaScript/EventLoop.hs
--- a/src/Foreign/JavaScript/EventLoop.hs
+++ b/src/Foreign/JavaScript/EventLoop.hs
@@ -3,10 +3,9 @@
 module Foreign.JavaScript.EventLoop (
     eventLoop,
     runEval, callEval, debug, onDisconnect,
-    newHandler, fromJSStablePtr,
+    newHandler, fromJSStablePtr, newJSObjectFromCoupon
     ) where
 
-import           Control.Applicative
 import           Control.Concurrent
 import           Control.Concurrent.Async
 import           Control.Concurrent.STM   as STM
@@ -15,10 +14,7 @@
 import           Control.Monad
 import qualified Data.Aeson               as JSON
 import qualified Data.ByteString.Char8    as BS
-import           Data.IORef
-import qualified Data.Map                 as Map
 import qualified Data.Text                as T
-import qualified System.Mem
 
 import Foreign.RemotePtr             as Foreign
 import Foreign.JavaScript.CallBuffer
@@ -35,11 +31,12 @@
     Event Loop
 ------------------------------------------------------------------------------}
 -- | Handle a single event
-handleEvent w@(Window{..}) (name, args) = do
+handleEvent :: Window -> (Coupon, JSON.Value) -> IO ()
+handleEvent Window{..} (name, args) = do
     mhandler <- Foreign.lookup name wEventHandlers
     case mhandler of
         Nothing -> return ()
-        Just f  -> withRemotePtr f (\_ f -> f args)
+        Just f  -> withRemotePtr f (\_ g -> g args)
 
 
 type Result = Either String JSON.Value
@@ -47,7 +44,7 @@
 -- | Event loop for a browser window.
 -- Supports concurrent invocations of `runEval` and `callEval`.
 eventLoop :: (Window -> IO void) -> EventLoop
-eventLoop init server info comm = void $ do
+eventLoop initialize server info comm = void $ do
     -- To support concurrent FFI calls, we need three threads.
     -- A fourth thread supports 
     --
@@ -112,12 +109,12 @@
 
     -- Send FFI calls to client and collect results
     let handleCalls = forever $ do
-            ref <- atomically $ do
-                (ref, msg) <- readTQueue calls
+            mref <- atomically $ do
+                (mref, msg) <- readTQueue calls
                 writeServer comm msg
-                return ref
+                return mref
             atomically $
-                case ref of
+                case mref of
                     Just ref -> do
                         result <- readTQueue results
                         putTMVar ref result
@@ -155,7 +152,7 @@
         withAsync multiplexer $ \_ ->
         withAsync handleCalls $ \_ ->
         withAsync (flushCallBufferPeriodically w) $ \_ ->
-        E.finally (init w >> handleEvents) $ do
+        E.finally (initialize w >> handleEvents) $ do
             putStrLn "Foreign.JavaScript: Browser window disconnected."
             -- close communication channel if still necessary
             commClose comm
@@ -175,7 +172,7 @@
 ------------------------------------------------------------------------------}
 -- | Turn a Haskell function into an event handler.
 newHandler :: Window -> ([JSON.Value] -> IO ()) -> IO HsEvent
-newHandler w@(Window{..}) handler = do
+newHandler Window{..} handler = do
     coupon <- newCoupon wEventHandlers
     newRemotePtr coupon (handler . parseArgs) wEventHandlers
     where
@@ -186,16 +183,20 @@
     -- parseArgs x = Map.elems (fromSuccess (JSON.fromJSON x) :: Map.Map String JSON.Value)
 
 
--- | Convert a stable pointer from JavaScript into a 'JSObject'.
+-- | Retrieve 'JSObject' associated with a JavaScript stable pointer.
 fromJSStablePtr :: JSON.Value -> Window -> IO JSObject
 fromJSStablePtr js w@(Window{..}) = do
     let JSON.Success coupon = JSON.fromJSON js
     mhs <- Foreign.lookup coupon wJSObjects
     case mhs of
         Just hs -> return hs
-        Nothing -> do
-            ptr <- newRemotePtr coupon (JSPtr coupon) wJSObjects
-            addFinalizer ptr $
-                runEval ("Haskell.freeStablePtr('" ++ T.unpack coupon ++ "')")
-            return ptr
+        Nothing -> newJSObjectFromCoupon w coupon
+
+-- | Create a new JSObject by registering a new coupon.
+newJSObjectFromCoupon :: Window -> Foreign.Coupon -> IO JSObject
+newJSObjectFromCoupon w@(Window{..}) coupon = do
+    ptr <- newRemotePtr coupon (JSPtr coupon) wJSObjects
+    addFinalizer ptr $
+        bufferRunEval w ("Haskell.freeStablePtr('" ++ T.unpack coupon ++ "')")
+    return ptr
 
diff --git a/src/Foreign/JavaScript/Include.hs b/src/Foreign/JavaScript/Include.hs
--- a/src/Foreign/JavaScript/Include.hs
+++ b/src/Foreign/JavaScript/Include.hs
@@ -1,15 +1,14 @@
 {-# LANGUAGE TemplateHaskell, CPP #-}
 module Foreign.JavaScript.Include (include) where
 
-import           Data.Functor
 import           Data.FileEmbed      (makeRelativeToProject)
 import           Language.Haskell.TH
 import           System.IO
 
 include :: FilePath -> Q Exp
 include path = do
-    path <- makeRelativeToProject path
-    LitE . StringL <$> runIO (readFileUTF8 path)
+    relativePath <- makeRelativeToProject path
+    LitE . StringL <$> runIO (readFileUTF8 relativePath)
 
 readFileUTF8 :: FilePath -> IO String
 readFileUTF8 path = do
diff --git a/src/Foreign/JavaScript/Marshal.hs b/src/Foreign/JavaScript/Marshal.hs
--- a/src/Foreign/JavaScript/Marshal.hs
+++ b/src/Foreign/JavaScript/Marshal.hs
@@ -19,8 +19,6 @@
 #else
 import qualified Data.Aeson.Text        as JSON   (encodeToTextBuilder)
 #endif
-import qualified Data.Aeson.Types       as JSON
-import           Data.Functor                     ((<$>))
 import           Data.List                        (intercalate)
 import qualified Data.Text              as T
 import qualified Data.Text.Lazy
@@ -28,7 +26,7 @@
 import qualified Data.Vector            as Vector
 import           Safe                             (atMay)
 
-import Foreign.JavaScript.EventLoop (fromJSStablePtr)
+import Foreign.JavaScript.EventLoop (fromJSStablePtr, newJSObjectFromCoupon )
 import Foreign.JavaScript.Types
 import Foreign.RemotePtr
 
@@ -48,6 +46,7 @@
         ys <- mapM render xs
         jsCode $ "[" ++ intercalate "," (map unJSCode ys) ++ "]"
 
+jsCode :: String -> IO JSCode
 jsCode = return . JSCode
 
 instance ToJS Float      where render   = render . JSON.toJSON
@@ -122,14 +121,17 @@
 instance FromJS NewJSObject where
     fromJS = FromJS' { wrapCode = id, marshal = \_ _ -> return NewJSObject }
 
+-- | Impose a JS stable pointer upon a newly created JavaScript object.
+--   In this way, JSObject can be created without waiting for the browser
+--   to return a result.
 wrapImposeStablePtr :: Window -> JSFunction NewJSObject -> IO (JSFunction JSObject)
-wrapImposeStablePtr w@(Window{..}) f = do
+wrapImposeStablePtr (Window{..}) f = do
     coupon  <- newCoupon wJSObjects
     rcoupon <- render coupon
     rcode   <- code f
     return $ JSFunction
         { code = return $ apply "Haskell.imposeStablePtr(%1,%2)" [rcode, rcoupon]
-        , marshalResult = \w _ -> newRemotePtr coupon (JSPtr coupon) wJSObjects
+        , marshalResult = \w _ -> newJSObjectFromCoupon w coupon
         }
 
 {-----------------------------------------------------------------------------
diff --git a/src/Foreign/JavaScript/Server.hs b/src/Foreign/JavaScript/Server.hs
--- a/src/Foreign/JavaScript/Server.hs
+++ b/src/Foreign/JavaScript/Server.hs
@@ -4,7 +4,6 @@
     ) where
 
 -- import general libraries
-import           Control.Applicative
 import           Control.Concurrent
 import           Control.Concurrent.Async
 import           Control.Concurrent.STM     as STM
@@ -15,17 +14,16 @@
 import qualified Data.ByteString.Char8      as BS
 import qualified Data.ByteString.Lazy.Char8 as LBS
 import qualified Data.Map                   as M
-import           Data.Text
+import           Data.Text                          (Text)
 import qualified Safe                       as Safe
 import           System.Environment
 import           System.FilePath
 
 -- import web libraries
-import           Data.Aeson                             ((.=))
 import qualified Data.Aeson                    as JSON
 import qualified Network.WebSockets            as WS
 import qualified Network.WebSockets.Snap       as WS
-import           Snap.Core                     as Snap
+import           Snap.Core                     as Snap hiding (path, dir)
 import qualified Snap.Http.Server              as Snap
 import           Snap.Util.FileServe
 
@@ -40,13 +38,10 @@
 httpComm :: Config -> EventLoop -> IO ()
 httpComm Config{..} worker = do
     env <- getEnvironment
-    let portEnv = Safe.readMay =<< Prelude.lookup "PORT" env
-    let addrEnv = fmap BS.pack $ Prelude.lookup "ADDR" env
-    
-    let config = Snap.setPort      (maybe defaultPort id (jsPort `mplus` portEnv))
-               $ Snap.setBind      (maybe defaultAddr id (jsAddr `mplus` addrEnv))
-               $ Snap.setErrorLog  (Snap.ConfigIoLog jsLog)
-               $ Snap.setAccessLog (Snap.ConfigIoLog jsLog)
+
+    let config = Snap.setErrorLog     (Snap.ConfigIoLog jsLog)
+               $ Snap.setAccessLog    (Snap.ConfigIoLog jsLog)
+               $ maybe (configureHTTP env) configureSSL jsUseSSL
                $ Snap.defaultConfig
 
     server <- Server <$> newMVar newFilepaths <*> newMVar newFilepaths <*> return jsLog
@@ -55,6 +50,22 @@
         routeResources server jsCustomHTML jsStatic
         ++ routeWebsockets (worker server)
 
+    where
+    configureHTTP :: [(String, String)] -> Snap.Config m a -> Snap.Config m a
+    configureHTTP env config =
+        let portEnv = Safe.readMay =<< Prelude.lookup "PORT" env
+            addrEnv = fmap BS.pack $ Prelude.lookup "ADDR" env
+         in Snap.setPort (maybe defaultPort id (jsPort `mplus` portEnv))
+                $ Snap.setBind (maybe defaultAddr id (jsAddr `mplus` addrEnv)) config
+
+    configureSSL :: ConfigSSL -> Snap.Config m a -> Snap.Config m a
+    configureSSL cfgSsl config =
+        Snap.setSSLBind            (jsSSLBind cfgSsl)
+            . Snap.setSSLPort      (jsSSLPort cfgSsl)
+            . Snap.setSSLCert      (jsSSLCert cfgSsl)
+            . Snap.setSSLKey       (jsSSLKey cfgSsl)
+            $ Snap.setSSLChainCert (jsSSLChainCert cfgSsl) config
+
 -- | Route the communication between JavaScript and the server
 routeWebsockets :: (RequestInfo -> Comm -> IO void) -> Routes
 routeWebsockets worker = [("websocket", response)]
@@ -101,15 +112,15 @@
     let commClose = atomically $ STM.writeTVar commOpen False
 
     -- read/write data until an exception occurs or the channel is no longer open
-    forkFinally (sendData `race_` readData `race_` sentry) $ \_ -> void $ do
+    _ <- forkFinally (sendData `race_` readData `race_` sentry) $ \_ -> void $ do
         -- close the communication channel explicitly if that didn't happen yet
         commClose
 
         -- attempt to close websocket if still necessary/possible
         -- ignore any exceptions that may happen if it's already closed
-        let all :: E.SomeException -> Maybe ()
-            all _ = Just ()
-        E.tryJust all $ WS.sendClose connection $ LBS.pack "close"
+        let allExceptions :: E.SomeException -> Maybe ()
+            allExceptions _ = Just ()
+        E.tryJust allExceptions $ WS.sendClose connection $ LBS.pack "close"
 
     return $ Comm {..}
 
@@ -142,6 +153,7 @@
             Nothing  -> logError "Foreign.JavaScript: Cannot use jsCustomHTML file without jsStatic"
         Nothing   -> writeTextMime defaultHtmlFile "text/html"
 
+writeTextMime :: MonadSnap m => Text -> ByteString -> m ()
 writeTextMime text mime = do
     modifyResponse (setHeader "Content-type" mime)
     writeText text
diff --git a/src/Foreign/JavaScript/Types.hs b/src/Foreign/JavaScript/Types.hs
--- a/src/Foreign/JavaScript/Types.hs
+++ b/src/Foreign/JavaScript/Types.hs
@@ -1,23 +1,50 @@
 {-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
 module Foreign.JavaScript.Types where
 
-import           Control.Applicative
+import Control.Concurrent.STM
+    ( STM
+    , TMVar
+    , TQueue
+    , TVar
+    )
+import Control.DeepSeq
+    ( NFData (..)
+    , force
+    )
+import Data.Aeson
+    ( toJSON
+    , (.=)
+    , (.:)
+    )
+import Data.ByteString.Char8
+    ( ByteString
+    )
+import Data.Map
+    ( Map
+    )
+import Data.String
+    ( fromString
+    )
+import Data.Text
+    ( Text
+    )
+import Data.Typeable
+    ( Typeable
+    )
+import Snap.Core
+    ( Cookie(..)
+    )
+import System.IO
+    ( stderr
+    )
+
+import qualified Control.Concurrent.STM  as STM
 import qualified Control.Exception       as E
-import           Control.Concurrent.STM  as STM
-import           Control.Concurrent.Chan as Chan
-import           Control.Concurrent.MVar
-import           Control.DeepSeq
-import           Data.Aeson              as JSON
-import           Data.ByteString.Char8           (ByteString)
-import qualified Data.ByteString.Char8   as BS   (hPutStrLn)
-import           Data.IORef
-import           Data.Map                as Map
-import           Data.String
-import           Data.Text
-import           Data.Typeable
-import           Snap.Core                       (Cookie(..))
-import           System.IO                       (stderr)
+import qualified Data.Aeson as JSON
+import qualified Data.ByteString.Char8  as BS   (hPutStrLn)
+import qualified Data.Map as Map
 
+import Control.Concurrent.MVar
 import Foreign.RemotePtr
 
 {-----------------------------------------------------------------------------
@@ -30,7 +57,7 @@
 
 This is a record type which has the following fields:
 
-* @jsPort :: Maybe Int@          
+* @jsPort :: Maybe Int@
 
     Port number.
     @Nothing@ means that the port number is read from the environment variable @PORT@.
@@ -64,19 +91,64 @@
     The initial 'CallBufferMode' to use for 'runFunction'.
     It can be changed at any time with 'setCallBufferMode'.
 
+* @jsUseSSLBind :: Maybe ConfigSSL@
+
+    Whether to serve on a HTTPS connection instead of HTTP for improved security.
+
+    * 'Just' with a 'ConfigSSL' to serve on HTTPS.
+        Note that this will fail silently unless the @snap-server@ package
+        has been compiled with the @openssl@ flag enabled.
+
+    * 'Nothing' to serve on HTTP.
+
 (For reasons of forward compatibility, the constructor is not exported.)
 
 -}
 data Config = Config
-    { jsPort       :: Maybe Int           
+    { jsPort       :: Maybe Int
     , jsAddr       :: Maybe ByteString
     , jsCustomHTML :: Maybe FilePath
     , jsStatic     :: Maybe FilePath
     , jsLog        :: ByteString -> IO ()
     , jsWindowReloadOnDisconnect :: Bool
     , jsCallBufferMode :: CallBufferMode
+    , jsUseSSL      :: Maybe ConfigSSL
     }
 
+{- | Static configuration for the SSL version of the "Foreign.JavaScript" server.
+
+This is a record type which has the following fields:
+
+* @jsSSLBind :: ByteString@
+
+    Bind address.
+
+* @jsSSLCert :: FilePath@
+
+    Path to SSL certificate file. Example: @cert.pem@.
+
+* @jsSSLChainCert :: Bool@
+
+    If it is SSL chain certificate file.
+
+* @jsSSLKey :: FilePath@
+
+    Path to SSL key file. Example: @key.pem@.
+
+* @jsSSLPort :: ByteString@
+
+    Port number. Example: 443.
+
+-}
+
+data ConfigSSL = ConfigSSL
+    { jsSSLBind      :: ByteString
+    , jsSSLCert      :: FilePath
+    , jsSSLChainCert :: Bool
+    , jsSSLKey       :: FilePath
+    , jsSSLPort      :: Int
+    }
+
 defaultPort :: Int
 defaultPort = 8023
 
@@ -99,6 +171,7 @@
     , jsStatic     = Nothing
     , jsLog        = BS.hPutStrLn stderr
     , jsCallBufferMode = FlushOften
+    , jsUseSSL     = Nothing
     }
 
 {-----------------------------------------------------------------------------
@@ -121,6 +194,8 @@
     , sLog   :: ByteString -> IO () -- function for logging
     }
 type Filepaths = (Integer, Map ByteString (FilePath, MimeType))
+
+newFilepaths :: Filepaths
 newFilepaths = (0, Map.empty)
 
 {-----------------------------------------------------------------------------
@@ -151,8 +226,8 @@
     | Quit
     deriving (Eq, Show)
 
-instance FromJSON ClientMsg where
-    parseJSON (Object msg) = do
+instance JSON.FromJSON ClientMsg where
+    parseJSON (JSON.Object msg) = do
         tag <- msg .: "tag"
         case (tag :: Text) of
             "Event"     -> Event     <$> (msg .: "name") <*> (msg .: "arguments")
@@ -164,8 +239,10 @@
 readClient c = do
     msg <- readComm c
     case JSON.fromJSON msg of
-        Error   s -> error $ "Foreign.JavaScript: Error parsing client message " ++ show s
-        Success x -> return x
+        JSON.Error s ->
+            error $ "Foreign.JavaScript: Error parsing client message " ++ show s
+        JSON.Success x
+            -> pure x
 
 -- | Messages sent by the Haskell server.
 data ServerMsg
@@ -181,13 +258,18 @@
     rnf (Debug     x) = rnf x
     rnf (Timestamp  ) = ()
 
-instance ToJSON ServerMsg where
-    toJSON (Debug    x) = object [ "tag" .= t "Debug"   , "contents" .= toJSON x]
-    toJSON (Timestamp ) = object [ "tag" .= t "Timestamp" ]
-    toJSON (RunEval  x) = object [ "tag" .= t "RunEval" , "contents" .= toJSON x]
-    toJSON (CallEval x) = object [ "tag" .= t "CallEval", "contents" .= toJSON x]
+instance JSON.ToJSON ServerMsg where
+    toJSON (Debug x) =
+        JSON.object [ "tag" .= t "Debug", "contents" .= toJSON x]
+    toJSON Timestamp =
+        JSON.object [ "tag" .= t "Timestamp" ]
+    toJSON (RunEval x) =
+        JSON.object [ "tag" .= t "RunEval", "contents" .= toJSON x]
+    toJSON (CallEval x) =
+        JSON.object [ "tag" .= t "CallEval", "contents" .= toJSON x]
 
-t s = fromString s :: Text
+t :: String -> Text
+t s = fromString s
 
 writeServer :: Comm -> ServerMsg -> STM ()
 writeServer c = writeComm c . toJSON . force
@@ -271,7 +353,7 @@
     , runEval        :: String -> IO ()
     , callEval       :: String -> IO JSON.Value
 
-    , wCallBuffer     :: TVar (String -> String)
+    , wCallBuffer     :: TMVar (String -> String)
     , wCallBufferMode :: TVar CallBufferMode
 
     , timestamp      :: IO ()
@@ -289,8 +371,8 @@
 newPartialWindow :: IO Window
 newPartialWindow = do
     ptr <- newRemotePtr "" () =<< newVendor
-    b1  <- newTVarIO id
-    b2  <- newTVarIO NoBuffering
+    b1  <- STM.newTMVarIO id
+    b2  <- STM.newTVarIO NoBuffering
     let nop = const $ return ()
     Window undefined [] nop undefined b1 b2 (return ()) nop nop ptr <$> newVendor <*> newVendor
 
diff --git a/src/Foreign/RemotePtr.hs b/src/Foreign/RemotePtr.hs
--- a/src/Foreign/RemotePtr.hs
+++ b/src/Foreign/RemotePtr.hs
@@ -17,15 +17,11 @@
 
 import Prelude hiding (lookup)
 import Control.Monad
-import           Control.Concurrent
 import qualified Data.Text             as T
-import qualified Data.Map              as Map
-import Data.Functor
+import qualified Data.HashMap.Strict   as Map
 import Data.IORef
 
-import           System.IO.Unsafe         (unsafePerformIO)
 import           System.Mem.Weak          hiding (addFinalizer)
-import qualified System.Mem.Weak  as Weak
 
 import qualified GHC.Base  as GHC
 import qualified GHC.Weak  as GHC
@@ -42,18 +38,18 @@
 mkWeakIORefValue :: IORef a -> value -> IO () -> IO (Weak value)
 #if CABAL
 #if MIN_VERSION_base(4,9,0)
-mkWeakIORefValue r@(GHC.IORef (GHC.STRef r#)) v (GHC.IO f) = GHC.IO $ \s ->
+mkWeakIORefValue (GHC.IORef (GHC.STRef r#)) v (GHC.IO f) = GHC.IO $ \s ->
   case GHC.mkWeak# r# v f s of (# s1, w #) -> (# s1, GHC.Weak w #)
 #else
-mkWeakIORefValue r@(GHC.IORef (GHC.STRef r#)) v f = GHC.IO $ \s ->
+mkWeakIORefValue (GHC.IORef (GHC.STRef r#)) v f = GHC.IO $ \s ->
   case GHC.mkWeak# r# v f s of (# s1, w #) -> (# s1, GHC.Weak w #)
 #endif
 #else
-mkWeakIORefValue r@(GHC.IORef (GHC.STRef r#)) v (GHC.IO f) = GHC.IO $ \s ->
+mkWeakIORefValue (GHC.IORef (GHC.STRef r#)) v (GHC.IO f) = GHC.IO $ \s ->
   case GHC.mkWeak# r# v f s of (# s1, w #) -> (# s1, GHC.Weak w #)
 #endif
 
-type Map = Map.Map
+type Map = Map.HashMap
 
 {-----------------------------------------------------------------------------
     Types
@@ -97,8 +93,8 @@
 -- A single 'RemotePtr' will always be associated with the same 'Coupon'.
 
 data Vendor a = Vendor
-    { coupons :: MVar (Map Coupon (Weak (RemotePtr a)))
-    , counter :: MVar [Integer]
+    { coupons :: IORef (Map Coupon (Weak (RemotePtr a)))
+    , counter :: IORef Integer
     }
 
 {-----------------------------------------------------------------------------
@@ -107,14 +103,14 @@
 -- | Create a new 'Vendor' for trading 'Coupon's and 'RemotePtr's.
 newVendor :: IO (Vendor a)
 newVendor = do
-    counter <- newMVar [0..]
-    coupons <- newMVar Map.empty
+    counter <- newIORef 0
+    coupons <- newIORef Map.empty
     return $ Vendor {..}
 
 -- | Take a 'Coupon' to a 'Vendor' and maybe you'll get a 'RemotePtr' for it.
 lookup :: Coupon -> Vendor a -> IO (Maybe (RemotePtr a))
 lookup coupon Vendor{..} = do
-    w <- Map.lookup coupon <$> readMVar coupons
+    w <- Map.lookup coupon <$> readIORef coupons
     maybe (return Nothing) deRefWeak w
 
 -- | Create a new 'Coupon'.
@@ -124,7 +120,7 @@
 -- certainly not on a remote machine.
 newCoupon :: Vendor a -> IO Coupon
 newCoupon Vendor{..} =
-    T.pack . show <$> modifyMVar counter (\(n:ns) -> return (ns,n))
+    T.pack . show <$> atomicModifyIORef' counter (\n -> (n+1,n))
 
 -- | Create a new 'RemotePtr' from a 'Coupon' and register it with a 'Vendor'.
 newRemotePtr :: Coupon -> a -> Vendor a -> IO (RemotePtr a)
@@ -133,9 +129,10 @@
     let self = undefined
     ptr      <- newIORef RemoteData{..}
     
-    let finalize = modifyMVar coupons $ \m -> return (Map.delete coupon m, ())
-    w <- mkWeakIORef ptr finalize
-    modifyMVar coupons $ \m -> return (Map.insert coupon w m, ())
+    let doFinalize =
+            atomicModifyIORef' coupons $ \m -> (Map.delete coupon m, ())
+    w <- mkWeakIORef ptr doFinalize
+    atomicModifyIORef' coupons $ \m -> (Map.insert coupon w m, ())
     atomicModifyIORef' ptr $ \itemdata -> (itemdata { self = w }, ())
     return ptr
 
@@ -148,10 +145,10 @@
 -- will not be garbage collected
 -- and its 'Coupon' can be successfully redeemed at the 'Vendor'.
 withRemotePtr :: RemotePtr a -> (Coupon -> a -> IO b) -> IO b
-withRemotePtr ptr f = do
-        RemoteData{..} <- readIORef ptr
+withRemotePtr ptr0 f = do
+        RemoteData{..} <- readIORef ptr0
         b <- f coupon value
-        touch ptr
+        touch ptr0
         return b
     where
     -- make sure that the pointer is alive at this point in the code
diff --git a/src/Graphics/UI/Threepenny/Attributes.hs b/src/Graphics/UI/Threepenny/Attributes.hs
--- a/src/Graphics/UI/Threepenny/Attributes.hs
+++ b/src/Graphics/UI/Threepenny/Attributes.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-missing-signatures #-}
 module Graphics.UI.Threepenny.Attributes (
     -- * Synopsis
     -- | Element attributes.
@@ -50,13 +51,13 @@
     http://hackage.haskell.org/package/html
 ------------------------------------------------------------------------------}
 strAttr :: String -> WriteAttr Element String
-strAttr name = mkWriteAttr (set' (attr name))
+strAttr attrname = mkWriteAttr (set' (attr attrname))
 
 intAttr :: String -> WriteAttr Element Int
-intAttr name = mkWriteAttr (set' (attr name) . show)
+intAttr attrname = mkWriteAttr (set' (attr attrname) . show)
 
 emptyAttr :: String -> WriteAttr Element Bool
-emptyAttr name = mkWriteAttr (set' (attr name) . f)
+emptyAttr attrname = mkWriteAttr (set' (attr attrname) . f)
     where
     f True  = "1"
     f False = "0"
diff --git a/src/Graphics/UI/Threepenny/Canvas.hs b/src/Graphics/UI/Threepenny/Canvas.hs
--- a/src/Graphics/UI/Threepenny/Canvas.hs
+++ b/src/Graphics/UI/Threepenny/Canvas.hs
@@ -20,7 +20,6 @@
 import Numeric (showHex)
 
 import Graphics.UI.Threepenny.Core
-import qualified Data.Aeson as JSON
 
 {-----------------------------------------------------------------------------
     Canvas
@@ -240,8 +239,8 @@
 -- The 'textAlign' attributes determines the position of the text
 -- relative to the point.
 fillText :: String -> Point -> Canvas -> UI ()
-fillText text (x,y) canvas =
-  runFunction $ ffi "%1.getContext('2d').fillText(%2, %3, %4)" canvas text x y
+fillText t (x,y) canvas =
+  runFunction $ ffi "%1.getContext('2d').fillText(%2, %3, %4)" canvas t x y
 
 -- | Render the outline of a text at a certain point on the canvas.
 -- 
@@ -250,8 +249,8 @@
 -- The 'textAlign' attributes determines the position of the text
 -- relative to the point.
 strokeText :: String -> Point -> Canvas -> UI ()
-strokeText text (x,y) canvas =
-  runFunction $ ffi "%1.getContext('2d').strokeText(%2, %3, %4)" canvas text x y
+strokeText t (x,y) canvas =
+  runFunction $ ffi "%1.getContext('2d').strokeText(%2, %3, %4)" canvas t x y
 
 {-----------------------------------------------------------------------------
     helper functions
diff --git a/src/Graphics/UI/Threepenny/Core.hs b/src/Graphics/UI/Threepenny/Core.hs
--- a/src/Graphics/UI/Threepenny/Core.hs
+++ b/src/Graphics/UI/Threepenny/Core.hs
@@ -5,7 +5,7 @@
 
     -- * Server
     -- $server
-    Config(..), defaultConfig, startGUI,
+    Config(..), ConfigSSL (..), defaultConfig, startGUI,
     loadFile, loadDirectory,
 
     -- * UI monad
@@ -70,7 +70,7 @@
 import qualified Reactive.Threepenny             as Reactive
 
 -- exports
-import Foreign.JavaScript                   (Config(..), defaultConfig)
+import Foreign.JavaScript                   (Config(..), ConfigSSL (..), defaultConfig)
 import Graphics.UI.Threepenny.Internal
 import Reactive.Threepenny                  hiding (onChange)
 
@@ -134,7 +134,7 @@
 
 -- | Set CSS style of an Element
 style :: WriteAttr Element [(String,String)]
-style = mkWriteAttr $ \xs el -> forM_ xs $ \(name,val) -> 
+style = mkWriteAttr $ \xs el -> forM_ xs $ \(name,val) ->
     runFunction $ ffi "%1.style[%2] = %3" el name val
 
 -- | Value attribute of an element.
@@ -175,17 +175,19 @@
     :: Window              -- ^ Browser window
     -> String              -- ^ The ID string.
     -> UI (Maybe Element)  -- ^ Element (if any) with given ID.
-getElementById _ id =
-    E.handle (\(e :: JS.JavaScriptException) -> return Nothing) $
-        fmap Just . fromJSObject =<< callFunction (ffi "document.getElementById(%1)" id)
+getElementById _ ident =
+    E.handle (\(_ :: JS.JavaScriptException) -> return Nothing) $
+        fmap Just . fromJSObject
+            =<< callFunction (ffi "document.getElementById(%1)" ident)
 
 -- | Get a list of elements by particular class.
 getElementsByClassName
     :: Window        -- ^ Browser window
     -> String        -- ^ The class string.
     -> UI [Element]  -- ^ Elements with given class.
-getElementsByClassName window s =
-    mapM fromJSObject =<< callFunction (ffi "document.getElementsByClassName(%1)" s)
+getElementsByClassName _ s =
+    mapM fromJSObject
+        =<< callFunction (ffi "document.getElementsByClassName(%1)" s)
 
 {-----------------------------------------------------------------------------
     Layout
@@ -222,9 +224,9 @@
         rows0 <- mapM (sequence) mrows
 
         rows  <- forM rows0 $ \row0 -> do
-            row <- forM row0 $ \entry ->
+            row1 <- forM row0 $ \entry ->
                 wrap "table-cell" [entry]
-            wrap "table-row" row
+            wrap "table-row" row1
         wrap "table" rows
 
     where
@@ -306,9 +308,9 @@
 -- | Map input and output type of an attribute.
 bimapAttr :: (i' -> i) -> (o -> o')
           -> ReadWriteAttr x i o -> ReadWriteAttr x i' o'
-bimapAttr from to attr = attr
-    { get' = fmap to . get' attr
-    , set' = \i' -> set' attr (from i')
+bimapAttr from to attribute = attribute
+    { get' = fmap to . get' attribute
+    , set' = \i' -> set' attribute (from i')
     }
 
 -- | Set value of an attribute in the 'UI' monad.
@@ -321,47 +323,47 @@
 -- Note: For reasons of efficiency, the attribute is only
 -- updated when the value changes.
 sink :: ReadWriteAttr x i o -> Behavior i -> UI x -> UI x
-sink attr bi mx = do
+sink attribute bi mx = do
     x <- mx
     window <- askWindow
     liftIOLater $ do
-        i <- currentValue bi
-        runUI window $ set' attr i x
-        Reactive.onChange bi  $ \i -> runUI window $ set' attr i x
+        i0 <- currentValue bi
+        runUI window $ set' attribute i0 x
+        Reactive.onChange bi  $ \i -> runUI window $ set' attribute i x
     return x
 
 -- | Get attribute value.
 get :: ReadWriteAttr x i o -> x -> UI o
-get attr = get' attr
+get attribute = get' attribute
 
 -- | Build an attribute from a getter and a setter.
 mkReadWriteAttr
     :: (x -> UI o)          -- ^ Getter.
     -> (i -> x -> UI ())    -- ^ Setter.
     -> ReadWriteAttr x i o
-mkReadWriteAttr get set = ReadWriteAttr { get' = get, set' = set }
+mkReadWriteAttr geti seto = ReadWriteAttr { get' = geti, set' = seto }
 
 -- | Build attribute from a getter.
 mkReadAttr :: (x -> UI o) -> ReadAttr x o
-mkReadAttr get = mkReadWriteAttr get (\_ _ -> return ())
+mkReadAttr geti = mkReadWriteAttr geti (\_ _ -> return ())
 
 -- | Build attribute from a setter.
 mkWriteAttr :: (i -> x -> UI ()) -> WriteAttr x i
-mkWriteAttr set = mkReadWriteAttr (\_ -> return ()) set
+mkWriteAttr seto = mkReadWriteAttr (\_ -> return ()) seto
 
 -- | Turn a jQuery property @.prop()@ into an attribute.
 fromJQueryProp :: String -> (JSON.Value -> a) -> (a -> JSON.Value) -> Attr Element a
-fromJQueryProp name from to = mkReadWriteAttr get set
+fromJQueryProp name from to = mkReadWriteAttr geti seto
     where
-    set v el = runFunction $ ffi "$(%1).prop(%2,%3)" el name (to v)
-    get   el = fmap from $ callFunction $ ffi "$(%1).prop(%2)" el name
+    seto v el = runFunction $ ffi "$(%1).prop(%2,%3)" el name (to v)
+    geti   el = fmap from $ callFunction $ ffi "$(%1).prop(%2)" el name
 
 -- | Turn a JavaScript object property @.prop = ...@ into an attribute.
 fromObjectProperty :: (FromJS a, ToJS a) => String -> Attr Element a
-fromObjectProperty name = mkReadWriteAttr get set
+fromObjectProperty name = mkReadWriteAttr geti seto
     where
-    set v el = runFunction  $ ffi ("%1." ++ name ++ " = %2") el v    
-    get   el = callFunction $ ffi ("%1." ++ name) el
+    seto v el = runFunction  $ ffi ("%1." ++ name ++ " = %2") el v
+    geti   el = callFunction $ ffi ("%1." ++ name) el
 
 {-----------------------------------------------------------------------------
     Widget class
diff --git a/src/Graphics/UI/Threepenny/DragNDrop.hs b/src/Graphics/UI/Threepenny/DragNDrop.hs
--- a/src/Graphics/UI/Threepenny/DragNDrop.hs
+++ b/src/Graphics/UI/Threepenny/DragNDrop.hs
@@ -70,6 +70,7 @@
 -- Change this to 'Maybe String' instead.
 type DragData = String
 
+withDragData :: Event EventData -> Event String
 withDragData = fmap (extract . unsafeFromJSON)
     where
     extract [s] = s
diff --git a/src/Graphics/UI/Threepenny/Elements.hs b/src/Graphics/UI/Threepenny/Elements.hs
--- a/src/Graphics/UI/Threepenny/Elements.hs
+++ b/src/Graphics/UI/Threepenny/Elements.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-missing-signatures #-}
 -- | Predefined DOM elements, for convenience.
 module Graphics.UI.Threepenny.Elements (
     -- * Combinations and utilities
@@ -22,7 +23,6 @@
     ) where
 
 import           Control.Monad
-import           Control.Monad.Trans.Reader
 import           Graphics.UI.Threepenny.Core
 import           Prelude                     hiding (div, map, span)
 
diff --git a/src/Graphics/UI/Threepenny/Events.hs b/src/Graphics/UI/Threepenny/Events.hs
--- a/src/Graphics/UI/Threepenny/Events.hs
+++ b/src/Graphics/UI/Threepenny/Events.hs
@@ -9,12 +9,16 @@
     click, contextmenu, mousemove, mousedown, mouseup,
     hover, leave,
     focus, blur,
-    KeyCode, keyup, keydown,
+    KeyCode, keyup, keydown, keypress,
+
+    -- * Migration
+    roundCoordinates
     ) where
 
 import Graphics.UI.Threepenny.Attributes
 import Graphics.UI.Threepenny.Core
 
+silence :: Event a -> Event ()
 silence = fmap (const ())
 
 {-----------------------------------------------------------------------------
@@ -24,6 +28,7 @@
 valueChange :: Element -> Event String
 valueChange el = unsafeMapUI el (const $ get value el) (domEvent "keydown" el)
 
+unsafeMapUI :: Element -> (t -> UI b) -> Event t -> Event b
 unsafeMapUI el f = unsafeMapIO (\a -> getWindow el >>= \w -> runUI w (f a))
 
 -- | Event that occurs when the /user/ changes the selection of a @<select>@ element.
@@ -43,7 +48,9 @@
 click = silence . domEvent "click"
 
 -- | Context menu event.
-contextmenu :: Element -> Event (Int,Int)
+--
+-- The mouse coordinates are relative to the upper left corner of the element.
+contextmenu :: Element -> Event (Double,Double)
 contextmenu = fmap readCoordinates . domEvent "contextmenu"
 
 -- | Mouse enters an element.
@@ -58,21 +65,48 @@
 -- Note: The @<body>@ element responds to mouse move events,
 -- but only in the area occupied by actual content,
 -- not the whole browser window.
-mousemove :: Element -> Event (Int,Int)
+mousemove :: Element -> Event (Double,Double)
 mousemove = fmap readCoordinates . domEvent "mousemove"
 
-readCoordinates :: EventData -> (Int,Int)
+-- NB:
+-- The return types of mouse events have been redefined from @long@
+-- to @double@ in the CSS Object Model View Model working draft,
+-- which browsers have begun to adopt.
+-- See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent#Specifications
+-- and https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX
+--
+-- Similarly, we rely on jQuery's @.offset()@ to return
+-- coordinates relative to the upper left corner of the
+-- element, and this may return fractional data.
+-- https://api.jquery.com/offset/
+readCoordinates :: EventData -> (Double,Double)
 readCoordinates json = (x,y)
     where [x,y] = unsafeFromJSON json
 
+-- | Round a pair of `Double` to the next integers.
+-- This function helps you migrate from previous versions of Threepenny-GUI.
+--
+-- The return types of mouse events (`mousedown`, `mouseup`, `mousemove`, `contextmenu`) 
+-- have been redefined from @long@
+-- to @double@ in the CSS Object Model View Model working draft,
+-- which browsers have begun to adopt.
+--
+-- See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent#Specifications
+--
+-- and https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX
+roundCoordinates :: (Double,Double) -> (Int,Int)
+roundCoordinates (x,y) = (round x, round y)
+
 -- | Mouse down event.
--- The mouse coordinates are relative to the element.
-mousedown :: Element -> Event (Int,Int)
+--
+-- The mouse coordinates are relative to the upper left corner of the element.
+mousedown :: Element -> Event (Double,Double)
 mousedown = fmap readCoordinates . domEvent "mousedown"
 
 -- | Mouse up event.
--- The mouse coordinates are relative to the element.
-mouseup :: Element -> Event (Int,Int)
+--
+-- The mouse coordinates are relative to the upper left corner of the element.
+mouseup :: Element -> Event (Double,Double)
 mouseup = fmap readCoordinates . domEvent "mouseup"
 
 -- | Mouse leaving an element.
@@ -91,9 +125,16 @@
 type KeyCode = Int
 
 -- | Key pressed while element has focus.
+-- Returns the keycode (as opposed to the ASCII value) of any key, including
+-- SHIFT, CTRL and arrow keys.
 keydown :: Element -> Event KeyCode
 keydown = fmap unsafeFromJSON . domEvent "keydown"
 
 -- | Key released while element has focus.
 keyup :: Element -> Event KeyCode
 keyup   = fmap unsafeFromJSON . domEvent "keyup"
+
+-- | Key pressed while element has focus.
+-- Returns the actual character, taking into account SHIFT or CAPS LOCK.
+keypress :: Element -> Event Char
+keypress = fmap (toEnum . read . head . unsafeFromJSON) . domEvent "keypress"
diff --git a/src/Graphics/UI/Threepenny/Internal.hs b/src/Graphics/UI/Threepenny/Internal.hs
--- a/src/Graphics/UI/Threepenny/Internal.hs
+++ b/src/Graphics/UI/Threepenny/Internal.hs
@@ -21,7 +21,6 @@
     EventData, domEvent, unsafeFromJSON,
     ) where
 
-import           Control.Applicative                   (Applicative)
 import           Control.Monad
 import           Control.Monad.Catch
 import           Control.Monad.Fix
@@ -57,7 +56,7 @@
     :: Config               -- ^ Server configuration.
     -> (Window -> UI ())    -- ^ Action to run whenever a client browser connects.
     -> IO ()
-startGUI config init = JS.serve config $ \w -> do
+startGUI config initialize = JS.serve config $ \w -> do
     -- set up disconnect event
     (eDisconnect, handleDisconnect) <- RB.newEvent
     JS.onDisconnect w $ handleDisconnect ()
@@ -73,7 +72,7 @@
             }
 
     -- run initialization
-    runUI window $ init window
+    runUI window $ initialize window
 
 -- | Event that occurs whenever the client has disconnected,
 -- be it by closing the browser window or by exception.
@@ -119,7 +118,7 @@
 -- | Lookup or create reachability information for the children of
 -- an element that is represented by a JavaScript object.
 getChildren :: JS.JSObject -> Window -> IO Children
-getChildren el window@Window{ wChildren = wChildren } =
+getChildren el Window{ wChildren = wChildren } =
     Foreign.withRemotePtr el $ \coupon _ -> do
         mptr <- Foreign.lookup coupon wChildren
         case mptr of
@@ -221,7 +220,7 @@
 --
 -- This operation removes the element from the browser window DOM
 -- and marks it for garbage collection on the Haskell side.
--- The element is unuseable afterwards.
+-- The element is unusable afterwards.
 --
 -- NOTE: If you wish to temporarily remove an element from the DOM tree,
 -- change the 'children' property of its parent element instead.
@@ -288,11 +287,11 @@
     fmap f = UI . fmap f . unUI
 
 instance Applicative UI where
-    pure  = return
+    pure  = UI . pure
     (<*>) = ap
 
 instance Monad UI where
-    return  = UI . return
+    return  = pure
     m >>= k = UI $ unUI m >>= unUI . k
 
 instance MonadIO UI where
diff --git a/src/Graphics/UI/Threepenny/JQuery.hs b/src/Graphics/UI/Threepenny/JQuery.hs
--- a/src/Graphics/UI/Threepenny/JQuery.hs
+++ b/src/Graphics/UI/Threepenny/JQuery.hs
@@ -1,10 +1,7 @@
 module Graphics.UI.Threepenny.JQuery where
 
-import Control.Arrow
-import Data.String
 import Data.Char
 import Data.Default
-import Data.Maybe
 
 import Graphics.UI.Threepenny.Core
 
diff --git a/src/Graphics/UI/Threepenny/SVG/Attributes.hs b/src/Graphics/UI/Threepenny/SVG/Attributes.hs
--- a/src/Graphics/UI/Threepenny/SVG/Attributes.hs
+++ b/src/Graphics/UI/Threepenny/SVG/Attributes.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-missing-signatures #-}
 module Graphics.UI.Threepenny.SVG.Attributes (
     -- * Synopsis
     -- | SVG attributes as defined by W3C, Scalable Vector Graphics (SVG) 1.1
@@ -38,7 +39,7 @@
     panose_1, path, pathLength, patternContentUnits,
     patternTransform, patternUnits, points, pointsAtX, pointsAtY, pointsAtZ,
     preserveAlpha, preserveAspectRatio, primitiveUnits,
-    r, radius, refx, refy, rendering_intent, repeatCount, repeatDur,
+    r, radius, refX, refY, rendering_intent, repeatCount, repeatDur,
     requiredExtensions, requiredFeatures, restart, result, rotate, rx, ry,
     scale, seed, slope, spacing, specularConstant, specularExponent, spreadMethod,
     startOffset, stdDeviation, stemh, stemv, stitchTiles,
@@ -55,6 +56,9 @@
     y, y1, y2, yChannelSelector,
     z, zoomAndPan,
 
+    -- * Regular attributes (alternative spellings, deprecated)
+    refx, refy,
+
     -- * Presentation attributes
     alignment_baseline, baseline_shift,
     clip_path, clip_rule, clip, color_interpolation_filters, color_interpolation,
@@ -260,8 +264,11 @@
 primitiveUnits               =  strAttr "primitiveUnits"
 r                            =  strAttr "r"
 radius                       =  strAttr "radius"
-refx                         =  strAttr "refx"
-refy                         =  strAttr "refy"
+refX                         =  strAttr "refX"
+refY                         =  strAttr "refY"
+refx                         =  refX
+refy                         =  refY
+{-# DEPRECATED refx, refy "Use 'refX' and 'refY' instead" #-}
 rendering_intent             =  strAttr "rendering-intent"
 repeatCount                  =  strAttr "repeatCount"
 repeatDur                    =  strAttr "repeatDur"
diff --git a/src/Graphics/UI/Threepenny/SVG/Elements.hs b/src/Graphics/UI/Threepenny/SVG/Elements.hs
--- a/src/Graphics/UI/Threepenny/SVG/Elements.hs
+++ b/src/Graphics/UI/Threepenny/SVG/Elements.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-missing-signatures #-}
 module Graphics.UI.Threepenny.SVG.Elements (
     -- * Synopsis
     -- | SVG elements as defined by W3C, Scalable Vector Graphics (SVG) 1.1
diff --git a/src/Graphics/UI/Threepenny/Timer.hs b/src/Graphics/UI/Threepenny/Timer.hs
--- a/src/Graphics/UI/Threepenny/Timer.hs
+++ b/src/Graphics/UI/Threepenny/Timer.hs
@@ -13,7 +13,7 @@
     ) where
 
 import Data.Typeable
-import Control.Monad (when, forever, void)
+import Control.Monad (when, forever)
 import Control.Concurrent
 import Control.Concurrent.STM
 import Reactive.Threepenny
@@ -34,7 +34,7 @@
     tvInterval    <- newTVarIO 1000
     (tTick, fire) <- newEvent
     
-    forkIO $ forever $ do
+    _ <- forkIO $ forever $ do
         atomically $ do
             b <- readTVar tvRunning
             when (not b) retry
diff --git a/src/Graphics/UI/Threepenny/Widgets.hs b/src/Graphics/UI/Threepenny/Widgets.hs
--- a/src/Graphics/UI/Threepenny/Widgets.hs
+++ b/src/Graphics/UI/Threepenny/Widgets.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE RecordWildCards, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -Wno-unused-do-bind #-}
 module Graphics.UI.Threepenny.Widgets (
     -- * Synopsis
     -- | Widgets are reusable building blocks for a graphical user interface.
@@ -92,7 +93,7 @@
         bindices = (Map.fromList . flip zip [0..]) <$> bitems
         bindex   = lookupIndex <$> bindices <*> bsel
 
-        lookupIndex indices Nothing    = Nothing
+        lookupIndex _indices Nothing   = Nothing
         lookupIndex indices (Just sel) = Map.lookup sel indices
 
     element list # sink UI.selection bindex
@@ -111,8 +112,9 @@
 
     return ListBox {..}
 
+items :: WriteAttr Element [UI Element]
 items = mkWriteAttr $ \i x -> void $ do
-    return x # set children [] #+ map (\i -> UI.option #+ [i]) i
+    return x # set children [] #+ map (\j -> UI.option #+ [j]) i
 
 
 
diff --git a/src/Reactive/Threepenny.hs b/src/Reactive/Threepenny.hs
--- a/src/Reactive/Threepenny.hs
+++ b/src/Reactive/Threepenny.hs
@@ -42,6 +42,9 @@
     -- | Functions reserved for special circumstances.
     -- Do not use unless you know what you're doing.
     onChange, unsafeMapIO, newEventsNamed,
+    
+    -- * Testing
+    test, test_recursion1
     ) where
 
 import Control.Applicative
@@ -55,7 +58,6 @@
 
 type Pulse = Prim.Pulse
 type Latch = Prim.Latch
-type Map   = Map.Map
 
 {-----------------------------------------------------------------------------
     Types
@@ -104,7 +106,7 @@
 newEventsNamed :: Ord name
     => Handler (name, Event a, Handler a)   -- ^ Initialization procedure.
     -> IO (name -> Event a)                 -- ^ Series of events.
-newEventsNamed init = do
+newEventsNamed initialize = do
     eventsRef <- newIORef Map.empty
     return $ \name -> E $ memoize $ do
         events <- readIORef eventsRef
@@ -113,7 +115,7 @@
             Nothing -> do
                 (p, fire) <- Prim.newPulse
                 writeIORef eventsRef $ Map.insert name p events
-                init (name, E $ fromPure p, fire)
+                initialize (name, E $ fromPure p, fire)
                 return p
 
 
@@ -165,6 +167,7 @@
 -- Think of it as
 --
 -- > filterJust es = [(time,a) | (time,Just a) <- es]
+filterJust :: Event (Maybe a) -> Event a
 filterJust e = E $ liftMemo1 Prim.filterJustP (unE e)
 
 -- | Merge two event streams of the same type.
@@ -218,7 +221,7 @@
 -- > stepper x0 ex = return $ \time ->
 -- >     last (x0 : [x | (timex,x) <- ex, timex < time])
 --
--- Note that the smaller-than-sign in the comparision @timex < time@ means
+-- Note that the smaller-than-sign in the comparison @timex < time@ means
 -- that the value of the behavior changes \"slightly after\"
 -- the event occurrences. This allows for recursive definitions.
 stepper :: MonadIO m => a -> Event a -> m (Behavior a)
@@ -308,8 +311,8 @@
 split e = (filterJust $ fromLeft <$> e, filterJust $ fromRight <$> e)
     where
     fromLeft  (Left  a) = Just a
-    fromLeft  (Right b) = Nothing
-    fromRight (Left  a) = Nothing
+    fromLeft  (Right _) = Nothing
+    fromRight (Left  _) = Nothing
     fromRight (Right b) = Just b
 
 -- | Collect simultaneous event occurrences in a list.
@@ -366,9 +369,9 @@
 pair (T bx ex) (T by ey) = T b e
     where
     b = (,) <$> bx <*> by
-    x = flip (,) <$> by <@> ex
-    y = (,) <$> bx <@> ey
-    e = unionWith (\(x,_) (_,y) -> (x,y)) x y
+    ex' = flip (,) <$> by <@> ex
+    ey' = (,) <$> bx <@> ey
+    e = unionWith (\(x,_) (_,y) -> (x,y)) ex' ey'
 
 
 {-----------------------------------------------------------------------------
diff --git a/src/Reactive/Threepenny/Memo.hs b/src/Reactive/Threepenny/Memo.hs
--- a/src/Reactive/Threepenny/Memo.hs
+++ b/src/Reactive/Threepenny/Memo.hs
@@ -3,8 +3,6 @@
     Memo, fromPure, memoize, at, liftMemo1, liftMemo2,
     ) where
 
-import Control.Monad
-import Data.Functor
 import Data.IORef
 import System.IO.Unsafe
 
@@ -17,6 +15,7 @@
 
 type MemoD a = Either (IO a) a
 
+fromPure :: a -> Memo a
 fromPure = Const
 
 at :: Memo a -> IO a
diff --git a/src/Reactive/Threepenny/PulseLatch.hs b/src/Reactive/Threepenny/PulseLatch.hs
--- a/src/Reactive/Threepenny/PulseLatch.hs
+++ b/src/Reactive/Threepenny/PulseLatch.hs
@@ -6,18 +6,18 @@
     Latch,
     pureL, mapL, applyL, accumL, applyP,
     readLatch,
+    
+    -- * Internal
+    test, test_recursion1
     ) where
 
 
-import Control.Applicative
 import Control.Monad
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.RWS     as Monad
 
 import Data.IORef
-import Data.Monoid (Endo(..))
 
-import           Data.Hashable
 import qualified Data.HashMap.Strict as Map
 import qualified Data.Vault.Strict   as Vault
 import           Data.Unique.Really
@@ -25,8 +25,6 @@
 import Reactive.Threepenny.Monads
 import Reactive.Threepenny.Types
 
-type Map = Map.HashMap
-
 {-----------------------------------------------------------------------------
     Pulse
 ------------------------------------------------------------------------------}
@@ -114,11 +112,11 @@
 
 -- | Map an IO function over pulses. Is only executed once.
 unsafeMapIOP :: (a -> IO b) -> Pulse a -> Build (Pulse b)
-unsafeMapIOP f p = (`dependOn` p) <$> cacheEval (traverse . fmap f =<< evalP p)
+unsafeMapIOP f p = (`dependOn` p) <$> cacheEval (traverse' . fmap f =<< evalP p)
     where
-    traverse :: Maybe (IO a) -> EvalP (Maybe a)
-    traverse Nothing  = return Nothing
-    traverse (Just m) = Just <$> lift m
+    traverse' :: Maybe (IO a) -> EvalP (Maybe a)
+    traverse' Nothing  = return Nothing
+    traverse' (Just m) = Just <$> lift m
 
 -- | Filter occurrences. Only keep those of the form 'Just'.
 filterJustP :: Pulse (Maybe a) -> Build (Pulse a)
diff --git a/src/Reactive/Threepenny/Types.hs b/src/Reactive/Threepenny/Types.hs
--- a/src/Reactive/Threepenny/Types.hs
+++ b/src/Reactive/Threepenny/Types.hs
@@ -20,7 +20,9 @@
     , evalP       :: EvalP (Maybe a)
     }
 
-instance Hashable Priority where hashWithSalt _ = fromEnum
+instance Hashable Priority where
+    hashWithSalt = hashUsing fromEnum
+    hash         = fromEnum
 
 data Latch a = Latch { readL :: EvalL a }
 
diff --git a/threepenny-gui.cabal b/threepenny-gui.cabal
--- a/threepenny-gui.cabal
+++ b/threepenny-gui.cabal
@@ -1,7 +1,7 @@
-Name:                threepenny-gui
-Version:             0.8.2.0
-Synopsis:            GUI framework that uses the web browser as a display.
-Description:
+name:                threepenny-gui
+version:             0.9.4.2
+synopsis:            GUI framework that uses the web browser as a display.
+description:
     Threepenny-GUI is a GUI framework that uses the web browser as a display.
     .
     It's very easy to install because everyone has a web browser installed.
@@ -19,30 +19,45 @@
     .
     @cabal install threepenny-gui -fbuildExamples@
 
-License:             BSD3
-License-file:        LICENSE
-Author:              Heinrich Apfelmus
-Maintainer:          Heinrich Apfelmus <apfelmus at quantentunnel dot de>
-Homepage:            http://wiki.haskell.org/Threepenny-gui
+license:             BSD3
+license-file:        LICENSE
+author:              Heinrich Apfelmus
+maintainer:          Heinrich Apfelmus <apfelmus at quantentunnel dot de>
+homepage:            http://wiki.haskell.org/Threepenny-gui
 bug-reports:         https://github.com/HeinrichApfelmus/threepenny-gui/issues
-Category:            Web, GUI
-Build-type:          Simple
-Cabal-version:       >=1.8
+category:            Web, GUI
+build-type:          Simple
+cabal-version:       >=1.10
+tested-with:
+      GHC == 8.0.2
+    , GHC == 8.2.2
+    , GHC == 8.4.4
+    , GHC == 8.6.5
+    , GHC == 8.8.4
+    , GHC == 8.10.7
+    , GHC == 9.2.8
+    , GHC == 9.4.7
+    , GHC == 9.6.6
+    , GHC == 9.8.4
+    , GHC == 9.10.1
+    , GHC == 9.12.1
 
-Extra-Source-Files:  CHANGELOG.md
-                    ,README.md
-                    ,samples/README.md
-                    ,js/*.html
-                    ,js/*.css
-                    ,js/*.js
-                    ,js/lib/*.js
+extra-source-Files:
+      CHANGELOG.md
+    , README.md
+    , samples/README.md
+    , js/*.html
+    , js/*.css
+    , js/*.js
+    , js/lib/*.js
 
-Data-dir:           .
-Data-files:          samples/static/css/*.css
-                    ,samples/static/css/*.png
-                    ,samples/static/*.html
-                    ,samples/static/*.png
-                    ,samples/static/*.wav
+data-dir:           .
+data-files:
+      samples/static/css/*.css
+    , samples/static/css/*.png
+    , samples/static/*.html
+    , samples/static/*.png
+    , samples/static/*.wav
 
 
 flag buildExamples
@@ -50,11 +65,6 @@
     default:     False
     manual:      True
 
-flag network-uri
-    description: Get Network.URI from the network-uri package
-    default:     True
-    manual:      False
-
 flag rebug
     description: The library uses some techniques that are highly
                  non-deterministic, for example garbage collection
@@ -64,88 +74,86 @@
     default:     False
     manual:      True
 
-Source-repository head
+source-repository head
     type:               git
     location:           git://github.com/HeinrichApfelmus/threepenny-gui.git
 
-
-Library
+library
   hs-source-dirs:    src
   exposed-modules:
-                     Foreign.JavaScript
-                    ,Foreign.RemotePtr
-                    ,Graphics.UI.Threepenny
-                    ,Graphics.UI.Threepenny.Attributes
-                    ,Graphics.UI.Threepenny.Canvas
-                    ,Graphics.UI.Threepenny.Core
-                    ,Graphics.UI.Threepenny.DragNDrop
-                    ,Graphics.UI.Threepenny.Elements
-                    ,Graphics.UI.Threepenny.Events
-                    ,Graphics.UI.Threepenny.JQuery
-                    ,Graphics.UI.Threepenny.SVG
-                    ,Graphics.UI.Threepenny.SVG.Attributes
-                    ,Graphics.UI.Threepenny.SVG.Elements
-                    ,Graphics.UI.Threepenny.Timer
-                    ,Graphics.UI.Threepenny.Widgets
-                    ,Reactive.Threepenny
+    Foreign.JavaScript
+    Foreign.RemotePtr
+    Graphics.UI.Threepenny
+    Graphics.UI.Threepenny.Attributes
+    Graphics.UI.Threepenny.Canvas
+    Graphics.UI.Threepenny.Core
+    Graphics.UI.Threepenny.DragNDrop
+    Graphics.UI.Threepenny.Elements
+    Graphics.UI.Threepenny.Events
+    Graphics.UI.Threepenny.JQuery
+    Graphics.UI.Threepenny.SVG
+    Graphics.UI.Threepenny.SVG.Attributes
+    Graphics.UI.Threepenny.SVG.Elements
+    Graphics.UI.Threepenny.Timer
+    Graphics.UI.Threepenny.Widgets
+    Reactive.Threepenny
   other-modules:
-                     Foreign.JavaScript.CallBuffer
-                    ,Foreign.JavaScript.EventLoop
-                    ,Foreign.JavaScript.Include
-                    ,Foreign.JavaScript.Marshal
-                    ,Foreign.JavaScript.Resources
-                    ,Foreign.JavaScript.Server
-                    ,Foreign.JavaScript.Types
-                    ,Graphics.UI.Threepenny.Internal
-                    ,Reactive.Threepenny.Memo
-                    ,Reactive.Threepenny.Monads
-                    ,Reactive.Threepenny.PulseLatch
-                    ,Reactive.Threepenny.Types
-                    ,Paths_threepenny_gui
-  extensions:        CPP
+    Foreign.JavaScript.CallBuffer
+    Foreign.JavaScript.EventLoop
+    Foreign.JavaScript.Include
+    Foreign.JavaScript.Marshal
+    Foreign.JavaScript.Resources
+    Foreign.JavaScript.Server
+    Foreign.JavaScript.Types
+    Graphics.UI.Threepenny.Internal
+    Reactive.Threepenny.Memo
+    Reactive.Threepenny.Monads
+    Reactive.Threepenny.PulseLatch
+    Reactive.Threepenny.Types
+    Paths_threepenny_gui
+  other-extensions: CPP
   cpp-options:      -DCABAL
   if flag(rebug)
       cpp-options:  -DREBUG
       ghc-options:  -O2
-  build-depends:     base                   >= 4.6   && < 4.11
-                    ,aeson                  (>= 0.7 && < 0.10) || == 0.11.* || (>= 1.0 && < 1.3)
-                    ,async                  >= 2.0   && < 2.2
-                    ,bytestring             >= 0.9.2 && < 0.11
-                    ,containers             >= 0.4.2 && < 0.6
-                    ,data-default           >= 0.5.0 && < 0.8
-                    ,deepseq                >= 1.3.0 && < 1.5
-                    ,exceptions             >= 0.6   && < 0.9
-                    ,filepath               >= 1.3.0 && < 1.5.0
-                    ,file-embed             >= 0.0.10 && < 0.1
-                    ,hashable               >= 1.1.0 && < 1.3
-                    ,safe                   == 0.3.*
-                    ,snap-server            >= 0.9.0 && < 1.1
-                    ,snap-core              >= 0.9.0 && < 1.1
-                    ,stm                    >= 2.2    && < 2.5
-                    ,template-haskell       >= 2.7.0  && < 2.13
-                    ,text                   >= 0.11   && < 1.3
-                    ,transformers           >= 0.3.0  && < 0.6
-                    ,unordered-containers   == 0.2.*
-                    ,websockets             >= 0.8    && < 0.13
-                    ,websockets-snap        >= 0.8    && < 0.11
-                    ,vault                  == 0.3.*
-                    ,vector                 >= 0.10   && < 0.13
-  if flag(network-uri)
-      build-depends: network-uri            >= 2.6    && < 2.7
-  else
-      build-depends: network                >= 2.3.0  && < 2.6
+  build-depends:
+      base                   >= 4.8   && < 4.22
+    , aeson                  (>= 0.7 && < 0.10) || == 0.11.* || (>= 1.0 && < 2.3)
+    , async                  >= 2.0    && < 2.3
+    , bytestring             >= 0.9.2  && < 0.13
+    , containers             >= 0.4.2  && < 0.8
+    , data-default           >= 0.5.0  && < 0.8
+    , deepseq                >= 1.3.0  && < 1.6
+    , exceptions             >= 0.6    && < 0.11
+    , filepath               >= 1.3.0  && < 1.6.0
+    , file-embed             >= 0.0.10 && < 0.1
+    , hashable               >= 1.2.0  && < 1.6
+    , safe                   == 0.3.*
+    , snap-server            >= 0.9.0  && < 1.2
+    , snap-core              >= 0.9.0  && < 1.1
+    , stm                    >= 2.2    && < 2.6
+    , template-haskell       >= 2.7.0  && < 2.24
+    , text                   >= 0.11   && < 2.2
+    , transformers           >= 0.3.0  && < 0.7
+    , unordered-containers   == 0.2.*
+    , websockets             (>= 0.8    && < 0.12.5) || (> 0.12.5.0 && < 0.14)
+    , websockets-snap        >= 0.8    && < 0.11
+    , vault                  >= 0.3    && < 0.4
+    , vector                 >= 0.10   && < 0.14
+  if impl(ghc >= 8.0)
+      ghc-options: -Wcompat -Wnoncanonical-monad-instances
+  default-language: Haskell2010
 
 Executable threepenny-examples-bartab
     if flag(buildExamples)
         cpp-options:       -DCABAL
         build-depends:     base                      >= 4     && < 5
                           ,threepenny-gui
-                          ,filepath
     else
         buildable: False
     main-is:           BarTab.hs
-    other-modules:     Paths_threepenny_gui, Paths
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-buttons
     if flag(buildExamples)
@@ -158,6 +166,7 @@
     main-is:           Buttons.hs
     other-modules:     Paths_threepenny_gui, Paths
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-canvas
     if flag(buildExamples)
@@ -168,15 +177,15 @@
     else
         buildable: False
     main-is:           Canvas.hs
-    other-modules:     Paths
+    other-modules:     Paths_threepenny_gui, Paths
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-chat
     if flag(buildExamples)
         cpp-options:       -DCABAL
         build-depends:     base                      >= 4     && < 5
                           ,threepenny-gui
-                          ,transformers
                           ,filepath
                           ,time
     else
@@ -184,6 +193,7 @@
     main-is:           Chat.hs
     other-modules:     Paths_threepenny_gui, Paths, Data.List.Extra
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-crud
     if flag(buildExamples)
@@ -195,6 +205,7 @@
         buildable: False
     main-is:           CRUD.hs
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-currencyconverter
     if flag(buildExamples)
@@ -206,6 +217,7 @@
         buildable: False
     main-is:           CurrencyConverter.hs
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-dragndropexample
     if flag(buildExamples)
@@ -218,6 +230,7 @@
     main-is:           DragNDropExample.hs
     other-modules:     Paths_threepenny_gui, Paths
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-drummachine
     if flag(buildExamples)
@@ -230,6 +243,7 @@
     main-is:           DrumMachine.hs
     other-modules:     Paths_threepenny_gui, Paths
     hs-source-dirs:    samples
+    default-language: Haskell2010
 
 Executable threepenny-examples-svg
     if flag(buildExamples)
@@ -239,5 +253,5 @@
     else
         buildable: False
     main-is:           Svg.hs
-    other-modules:     Paths_threepenny_gui, Paths
     hs-source-dirs:    samples
+    default-language: Haskell2010
