diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, Alp Mestanogullari
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Alp Mestanogullari nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/auth-combinator/auth-combinator.hs b/auth-combinator/auth-combinator.hs
new file mode 100644
--- /dev/null
+++ b/auth-combinator/auth-combinator.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+import Data.Aeson
+import Data.ByteString (ByteString)
+import Data.Text (Text)
+import GHC.Generics
+import Network.HTTP.Types
+import Network.Wai
+import Network.Wai.Handler.Warp
+import Servant
+import Servant.Server.Internal
+
+-- Pretty much stolen/adapted from
+-- https://github.com/haskell-servant/HaskellSGMeetup2015/blob/master/examples/authentication-combinator/AuthenticationCombinator.hs
+
+type DBLookup = ByteString -> IO Bool
+
+isGoodCookie :: DBLookup
+isGoodCookie = return . (== "good password")
+
+data AuthProtected
+
+instance HasServer rest => HasServer (AuthProtected :> rest) where
+  type ServerT (AuthProtected :> rest) m = ServerT rest m
+
+  route Proxy a request respond =
+    case lookup "Cookie" (requestHeaders request) of
+      Nothing -> respond . succeedWith $ responseLBS status401 [] "Missing auth header."
+      Just v  -> do
+        authGranted <- isGoodCookie v
+        if authGranted
+          then route (Proxy :: Proxy rest) a request respond
+          else respond . succeedWith $ responseLBS status403 [] "Invalid cookie."
+
+type PrivateAPI = Get '[JSON] [PrivateData]
+
+type PublicAPI = Get '[JSON] [PublicData]
+
+type API = "private" :> AuthProtected :> PrivateAPI
+      :<|> PublicAPI
+
+newtype PrivateData = PrivateData { ssshhh :: Text }
+  deriving (Eq, Show, Generic)
+
+instance ToJSON PrivateData
+
+newtype PublicData = PublicData { somedata :: Text }
+  deriving (Eq, Show, Generic)
+
+instance ToJSON PublicData
+
+api :: Proxy API
+api = Proxy
+
+server :: Server API
+server = return prvdata :<|> return pubdata
+
+  where prvdata = [PrivateData "this is a secret"]
+        pubdata = [PublicData "this is a public piece of data"]
+
+main :: IO ()
+main = run 8080 (serve api server)
+
+{- Sample session:
+$ curl http://localhost:8080/
+[{"somedata":"this is a public piece of data"}]
+$ curl http://localhost:8080/private
+Missing auth header.
+$ curl -H "Cookie: good password" http://localhost:8080/private
+[{"ssshhh":"this is a secret"}]
+$ curl -H "Cookie: bad password" http://localhost:8080/private
+Invalid cookie.
+-}
diff --git a/hackage/hackage.hs b/hackage/hackage.hs
new file mode 100644
--- /dev/null
+++ b/hackage/hackage.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE OverloadedStrings #-}
+import Control.Applicative
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Either
+import Data.Aeson
+import Data.Monoid
+import Data.Proxy
+import Data.Text (Text)
+import GHC.Generics
+import Servant.API
+import Servant.Client
+
+import qualified Data.Text    as T
+import qualified Data.Text.IO as T
+
+type HackageAPI =
+       "users" :> Get '[JSON] [UserSummary]
+  :<|> "user" :> Capture "username" Username :> Get '[JSON] UserDetailed
+  :<|> "packages" :> Get '[JSON] [Package]
+
+type Username = Text
+
+data UserSummary = UserSummary
+  { summaryUsername :: Username
+  , summaryUserid   :: Int
+  } deriving (Eq, Show)
+
+instance FromJSON UserSummary where
+  parseJSON (Object o) =
+    UserSummary <$> o .: "username"
+                <*> o .: "userid"
+
+  parseJSON _ = mzero
+
+type Group = Text
+
+data UserDetailed = UserDetailed
+  { username :: Username
+  , userid   :: Int
+  , groups   :: [Group]
+  } deriving (Eq, Show, Generic)
+
+instance FromJSON UserDetailed
+
+newtype Package = Package { packageName :: Text }
+  deriving (Eq, Show, Generic)
+
+instance FromJSON Package
+
+hackageAPI :: Proxy HackageAPI
+hackageAPI = Proxy
+
+getUsers :: EitherT ServantError IO [UserSummary]
+getUser :: Username -> EitherT ServantError IO UserDetailed
+getPackages :: EitherT ServantError IO [Package]
+getUsers :<|> getUser :<|> getPackages = client hackageAPI $ BaseUrl Http "hackage.haskell.org" 80
+
+main :: IO ()
+main = print =<< uselessNumbers
+
+uselessNumbers :: IO (Either ServantError ())
+uselessNumbers = runEitherT $ do
+  users <- getUsers
+  liftIO . putStrLn $ show (length users) ++ " users"
+
+  user <- liftIO $ do
+    putStrLn "Enter a valid hackage username"
+    T.getLine
+  userDetailed <- (getUser user)
+  liftIO . T.putStrLn $ user <> " maintains " <> T.pack (show (length $ groups userDetailed)) <> " packages"
+
+  packages <- getPackages
+  let monadPackages = filter (isMonadPackage . packageName) packages
+  liftIO . putStrLn $ show (length monadPackages) ++ " monad packages"
+
+  where isMonadPackage = T.isInfixOf "monad"
diff --git a/servant-examples.cabal b/servant-examples.cabal
new file mode 100644
--- /dev/null
+++ b/servant-examples.cabal
@@ -0,0 +1,95 @@
+name:                servant-examples
+version:             0.4.2
+synopsis:            Example programs for servant
+description:         Example programs for servant,
+                     showcasing solutions to common needs.
+homepage:            http://haskell-servant.github.io/
+license:             BSD3
+license-file:        LICENSE
+author:              Alp Mestanogullari
+maintainer:          alpmestan@gmail.com
+-- copyright:
+category:            Web
+build-type:          Simple
+cabal-version:       >=1.10
+
+executable tutorial
+  main-is: tutorial.hs
+  other-modules: T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
+  build-depends:
+      aeson >= 0.8
+    , base >= 4.7 && < 5
+    , bytestring
+    , directory
+    , either
+    , http-types
+    , js-jquery
+    , lucid
+    , random
+    , servant == 0.4.*
+    , servant-docs == 0.4.*
+    , servant-jquery == 0.4.*
+    , servant-lucid == 0.4.*
+    , servant-server == 0.4.*
+    , text
+    , time
+    , transformers
+    , wai
+    , warp
+  hs-source-dirs: tutorial
+  default-language: Haskell2010
+
+executable t8-main
+  main-is: t8-main.hs
+  hs-source-dirs: tutorial
+  default-language: Haskell2010
+  build-depends:
+      aeson
+    , base >= 4.7 && < 5
+    , either
+    , servant == 0.4.*
+    , servant-client == 0.4.*
+    , servant-server == 0.4.*
+    , wai
+
+executable hackage
+  main-is:             hackage.hs
+  build-depends:
+      aeson >= 0.8
+    , base >=4.7 && < 5
+    , either
+    , servant == 0.4.*
+    , servant-client == 0.4.*
+    , text
+    , transformers
+  hs-source-dirs:      hackage
+  default-language:    Haskell2010
+
+executable wai-middleware
+  main-is: wai-middleware.hs
+  build-depends:
+      aeson >= 0.8
+    , base >= 4.7 && < 5
+    , servant == 0.4.*
+    , servant-server == 0.4.*
+    , text
+    , wai
+    , wai-extra
+    , warp
+  hs-source-dirs: wai-middleware
+  default-language: Haskell2010
+
+executable auth-combinator
+  main-is: auth-combinator.hs
+  build-depends:
+      aeson >= 0.8
+    , base >= 4.7 && < 5
+    , bytestring
+    , http-types
+    , servant == 0.4.*
+    , servant-server == 0.4.*
+    , text
+    , wai
+    , warp
+  hs-source-dirs: auth-combinator
+  default-language: Haskell2010
diff --git a/tutorial/T1.hs b/tutorial/T1.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T1.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+module T1 where
+
+import Data.Aeson
+import Data.Time.Calendar
+import GHC.Generics
+import Network.Wai
+import Servant
+
+data User = User
+  { name :: String
+  , age :: Int
+  , email :: String
+  , registration_date :: Day
+  } deriving (Eq, Show, Generic)
+
+-- orphan ToJSON instance for Day. necessary to derive one for User
+instance ToJSON Day where
+  -- display a day in YYYY-mm-dd format
+  toJSON d = toJSON (showGregorian d)
+
+instance ToJSON User
+
+type UserAPI = "users" :> Get '[JSON] [User]
+
+users :: [User]
+users = 
+  [ User "Isaac Newton"    372 "isaac@newton.co.uk" (fromGregorian 1683  3 1)
+  , User "Albert Einstein" 136 "ae@mc2.org"         (fromGregorian 1905 12 1)
+  ]
+
+userAPI :: Proxy UserAPI
+userAPI = Proxy
+
+server :: Server UserAPI
+server = return users
+
+app :: Application
+app = serve userAPI server
diff --git a/tutorial/T10.hs b/tutorial/T10.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T10.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+module T10 where
+
+import Data.ByteString.Lazy (ByteString)
+import Data.Text.Lazy (pack)
+import Data.Text.Lazy.Encoding (encodeUtf8)
+import Network.HTTP.Types
+import Network.Wai
+import Servant
+import Servant.Docs
+import qualified T3
+
+type DocsAPI = T3.API :<|> Raw
+
+instance ToCapture (Capture "x" Int) where
+  toCapture _ = DocCapture "x" "(integer) position on the x axis"
+
+instance ToCapture (Capture "y" Int) where
+  toCapture _ = DocCapture "y" "(integer) position on the y axis"
+
+instance ToSample T3.Position T3.Position where
+  toSample _ = Just (T3.Position 3 14)
+
+instance ToParam (QueryParam "name" String) where
+  toParam _ =
+    DocQueryParam "name"
+                  ["Alp", "John Doe", "..."]
+                  "Name of the person to say hello to."
+                  Normal
+
+instance ToSample T3.HelloMessage T3.HelloMessage where
+  toSamples _ =
+    [ ("When a value is provided for 'name'", T3.HelloMessage "Hello, Alp")
+    , ("When 'name' is not specified", T3.HelloMessage "Hello, anonymous coward")
+    ]
+
+ci :: T3.ClientInfo
+ci = T3.ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"]
+
+instance ToSample T3.ClientInfo T3.ClientInfo where
+  toSample _ = Just ci
+
+instance ToSample T3.Email T3.Email where
+  toSample _ = Just (T3.emailForClient ci)
+
+api :: Proxy DocsAPI
+api = Proxy
+
+docsBS :: ByteString
+docsBS = encodeUtf8
+       . pack
+       . markdown
+       $ docsWithIntros [intro] T3.api
+
+  where intro = DocIntro "Welcome" ["This is our super webservice's API.", "Enjoy!"]
+
+server :: Server DocsAPI
+server = T3.server :<|> serveDocs
+
+  where serveDocs _ respond =
+          respond $ responseLBS ok200 [plain] docsBS
+
+        plain = ("Content-Type", "text/plain")
+
+app :: Application
+app = serve api server
diff --git a/tutorial/T2.hs b/tutorial/T2.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T2.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+module T2 where
+
+import Data.Aeson
+import Data.Time.Calendar
+import GHC.Generics
+import Network.Wai
+import Servant
+
+data User = User
+  { name :: String
+  , age :: Int
+  , email :: String
+  , registration_date :: Day
+  } deriving (Eq, Show, Generic)
+
+-- orphan ToJSON instance for Day. necessary to derive one for User
+instance ToJSON Day where
+  -- display a day in YYYY-mm-dd format
+  toJSON d = toJSON (showGregorian d)
+
+instance ToJSON User
+
+type UserAPI = "users" :> Get '[JSON] [User]
+          :<|> "albert" :> Get '[JSON] User
+          :<|> "isaac" :> Get '[JSON] User
+
+isaac :: User
+isaac = User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
+
+albert :: User
+albert = User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
+
+users :: [User]
+users = [isaac, albert]
+
+userAPI :: Proxy UserAPI
+userAPI = Proxy
+
+server :: Server UserAPI
+server = return users
+    :<|> return albert
+    :<|> return isaac
+
+app :: Application
+app = serve userAPI server
diff --git a/tutorial/T3.hs b/tutorial/T3.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T3.hs
@@ -0,0 +1,84 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+module T3 where
+
+import Control.Monad.Trans.Either
+import Data.Aeson
+import Data.List
+import GHC.Generics
+import Network.Wai
+import Servant
+
+data Position = Position
+  { x :: Int
+  , y :: Int
+  } deriving (Show, Generic)
+
+instance FromJSON Position
+instance ToJSON Position
+
+newtype HelloMessage = HelloMessage { msg :: String }
+  deriving (Show, Generic)
+
+instance FromJSON HelloMessage
+instance ToJSON HelloMessage
+
+data ClientInfo = ClientInfo
+  { name :: String
+  , email :: String
+  , age :: Int
+  , interested_in :: [String]
+  } deriving (Show, Generic)
+
+instance FromJSON ClientInfo
+instance ToJSON ClientInfo
+
+data Email = Email
+  { from :: String
+  , to :: String
+  , subject :: String
+  , body :: String
+  } deriving (Show, Generic)
+
+instance FromJSON Email
+instance ToJSON Email
+
+emailForClient :: ClientInfo -> Email
+emailForClient c = Email from' to' subject' body'
+
+  where from'    = "great@company.com"
+        to'      = email c
+        subject' = "Hey " ++ name c ++ ", we miss you!"
+        body'    = "Hi " ++ name c ++ ",\n\n"
+                ++ "Since you've recently turned " ++ show (age c)
+                ++ ", have you checked out our latest "
+                ++ intercalate ", " (interested_in c)
+                ++ " products? Give us a visit!"
+
+type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
+      :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
+      :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
+
+api :: Proxy API
+api = Proxy
+
+server :: Server API
+server = position
+    :<|> hello
+    :<|> marketing
+
+  where position :: Int -> Int -> EitherT ServantErr IO Position
+        position x y = return (Position x y)
+
+        hello :: Maybe String -> EitherT ServantErr IO HelloMessage
+        hello mname = return . HelloMessage $ case mname of
+          Nothing -> "Hello, anonymous coward"
+          Just n  -> "Hello, " ++ n
+
+        marketing :: ClientInfo -> EitherT ServantErr IO Email
+        marketing clientinfo = return (emailForClient clientinfo)
+
+app :: Application
+app = serve api server
diff --git a/tutorial/T4.hs b/tutorial/T4.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T4.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+module T4 where
+
+import Data.Aeson
+import Data.Foldable (foldMap)
+import GHC.Generics
+import Lucid
+import Network.Wai
+import Servant
+import Servant.HTML.Lucid
+
+data Person = Person
+  { firstName :: String
+  , lastName  :: String
+  , age       :: Int
+  } deriving Generic -- for the JSON instance
+
+-- JSON serialization
+instance ToJSON Person
+
+-- HTML serialization of a single person
+instance ToHtml Person where
+  toHtml p =
+    tr_ $ do
+      td_ (toHtml $ firstName p)
+      td_ (toHtml $ lastName p)
+      td_ (toHtml . show $ age p)
+
+  toHtmlRaw = toHtml
+
+-- HTML serialization of a list of persons
+instance ToHtml [Person] where
+  toHtml persons = table_ $ do
+    tr_ $ do
+      td_ "first name"
+      td_ "last name"
+      td_ "age"
+
+    foldMap toHtml persons
+
+  toHtmlRaw = toHtml
+
+persons :: [Person]
+persons =
+  [ Person "Isaac"  "Newton"   372
+  , Person "Albert" "Einstein" 136
+  ]
+
+type PersonAPI = "persons" :> Get '[JSON, HTML] [Person]
+
+personAPI :: Proxy PersonAPI
+personAPI = Proxy
+
+server :: Server PersonAPI
+server = return persons
+
+app :: Application
+app = serve personAPI server
diff --git a/tutorial/T5.hs b/tutorial/T5.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T5.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE OverloadedStrings #-}
+module T5 where
+
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Either
+import Data.Aeson
+import GHC.Generics
+import Network.Wai
+import Servant
+import System.Directory
+
+type IOAPI = "myfile.txt" :> Get '[JSON] FileContent
+
+ioAPI :: Proxy IOAPI
+ioAPI = Proxy
+
+newtype FileContent = FileContent
+  { content :: String }
+  deriving Generic
+
+instance ToJSON FileContent
+
+server :: Server IOAPI
+server = do
+  exists <- liftIO (doesFileExist "myfile.txt")
+  if exists
+    then liftIO (readFile "myfile.txt") >>= return . FileContent
+    else left custom404Err
+
+  where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
+
+app :: Application
+app = serve ioAPI server
diff --git a/tutorial/T6.hs b/tutorial/T6.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T6.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+module T6 where
+
+import Network.Wai
+import Servant
+
+type API = "code" :> Raw
+
+api :: Proxy API
+api = Proxy
+
+server :: Server API
+server = serveDirectory "tutorial"
+
+app :: Application
+app = serve api server
diff --git a/tutorial/T7.hs b/tutorial/T7.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T7.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+module T7 where
+
+import Control.Monad.Trans.Either
+import Control.Monad.Trans.Reader
+import Network.Wai
+import Servant
+
+type ReaderAPI = "a" :> Get '[JSON] Int
+            :<|> "b" :> Get '[JSON] String
+
+readerAPI :: Proxy ReaderAPI
+readerAPI = Proxy
+
+readerServerT :: ServerT ReaderAPI (Reader String)
+readerServerT = a :<|> b
+
+  where a :: Reader String Int
+        a = return 1797
+
+        b :: Reader String String
+        b = ask
+
+readerServer :: Server ReaderAPI
+readerServer = enter readerToEither readerServerT
+
+  where readerToEither :: Reader String :~> EitherT ServantErr IO
+        readerToEither = Nat $ \r -> return (runReader r "hi")
+
+app :: Application
+app = serve readerAPI readerServer
diff --git a/tutorial/T8.hs b/tutorial/T8.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T8.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+module T8 where
+
+import Control.Monad.Trans.Either
+import Data.Aeson
+import Servant
+import Servant.Client
+
+import T3
+
+position :: Int -- ^ value for "x"
+         -> Int -- ^ value for "y"
+         -> EitherT ServantError IO Position
+
+hello :: Maybe String -- ^ an optional value for "name"
+      -> EitherT ServantError IO HelloMessage
+
+marketing :: ClientInfo -- ^ value for the request body
+          -> EitherT ServantError IO Email
+
+position :<|> hello :<|> marketing = client api baseUrl
+
+baseUrl :: BaseUrl
+baseUrl = BaseUrl Http "localhost" 8081
+
+queries :: EitherT ServantError IO (Position, HelloMessage, Email)
+queries = do
+  pos <- position 10 10
+  msg <- hello (Just "servant")
+  em  <- marketing (ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"])
+  return (pos, msg, em)
+
+run :: IO ()
+run = do
+  res <- runEitherT queries
+  case res of
+    Left err -> putStrLn $ "Error: " ++ show err
+    Right (pos, msg, em) -> do
+      print pos
+      print msg
+      print em
diff --git a/tutorial/T9.hs b/tutorial/T9.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/T9.hs
@@ -0,0 +1,104 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE OverloadedStrings #-}
+module T9 where
+
+import Control.Applicative
+import Control.Monad.IO.Class
+import Data.Aeson
+import Data.Text (Text)
+import GHC.Generics
+import Network.Wai
+import Servant
+import Servant.JQuery
+import System.Random
+
+import qualified Data.Text                  as T
+import qualified Language.Javascript.JQuery as JQ
+
+data Point = Point
+  { x :: Double
+  , y :: Double
+  } deriving Generic
+
+instance ToJSON Point
+
+randomPoint :: MonadIO m => m Point
+randomPoint = liftIO . getStdRandom $ \g ->
+  let (rx, g')  = randomR (-1, 1) g
+      (ry, g'') = randomR (-1, 1) g'
+  in (Point rx ry, g'')
+
+data Search a = Search
+  { query   :: Text
+  , results :: [a]
+  } deriving Generic
+
+mkSearch :: Text -> [a] -> Search a
+mkSearch = Search
+
+instance ToJSON a => ToJSON (Search a)
+
+data Book = Book
+  { author :: Text
+  , title  :: Text
+  , year   :: Int
+  } deriving Generic
+
+instance ToJSON Book
+
+book :: Text -> Text -> Int -> Book
+book = Book
+
+books :: [Book]
+books =
+  [ book "Paul Hudak" "The Haskell School of Expression: Learning Functional Programming through Multimedia" 2000
+  , book "Bryan O'Sullivan, Don Stewart, and John Goerzen" "Real World Haskell" 2008
+  , book "Miran Lipovača" "Learn You a Haskell for Great Good!" 2011
+  , book "Graham Hutton" "Programming in Haskell" 2007
+  , book "Simon Marlow" "Parallel and Concurrent Programming in Haskell" 2013
+  , book "Richard Bird" "Introduction to Functional Programming using Haskell" 1998
+  ]
+
+searchBook :: Monad m => Maybe Text -> m (Search Book)
+searchBook Nothing  = return (mkSearch "" books)
+searchBook (Just q) = return (mkSearch q books')
+
+  where books' = filter (\b -> q' `T.isInfixOf` T.toLower (author b)
+                            || q' `T.isInfixOf` T.toLower (title b)
+                        )
+                        books
+        q' = T.toLower q
+
+type API = "point" :> Get '[JSON] Point
+      :<|> "books" :> QueryParam "q" Text :> Get '[JSON] (Search Book)
+
+type API' = API :<|> Raw
+
+api :: Proxy API
+api = Proxy
+
+api' :: Proxy API'
+api' = Proxy
+
+server :: Server API
+server = randomPoint
+    :<|> searchBook
+
+server' :: Server API'
+server' = server
+     :<|> serveDirectory "tutorial/t9"
+
+apiJS :: String
+apiJS = jsForAPI api
+
+writeJSFiles :: IO ()
+writeJSFiles = do
+  writeFile "tutorial/t9/api.js" apiJS
+  jq <- readFile =<< JQ.file
+  writeFile "tutorial/t9/jq.js" jq
+
+app :: Application
+app = serve api' server'
diff --git a/tutorial/t8-main.hs b/tutorial/t8-main.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/t8-main.hs
@@ -0,0 +1,4 @@
+import T8
+
+main :: IO ()
+main = run
diff --git a/tutorial/tutorial.hs b/tutorial/tutorial.hs
new file mode 100644
--- /dev/null
+++ b/tutorial/tutorial.hs
@@ -0,0 +1,39 @@
+import Network.Wai
+import Network.Wai.Handler.Warp
+import System.Environment
+
+import qualified T1
+import qualified T2
+import qualified T3
+import qualified T4
+import qualified T5
+import qualified T6
+import qualified T7
+import qualified T9
+import qualified T10
+
+app :: String -> (Application -> IO ()) -> IO ()
+app n f = case n of
+  "1" -> f T1.app
+  "2" -> f T2.app
+  "3" -> f T3.app
+  "4" -> f T4.app
+  "5" -> f T5.app
+  "6" -> f T6.app
+  "7" -> f T7.app
+  "8" -> f T3.app
+  "9" -> T9.writeJSFiles >> f T9.app
+  "10" -> f T10.app
+  _   -> usage
+
+main :: IO ()
+main = do
+  args <- getArgs
+  case args of
+    [n] -> app n (run 8081)
+    _   -> usage
+
+usage :: IO ()
+usage = do
+  putStrLn "Usage:\t tutorial N"
+  putStrLn "\t\twhere N is the number of the example you want to run."
diff --git a/wai-middleware/wai-middleware.hs b/wai-middleware/wai-middleware.hs
new file mode 100644
--- /dev/null
+++ b/wai-middleware/wai-middleware.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
+import Data.Aeson
+import Data.Text
+import GHC.Generics
+import Network.Wai
+import Network.Wai.Handler.Warp
+import Network.Wai.Middleware.RequestLogger
+import Servant
+
+data Product = Product
+  { name              :: Text
+  , brand             :: Text
+  , current_price_eur :: Double
+  , available         :: Bool
+  } deriving (Eq, Show, Generic)
+
+instance ToJSON Product
+
+products :: [Product]
+products = [p1, p2]
+
+  where p1 = Product "Haskell laptop sticker"
+                     "GHC Industries"
+                     2.50
+                     True
+
+        p2 = Product "Foldable USB drive"
+                     "Well-Typed"
+                     13.99
+                     False
+
+type SimpleAPI = Get '[JSON] [Product]
+
+simpleAPI :: Proxy SimpleAPI
+simpleAPI = Proxy
+
+server :: Server SimpleAPI
+server = return products
+
+-- logStdout :: Middleware
+-- i.e, logStdout :: Application -> Application
+-- serve :: Proxy api -> Server api -> Application
+-- so applying a middleware is really as simple as
+-- applying a function to the result of 'serve'
+app :: Application
+app = logStdout (serve simpleAPI server)
+
+main :: IO ()
+main = run 8080 app
