diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
 #Change Log
 
+##hs-webdriver 0.5
+###API changes
+* Test.WebDriver.Commands.Wait.unexpected now accepts a String argument, which is used as an error message
+* screenshot and uploadZipEntry from Test.WebDriver.Commands now use lazy bytestrings
+*wdBasePath field added to WDSession. This allows you to specify a custom base path for all WebDriver requests. The default, as specified in the WebDriver standard, is "/wd/hub"
+
+###new features
+* added Test.WebDriver.Commands.screenshotBase64
+
 ##hs-webdriver 0.4
 
 ###API changes
diff --git a/src/Test/WebDriver.hs b/src/Test/WebDriver.hs
--- a/src/Test/WebDriver.hs
+++ b/src/Test/WebDriver.hs
@@ -1,8 +1,8 @@
-{-| 
+{-|
 This module serves as the top-level interface to the Haskell WebDriver bindings,
 providing most of the functionality you're likely to want.
 -}
-module Test.WebDriver 
+module Test.WebDriver
        ( -- * WebDriver sessions
          WD(..), WDSession(..), defaultSession, SessionId(..)
          -- * Running WebDriver tests
diff --git a/src/Test/WebDriver/Capabilities.hs b/src/Test/WebDriver/Capabilities.hs
--- a/src/Test/WebDriver/Capabilities.hs
+++ b/src/Test/WebDriver/Capabilities.hs
@@ -19,7 +19,7 @@
 import Control.Exception.Lifted (throw)
 
 {- |A structure describing the capabilities of a session. This record
-serves dual roles. 
+serves dual roles.
 
 * It's used to specify the desired capabilities for a session before
 it's created. In this usage, fields that are set to Nothing indicate
@@ -31,12 +31,12 @@
 support the capability. Thus, for Maybe Bool fields, both Nothing and
 Just False indicate a lack of support for the desired capability.
 -}
-data Capabilities = 
+data Capabilities =
   Capabilities { -- |Browser choice and browser specific settings.
                  browser                  :: Browser
                  -- |Browser version to use.
                , version                  :: Maybe String
-                 -- |Platform on which the browser should run.   
+                 -- |Platform on which the browser should run.
                , platform                 :: Platform
                  -- |Proxy configuration settings.
                , proxy                    :: ProxyType
@@ -47,7 +47,7 @@
                  -- current page with the 'screenshot' command
                , takesScreenshot          :: Maybe Bool
                  -- |Whether the session can interact with modal popups,
-                 -- such as window.alert and window.confirm via 
+                 -- such as window.alert and window.confirm via
                  -- 'acceptAlerts', 'dismissAlerts', etc.
                , handlesAlerts            :: Maybe Bool
                  -- |Whether the session can interact with database storage.
@@ -64,7 +64,7 @@
                  -- |Whether the session supports CSS selectors when searching
                  -- for elements.
                , cssSelectorsEnabled      :: Maybe Bool
-                 -- |Whether Web Storage ('getKey', 'setKey', etc) support is 
+                 -- |Whether Web Storage ('getKey', 'setKey', etc) support is
                  -- enabled
                , webStorageEnabled        :: Maybe Bool
                  -- |Whether the session can rotate the current page's current
@@ -96,14 +96,14 @@
                      , proxy = UseSystemSettings
                      }
 
--- |Default capabilities. This is the same as the 'Default' instance, but with 
--- less polymorphism. By default, we use 'firefox' of an unspecified 'version' 
+-- |Default capabilities. This is the same as the 'Default' instance, but with
+-- less polymorphism. By default, we use 'firefox' of an unspecified 'version'
 -- with default system-wide 'proxy' settings on whatever 'platform' is available
 -- . All Maybe Bool capabilities are set to Nothing (no preference).
 defaultCaps :: Capabilities
 defaultCaps = def
 
--- |Same as 'defaultCaps', but with all Maybe Bool capabilities set to 
+-- |Same as 'defaultCaps', but with all Maybe Bool capabilities set to
 -- Just True.
 allCaps :: Capabilities
 allCaps = defaultCaps { javascriptEnabled = Just True
@@ -119,10 +119,10 @@
                       , acceptSSLCerts = Just True
                       , nativeEvents = Just True
                       }
-      
 
+
 instance ToJSON Capabilities where
-  toJSON Capabilities{..} = 
+  toJSON Capabilities{..} =
     object $ [ "browserName" .= browser
              , "version" .= version
              , "platform" .= platform
@@ -140,7 +140,7 @@
              , "acceptSslCerts" .= acceptSSLCerts
              , "nativeEvents" .= nativeEvents
              ] ++ browserInfo
-    where 
+    where
       browserInfo = case browser of
         Firefox {..}
           -> ["firefox_profile" .= ffProfile
@@ -149,11 +149,11 @@
              ]
         Chrome {..}
           -> catMaybes [ opt "chrome.chromedriverVersion" chromeDriverVersion
-                       , opt "chrome.binary" chromeBinary 
+                       , opt "chrome.binary" chromeBinary
                        ]
              ++ ["chrome.switches" .= chromeOptions
                 ,"chrome.extensions" .= chromeExtensions
-                ]       
+                ]
         IE {..}
           -> ["IgnoreProtectedModeSettings" .= ignoreProtectedModeSettings
              --,"useLegacyInternalServer" .= u
@@ -165,7 +165,7 @@
                        , opt "opera.launcher" operaLauncher
                        , opt "opera.host" operaHost
                        , opt "opera.logging.file" operaLogFile
-                       ] 
+                       ]
              ++ ["opera.detatch" .= operaDetach
                 ,"opera.no_quit" .= operaDetach --backwards compatability
                 ,"opera.autostart" .= operaAutoStart
@@ -177,12 +177,12 @@
                 ,"opera.logging.level" .= operaLogPref
                 ]
         _ -> []
-          
+
         where
           opt k = fmap (k .=)
 
 
-instance FromJSON Capabilities where  
+instance FromJSON Capabilities where
   parseJSON (Object o) = Capabilities <$> req "browserName"
                                       <*> opt "version" Nothing
                                       <*> req "platform"
@@ -207,7 +207,7 @@
           b k = opt k Nothing     -- Maybe Bool field
   parseJSON v = typeMismatch "Capabilities" v
 
--- |This constructor simultaneously specifies which browser the session will 
+-- |This constructor simultaneously specifies which browser the session will
 -- use, while also providing browser-specific configuration. Default
 -- configuration is provided for each browser by 'firefox', 'chrome', 'opera',
 -- 'ie', etc.
@@ -220,7 +220,7 @@
                          ffProfile :: Maybe (PreparedProfile Firefox)
                          -- |Firefox logging preference
                        , ffLogPref :: LogPref
-                         -- |Server-side path to Firefox binary. If Nothing, 
+                         -- |Server-side path to Firefox binary. If Nothing,
                          -- use a sensible system-based default.
                        , ffBinary :: Maybe FilePath
                        }
@@ -228,27 +228,27 @@
                         --
                         -- for more information on chromedriver see
                         -- <http://code.google.com/p/selenium/wiki/ChromeDriver>
-                        chromeDriverVersion :: Maybe String 
-                        -- |Server-side path to Chrome binary. If Nothing, 
+                        chromeDriverVersion :: Maybe String
+                        -- |Server-side path to Chrome binary. If Nothing,
                         -- use a sensible system-based default.
                       , chromeBinary :: Maybe FilePath
-                        -- |A list of command-line options to pass to the 
+                        -- |A list of command-line options to pass to the
                         -- Chrome binary.
                       , chromeOptions :: [String]
                         -- |A list of extensions to use.
                       , chromeExtensions :: [ChromeExtension]
-                      } 
-             | IE { -- |Whether to skip the protected mode check. If set, tests 
-                    -- may become flaky, unresponsive, or browsers may hang. If 
+                      }
+             | IE { -- |Whether to skip the protected mode check. If set, tests
+                    -- may become flaky, unresponsive, or browsers may hang. If
                     -- not set, and protected mode settings are not the same for
-                    -- all zones, an exception will be thrown on driver 
-                    -- construction. 
+                    -- all zones, an exception will be thrown on driver
+                    -- construction.
                     ignoreProtectedModeSettings :: Bool
                   --, useLegacyInternalServer     :: Bool
                   }
              | Opera { -- |Server-side path to the Opera binary
                        operaBinary    :: Maybe FilePath
-                     --, operaNoRestart :: Maybe Bool 
+                     --, operaNoRestart :: Maybe Bool
                        -- |Which Opera product we're using, e.g. \"desktop\",
                        -- \"core\"
                      , operaProduct   :: Maybe String
@@ -284,14 +284,14 @@
                      , operaHost      :: Maybe String
                        -- |Command-line arguments to pass to Opera.
                      , operaOptions   :: String
-                       -- |Where to send the log output. If Nothing, logging is 
+                       -- |Where to send the log output. If Nothing, logging is
                        -- disabled.
                      , operaLogFile   :: Maybe FilePath
                        -- |Log level preference. Defaults to 'LogInfo'
                      , operaLogPref   :: LogPref
                      }
              | HTMLUnit
-             | IPhone 
+             | IPhone
              | IPad
              | Android
              deriving (Eq, Show)
@@ -385,13 +385,13 @@
     "vista"   -> return Vista
     "mac"     -> return Mac
     "linux"   -> return Linux
-    "unix"    -> return Unix 
+    "unix"    -> return Unix
     "any"     -> return Any
-    err -> fail $ "Invalid Platform string " ++ show err 
+    err -> fail $ "Invalid Platform string " ++ show err
   parseJSON v = typeMismatch "Platform" v
 
 -- |Available settings for the proxy 'Capabilities' field
-data ProxyType = NoProxy 
+data ProxyType = NoProxy
                | UseSystemSettings
                | AutoDetect
                  -- |Use a proxy auto-config file specified by URL
@@ -411,24 +411,24 @@
       "direct" -> return NoProxy
       "system" -> return UseSystemSettings
       "pac"    -> PAC <$> f "autoConfigUrl"
-      "manual" -> Manual <$> f "ftpProxy" 
+      "manual" -> Manual <$> f "ftpProxy"
                          <*> f "sslProxy"
                          <*> f "httpProxy"
       _ -> fail $ "Invalid ProxyType " ++ show pTyp
     where
-      f :: FromJSON a => Text -> Parser a 
+      f :: FromJSON a => Text -> Parser a
       f = (obj .:)
   parseJSON v = typeMismatch "ProxyType" v
-      
+
 instance ToJSON ProxyType where
   toJSON pt = object $ case pt of
-    NoProxy -> 
+    NoProxy ->
       ["proxyType" .= ("DIRECT" :: String)]
-    UseSystemSettings -> 
+    UseSystemSettings ->
       ["proxyType" .= ("SYSTEM" :: String)]
     AutoDetect ->
       ["proxyType" .= ("AUTODETECT" :: String)]
-    PAC{autoConfigUrl = url} -> 
+    PAC{autoConfigUrl = url} ->
       ["proxyType" .= ("PAC" :: String)
       ,"autoConfigUrl" .= url
       ]
@@ -440,7 +440,7 @@
       ]
 
 -- |Indicates log verbosity. Used in 'Firefox' and 'Opera' configuration.
-data LogPref = LogOff | LogSevere | LogWarning | LogInfo | LogConfig 
+data LogPref = LogOff | LogSevere | LogWarning | LogInfo | LogConfig
              | LogFine | LogFiner | LogFinest | LogAll
              deriving (Eq, Show, Ord, Bounded, Enum)
 
@@ -458,7 +458,7 @@
     LogFiner -> "FINER"
     LogFinest -> "FINEST"
     LogAll -> "ALL"
-    
+
 instance FromJSON LogPref where
   parseJSON (String s) = return $ case s of
     "OFF" -> LogOff
diff --git a/src/Test/WebDriver/Chrome/Extension.hs b/src/Test/WebDriver/Chrome/Extension.hs
--- a/src/Test/WebDriver/Chrome/Extension.hs
+++ b/src/Test/WebDriver/Chrome/Extension.hs
@@ -1,9 +1,9 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts #-}
 -- |Functions and types for working with Google Chrome extensions.
-module Test.WebDriver.Chrome.Extension 
+module Test.WebDriver.Chrome.Extension
        ( ChromeExtension
        , loadExtension
-       , loadRawExtension 
+       , loadRawExtension
        ) where
 import Data.ByteString as BS
 import Data.ByteString.Base64 as B64
@@ -12,7 +12,7 @@
 import Control.Monad.Base
 
 -- |An opaque type representing a Google Chrome extension. Values of this type
--- are passed to the 'Test.Webdriver.chromeExtensions' field. 
+-- are passed to the 'Test.Webdriver.chromeExtensions' field.
 newtype ChromeExtension = ChromeExtension ByteString
                         deriving (Eq, Show, Read, ToJSON, FromJSON)
 
diff --git a/src/Test/WebDriver/Classes.hs b/src/Test/WebDriver/Classes.hs
--- a/src/Test/WebDriver/Classes.hs
+++ b/src/Test/WebDriver/Classes.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, FlexibleContexts, 
+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, FlexibleContexts,
              GeneralizedNewtypeDeriving #-}
 module Test.WebDriver.Classes
        ( -- * WebDriver class
@@ -45,10 +45,10 @@
 -- "Test.WebDriver.Commands". For more information on the wire protocol see
 -- <http://code.google.com/p/selenium/wiki/JsonWireProtocol>
 class SessionState wd => WebDriver wd where
-  doCommand :: (ToJSON a, FromJSON b) => 
-                RequestMethod -- ^HTTP request method 
-                -> Text       -- ^URL of request 
-                -> a          -- ^JSON parameters passed in the body 
+  doCommand :: (ToJSON a, FromJSON b) =>
+                RequestMethod -- ^HTTP request method
+                -> Text       -- ^URL of request
+                -> a          -- ^JSON parameters passed in the body
                               -- of the request. Note that, as a special case,
                               -- () will result in an empty request body.
                 -> wd b       -- ^The JSON result of the HTTP request.
@@ -59,40 +59,43 @@
 {- |Information about a WebDriver session. This structure is passed
 implicitly through all 'WD' computations, and is also used to configure the 'WD'
 monad before execution. -}
-data WDSession = WDSession { 
-                             -- |Host name of the WebDriver server for this 
+data WDSession = WDSession {
+                             -- |Host name of the WebDriver server for this
                              -- session
-                             wdHost   :: String
+                             wdHost     :: String
                              -- |Port number of the server
-                           , wdPort   :: Word16
+                           , wdPort     :: Word16
+                             -- |Base path (usually "/wd/hub")
+                           , wdBasePath :: String
                              -- |An opaque reference identifying the session to
                              -- use with 'WD' commands.
-                             -- A value of Nothing indicates that a session 
+                             -- A value of Nothing indicates that a session
                              -- hasn't been created yet.
                              -- Sessions can be created within 'WD' via
                              -- 'Test.WebDriver.createSession', or created
-                             -- and closed automatically with 
+                             -- and closed automatically with
                              -- 'Test.WebDriver.runSession'
-                           , wdSessId :: Maybe SessionId 
+                           , wdSessId   :: Maybe SessionId
                            } deriving (Eq, Show)
 
 instance Default WDSession where
-  def = WDSession { wdHost   = "127.0.0.1"
-                  , wdPort   = 4444
-                  , wdSessId = Nothing
+  def = WDSession { wdHost     = "127.0.0.1"
+                  , wdPort     = 4444
+                  , wdBasePath = "/wd/hub"
+                  , wdSessId   = Nothing
                   }
 
-{- |A default session connects to localhost on port 4444, and hasn't been 
+{- |A default session connects to localhost on port 4444, and hasn't been
 initialized server-side. This value is the same as 'def' but with a less
 polymorphic type. -}
 defaultSession :: WDSession
 defaultSession = def
 
 
-{- |An opaque identifier for a WebDriver session. These handles are produced by 
-the server on session creation, and act to identify a session in progress. -} 
+{- |An opaque identifier for a WebDriver session. These handles are produced by
+the server on session creation, and act to identify a session in progress. -}
 newtype SessionId = SessionId Text
-                  deriving (Eq, Ord, Show, Read, 
+                  deriving (Eq, Ord, Show, Read,
                             FromJSON, ToJSON)
 
 
@@ -171,4 +174,3 @@
 
 instance (Monoid w, WebDriver wd) => WebDriver (LRWS.RWST r w s wd) where
   doCommand rm t a = lift (doCommand rm t a)
-
diff --git a/src/Test/WebDriver/Commands.hs b/src/Test/WebDriver/Commands.hs
--- a/src/Test/WebDriver/Commands.hs
+++ b/src/Test/WebDriver/Commands.hs
@@ -2,14 +2,14 @@
              TemplateHaskell #-}
 -- |This module exports basic WD actions that can be used to interact with a
 -- browser session.
-module Test.WebDriver.Commands 
+module Test.WebDriver.Commands
        ( -- * Sessions
          createSession, closeSession, sessions, getCaps
          -- * Browser interaction
          -- ** Web navigation
        , openPage, forward, back, refresh
          -- ** Page info
-       , getCurrentURL, getSource, getTitle, screenshot                    
+       , getCurrentURL, getSource, getTitle, screenshot, screenshotBase64
          -- * Timeouts
        , setImplicitWait, setScriptTimeout, setPageLoadTimeout
          -- * Web elements
@@ -26,10 +26,10 @@
        , tagName, activeElem, elemInfo
          -- ** Element equality
        , (<==>), (</=>)
-         -- * Javascript            
+         -- * Javascript
        , executeJS, asyncJS
        , JSArg(..)
-         -- * Windows                                                       
+         -- * Windows
        , WindowHandle(..), currentWindow
        , getCurrentWindow, closeWindow, windows, focusWindow,  maximize
        , getWindowSize, setWindowSize, getWindowPos, setWindowPos
@@ -40,7 +40,7 @@
        , cookies, setCookie, deleteCookie, deleteVisibleCookies
          -- * Alerts
        , getAlertText, replyToAlert, acceptAlert, dismissAlert
-         -- * Mouse gestures                                          
+         -- * Mouse gestures
        , moveTo, moveToCenter, moveToFrom
        , clickWith, MouseButton(..)
        , mouseDown, mouseUp, withMouseDown, doubleClick
@@ -59,11 +59,11 @@
        , touchClick, touchDown, touchUp, touchMove
        , touchScroll, touchScrollFrom, touchDoubleClick
        , touchLongClick, touchFlick, touchFlickFrom
-         -- * IME support              
+         -- * IME support
        , availableIMEEngines, activeIMEEngine, checkIMEActive
        , activateIME, deactivateIME
          -- * Uploading files to remote server
-         -- |These functions allow you to upload a file to a remote server. 
+         -- |These functions allow you to upload a file to a remote server.
          -- Note that this operation isn't supported by all WebDriver servers,
          -- and the location where the file is stored is not standardized.
        , uploadFile, uploadRawFile, uploadZipEntry
@@ -82,9 +82,8 @@
 import Data.Aeson.TH
 import qualified Data.Text as T
 import Data.Text (Text, splitOn, append, toUpper, toLower)
-import Data.ByteString as SBS (ByteString, concat)
-import Data.ByteString.Base64 as B64
-import Data.ByteString.Lazy as LBS (ByteString, toChunks)
+import Data.ByteString.Base64.Lazy as B64
+import Data.ByteString.Lazy as LBS (ByteString)
 import Network.URI hiding (path)  -- suppresses warnings
 import Codec.Archive.Zip
 
@@ -99,8 +98,8 @@
 
 import Prelude hiding (catch)
 
--- |Get information from the server as a JSON 'Object'. For more information 
--- about this object see 
+-- |Get information from the server as a JSON 'Object'. For more information
+-- about this object see
 -- <http://code.google.com/p/selenium/wiki/JsonWireProtocol#/status>
 serverStatus :: (WebDriver wd) => wd Value   -- todo: make this a record type
 serverStatus = doCommand GET "/status" ()
@@ -129,23 +128,23 @@
 closeSession :: WebDriver wd => wd ()
 closeSession = do s <- getSession
                   doSessCommand DELETE "" () :: WebDriver wd => wd ()
-                  putSession s { wdSessId = Nothing } 
+                  putSession s { wdSessId = Nothing }
 
 -- |Sets the amount of time we implicitly wait when searching for elements.
 setImplicitWait :: WebDriver wd => Integer -> wd ()
-setImplicitWait ms = 
+setImplicitWait ms =
   doSessCommand POST "/timeouts/implicit_wait" (object msField)
-    `catch` \(_ :: SomeException) ->  
+    `catch` \(_ :: SomeException) ->
       doSessCommand POST "/timeouts" (object allFields)
-  where msField   = ["ms" .= ms] 
+  where msField   = ["ms" .= ms]
         allFields = ["type" .= ("implicit" :: String)] ++ msField
 
--- |Sets the amount of time we wait for an asynchronous script to return a 
+-- |Sets the amount of time we wait for an asynchronous script to return a
 -- result.
-setScriptTimeout :: WebDriver wd => Integer -> wd () 
+setScriptTimeout :: WebDriver wd => Integer -> wd ()
 setScriptTimeout ms =
   doSessCommand POST "/timeouts/async_script" (object msField)
-    `catch` \(_ :: SomeException) ->  
+    `catch` \(_ :: SomeException) ->
       doSessCommand POST "/timeouts" (object allFields)
   where msField   = ["ms" .= ms]
         allFields = ["type" .= ("script" :: String)] ++ msField
@@ -162,7 +161,7 @@
 
 -- |Opens a new page by the given URL.
 openPage :: WebDriver wd => String -> wd ()
-openPage url 
+openPage url
   | isURI url = doSessCommand POST "/url" . single "url" $ url
   | otherwise = throwIO . InvalidURL $ url
 
@@ -203,28 +202,31 @@
 -}
 executeJS :: (WebDriver wd, FromJSON a) => [JSArg] -> Text -> wd a
 executeJS a s = fromJSON' =<< getResult
-  where 
+  where
     getResult = doSessCommand POST "/execute" . pair ("args", "script") $ (a,s)
 
 {- |Executes a snippet of Javascript code asynchronously. This function works
 similarly to 'executeJS', except that the Javascript is passed a callback
 function as its final argument. The script should call this function
 to signal that it has finished executing, passing to it a value that will be
-returned as the result of asyncJS. A result of Nothing indicates that the 
+returned as the result of asyncJS. A result of Nothing indicates that the
 Javascript function timed out (see 'setScriptTimeout')
 -}
 asyncJS :: (WebDriver wd, FromJSON a) => [JSArg] -> Text -> wd (Maybe a)
 asyncJS a s = handle timeout $ fromJSON' =<< getResult
-  where 
-    getResult = doSessCommand POST "/execute_async" . pair ("args", "script") 
+  where
+    getResult = doSessCommand POST "/execute_async" . pair ("args", "script")
                 $ (a,s)
     timeout (FailedCommand Timeout _) = return Nothing
     timeout err = throwIO err
 
 -- |Grab a screenshot of the current page as a PNG image
-screenshot :: WebDriver wd => wd SBS.ByteString
-screenshot = B64.decodeLenient <$> doSessCommand GET "/screenshot" () 
+screenshot :: WebDriver wd => wd LBS.ByteString
+screenshot = B64.decodeLenient <$> screenshotBase64
 
+-- |Grab a screenshot as a base-64 encoded PNG image. This is the protocol-defined format.
+screenshotBase64 :: WebDriver wd => wd LBS.ByteString
+screenshotBase64 = doSessCommand GET "/screenshot" ()
 
 availableIMEEngines :: WebDriver wd => wd [Text]
 availableIMEEngines = doSessCommand GET "/ime/available_engines" ()
@@ -243,7 +245,7 @@
 
 
 -- |Specifies the frame used by 'Test.WebDriver.Commands.focusFrame'
-data FrameSelector = WithIndex Integer       
+data FrameSelector = WithIndex Integer
                      -- |focus on a frame by name or ID
                    | WithName Text
                      -- |focus on a frame 'Element'
@@ -262,7 +264,7 @@
 
 -- |Switch focus to the frame specified by the FrameSelector.
 focusFrame :: WebDriver wd => FrameSelector -> wd ()
-focusFrame s = doSessCommand POST "/frame" . single "id" $ s 
+focusFrame s = doSessCommand POST "/frame" . single "id" $ s
 
 -- |Returns a handle to the currently focused window
 getCurrentWindow :: WebDriver wd => wd WindowHandle
@@ -285,17 +287,17 @@
 
 -- |Get the dimensions of the current window.
 getWindowSize :: WebDriver wd => wd (Word, Word)
-getWindowSize = doWinCommand GET currentWindow "/size" () 
+getWindowSize = doWinCommand GET currentWindow "/size" ()
                 >>= parsePair "width" "height" "getWindowSize"
 
 -- |Set the dimensions of the current window.
 setWindowSize :: WebDriver wd => (Word, Word) -> wd ()
-setWindowSize = doWinCommand POST currentWindow "/size" 
+setWindowSize = doWinCommand POST currentWindow "/size"
                 . pair ("width", "height")
 
 -- |Get the coordinates of the current window.
 getWindowPos :: WebDriver wd => wd (Int, Int)
-getWindowPos = doWinCommand GET currentWindow "/position" () 
+getWindowPos = doWinCommand GET currentWindow "/position" ()
                >>= parsePair "x" "y" "getWindowPos"
 
 -- |Set the coordinates of the current window.
@@ -307,7 +309,7 @@
 -- cookies from the server, a value of Nothing indicates that the server is unable
 -- to specify the value.
 data Cookie = Cookie { cookName   :: Text
-                     , cookValue  :: Text          -- ^ 
+                     , cookValue  :: Text          -- ^
                      , cookPath   :: Maybe Text    -- ^path of this cookie.
                                                    -- if Nothing, defaults to /
                      , cookDomain :: Maybe Text    -- ^domain of this cookie.
@@ -316,9 +318,9 @@
                      , cookSecure :: Maybe Bool    -- ^Is this cookie secure?
                      , cookExpiry :: Maybe Integer -- ^Expiry date expressed as
                                                    -- seconds since the Unix epoch
-                                                   -- Nothing indicates that the 
+                                                   -- Nothing indicates that the
                                                    -- cookie never expires
-                     } deriving (Eq, Show)              
+                     } deriving (Eq, Show)
 
 -- |Creates a Cookie with only a name and value specified. All other
 -- fields are set to Nothing, which tells the server to use default values.
@@ -328,7 +330,7 @@
                                cookSecure = Nothing, cookExpiry = Nothing
                              }
 
--- This line causes a strange out of scope error. Moving to the bottom of the 
+-- This line causes a strange out of scope error. Moving to the bottom of the
 -- file fixed it.
 -- $( deriveToJSON (map C.toLower . drop 4) ''Cookie )
 
@@ -339,7 +341,7 @@
                                 <*> opt "domain" Nothing
                                 <*> opt "secure" Nothing
                                 <*> opt "expiry" Nothing
-    where 
+    where
       req :: FromJSON a => Text -> Parser a
       req = (o .:)
       opt :: FromJSON a => Text -> a -> Parser a
@@ -351,12 +353,12 @@
 cookies = doSessCommand GET "/cookie" ()
 
 -- |Set a cookie. If the cookie path is not specified, it will default to \"/\".
--- Likewise, if the domain is omitted, it will default to the current page's 
+-- Likewise, if the domain is omitted, it will default to the current page's
 -- domain
 setCookie :: WebDriver wd => Cookie -> wd ()
 setCookie = doSessCommand POST "/cookie" . single "cookie"
 
--- |Delete a cookie. This will do nothing is the cookie isn't visible to the 
+-- |Delete a cookie. This will do nothing is the cookie isn't visible to the
 -- current page.
 deleteCookie :: WebDriver wd => Cookie -> wd ()
 deleteCookie c = doSessCommand DELETE ("/cookie/" `append` cookName c) ()
@@ -374,12 +376,12 @@
 getTitle = doSessCommand GET "/title" ()
 
 -- |Specifies element(s) within a DOM tree using various selection methods.
-data Selector = ById Text  
+data Selector = ById Text
               | ByName Text
-              | ByClass Text -- ^ (Note: multiple classes are not  
+              | ByClass Text -- ^ (Note: multiple classes are not
                              -- allowed. For more control, use 'ByCSS')
-              | ByTag Text            
-              | ByLinkText Text       
+              | ByTag Text
+              | ByLinkText Text
               | ByPartialLinkText Text
               | ByCSS Text
               | ByXPath Text
@@ -409,7 +411,7 @@
 
 -- |Return the element that currently has focus.
 activeElem :: WebDriver wd => wd Element
-activeElem = doSessCommand POST "/element/active" () 
+activeElem = doSessCommand POST "/element/active" ()
 
 -- |Search for an element using the given element as root.
 findElemFrom :: WebDriver wd => Element -> Selector -> wd Element
@@ -419,7 +421,7 @@
 findElemsFrom :: WebDriver wd => Element -> Selector -> wd [Element]
 findElemsFrom e = doElemCommand POST e "/elements"
 
--- |Describe the element. Returns a JSON object whose meaning is currently  
+-- |Describe the element. Returns a JSON object whose meaning is currently
 -- undefined by the WebDriver protocol.
 elemInfo :: WebDriver wd => Element -> wd Value
 elemInfo e = doElemCommand GET e "" ()
@@ -438,7 +440,7 @@
 getText e = doElemCommand GET e "/text" ()
 
 -- |Send a sequence of keystrokes to an element. All modifier keys are released
--- at the end of the function. For more information about modifier keys, see 
+-- at the end of the function. For more information about modifier keys, see
 -- <http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value>
 sendKeys :: WebDriver wd => Text -> Element -> wd ()
 sendKeys t e = doElemCommand POST e "/value" . single "value" $ [t]
@@ -482,7 +484,7 @@
 
 -- |Retrieve an element's current size.
 elemSize :: WebDriver wd => Element -> wd (Word, Word)
-elemSize e = doElemCommand GET e "/size" () 
+elemSize e = doElemCommand GET e "/size" ()
              >>= parsePair "width" "height" "elemSize"
 
 infix 4 <==>
@@ -539,13 +541,13 @@
 
 -- |Moves the mouse to the center of a given element.
 moveToCenter :: WebDriver wd => Element -> wd ()
-moveToCenter (Element e) = 
+moveToCenter (Element e) =
   doSessCommand POST "/moveto" . single "element" $ e
 
 -- |Moves the mouse to the given position relative to the given element.
 moveToFrom :: WebDriver wd => (Int, Int) -> Element -> wd ()
-moveToFrom (x,y) (Element e) = 
-  doSessCommand POST "/moveto" 
+moveToFrom (x,y) (Element e) =
+  doSessCommand POST "/moveto"
   . triple ("element","xoffset","yoffset") $ (e,x,y)
 
 -- |A mouse button
@@ -554,7 +556,7 @@
 
 instance ToJSON MouseButton where
   toJSON = toJSON . fromEnum
-  
+
 instance FromJSON MouseButton where
   parseJSON v = do
     n <- parseJSON v
@@ -574,7 +576,7 @@
 withMouseDown :: WebDriver wd => wd a -> wd a
 withMouseDown wd = mouseDown >> wd <* mouseUp
 
--- |Press and hold the left mouse button down. Note that undefined behavior 
+-- |Press and hold the left mouse button down. Note that undefined behavior
 -- occurs if the next mouse command is not mouseUp.
 mouseDown :: WebDriver wd => wd ()
 mouseDown = doSessCommand POST "/buttondown" ()
@@ -589,8 +591,8 @@
 
 -- |Single tap on the touch screen at the given element's location.
 touchClick :: WebDriver wd => Element -> wd ()
-touchClick (Element e) = 
-  doSessCommand POST "/touch/click" . single "element" $ e 
+touchClick (Element e) =
+  doSessCommand POST "/touch/click" . single "element" $ e
 
 -- |Emulates pressing a finger down on the screen at the given location.
 touchDown :: WebDriver wd => (Int, Int) -> wd ()
@@ -612,7 +614,7 @@
 -- |Emulate finger-based touch scroll, starting from the given location relative
 -- to the given element.
 touchScrollFrom :: WebDriver wd => (Int, Int) -> Element -> wd ()
-touchScrollFrom (x, y) (Element e) = 
+touchScrollFrom (x, y) (Element e) =
   doSessCommand POST "/touch/scroll"
   . triple ("xoffset", "yoffset", "element")
   $ (x, y, e)
@@ -626,29 +628,29 @@
 touchLongClick :: WebDriver wd => Element -> wd ()
 touchLongClick (Element e) = doSessCommand POST "/touch/longclick"
                              . single "element" $ e
--- |Emulate a flick on the touch screen. The coordinates indicate x and y 
--- velocity, respectively. Use this function if you don't care where the 
+-- |Emulate a flick on the touch screen. The coordinates indicate x and y
+-- velocity, respectively. Use this function if you don't care where the
 -- flick starts.
 touchFlick :: WebDriver wd => (Int, Int) -> wd ()
 touchFlick = doSessCommand POST "/touch/flick" . pair ("xSpeed", "ySpeed")
 
 -- |Emulate a flick on the touch screen.
-touchFlickFrom :: WebDriver wd => 
+touchFlickFrom :: WebDriver wd =>
                   Int           -- ^ flick velocity
                   -> (Int, Int) -- ^ a location relative to the given element
                   -> Element    -- ^ the given element
                   -> wd ()
-touchFlickFrom s (x,y) (Element e) = 
+touchFlickFrom s (x,y) (Element e) =
   doSessCommand POST "/touch/flick" . object $
   ["xoffset" .= x
   ,"yoffset" .= y
   ,"speed"   .= s
   ,"element" .= e
   ]
-  
+
 -- |Get the current geographical location of the device.
 getLocation :: WebDriver wd => wd (Int, Int, Int)
-getLocation = doSessCommand GET "/location" () 
+getLocation = doSessCommand GET "/location" ()
               >>= parseTriple "latitude" "longitude" "altitude" "getLocation"
 
 -- |Set the current geographical location of the device.
@@ -660,11 +662,11 @@
 -- |Uploads a file from the local filesystem by its file path.
 uploadFile :: WebDriver wd => FilePath -> wd ()
 uploadFile path = uploadZipEntry =<< liftBase (readEntry [] path)
-  
+
 -- |Uploads a raw bytestring with associated file info.
 uploadRawFile :: WebDriver wd =>
                  FilePath          -- ^File path to use with this bytestring.
-                 -> Integer        -- ^Modification time 
+                 -> Integer        -- ^Modification time
                                    -- (in seconds since Unix epoch).
                  -> LBS.ByteString -- ^ The file contents as a lazy ByteString
                  -> wd ()
@@ -675,9 +677,8 @@
 -- This allows you to specify the exact details of
 -- the zip entry sent across network.
 uploadZipEntry :: WebDriver wd => Entry -> wd ()
-uploadZipEntry = doSessCommand POST "/file" . single "file" 
-                 . B64.encode . SBS.concat . toChunks 
-                 . fromArchive . (`addEntryToArchive` emptyArchive)
+uploadZipEntry = doSessCommand POST "/file" . single "file"
+                 . B64.encode . fromArchive . (`addEntryToArchive` emptyArchive)
 
 
 -- |Get the current number of keys in a web storage area.
@@ -693,9 +694,9 @@
 deleteAllKeys s = doStorageCommand DELETE s "" ()
 
 -- |An HTML 5 storage type
-data WebStorageType = LocalStorage | SessionStorage 
+data WebStorageType = LocalStorage | SessionStorage
                     deriving (Eq, Show, Ord, Bounded, Enum)
-          
+
 -- |Get the value associated with a key in the given web storage area.
 -- Unset keys result in empty strings, since the Web Storage spec
 -- makes no distinction between the empty string and an undefined value.
@@ -706,7 +707,7 @@
 setKey :: WebDriver wd => WebStorageType -> Text -> Text -> wd Text
 setKey s k v = doStorageCommand POST s "" . object $ ["key"   .= k,
                                                       "value" .= v ]
--- |Delete a key in the given web storage area. 
+-- |Delete a key in the given web storage area.
 deleteKey :: WebDriver wd => WebStorageType -> Text -> wd ()
 deleteKey s k = doStorageCommand POST s ("/key/" `T.append` k) ()
 
@@ -719,6 +720,6 @@
           SessionStorage -> "session_storage"
 
 
--- Moving this closer to the definition of Cookie seems to cause strange compile 
+-- Moving this closer to the definition of Cookie seems to cause strange compile
 -- errors, so I'm leaving it here for now.
 $( deriveToJSON (map C.toLower . drop 4) ''Cookie )
diff --git a/src/Test/WebDriver/Commands/Internal.hs b/src/Test/WebDriver/Commands/Internal.hs
--- a/src/Test/WebDriver/Commands/Internal.hs
+++ b/src/Test/WebDriver/Commands/Internal.hs
@@ -1,9 +1,9 @@
 {-# LANGUAGE OverloadedStrings, DeriveDataTypeable, GeneralizedNewtypeDeriving  #-}
 {-# OPTIONS_HADDOCK not-home #-}
--- |Internal functions used to implement the functions exported by 
--- "Test.WebDriver.Commands". These may be useful for implementing non-standard 
+-- |Internal functions used to implement the functions exported by
+-- "Test.WebDriver.Commands". These may be useful for implementing non-standard
 -- webdriver commands.
-module Test.WebDriver.Commands.Internal 
+module Test.WebDriver.Commands.Internal
        (-- * Low-level webdriver functions
          doCommand
         -- ** Commands with :sessionId URL parameter
@@ -41,7 +41,7 @@
 
 {- |An opaque identifier for a browser window -}
 newtype WindowHandle = WindowHandle Text
-                     deriving (Eq, Ord, Show, Read, 
+                     deriving (Eq, Ord, Show, Read,
                                FromJSON, ToJSON)
 instance Default WindowHandle where
   def = currentWindow
@@ -52,42 +52,42 @@
 currentWindow = WindowHandle "current"
 
 instance Exception NoSessionId
--- |A command requiring a session ID was attempted when no session ID was 
+-- |A command requiring a session ID was attempted when no session ID was
 -- available.
-newtype NoSessionId = NoSessionId String 
+newtype NoSessionId = NoSessionId String
                  deriving (Eq, Show, Typeable)
 
 -- |This a convenient wrapper around 'doCommand' that automatically prepends
 -- the session URL parameter to the wire command URL. For example, passing
 -- a URL of \"/refresh\" will expand to \"/session/:sessionId/refresh\", where
--- :sessionId is a URL parameter as described in 
+-- :sessionId is a URL parameter as described in
 -- <http://code.google.com/p/selenium/wiki/JsonWireProtocol>
-doSessCommand :: (WebDriver wd, ToJSON a, FromJSON b) => 
+doSessCommand :: (WebDriver wd, ToJSON a, FromJSON b) =>
                   RequestMethod -> Text -> a -> wd b
 doSessCommand method path args = do
   WDSession { wdSessId = mSessId } <- getSession
-  case mSessId of 
+  case mSessId of
       Nothing -> throwIO . NoSessionId $ msg
-        where 
+        where
           msg = "doSessCommand: No session ID found for relative URL "
                 ++ show path
-      Just (SessionId sId) -> doCommand method 
+      Just (SessionId sId) -> doCommand method
                               (T.concat ["/session/", sId, path]) args
 
 -- |A wrapper around 'doSessCommand' to create element URLs.
--- For example, passing a URL of "/active" will expand to 
+-- For example, passing a URL of "/active" will expand to
 -- \"/session/:sessionId/element/:id/active\", where :sessionId and :id are URL
 -- parameters as described in the wire protocol.
-doElemCommand :: (WebDriver wd, ToJSON a, FromJSON b) => 
+doElemCommand :: (WebDriver wd, ToJSON a, FromJSON b) =>
                   RequestMethod -> Element -> Text -> a -> wd b
 doElemCommand m (Element e) path a =
   doSessCommand m (T.concat ["/element/", e, path]) a
 
 -- |A wrapper around 'doSessCommand' to create window handle URLS.
 -- For example, passing a URL of \"/size\" will expand to
--- \"/session/:sessionId/window/:windowHandle/\", where :sessionId and 
+-- \"/session/:sessionId/window/:windowHandle/\", where :sessionId and
 -- :windowHandle are URL parameters as described in the wire protocol
-doWinCommand :: (WebDriver wd, ToJSON a, FromJSON b) => 
+doWinCommand :: (WebDriver wd, ToJSON a, FromJSON b) =>
                  RequestMethod -> WindowHandle -> Text -> a -> wd b
-doWinCommand m (WindowHandle w) path a = 
+doWinCommand m (WindowHandle w) path a =
   doSessCommand m (T.concat ["/window/", w, path]) a
diff --git a/src/Test/WebDriver/Commands/Wait.hs b/src/Test/WebDriver/Commands/Wait.hs
--- a/src/Test/WebDriver/Commands/Wait.hs
+++ b/src/Test/WebDriver/Commands/Wait.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, FlexibleContexts #-}
-module Test.WebDriver.Commands.Wait 
+module Test.WebDriver.Commands.Wait
        ( -- * Wait on expected conditions
          waitUntil, waitUntil'
        , waitWhile, waitWhile'
@@ -24,11 +24,13 @@
 
 instance Exception ExpectFailed
 -- |An exception representing the failure of an expected condition.
-data ExpectFailed = ExpectFailed deriving (Show, Eq, Typeable)
+data ExpectFailed = ExpectFailed String deriving (Show, Eq, Typeable)
 
 -- |throws 'ExpectFailed'. This is nice for writing your own abstractions.
-unexpected :: MonadBaseControl IO m => m a
-unexpected = throwIO ExpectFailed
+unexpected :: MonadBaseControl IO m =>
+              String -- ^ Reason why the expected condition failed.
+           -> m a
+unexpected = throwIO . ExpectFailed
 
 -- |An expected condition. This function allows you to express assertions in
 -- your explicit wait. This function raises 'ExpectFailed' if the given
@@ -36,22 +38,22 @@
 expect :: MonadBaseControl IO m => Bool -> m ()
 expect b
   | b         = return ()
-  | otherwise = unexpected
+  | otherwise = unexpected "Test.WebDriver.Commands.Wait.expect"
 
--- |Apply a monadic predicate to every element in a list, and 'expect' that 
+-- |Apply a monadic predicate to every element in a list, and 'expect' that
 -- at least one succeeds.
 expectAny :: MonadBaseControl IO m => (a -> m Bool) -> [a] -> m ()
 expectAny p xs = expect . or =<< mapM p xs
 
--- |Apply a monadic predicate to every element in a list, and 'expect' that all 
+-- |Apply a monadic predicate to every element in a list, and 'expect' that all
 -- succeed.
 expectAll :: MonadBaseControl IO m => (a -> m Bool) -> [a] -> m ()
 expectAll p xs = expect . and =<< mapM p xs
 
 -- |Wait until either the given action succeeds or the timeout is reached.
 -- The action will be retried every .5 seconds until no 'ExpectFailed' or
--- 'FailedCommand' 'NoSuchElement' exceptions occur. If the timeout is reached, 
--- then a 'Timeout' exception will be raised. The timeout value 
+-- 'FailedCommand' 'NoSuchElement' exceptions occur. If the timeout is reached,
+-- then a 'Timeout' exception will be raised. The timeout value
 -- is expressed in seconds.
 waitUntil :: SessionState m => Double -> m a -> m a
 waitUntil = waitUntil' 500000
@@ -67,7 +69,7 @@
       where
         handleFailedCommand (FailedCommand NoSuchElement _) = retry
         handleFailedCommand err = throwIO err
-                              
+
         handleExpectFailed (_ :: ExpectFailed) = retry
 
 -- |Like 'waitUntil', but retries the action until it fails or until the timeout
@@ -75,12 +77,12 @@
 waitWhile :: SessionState m => Double -> m a -> m ()
 waitWhile = waitWhile' 500000
 
--- |Like 'waitUntil'', but retries the action until it either fails or 
+-- |Like 'waitUntil'', but retries the action until it either fails or
 -- until the timeout is exceeded.
 waitWhile' :: SessionState m => Int -> Double -> m a -> m ()
 waitWhile' = wait' handler
   where
-    handler retry wd = do 
+    handler retry wd = do
       b <- (wd >> return True) `catches` [Handler handleFailedCommand
                                          ,Handler handleExpectFailed
                                          ]
@@ -88,25 +90,25 @@
       where
         handleFailedCommand (FailedCommand NoSuchElement _) = return False
         handleFailedCommand err = throwIO err
-                               
+
         handleExpectFailed (_ :: ExpectFailed) = return False
-    
-wait' :: SessionState m => 
+
+wait' :: SessionState m =>
          (m b -> m a -> m b) -> Int -> Double -> m a -> m b
 wait' handler waitAmnt t wd = waitLoop =<< liftBase getCurrentTime
   where timeout = realToFrac t
         waitLoop startTime = handler retry wd
-          where 
+          where
             retry = do
               now <- liftBase getCurrentTime
               if diffUTCTime now startTime >= timeout
-                then 
+                then
                   failedCommand Timeout "wait': explicit wait timed out."
-                else do 
+                else do
                   liftBase . threadDelay $ waitAmnt
                   waitLoop startTime
 
--- |Convenience function to catch 'FailedCommand' 'Timeout' exceptions 
+-- |Convenience function to catch 'FailedCommand' 'Timeout' exceptions
 -- and perform some action.
 --
 -- Example:
diff --git a/src/Test/WebDriver/Common/Profile.hs b/src/Test/WebDriver/Common/Profile.hs
--- a/src/Test/WebDriver/Common/Profile.hs
+++ b/src/Test/WebDriver/Common/Profile.hs
@@ -1,7 +1,7 @@
-{-# LANGUAGE CPP, TypeSynonymInstances, DeriveDataTypeable, FlexibleInstances, 
+{-# LANGUAGE CPP, TypeSynonymInstances, DeriveDataTypeable, FlexibleInstances,
              GeneralizedNewtypeDeriving, OverloadedStrings, FlexibleContexts #-}
 {-# OPTIONS_HADDOCK not-home #-}
--- |A type for profile preferences. These preference values are used by both 
+-- |A type for profile preferences. These preference values are used by both
 -- Firefox and Opera profiles.
 module Test.WebDriver.Common.Profile
        ( -- *Profiles and profile preferences
@@ -20,7 +20,7 @@
        , prepareZippedProfile, prepareZipArchive,
          prepareRawZip
          -- *Profile errors
-       , ProfileParseError(..) 
+       , ProfileParseError(..)
        ) where
 
 import System.Directory
@@ -49,16 +49,16 @@
 import Control.Monad.Base
 
 -- |This structure allows you to construct and manipulate profiles in pure code,
--- deferring execution of IO operations until the profile is \"prepared\". This 
--- type is shared by both Firefox and Opera profiles; when a distinction 
+-- deferring execution of IO operations until the profile is \"prepared\". This
+-- type is shared by both Firefox and Opera profiles; when a distinction
 -- must be made, the phantom type parameter is used to differentiate.
-data Profile b = Profile 
+data Profile b = Profile
                  { -- |A mapping from relative destination filepaths to source
-                   -- filepaths found on the filesystem. When the profile is 
+                   -- filepaths found on the filesystem. When the profile is
                    -- prepared, these source filepaths will be moved to their
                    -- destinations within the profile directory.
                    --
-                   -- Using the destination path as the key ensures that 
+                   -- Using the destination path as the key ensures that
                    -- there is one unique source path going to each
                    -- destination path.
                    profileFiles   :: HM.HashMap FilePath FilePath
@@ -69,14 +69,14 @@
                  }
                deriving (Eq, Show)
 
--- |Represents a profile that has been prepared for 
+-- |Represents a profile that has been prepared for
 -- network transmission. The profile cannot be modified in this form.
 newtype PreparedProfile b = PreparedProfile ByteString
   deriving (Eq, Show)
 
 instance FromJSON (PreparedProfile s) where
   parseJSON v = PreparedProfile <$> parseJSON v
-  
+
 instance ToJSON (PreparedProfile s) where
   toJSON (PreparedProfile s) = toJSON s
 
@@ -113,13 +113,13 @@
 
 instance ToPref Text where
   toPref = PrefString
-  
+
 instance ToPref String where
   toPref = toPref . pack
 
 instance ToPref Bool where
   toPref = PrefBool
-  
+
 instance ToPref Integer where
   toPref = PrefInteger
 
@@ -141,10 +141,10 @@
 
 instance ToPref Float where
   toPref = PrefDouble . realToFrac
-  
+
 instance (Integral a) => ToPref (Ratio a) where
   toPref = PrefDouble . realToFrac
-  
+
 instance (HasResolution r) => ToPref (Fixed r) where
   toPref = PrefDouble . realToFrac
 
@@ -164,7 +164,7 @@
 deletePref k p = onProfilePrefs p $ HM.delete k
 
 -- |Add a file to the profile directory. The first argument is the source
--- of the file on the local filesystem. The second argument is the destination 
+-- of the file on the local filesystem. The second argument is the destination
 -- as a path relative to a profile directory. Overwrites any file that
 -- previously pointed to the same destination
 addFile :: FilePath -> FilePath -> Profile b -> Profile b
@@ -186,35 +186,35 @@
 addExtension path = addFile path ("extensions" </> name)
   where (_, name) = splitFileName path
 
--- |Delete an existing extension from the profile. The string parameter 
--- should refer to an .xpi file or directory located within the extensions 
--- directory of the profile. This operation has no effect if the extension was 
+-- |Delete an existing extension from the profile. The string parameter
+-- should refer to an .xpi file or directory located within the extensions
+-- directory of the profile. This operation has no effect if the extension was
 -- never added to the profile.
 deleteExtension :: String -> Profile b -> Profile b
 deleteExtension name = deleteFile ("extensions" </> name)
 
--- |Determines if a profile contains the given extension. specified as an 
+-- |Determines if a profile contains the given extension. specified as an
 -- .xpi file or directory name
 hasExtension :: String -> Profile b -> Bool
 hasExtension name prof = hasFile ("extensions" </> name) prof
 
 
--- |Takes the union of two profiles. This is the union of their 'HashMap' 
+-- |Takes the union of two profiles. This is the union of their 'HashMap'
 -- fields.
 unionProfiles :: Profile b -> Profile b -> Profile b
-unionProfiles (Profile f1 p1) (Profile f2 p2) 
+unionProfiles (Profile f1 p1) (Profile f2 p2)
   = Profile (f1 `HM.union` f2) (p1 `HM.union` p2)
 
 -- |Modifies the 'profilePrefs' field of a profile.
 onProfilePrefs :: Profile b
-                  -> (HM.HashMap Text ProfilePref 
+                  -> (HM.HashMap Text ProfilePref
                       -> HM.HashMap Text ProfilePref)
                   -> Profile b
 onProfilePrefs (Profile hs hm) f = Profile hs (f hm)
 
 -- |Modifies the 'profileFiles' field of a profile
 onProfileFiles :: Profile b
-                  -> (HM.HashMap FilePath FilePath 
+                  -> (HM.HashMap FilePath FilePath
                       -> HM.HashMap FilePath FilePath)
                   -> Profile b
 onProfileFiles (Profile ls hm) f = Profile (f ls) hm
@@ -228,13 +228,13 @@
   oldWd <- getCurrentDirectory
   setCurrentDirectory path
   prepareZipArchive <$>
-    liftBase (addFilesToArchive [OptRecursive] 
+    liftBase (addFilesToArchive [OptRecursive]
               emptyArchive ["."])
     <* setCurrentDirectory oldWd
 
 -- |Prepare a zip file of a profile on disk for network transmission.
 -- This function is very efficient at loading large profiles from disk.
-prepareZippedProfile :: MonadBase IO m => 
+prepareZippedProfile :: MonadBase IO m =>
                         FilePath -> m (PreparedProfile a)
 prepareZippedProfile path = prepareRawZip <$> liftBase (LBS.readFile path)
 
@@ -245,4 +245,3 @@
 -- |Prepare a ByteString of raw zip data for network transmission
 prepareRawZip :: LBS.ByteString -> PreparedProfile a
 prepareRawZip = PreparedProfile . B64.encode . SBS.concat . LBS.toChunks
-
diff --git a/src/Test/WebDriver/Exceptions.hs b/src/Test/WebDriver/Exceptions.hs
--- a/src/Test/WebDriver/Exceptions.hs
+++ b/src/Test/WebDriver/Exceptions.hs
@@ -1,4 +1,4 @@
-module Test.WebDriver.Exceptions 
+module Test.WebDriver.Exceptions
        ( InvalidURL(..), NoSessionId(..), BadJSON(..)
        , HTTPStatusUnknown(..), HTTPConnError(..)
        , UnknownCommand(..), ServerError(..)
diff --git a/src/Test/WebDriver/Firefox/Profile.hs b/src/Test/WebDriver/Firefox/Profile.hs
--- a/src/Test/WebDriver/Firefox/Profile.hs
+++ b/src/Test/WebDriver/Firefox/Profile.hs
@@ -1,10 +1,10 @@
-{-# LANGUAGE CPP, OverloadedStrings, FlexibleContexts, 
-             GeneralizedNewtypeDeriving, EmptyDataDecls, 
+{-# LANGUAGE CPP, OverloadedStrings, FlexibleContexts,
+             GeneralizedNewtypeDeriving, EmptyDataDecls,
              ScopedTypeVariables #-}
 {-# OPTIONS_GHC -fno-warn-unused-do-bind #-} -- suppress warnings from attoparsec
 -- |A module for working with Firefox profiles. Firefox profiles are manipulated
--- in pure code and then \"prepared\" for network transmission. 
-module Test.WebDriver.Firefox.Profile 
+-- in pure code and then \"prepared\" for network transmission.
+module Test.WebDriver.Firefox.Profile
        ( -- * Profiles
          Firefox, Profile(..), PreparedProfile
        , defaultProfile
@@ -55,7 +55,7 @@
 
 -- |Default Firefox Profile, used when no profile is supplied.
 defaultProfile :: Profile Firefox
-defaultProfile = 
+defaultProfile =
   Profile HM.empty
   $ HM.fromList [("app.update.auto", PrefBool False)
                 ,("app.update.enabled", PrefBool False)
@@ -112,7 +112,7 @@
                 ,("dom.max_script_run_time", PrefInteger 30)
                 ]
     where
-#ifdef darwin_HOST_OS  
+#ifdef darwin_HOST_OS
       native_events = PrefBool False
 #else
       native_events = PrefBool True
@@ -123,38 +123,38 @@
 -- the 'Profile' will have no effect to the profile on disk.
 --
 -- To make automated browser run smoothly, preferences found in
--- 'defaultProfile' are automatically merged into the preferences of the on-disk-- profile. The on-disk profile's preference will override those found in the 
+-- 'defaultProfile' are automatically merged into the preferences of the on-disk-- profile. The on-disk profile's preference will override those found in the
 -- default profile.
 loadProfile :: MonadBaseControl IO m => FilePath -> m (Profile Firefox)
 loadProfile path = liftBase $ do
   unionProfiles defaultProfile <$> (Profile <$> getFiles <*> getPrefs)
   where
     userPrefFile = path </> "prefs" <.> "js"
-    
+
     getFiles = HM.fromList . map (id &&& (path </>)) . filter isNotIgnored
                <$> getDirectoryContents path
-      where isNotIgnored = (`notElem` 
+      where isNotIgnored = (`notElem`
                          [".", "..", "OfflineCache", "Cache"
                          ,"parent.lock", ".parentlock", ".lock"
                          ,userPrefFile])
-    
+
     getPrefs = HM.fromList <$> (parsePrefs =<< BS.readFile userPrefFile)
-      where parsePrefs s = either (throwIO . ProfileParseError) return 
+      where parsePrefs s = either (throwIO . ProfileParseError) return
                            $ parseOnly prefsParser s
 
 -- |Prepare a firefox profile for network transmission.
--- Internally, this function constructs a Firefox profile within a temp 
--- directory, archives it as a zip file, and then base64 encodes the zipped 
+-- Internally, this function constructs a Firefox profile within a temp
+-- directory, archives it as a zip file, and then base64 encodes the zipped
 -- data. The temporary directory is deleted afterwards.
 --
--- NOTE: because this function has to copy the profile files into a 
+-- NOTE: because this function has to copy the profile files into a
 -- a temp directory before zip archiving them, this operation is likely to be slow
--- for large profiles. In such a case, consider using 'prepareLoadedProfile_' or 
+-- for large profiles. In such a case, consider using 'prepareLoadedProfile_' or
 -- 'prepareZippedProfile' instead.
-prepareProfile :: MonadBaseControl IO m => 
+prepareProfile :: MonadBaseControl IO m =>
                   Profile Firefox -> m (PreparedProfile Firefox)
-prepareProfile Profile {profileFiles = files, profilePrefs = prefs} 
-  = liftBase $ do 
+prepareProfile Profile {profileFiles = files, profilePrefs = prefs}
+  = liftBase $ do
       tmpdir <- mkTemp
       mapM_ (installPath tmpdir) . HM.toList $ files
       installUserPrefs tmpdir
@@ -167,7 +167,7 @@
       if isDir
         then do
           createDirectoryIfMissing True dest `catch` ignoreIOException
-          FS.getDirectory src 
+          FS.getDirectory src
             >>= handle ignoreIOException . FS.copyTo_ dest
         else do
           let dir = takeDirectory dest
@@ -176,20 +176,20 @@
           copyFile src dest `catch` ignoreIOException
       where
         ignoreIOException :: IOException -> IO ()
-        ignoreIOException = print 
-    
+        ignoreIOException = print
+
     installUserPrefs d = LBS.writeFile (d </> "user" <.> "js") str
       where
         str = LBS.concat
-            . map (\(k, v) -> LBS.concat [ "user_pref(", encode k, 
-                                           ", ", encode v, ");\n"]) 
-            . HM.toList $ prefs  
+            . map (\(k, v) -> LBS.concat [ "user_pref(", encode k,
+                                           ", ", encode v, ");\n"])
+            . HM.toList $ prefs
 
 -- |Apply a function on a default profile, and
 -- prepare the result. The Profile passed to the handler function is
 -- the default profile used by sessions when Nothing is specified
-prepareTempProfile :: MonadBaseControl IO m => 
-                     (Profile Firefox -> Profile Firefox) 
+prepareTempProfile :: MonadBaseControl IO m =>
+                     (Profile Firefox -> Profile Firefox)
                      -> m (PreparedProfile Firefox)
 prepareTempProfile f = prepareProfile . f $ defaultProfile
 
@@ -202,11 +202,11 @@
                         -> (Profile Firefox -> Profile Firefox)
                         -> m (PreparedProfile Firefox)
 prepareLoadedProfile path f = liftM f (loadProfile path) >>= prepareProfile
-  
+
 -- firefox prefs.js parser
 
 prefsParser :: Parser [(Text, ProfilePref)]
-prefsParser = many1 $ do 
+prefsParser = many1 $ do
   padSpaces $ string "user_pref("
   k <- prefKey <?> "preference key"
   padSpaces $ char ','
@@ -215,20 +215,20 @@
   return (k,v)
   where
     prefKey = jstring
-    prefVal = do 
+    prefVal = do
       v <- value'
       case fromJSON v of
         Error str -> fail str
         Success p -> return p
-    
+
     padSpaces p = spaces >> p <* spaces
-    spaces = many (endOfLine <|> void space <|> void comment)      
+    spaces = many (endOfLine <|> void space <|> void comment)
       where
         comment = inlineComment <|> lineComment
         lineComment = char '#' *> manyTill anyChar endOfLine
         inlineComment = string "/*" *> manyTill anyChar (string "*/")
-        
-        
+
+
 mkTemp :: IO FilePath
 mkTemp = do
   d <- getTemporaryDirectory
diff --git a/src/Test/WebDriver/Internal.hs b/src/Test/WebDriver/Internal.hs
--- a/src/Test/WebDriver/Internal.hs
+++ b/src/Test/WebDriver/Internal.hs
@@ -1,11 +1,11 @@
 {-# LANGUAGE FlexibleContexts, OverloadedStrings, DeriveDataTypeable #-}
-module Test.WebDriver.Internal 
+module Test.WebDriver.Internal
        ( mkWDUri, mkRequest
        , handleHTTPErr, handleJSONErr, handleHTTPResp
-       
+
        , InvalidURL(..), HTTPStatusUnknown(..), HTTPConnError(..)
        , UnknownCommand(..), ServerError(..)
-       
+
        , FailedCommand(..), failedCommand, mkFailedCommandInfo
        , FailedCommandType(..), FailedCommandInfo(..), StackFrame(..)
        ) where
@@ -33,87 +33,88 @@
 import Control.Exception (Exception)
 import Data.Typeable (Typeable)
 import Data.List (isInfixOf)
-import Data.Maybe (fromJust, fromMaybe)
+import Data.Maybe (fromMaybe)
 import Data.String (fromString)
 import Data.Word (Word, Word8)
 
-mkWDUri :: (SessionState s) => String -> s URI  --todo: remove String :(
+mkWDUri :: (SessionState s) => String -> s URI
 mkWDUri path = do 
   WDSession{wdHost = host, 
-            wdPort = port
+            wdPort = port,
+            wdBasePath = basePath
            } <- getSession
   let urlStr   = "http://" ++ host ++ ":" ++ show port
-      relPath  = "/wd/hub" ++ path
+      relPath  = basePath ++ path
       mBaseURI = parseAbsoluteURI urlStr
       mRelURI  = parseRelativeReference relPath
   case (mBaseURI, mRelURI) of
-    (Nothing, _) -> throwIO $ InvalidURL urlStr 
+    (Nothing, _) -> throwIO $ InvalidURL urlStr
     (_, Nothing) -> throwIO $ InvalidURL relPath
-    (Just baseURI, Just relURI) -> return . fromJust $ relURI `relativeTo` baseURI
-  
-mkRequest :: (SessionState s, ToJSON a) => 
+    (Just baseURI, Just relURI) -> return $ relURI `relativeTo` baseURI
+
+mkRequest :: (SessionState s, ToJSON a) =>
              [Header] -> RequestMethod -> Text -> a -> s (Response ByteString)
 mkRequest headers method path args = do
   uri <- mkWDUri (T.unpack path)
   let body = case toJSON args of
         Array v | V.null v -> ""   --an ugly corner case to allow empty requests
-        other              -> encode other 
+        other              -> encode other
       req = Request { rqURI = uri             --todo: normalization of headers
                     , rqMethod = method
                     , rqBody = body
-                    , rqHeaders = headers ++ [ Header HdrAccept 
+                    , rqHeaders = headers ++ [ Header HdrAccept
                                                "application/json;charset=UTF-8"
-                                             , Header HdrContentType 
+                                             , Header HdrContentType
                                                "application/json;charset=UTF-8"
-                                             , Header HdrContentLength 
-                                               . show . BS.length $ body 
+                                             , Header HdrContentLength
+                                               . show . BS.length $ body
                                              ]
                     }
   r <- liftBase (simpleHTTP req) >>= either (throwIO . HTTPConnError) return
   return r
 
 handleHTTPErr :: SessionState s => Response ByteString -> s ()
-handleHTTPErr r@Response{rspBody = body, rspCode = code, rspReason = reason} = 
-  case code of 
+handleHTTPErr r@Response{rspBody = body, rspCode = code, rspReason = reason} =
+  case code of
     (4,_,_)  -> err UnknownCommand
-    (5,_,_)  -> 
+    (5,_,_)  ->
       case findHeader HdrContentType r of
         Just ct
-          | "application/json;" `isInfixOf` ct -> parseJSON' body 
-                                                  >>= handleJSONErr       
+          | "application/json;" `isInfixOf` ct -> parseJSON' body
+                                                  >>= handleJSONErr
           | otherwise -> err ServerError
-        Nothing -> 
+        Nothing ->
           err (ServerError . ("Missing content type. Server response: "++))
 
     (2,_,_)  -> return ()
     (3,0,2)  -> return ()
     _        -> err (HTTPStatusUnknown code)
-    where 
+    where
       err errType = throwIO $ errType reason
-      
+
 handleHTTPResp ::  (SessionState s, FromJSON a) => Response ByteString -> s a
-handleHTTPResp resp@Response{rspBody = body, rspCode = code} = 
+handleHTTPResp resp@Response{rspBody = body, rspCode = code} =
   case code of
     (2,0,4) -> returnEmptyArray
-    (3,0,2) -> fromJSON' =<< maybe statusErr (return . String . fromString) 
+    (3,0,2) -> fromJSON' =<< maybe statusErr (return . String . fromString)
                  (findHeader HdrLocation resp)
-               where 
-                 statusErr = throwIO . HTTPStatusUnknown code  
+               where
+                 statusErr = throwIO . HTTPStatusUnknown code
                              $ (BS.unpack body)
-    other 
+    other
       | BS.null body -> returnEmptyArray
       | otherwise -> fromJSON' . rspVal =<< parseJSON' body
   where
     returnEmptyArray = fromJSON' emptyArray
-    
+
 handleJSONErr :: SessionState s => WDResponse -> s ()
 handleJSONErr WDResponse{rspStatus = 0} = return ()
 handleJSONErr WDResponse{rspVal = val, rspStatus = status} = do
   sess <- getSession
   errInfo <- fromJSON' val
-  let screen = B64.decodeLenient <$> errScreen errInfo 
-      errInfo' = errInfo { errSess = sess 
-                         , errScreen = screen } 
+  let screen = B64.decodeLenient <$> errScreen errInfo
+      errInfo' = errInfo { errSess = sess
+                         , errScreen = screen }
       e errType = throwIO $ FailedCommand errType errInfo'
   case status of
     7   -> e NoSuchElement
@@ -135,7 +136,7 @@
     28  -> e ScriptTimeout
     29  -> e InvalidElementCoordinates
     30  -> e IMENotAvailable
-    31  -> e IMEEngineActivationFailed        
+    31  -> e IMEEngineActivationFailed
     32  -> e InvalidSelector
     34  -> e MoveTargetOutOfBounds
     51  -> e InvalidXPathSelector
@@ -149,7 +150,7 @@
                              , rspVal    :: Value
                              }
                   deriving (Eq, Show)
-                           
+
 instance FromJSON WDResponse where
   parseJSON (Object o) = WDResponse <$> o .:? "sessionId" .!= Nothing
                                     <*> o .: "status"
@@ -159,7 +160,7 @@
 
 instance Exception InvalidURL
 -- |An invalid URL was given
-newtype InvalidURL = InvalidURL String 
+newtype InvalidURL = InvalidURL String
                 deriving (Eq, Show, Typeable)
 
 instance Exception HTTPStatusUnknown
@@ -174,7 +175,7 @@
 
 instance Exception UnknownCommand
 -- |A command was sent to the WebDriver server that it didn't recognize.
-newtype UnknownCommand = UnknownCommand String 
+newtype UnknownCommand = UnknownCommand String
                     deriving (Eq, Show, Typeable)
 
 instance Exception ServerError
@@ -217,12 +218,12 @@
                        deriving (Eq, Ord, Enum, Bounded, Show)
 
 -- |Detailed information about the failed command provided by the server.
-data FailedCommandInfo = 
+data FailedCommandInfo =
   FailedCommandInfo { -- |The error message.
                       errMsg    :: String
-                      -- |The session associated with 
+                      -- |The session associated with
                       -- the exception.
-                    , errSess :: WDSession 
+                    , errSess :: WDSession
                       -- |A screen shot of the focused window
                       -- when the exception occured,
                       -- if provided.
@@ -238,8 +239,8 @@
 -- |Provides a readable printout of the error information, useful for
 -- logging.
 instance Show FailedCommandInfo where
-  show i = showChar '\n' 
-           . showString "Session: " . sess 
+  show i = showChar '\n'
+           . showString "Session: " . sess
            . showChar '\n'
            . showString className . showString ": " . showString (errMsg i)
            . showChar '\n'
@@ -247,8 +248,8 @@
            $ ""
     where
       className = fromMaybe "<unknown exception>" . errClass $ i
-      
-      sess = showString sessId . showString " at " 
+
+      sess = showString sessId . showString " at "
              . showString host . showChar ':' . shows port
         where
           sessId = case msid of
@@ -264,12 +265,12 @@
   return $ FailedCommandInfo {errMsg = m , errSess = sess , errScreen = Nothing
                              , errClass  = Nothing , errStack  = [] }
 
--- |Convenience function to throw a 'FailedCommand' locally with no server-side 
+-- |Convenience function to throw a 'FailedCommand' locally with no server-side
 -- info present.
 failedCommand :: SessionState s => FailedCommandType -> String -> s a
 failedCommand t m = throwIO . FailedCommand t =<< mkFailedCommandInfo m
 
--- |An individual stack frame from the stack trace provided by the server 
+-- |An individual stack frame from the stack trace provided by the server
 -- during a FailedCommand.
 data StackFrame = StackFrame { sfFileName   :: String
                              , sfClassName  :: String
@@ -280,7 +281,7 @@
 
 
 instance Show StackFrame where
-  show f = showString (sfClassName f) . showChar '.' 
+  show f = showString (sfClassName f) . showChar '.'
            . showString (sfMethodName f) . showChar ' '
            . showParen True ( showString (sfFileName f) . showChar ':'
                               . shows (sfLineNumber f))
@@ -288,13 +289,13 @@
 
 
 instance FromJSON FailedCommandInfo where
-  parseJSON (Object o) = 
+  parseJSON (Object o) =
     FailedCommandInfo <$> (req "message" >>= maybe (return "") return)
                       <*> pure undefined
                       <*> opt "screen"     Nothing
                       <*> opt "class"      Nothing
                       <*> opt "stackTrace" []
-    where req :: FromJSON a => Text -> Parser a 
+    where req :: FromJSON a => Text -> Parser a
           req = (o .:)            --required key
           opt :: FromJSON a => Text -> a -> Parser a
           opt k d = o .:? k .!= d --optional key
@@ -310,5 +311,3 @@
           reqStr :: Text -> Parser String
           reqStr k = req k >>= maybe (return "") return
   parseJSON v = typeMismatch "StackFrame" v
-
-
diff --git a/src/Test/WebDriver/JSON.hs b/src/Test/WebDriver/JSON.hs
--- a/src/Test/WebDriver/JSON.hs
+++ b/src/Test/WebDriver/JSON.hs
@@ -2,10 +2,10 @@
 -- |A collection of convenience functions for using and parsing JSON values
 -- within 'WD'. All monadic parse errors are converted to asynchronous
 -- 'BadJSON' exceptions.
--- 
+--
 -- These functions are used internally to implement webdriver commands, and may
 -- be useful for implementing non-standard commands.
-module Test.WebDriver.JSON 
+module Test.WebDriver.JSON
        ( -- * Access a JSON object key
          (!:)
          -- * Conversion from JSON within WD
@@ -14,16 +14,16 @@
        , parseJSON', fromJSON'
          -- * Tuple functions
          -- |Convenience functions for working with tuples.
-         
+
          -- ** JSON object constructors
        , single, pair, triple
          -- ** Extracting JSON objects into tuples
-       , parsePair, parseTriple 
+       , parsePair, parseTriple
          -- * Conversion from parser results to WD
          -- |These functions are used to implement the other functions
-         -- in this module, and could be used to implement other JSON 
+         -- in this module, and could be used to implement other JSON
          -- convenience functions
-       , apResultToWD, aesonResultToWD 
+       , apResultToWD, aesonResultToWD
          -- * Parse exception
        , BadJSON(..)
        ) where
@@ -43,21 +43,21 @@
 
 instance Exception BadJSON
 -- |An error occured when parsing a JSON value.
-newtype BadJSON = BadJSON String 
+newtype BadJSON = BadJSON String
              deriving (Eq, Show, Typeable)
 
 -- |Construct a singleton JSON 'object' from a key and value.
 single :: ToJSON a => Text -> a -> Value
 single a x = object [a .= x]
 
--- |Construct a 2-element JSON 'object' from a pair of keys and a pair of 
--- values. 
+-- |Construct a 2-element JSON 'object' from a pair of keys and a pair of
+-- values.
 pair :: (ToJSON a, ToJSON b) => (Text,Text) -> (a,b) -> Value
 pair (a,b) (x,y) = object [a .= x, b .= y]
 
 -- |Construct a 3-element JSON 'object' from a triple of keys and a triple of
 -- values.
-triple :: (ToJSON a, ToJSON b, ToJSON c) => 
+triple :: (ToJSON a, ToJSON b, ToJSON c) =>
           (Text,Text,Text) -> (a,b,c) -> Value
 triple (a,b,c) (x,y,z) = object [a .= x, b.= y, c .= z]
 
@@ -79,25 +79,25 @@
 -- |Parse a JSON 'Object' as a pair. The first two string arguments specify the
 -- keys to extract from the object. The third string is the name of the
 -- calling function, for better error reporting.
-parsePair :: (MonadBaseControl IO wd, FromJSON a, FromJSON b) => 
+parsePair :: (MonadBaseControl IO wd, FromJSON a, FromJSON b) =>
              String -> String -> String -> Value -> wd (a, b)
-parsePair a b funcName v = 
+parsePair a b funcName v =
   case v of
     Object o -> (,) <$> o !: fromString a <*> o !: fromString b
-    _        -> throwIO . BadJSON $ funcName ++ 
-                ": cannot parse non-object JSON response as a (" ++ a  
+    _        -> throwIO . BadJSON $ funcName ++
+                ": cannot parse non-object JSON response as a (" ++ a
                 ++ ", " ++ b ++ ") pair" ++ ")"
 
 
 -- |Parse a JSON Object as a triple. The first three string arguments
--- specify the keys to extract from the object. The fourth string is the name 
+-- specify the keys to extract from the object. The fourth string is the name
 -- of the calling function, for better error reporting.
 parseTriple :: (MonadBaseControl IO wd, FromJSON a, FromJSON b, FromJSON c) =>
                String -> String -> String ->  String -> Value -> wd (a, b, c)
-parseTriple a b c funcName v = 
+parseTriple a b c funcName v =
   case v of
-    Object o -> (,,) <$> o !: fromString a 
-                     <*> o !: fromString b 
+    Object o -> (,,) <$> o !: fromString a
+                     <*> o !: fromString b
                      <*> o !: fromString c
     _        -> throwIO . BadJSON $ funcName ++
                 ": cannot parse non-object JSON response as a (" ++ a
@@ -105,7 +105,7 @@
 
 
 
--- |Convert an attoparsec parser result to 'WD'. 
+-- |Convert an attoparsec parser result to 'WD'.
 apResultToWD :: (MonadBaseControl IO wd, FromJSON a) => AP.Result Value -> wd a
 apResultToWD p = case p of
   Done _ res -> fromJSON' res
diff --git a/src/Test/WebDriver/Monad.hs b/src/Test/WebDriver/Monad.hs
--- a/src/Test/WebDriver/Monad.hs
+++ b/src/Test/WebDriver/Monad.hs
@@ -5,7 +5,7 @@
        )where
 
 import Test.WebDriver.Classes
-import Test.WebDriver.Commands 
+import Test.WebDriver.Commands
 import Test.WebDriver.Capabilities
 import Test.WebDriver.Internal
 
@@ -19,7 +19,7 @@
 import Control.Monad.CatchIO (MonadCatchIO)
 import Control.Applicative
 
-{- |A monadic interface to the WebDriver server. This monad is a simple, strict 
+{- |A monadic interface to the WebDriver server. This monad is a simple, strict
 layer over 'IO', threading session information between sequential commands
 -}
 newtype WD a = WD (StateT WDSession IO a)
@@ -30,8 +30,8 @@
 
 instance MonadBaseControl IO WD where
   data StM WD a = StWD {unStWD :: StM (StateT WDSession IO) a}
-  
-  liftBaseWith f = WD $  
+
+  liftBaseWith f = WD $
     liftBaseWith $ \runInBase ->
     f (\(WD sT) -> liftM StWD . runInBase $ sT)
 
@@ -47,7 +47,7 @@
     handleHTTPErr r
     handleHTTPResp r
 
--- |Executes a 'WD' computation within the 'IO' monad, using the given 
+-- |Executes a 'WD' computation within the 'IO' monad, using the given
 -- 'WDSession'.
 runWD :: WDSession -> WD a -> IO a
 runWD sess (WD wd) = evalStateT wd sess
@@ -63,12 +63,12 @@
 withSession :: WDSession -> WD a -> WD a
 withSession s' (WD wd) = WD . lift $ evalStateT wd s'
 
--- |A finalizer ensuring that the session is always closed at the end of 
+-- |A finalizer ensuring that the session is always closed at the end of
 -- the given 'WD' action, regardless of any exceptions.
-finallyClose:: WebDriver wd => wd a -> wd a 
+finallyClose:: WebDriver wd => wd a -> wd a
 finallyClose wd = closeOnException wd <* closeSession
 
--- |A variant of 'finallyClose' that only closes the session when an 
+-- |A variant of 'finallyClose' that only closes the session when an
 -- asynchronous exception is thrown, but otherwise leaves the session open
 -- if the action was successful.
 closeOnException :: WebDriver wd => wd a -> wd a
diff --git a/src/Test/WebDriver/Types.hs b/src/Test/WebDriver/Types.hs
--- a/src/Test/WebDriver/Types.hs
+++ b/src/Test/WebDriver/Types.hs
@@ -1,17 +1,17 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable,
-    TemplateHaskell, OverloadedStrings, ExistentialQuantification, 
-    MultiParamTypeClasses, TypeFamilies, 
+    TemplateHaskell, OverloadedStrings, ExistentialQuantification,
+    MultiParamTypeClasses, TypeFamilies,
     RecordWildCards
   #-}
 {-# OPTIONS_HADDOCK not-home #-}
-module Test.WebDriver.Types 
+module Test.WebDriver.Types
        ( -- * WebDriver sessions
          WD(..), WDSession(..), defaultSession, SessionId(..)
          -- * Capabilities and configuration
        , Capabilities(..), defaultCaps, allCaps
        , Platform(..), ProxyType(..)
          -- ** Browser-specific configuration
-       , Browser(..), 
+       , Browser(..),
          -- ** Default settings for browsers
          firefox, chrome, ie, opera, iPhone, iPad, android
        , LogPref(..)
@@ -39,13 +39,3 @@
 import Test.WebDriver.Commands
 import Test.WebDriver.Exceptions
 import Test.WebDriver.Capabilities
-
-  
-
-
-
-
-  
-
-
-
diff --git a/webdriver.cabal b/webdriver.cabal
--- a/webdriver.cabal
+++ b/webdriver.cabal
@@ -1,5 +1,5 @@
 Name: webdriver
-Version: 0.4
+Version: 0.5
 Cabal-Version: >= 1.6
 License: BSD3
 License-File: LICENSE
@@ -11,29 +11,29 @@
 Build-type: Simple
 Extra-source-files: README.md, TODO, CHANGELOG.md, .ghci
 Description:
-        A Selenium WebDriver client for Haskell. 
-        You can use it to automate browser sessions 
+        A Selenium WebDriver client for Haskell.
+        You can use it to automate browser sessions
         for testing, system administration, etc.
         .
         For more information about Selenium itself, see
         <http://seleniumhq.org/>
         .
         To find out what's been changed in this version and others,
-        see the change log at 
+        see the change log at
         <https://github.com/kallisti-dev/hs-webdriver/blob/master/CHANGELOG.md>
 
 source-repository head
   type: git
-  location: git://github.com/kallisti-dev/hs-webdriver.git  
+  location: git://github.com/kallisti-dev/hs-webdriver.git
 
 library
   hs-source-dirs: src
-  ghc-options: -Wall    
+  ghc-options: -Wall
   build-depends:   base == 4.*
                  , aeson >= 0.4 && < 0.7
                  , HTTP >= 4000.1 && < 4000.3
                  , mtl >= 2.0 && < 2.2
-                 , network == 2.*
+                 , network == 2.4.*
                  , bytestring == 0.9.*
                  , text >= 0.7 && < 0.12
                  , time == 1.*
@@ -51,7 +51,7 @@
                  , filesystem-trees >= 0.1.0.2 && < 0.2
                  , data-default >= 0.2 && < 1.0
                  , temporary >= 1.0 && < 2.0
-                 , base64-bytestring == 0.1.*
+                 , base64-bytestring >= 1.0 && < 1.1
                  , cond >= 0.3 && < 0.5
 
   exposed-modules: Test.WebDriver
