diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2012 Matvey Aksenov, Dmitry Malikov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Network/Lastfm/API/Album.hs b/Network/Lastfm/API/Album.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Album.hs
@@ -0,0 +1,145 @@
+-- | Album API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Album
+  ( addTags, getBuyLinks, getInfo, getShouts, getTags
+  , getTopTags, removeTag, search, share
+  ) where
+
+import Control.Exception (throw)
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), Album, APIKey, Artist, Autocorrect, Country, Language, Limit
+                            , Mbid, Message, Page, Public, Recipient, SessionKey, Tag, User)
+
+-- | Tag an album using a list of user supplied tags.
+--
+-- More: <http://www.lastfm.ru/api/show/album.addTags>
+addTags :: (Artist, Album) -> [Tag] -> APIKey -> SessionKey -> Lastfm ()
+addTags (artist, album) tags apiKey sessionKey = dispatch go
+  where go
+          | null tags        = throw $ WrapperCallError method "empty tag list."
+          | length tags > 10 = throw $ WrapperCallError method "tag list length has exceeded maximum."
+          | otherwise        = void $ callAPI method
+          [ "artist" ?< artist
+          , "album" ?< album
+          , "tags" ?< tags
+          , "api_key" ?< apiKey
+          , "sk" ?< sessionKey
+          ]
+          where method = "album.addTags"
+
+-- | Get a list of Buy Links for a particular Album. It is required that you supply either the artist and track params or the mbid param.
+--
+-- More: <http://www.lastfm.ru/api/show/album.getBuylinks>
+getBuyLinks :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Country -> APIKey -> Lastfm Response
+getBuyLinks a autocorrect country apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "country" ?< country
+  , "api_key" ?< apiKey
+  ]
+  where method = "album.getBuyLinks"
+        target = case a of
+                   Left (artist, album) -> ["artist" ?< artist, "album" ?< album]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get the metadata for an album on Last.fm using the album name or a musicbrainz id. See playlist.fetch on how to get the album playlist.
+--
+-- More: <http://www.lastfm.ru/api/show/album.getInfo>
+getInfo :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Maybe Language -> Maybe User -> APIKey -> Lastfm Response
+getInfo a autocorrect lang username apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "lang" ?< lang
+  , "username" ?< username
+  , "api_key" ?< apiKey
+  ]
+  where method = "album.getInfo"
+        target = case a of
+                   Left (artist, album) -> ["artist" ?< artist, "album" ?< album]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get shouts for this album.
+--
+-- More: <http://www.lastfm.ru/api/show/album.getShouts>
+getShouts :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getShouts a autocorrect page limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "album.getShouts"
+        target = case a of
+                   Left (artist, album) -> ["artist" ?< artist, "album" ?< album]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get the tags applied by an individual user to an album on Last.fm.
+--
+-- More: <http://www.lastfm.ru/api/show/album.getTags>
+getTags :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Either User SessionKey -> APIKey -> Lastfm Response
+getTags a autocorrect b apiKey = dispatch $ callAPI method $ target ++ auth ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "album.getTags"
+        target = case a of
+                   Left (artist, album) -> ["artist" ?< artist, "album" ?< album]
+                   Right mbid           -> ["mbid" ?< mbid]
+        auth = case b of
+                 Left user        -> ["user" ?< user]
+                 Right sessionKey -> ["sk" ?< sessionKey]
+
+-- | Get the top tags for an album on Last.fm, ordered by popularity.
+--
+-- More: <http://www.lastfm.ru/api/show/album.getTopTags>
+getTopTags :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
+getTopTags a autocorrect apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "album.getTopTags"
+        target = case a of
+                   Left (artist, album) -> ["artist" ?< artist, "album" ?< album]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Remove a user's tag from an album.
+--
+-- More: <http://www.lastfm.ru/api/show/album.removeTag>
+removeTag :: Artist -> Album -> Tag -> APIKey -> SessionKey -> Lastfm ()
+removeTag artist album tag apiKey sessionKey = dispatch $ void $ callAPI "album.removeTag"
+  [ "artist" ?< artist
+  , "album" ?< album
+  , "tag" ?< tag
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Search for an album by name. Returns album matches sorted by relevance.
+--
+-- More: <http://www.lastfm.ru/api/show/album.search>
+search :: Album -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+search album page limit apiKey = dispatch $ callAPI "album.search"
+  [ "album" ?< album
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Share an album with one or more Last.fm users or other friends.
+--
+-- More: <http://www.lastfm.ru/api/show/album.share>
+share :: Artist -> Album -> [Recipient] -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Lastfm ()
+share artist album recipients message public apiKey sessionKey = dispatch go
+  where go
+          | null recipients        = throw $ WrapperCallError method "empty recipient list."
+          | length recipients > 10 = throw $ WrapperCallError method "recipient list length has exceeded maximum."
+          | otherwise              = void $ callAPI method
+            [ "artist" ?< artist
+            , "album" ?< album
+            , "public" ?< public
+            , "message" ?< message
+            , "recipient" ?< recipients
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            ]
+            where method = "album.share"
diff --git a/Network/Lastfm/API/Artist.hs b/Network/Lastfm/API/Artist.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Artist.hs
@@ -0,0 +1,267 @@
+-- | Artist API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Artist
+  ( addTags, getCorrection, getEvents, getImages, getInfo
+  , getPastEvents, getPodcast, getShouts, getSimilar, getTags, getTopAlbums
+  , getTopFans, getTopTags, getTopTracks, removeTag, search, share, shout
+  ) where
+
+import Control.Exception (throw)
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), APIKey, Artist, Autocorrect, FestivalsOnly, Language, Limit
+                            , Mbid, Message, Order, Page, Public, Recipient, SessionKey, Tag, User
+                            )
+
+-- | Tag an album using a list of user supplied tags.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.addTags>
+addTags :: Artist -> [Tag] -> APIKey -> SessionKey -> Lastfm ()
+addTags artist tags apiKey sessionKey = dispatch go
+  where go
+          | null tags        = throw $ WrapperCallError method "empty tag list."
+          | length tags > 10 = throw $ WrapperCallError method "tag list length has exceeded maximum."
+          | otherwise        = void $ callAPI method
+            [ "artist" ?< artist
+            , "tags" ?< tags
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            ]
+            where method = "artist.addTags"
+
+-- | Use the last.fm corrections data to check whether the supplied artist has a correction to a canonical artist
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getCorrection>
+getCorrection :: Artist -> APIKey -> Lastfm Response
+getCorrection artist apiKey = dispatch $ callAPI "artist.getCorrection"
+  [ "artist" ?< artist
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of upcoming events for this artist.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getEvents>
+getEvents :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> Maybe FestivalsOnly -> APIKey -> Lastfm Response
+getEvents a autocorrect page limit festivalsOnly apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "festivalsonly" ?< festivalsOnly
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getEvents"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get Images for this artist in a variety of sizes.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getImages>
+getImages :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> Maybe Order -> APIKey -> Lastfm Response
+getImages a autocorrect page limit order apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "order" ?< order
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getImages"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get the metadata for an artist. Includes biography.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getInfo>
+getInfo :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Language -> Maybe User -> APIKey -> Lastfm Response
+getInfo a autocorrect language user apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "lang" ?< language
+  , "username" ?< user
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getInfo"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get a paginated list of all the events this artist has played at in the past.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getPastEvents>
+getPastEvents :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getPastEvents a autocorrect page limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getPastEvents"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get a podcast of free mp3s based on an artist.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getPodcast>
+getPodcast :: Either Artist Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
+getPodcast a autocorrect apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getPodcast"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get shouts for this artist. Also available as an rss feed.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getShouts>
+getShouts :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getShouts a autocorrect page limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getShouts"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get all the artists similar to this artist.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getSimilar>
+getSimilar :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Limit -> APIKey -> Lastfm Response
+getSimilar a autocorrect limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getSimilar"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get the tags applied by an individual user to an artist on Last.fm. If accessed as an authenticated service /and/ you don't supply a user parameter then this service will return tags for the authenticated user.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getTags>
+getTags :: Either Artist Mbid -> Maybe Autocorrect -> Either User SessionKey -> APIKey -> Lastfm Response
+getTags a autocorrect b apiKey = dispatch $ callAPI method $ target ++ auth ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getTags"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+        auth = case b of
+                 Left user        -> ["user" ?< user]
+                 Right sessionKey -> ["sk" ?< sessionKey]
+
+-- | Get the top albums for an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getTopAlbums>
+getTopAlbums :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopAlbums a autocorrect page limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getTopAlbums"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get the top fans for an artist on Last.fm, based on listening data.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getTopFans>
+getTopFans :: Either Artist Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
+getTopFans a autocorrect apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getTopFans"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get the top tags for an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getTopTags>
+getTopTags :: Either Artist Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
+getTopTags a autocorrect apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getTopTags"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Get the top tracks by an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.getTopTracks>
+getTopTracks :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTracks a autocorrect page limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "artist.getTopTracks"
+        target = case a of
+                   Left artist -> ["artist" ?< artist]
+                   Right mbid  -> ["mbid" ?< mbid]
+
+-- | Remove a user's tag from an artist.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.removeTag>
+removeTag :: Artist -> Tag -> APIKey -> SessionKey -> Lastfm ()
+removeTag artist tag apiKey sessionKey = dispatch $ void $ callAPI "artist.removeTag"
+  [ "artist" ?< artist
+  , "tag" ?< tag
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Search for an artist by name. Returns artist matches sorted by relevance.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.search>
+search :: Artist -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+search artist page limit apiKey = dispatch $ callAPI "artist.search"
+  [ "artist" ?< artist
+  , "api_key" ?< apiKey
+  , "page" ?< page
+  , "limit" ?< limit
+  ]
+
+-- | Share an artist with Last.fm users or other friends.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.share>
+share :: Artist -> [Recipient] -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Lastfm ()
+share artist recipients message public apiKey sessionKey = dispatch go
+  where go
+          | null recipients        = throw $ WrapperCallError method "empty recipient list."
+          | length recipients > 10 = throw $ WrapperCallError method "recipient list length has exceeded maximum."
+          | otherwise              = void $ callAPI method
+            [ "artist" ?< artist
+            , "recipient" ?< recipients
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            , "public" ?< public
+            , "message" ?< message
+            ]
+            where method = "artist.share"
+
+-- | Shout in this artist's shoutbox.
+--
+-- More: <http://www.lastfm.ru/api/show/artist.shout>
+shout :: Artist -> Message -> APIKey -> SessionKey -> Lastfm ()
+shout artist message apiKey sessionKey = dispatch $ void $ callAPI "artist.shout"
+  [ "artist" ?< artist
+  , "message" ?< message
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
diff --git a/Network/Lastfm/API/Auth.hs b/Network/Lastfm/API/Auth.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Auth.hs
@@ -0,0 +1,38 @@
+-- | Auth API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Auth
+  ( getMobileSession, getSession, getToken
+  , getAuthorizeTokenLink
+  ) where
+
+import Control.Applicative ((<$>))
+import Control.Monad ((<=<), liftM)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, AuthToken, SessionKey(..), Token(..), User, unpack)
+
+-- | Create a web service session for a user. Used for authenticating a user when the password can be inputted by the user. Only suitable for standalone mobile devices.
+--
+-- More: <http://www.lastfm.ru/api/show/auth.getMobileSession>
+getMobileSession :: User -> APIKey -> AuthToken -> Lastfm Response
+getMobileSession user apiKey token = dispatch $ callAPI "auth.getMobileSession"
+  [ "username" ?< user
+  , "authToken" ?< token
+  , "api_key" ?< apiKey
+  ]
+
+-- | Fetch a session key for a user.
+--
+-- More: <http://www.lastfm.ru/api/show/auth.getSession>
+getSession :: APIKey -> Token -> Lastfm Response
+getSession apiKey token = dispatch $ callAPI "auth.getSession" ["api_key" ?< apiKey, "token" ?< token]
+
+-- | Fetch an unathorized request token for an API account.
+--
+-- More: <http://www.lastfm.ru/api/show/auth.getToken>
+getToken :: APIKey -> Lastfm Response
+getToken apiKey = dispatch $ callAPI "auth.getToken" ["api_key" ?< apiKey]
+
+-- | Construct the link to authorize token.
+getAuthorizeTokenLink :: APIKey -> Token -> String
+getAuthorizeTokenLink apiKey token = "http://www.last.fm/api/auth/?api_key=" ++ unpack apiKey ++ "&token=" ++ unpack token
diff --git a/Network/Lastfm/API/Chart.hs b/Network/Lastfm/API/Chart.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Chart.hs
@@ -0,0 +1,52 @@
+-- | Chart API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Chart
+  ( getHypedArtists, getHypedTracks, getLovedTracks
+  , getTopArtists, getTopTags, getTopTracks
+  ) where
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, Limit, Page)
+
+-- | Get the hyped artists chart.
+--
+-- More: <http://www.lastfm.ru/api/show/chart.getHypedArtists>
+getHypedArtists :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getHypedArtists = get "getHypedArtists"
+
+-- | Get the hyped tracks chart.
+--
+-- More: <http://www.lastfm.ru/api/show/chart.getHypedTracks>
+getHypedTracks :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getHypedTracks = get "getHypedTracks"
+
+-- | Get the most loved tracks chart.
+--
+-- More: <http://www.lastfm.ru/api/show/chart.getLovedTracks>
+getLovedTracks :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getLovedTracks = get "getLovedTracks"
+
+-- | Get the top artists chart.
+--
+-- More: <http://www.lastfm.ru/api/show/chart.getTopArtists>
+getTopArtists :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopArtists = get "getTopArtists"
+
+-- | Get top tags chart.
+--
+-- More: <http://www.lastfm.ru/api/show/chart.getTopTags>
+getTopTags :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTags = get "getTopTags"
+
+-- | Get the top tracks chart.
+--
+-- More: <http://www.lastfm.ru/api/show/chart.getTopTracks>
+getTopTracks :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTracks = get "getTopTracks"
+
+get :: String -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+get method page limit apiKey = dispatch $ callAPI ("chart." ++ method)
+  [ "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
diff --git a/Network/Lastfm/API/Event.hs b/Network/Lastfm/API/Event.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Event.hs
@@ -0,0 +1,84 @@
+-- | Event API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Event
+  ( attend, getAttendees, getInfo, getShouts, share, shout
+  ) where
+
+import Control.Exception (throw)
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), APIKey, Event, Limit, Message, Page
+                            , Public, Recipient, SessionKey, Status
+                            )
+
+-- | Set a user's attendance status for an event.
+--
+-- More: <http://www.lastfm.ru/api/show/event.attend>
+attend :: Event -> Status -> APIKey -> SessionKey -> Lastfm ()
+attend event status apiKey sessionKey = dispatch $ void $ callAPI "event.attend"
+  [ "event" ?< event
+  , "status" ?< status
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Get a list of attendees for an event.
+--
+-- More: <http://www.lastfm.ru/api/show/event.getAttendees>
+getAttendees :: Event -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getAttendees event page limit apiKey = dispatch $ callAPI "event.getAttendees"
+  [ "event" ?< event
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the metadata for an event on Last.fm. Includes attendance and lineup information.
+--
+-- More: <http://www.lastfm.ru/api/show/event.getInfo>
+getInfo :: Event -> APIKey -> Lastfm Response
+getInfo event apiKey = dispatch $ callAPI "event.getInfo"
+  [ "event" ?< event
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get shouts for this event.
+--
+-- More: <http://www.lastfm.ru/api/show/event.getShouts>
+getShouts :: Event -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getShouts event page limit apiKey = dispatch $ callAPI "event.getShouts"
+  [ "event" ?< event
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Share an event with one or more Last.fm users or other friends.
+--
+-- More: <http://www.lastfm.ru/api/show/event.share>
+share :: Event -> [Recipient] -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Lastfm ()
+share event recipients message public apiKey sessionKey = dispatch go
+  where go
+          | null recipients        = throw $ WrapperCallError method "empty recipient list."
+          | length recipients > 10 = throw $ WrapperCallError method "recipient list length has exceeded maximum."
+          | otherwise              = void $ callAPI method
+            [ "event" ?< event
+            , "public" ?< public
+            , "message" ?< message
+            , "recipient" ?< recipients
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            ]
+            where method = "event.share"
+
+-- | Shout in this event's shoutbox.
+--
+-- More: <http://www.lastfm.ru/api/show/event.shout>
+shout :: Event -> Message -> APIKey -> SessionKey -> Lastfm ()
+shout event message apiKey sessionKey = dispatch $ void $ callAPI "event.shout"
+  [ "event" ?< event
+  , "message" ?< message
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
diff --git a/Network/Lastfm/API/Geo.hs b/Network/Lastfm/API/Geo.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Geo.hs
@@ -0,0 +1,116 @@
+-- | Geo API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Geo
+  ( getEvents, getMetroArtistChart, getMetroHypeArtistChart, getMetroHypeTrackChart
+  , getMetroTrackChart, getMetroUniqueArtistChart, getMetroUniqueTrackChart
+  , getMetroWeeklyChartlist, getMetros, getTopArtists, getTopTracks
+  ) where
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), APIKey, Country, Distance, From, Latitude
+                            , Limit, Location, Longitude, Metro, Page, To
+                            )
+
+-- | Get all events in a specific location by country or city name.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getEvents>
+getEvents :: Maybe Latitude
+          -> Maybe Longitude
+          -> Maybe Location
+          -> Maybe Distance
+          -> Maybe Page
+          -> Maybe Limit
+          -> APIKey
+          -> Lastfm Response
+getEvents latitude longitude location distance page limit apiKey = dispatch $ callAPI "geo.getEvents"
+  [ "lat" ?< latitude
+  , "long" ?< longitude
+  , "location" ?< location
+  , "distance" ?< distance
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a chart of artists for a metro.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroArtistChart>
+getMetroArtistChart :: Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroArtistChart = getMetroChart "geo.getMetroArtistChart"
+
+-- | Get a chart of hyped (up and coming) artists for a metro.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroHypeArtistChart>
+getMetroHypeArtistChart :: Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroHypeArtistChart = getMetroChart "geo.getMetroHypeArtistChart"
+
+-- | Get a chart of hyped (up and coming) tracks for a metro.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroHypeTrackChart>
+getMetroHypeTrackChart :: Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroHypeTrackChart = getMetroChart "geo.getMetroHypeTrackChart"
+
+-- | Get a chart of tracks for a metro.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroTrackChart>
+getMetroTrackChart :: Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroTrackChart = getMetroChart "geo.getMetroTrackChart"
+
+-- | Get a chart of the artists which make that metro unique.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroUniqueArtistChart>
+getMetroUniqueArtistChart :: Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroUniqueArtistChart = getMetroChart "geo.getMetroUniqueArtistChart"
+
+-- | Get a chart of the tracks which make that metro unique.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroUniqueTrackChart>
+getMetroUniqueTrackChart :: Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroUniqueTrackChart = getMetroChart "geo.getMetroUniqueTrackChart"
+
+-- | Get a list of available chart periods for this metro, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetroWeeklyChartlist>
+getMetroWeeklyChartlist :: Metro -> APIKey -> Lastfm Response
+getMetroWeeklyChartlist metro apiKey = dispatch $ callAPI "geo.getMetroWeeklyChartlist" ["metro" ?< metro, "api_key" ?< apiKey]
+
+-- | Get a list of valid countries and metros for use in the other webservices.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getMetros>
+getMetros :: Maybe Country -> APIKey -> Lastfm Response
+getMetros country apiKey = dispatch $ callAPI "geo.getMetros"
+  [ "country" ?< country
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the most popular artists on Last.fm by country.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getTopArtists>
+getTopArtists :: Country -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopArtists country page limit apiKey = dispatch $ callAPI "geo.getTopArtists"
+  [ "country" ?< country
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the most popular tracks on Last.fm last week by country.
+--
+-- More: <http://www.lastfm.ru/api/show/geo.getTopTracks>
+getTopTracks :: Country -> Maybe Location -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTracks country location page limit apiKey = dispatch $ callAPI "geo.getTopTracks"
+  [ "country" ?< country
+  , "location" ?< location
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+getMetroChart :: String -> Country -> Metro -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getMetroChart method country metro from to apiKey = dispatch $ callAPI method
+  [ "country" ?< country
+  , "metro" ?< metro
+  , "start" ?< from
+  , "end" ?< to
+  , "api_key" ?< apiKey
+  ]
diff --git a/Network/Lastfm/API/Group.hs b/Network/Lastfm/API/Group.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Group.hs
@@ -0,0 +1,68 @@
+-- | Group API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Group
+  ( getHype, getMembers, getWeeklyChartList, getWeeklyAlbumChart, getWeeklyArtistChart, getWeeklyTrackChart
+  ) where
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, From, Group, Limit, Page, To)
+
+-- | Get the hype list for a group.
+--
+-- More: <http://www.lastfm.ru/api/show/group.getHype>
+getHype :: Group -> APIKey -> Lastfm Response
+getHype group apiKey = dispatch $ callAPI "group.getHype"
+  [ "group" ?< group
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of members for this group.
+--
+-- More: <http://www.lastfm.ru/api/show/group.getMembers>
+getMembers :: Group -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getMembers group page limit apiKey = dispatch $ callAPI "group.getMembers"
+  [ "group" ?< group
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get an album chart for a group, for a given date range. If no date range is supplied, it will return the most recent album chart for this group.
+--
+-- More: <http://www.lastfm.ru/api/show/group.getWeeklyAlbumChart>
+getWeeklyChartList :: Group -> APIKey -> Lastfm Response
+getWeeklyChartList group apiKey = dispatch $ callAPI "group.getWeeklyChartList" ["group" ?< group, "api_key" ?< apiKey]
+
+-- | Get an artist chart for a group, for a given date range. If no date range is supplied, it will return the most recent artist chart for this group.
+--
+-- More: <http://www.lastfm.ru/api/show/group.getWeeklyArtistChart>
+getWeeklyAlbumChart :: Group -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getWeeklyAlbumChart group from to apiKey = dispatch $ callAPI "group.getWeeklyAlbumChart"
+  [ "group" ?< group
+  , "api_key" ?< apiKey
+  , "from" ?< from
+  , "to" ?< to
+  ]
+
+-- | Get a list of available charts for this group, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.lastfm.ru/api/show/group.getWeeklyChartList>
+getWeeklyArtistChart :: Group -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getWeeklyArtistChart group from to apiKey = dispatch $ callAPI "group.getWeeklyArtistChart"
+  [ "group" ?< group
+  , "api_key" ?< apiKey
+  , "from" ?< from
+  , "to" ?< to
+  ]
+
+
+-- | Get a track chart for a group, for a given date range. If no date range is supplied, it will return the most recent track chart for this group.
+--
+-- More: <http://www.lastfm.ru/api/show/group.getWeeklyTrackChart>
+getWeeklyTrackChart :: Group -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getWeeklyTrackChart group from to apiKey = dispatch $ callAPI "group.getWeeklyTrackChart"
+  [ "group" ?< group
+  , "api_key" ?< apiKey
+  , "from" ?< from
+  , "to" ?< to
+  ]
diff --git a/Network/Lastfm/API/Library.hs b/Network/Lastfm/API/Library.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Library.hs
@@ -0,0 +1,123 @@
+-- | Library API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Library
+  ( addAlbum, addArtist, addTrack, getAlbums, getArtists, getTracks
+  , removeAlbum, removeArtist, removeScrobble, removeTrack
+  ) where
+
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), Album, APIKey, Artist, Limit, Page, SessionKey, Timestamp, Track, User)
+
+-- | Add an album or collection of albums to a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.addAlbum>
+addAlbum :: Artist -> Album -> APIKey -> SessionKey -> Lastfm ()
+addAlbum artist album apiKey sessionKey = dispatch $ void $ callAPI "library.addAlbum"
+  [ "artist" ?< artist
+  , "album" ?< album
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Add an artist to a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.addArtist>
+addArtist :: Artist -> APIKey -> SessionKey -> Lastfm ()
+addArtist artist apiKey sessionKey = dispatch $ void $ callAPI "library.addArtist"
+  [ "artist" ?< artist
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Add a track to a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.addTrack>
+addTrack :: Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+addTrack artist track apiKey sessionKey = dispatch $ void $ callAPI "library.addTrack"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | A paginated list of all the albums in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.lastfm.ru/api/show/library.getAlbums>
+getAlbums :: User -> Maybe Artist -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getAlbums user artist page limit apiKey = dispatch $ callAPI "library.getAlbums"
+  [ "user" ?< user
+  , "artist" ?< artist
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | A paginated list of all the artists in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.lastfm.ru/api/show/library.getArtists>
+getArtists :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getArtists user page limit apiKey = dispatch $ callAPI "library.getArtists"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | A paginated list of all the tracks in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.lastfm.ru/api/show/library.getTracks>
+getTracks :: User -> Maybe Artist -> Maybe Album -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTracks user artist album page limit apiKey = dispatch $ callAPI "library.getTracks"
+  [ "user" ?< user
+  , "artist" ?< artist
+  , "album" ?< album
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Remove an album from a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.removeAlbum>
+removeAlbum :: Artist -> Album -> APIKey -> SessionKey -> Lastfm ()
+removeAlbum artist album apiKey sessionKey = dispatch $ void $ callAPI "library.removeAlbum"
+  [ "artist" ?< artist
+  , "album" ?< album
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Remove an artist from a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.removeArtist>
+removeArtist :: Artist -> APIKey -> SessionKey -> Lastfm ()
+removeArtist artist apiKey sessionKey = dispatch $ void $ callAPI "library.removeArtist"
+  [ "artist" ?< artist
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Remove a scrobble from a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.removeScrobble>
+removeScrobble :: Artist -> Track -> Timestamp -> APIKey -> SessionKey -> Lastfm ()
+removeScrobble artist track timestamp apiKey sessionKey = dispatch $ void $ callAPI "library.removeScrobble"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "timestamp" ?< timestamp
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Remove a track from a user's Last.fm library.
+--
+-- More: <http://www.lastfm.ru/api/show/library.removeTrack>
+removeTrack :: Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+removeTrack artist track apiKey sessionKey = dispatch $ void $ callAPI "library.removeTrack"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
diff --git a/Network/Lastfm/API/Playlist.hs b/Network/Lastfm/API/Playlist.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Playlist.hs
@@ -0,0 +1,33 @@
+-- | Playlist API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Playlist
+  ( addTrack, create
+  ) where
+
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, Artist, Playlist, SessionKey, Title, Description, Track)
+
+-- | Add a track to a Last.fm user's playlist.
+--
+-- More: <http://www.lastfm.ru/api/show/playlist.addTrack>
+addTrack :: Playlist -> Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+addTrack playlist artist track apiKey sessionKey = dispatch $ void $ callAPI "playlist.addTrack"
+  [ "playlistID" ?< playlist
+  , "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Create a Last.fm playlist on behalf of a user.
+--
+-- More: <http://www.lastfm.ru/api/show/playlist.create>
+create :: Maybe Title -> Maybe Description -> APIKey -> SessionKey -> Lastfm ()
+create title description apiKey sessionKey = dispatch $ void $ callAPI "playlist.create"
+  [ "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  , "title" ?< title
+  , "description" ?< description
+  ]
diff --git a/Network/Lastfm/API/Radio.hs b/Network/Lastfm/API/Radio.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Radio.hs
@@ -0,0 +1,58 @@
+-- | Radio API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Radio
+  ( getPlaylist, search, tune
+  ) where
+
+import Control.Exception (throw)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), APIKey, Bitrate, BuyLinks, Discovery, Language
+                            , Multiplier, Name, RTP, Station, SessionKey, unpack
+                            )
+
+-- | Fetch new radio content periodically in an XSPF format.
+--
+-- More: <http://www.lastfm.ru/api/show/radio.getPlaylist>
+getPlaylist :: Maybe Discovery
+            -> Maybe RTP
+            -> Maybe BuyLinks
+            -> Multiplier
+            -> Bitrate
+            -> APIKey
+            -> SessionKey
+            -> Lastfm Response
+getPlaylist discovery rtp buylinks multiplier bitrate apiKey sessionKey = dispatch go
+  where go
+          | unpack multiplier /= "1.0" && unpack multiplier /= "2.0" = throw $ WrapperCallError method "unsupported multiplier."
+          | unpack bitrate /= "64" && unpack bitrate /= "128" = throw $ WrapperCallError method "unsupported bitrate."
+          | otherwise = callAPI method
+            [ "discovery" ?< discovery
+            , "rtp" ?< rtp
+            , "buylinks" ?< buylinks
+            , "speed_multiplier" ?< multiplier
+            , "bitrate" ?< bitrate
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            ]
+            where method = "radio.getPlaylist"
+
+-- | Resolve the name of a resource into a station depending on which resource it is most likely to represent.
+--
+-- More: <http://www.lastfm.ru/api/show/radio.search>
+search :: Name -> APIKey -> Lastfm Response
+search name apiKey = dispatch $ callAPI "radio.search"
+  [ "name" ?< name
+  , "api_key" ?< apiKey
+  ]
+
+-- | Tune in to a Last.fm radio station.
+--
+-- More: <http://www.lastfm.ru/api/show/radio.tune>
+tune :: Maybe Language -> Station -> APIKey -> SessionKey -> Lastfm Response
+tune language station apiKey sessionKey = dispatch $ callAPI "radio.tune"
+  [ "lang" ?< language
+  , "station" ?< station
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
diff --git a/Network/Lastfm/API/Tag.hs b/Network/Lastfm/API/Tag.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Tag.hs
@@ -0,0 +1,99 @@
+-- | Tag API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Tag
+  ( getInfo, getSimilar, getTopAlbums, getTopArtists, getTopTags, getTopTracks
+  , getWeeklyArtistChart, getWeeklyChartList, search
+  ) where
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, From, Language, Limit, Page, Tag, To)
+
+-- | Get the metadata for a tag.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getInfo>
+getInfo :: Tag -> Maybe Language -> APIKey -> Lastfm Response
+getInfo tag language apiKey = dispatch $ callAPI "tag.getInfo"
+  [ "tag" ?< tag
+  , "lang" ?< language
+  , "api_key" ?< apiKey
+  ]
+
+-- | Search for tags similar to this one. Returns tags ranked by similarity, based on listening data.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getSimilar>
+getSimilar :: Tag -> APIKey -> Lastfm Response
+getSimilar tag apiKey = dispatch $ callAPI "tag.getSimilar"
+  [ "tag" ?< tag
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the top albums tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getTopAlbums>
+getTopAlbums :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopAlbums tag page limit apiKey = dispatch $ callAPI "tag.getTopAlbums"
+  [ "tag" ?< tag
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the top artists tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getTopArtists>
+getTopArtists :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopArtists tag limit page apiKey = dispatch $ callAPI "tag.getTopArtists"
+  [ "tag" ?< tag
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Fetches the top global tags on Last.fm, sorted by popularity (number of times used).
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getTopTags>
+getTopTags :: APIKey -> Lastfm Response
+getTopTags apiKey = dispatch $ callAPI "tag.getTopArtists" ["api_key" ?< apiKey]
+
+-- | Get the top tracks tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getTopTracks>
+getTopTracks :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTracks tag limit page apiKey = dispatch $ callAPI "tag.getTopTracks"
+  [ "tag" ?< tag
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get an artist chart for a tag, for a given date range. If no date range is supplied, it will return the most recent artist chart for this tag.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getWeeklyArtistChart>
+getWeeklyArtistChart :: Tag -> Maybe From -> Maybe To -> Maybe Limit -> APIKey -> Lastfm Response
+getWeeklyArtistChart tag from to limit apiKey = dispatch $ callAPI "tag.getWeeklyArtistChart"
+  [ "tag" ?< tag
+  , "from" ?< from
+  , "to" ?< to
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of available charts for this tag, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.getWeeklyChartList>
+getWeeklyChartList :: Tag -> APIKey -> Lastfm Response
+getWeeklyChartList tag apiKey = dispatch $ callAPI "tag.getWeeklyChartList"
+  [ "tag" ?< tag
+  , "api_key" ?< apiKey
+  ]
+
+-- | Search for a tag by name. Returns matches sorted by relevance.
+--
+-- More: <http://www.lastfm.ru/api/show/tag.search>
+search :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+search tag page limit apiKey = dispatch $ callAPI "tag.search"
+  [ "tag" ?< tag
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
diff --git a/Network/Lastfm/API/Tasteometer.hs b/Network/Lastfm/API/Tasteometer.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Tasteometer.hs
@@ -0,0 +1,42 @@
+-- | Tasteometer API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Tasteometer
+  ( compare
+  ) where
+
+import Control.Exception (throw)
+import Prelude hiding (compare)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, Limit, Value(..))
+
+-- | Get a Tasteometer score from two inputs, along with a list of shared artists. If the input is a User some additional information is returned.
+--
+-- More: <http://www.lastfm.ru/api/show/tasteometer.compare>
+compare :: Value -> Value -> Maybe Limit -> APIKey -> Lastfm Response
+compare value1 value2 limit apiKey = dispatch go
+  where go
+          | isNull value1 = throw $ WrapperCallError method "empty first artists list."
+          | isNull value2 = throw $ WrapperCallError method "empty second artists list."
+          | isExceededMaximum value1 = throw $ WrapperCallError method "first artists list length has exceeded maximum (100)."
+          | isExceededMaximum value2 = throw $ WrapperCallError method "second artists list length has exceeded maximum (100)."
+          | otherwise = callAPI method
+            [ "type1" ?< type1
+            , "type2" ?< type2
+            , "value1" ?< value1
+            , "value2" ?< value2
+            , "limit" ?< limit
+            , "api_key" ?< apiKey
+            ]
+            where method = "tasteometer.compare"
+
+                  type1 = show value1
+                  type2 = show value2
+
+                  isNull :: Value -> Bool
+                  isNull (ValueUser _) = False
+                  isNull (ValueArtists as) = null as
+
+                  isExceededMaximum :: Value -> Bool
+                  isExceededMaximum (ValueUser _) = False
+                  isExceededMaximum (ValueArtists as) = length as > 100
diff --git a/Network/Lastfm/API/Track.hs b/Network/Lastfm/API/Track.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Track.hs
@@ -0,0 +1,291 @@
+-- | Track API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Track
+  ( addTags, ban, getBuyLinks, getCorrection, getFingerprintMetadata
+  , getInfo, getShouts, getSimilar, getTags, getTopFans, getTopTags
+  , love, removeTag, scrobble, search, share, unban, unlove, updateNowPlaying
+  ) where
+
+import Control.Exception (throw)
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), Album, AlbumArtist, APIKey, Artist, Autocorrect, ChosenByUser, Context, Country
+                            , Duration, Fingerprint, Limit, Mbid, Message, Page, Public, Recipient, SessionKey
+                            , StreamId, Tag, Timestamp, Track, TrackNumber, User
+                            )
+
+-- | Tag a track using a list of user supplied tags.
+--
+-- More: <http://www.lastfm.ru/api/show/track.addTags>
+addTags :: Artist -> Track -> [Tag] -> APIKey -> SessionKey -> Lastfm ()
+addTags artist track tags apiKey sessionKey = dispatch go
+  where go
+          | null tags        = throw $ WrapperCallError method "empty tag list."
+          | length tags > 10 = throw $ WrapperCallError method "tag list length has exceeded maximum."
+          | otherwise        = void $ callAPI method
+            [ "artist" ?< artist
+            , "track" ?< track
+            , "tags" ?< tags
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            ]
+            where method = "track.addTags"
+
+-- | Ban a track for a given user profile.
+--
+-- More: <http://www.lastfm.ru/api/show/track.ban>
+ban :: Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+ban artist track apiKey sessionKey = dispatch $ void $ callAPI "track.ban"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Get a list of Buy Links for a particular track.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getBuylinks>
+getBuyLinks :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Country -> APIKey -> Lastfm Response
+getBuyLinks a autocorrect country apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "country" ?< country
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getBuyLinks"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Use the last.fm corrections data to check whether the supplied track has a correction to a canonical track.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getCorrection>
+getCorrection :: Artist -> Track -> APIKey -> Lastfm Response
+getCorrection artist track apiKey = dispatch $ callAPI "track.getCorrection"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  ]
+
+-- | Retrieve track metadata associated with a fingerprint id generated by the Last.fm Fingerprinter. Returns track elements, along with a 'rank' value between 0 and 1 reflecting the confidence for each match.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getFingerprintMetadata>
+getFingerprintMetadata :: Fingerprint -> APIKey -> Lastfm Response
+getFingerprintMetadata fingerprint apiKey = dispatch $ callAPI "track.getFingerprintMetadata"
+  [ "fingerprintid" ?< fingerprint
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the metadata for a track on Last.fm.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getInfo>
+getInfo :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Maybe User -> APIKey -> Lastfm Response
+getInfo a autocorrect username apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "username" ?< username
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getInfo"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get shouts for this track. Also available as an rss feed.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getShouts>
+getShouts :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getShouts a autocorrect page limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getShouts"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get the similar tracks for this track on Last.fm, based on listening data.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getSimilar>
+getSimilar :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Maybe Limit -> APIKey -> Lastfm Response
+getSimilar a autocorrect limit apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getSimilar"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get the tags applied by an individual user to a track on Last.fm.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getTags>
+getTags :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Either User SessionKey -> APIKey -> Lastfm Response
+getTags a autocorrect b apiKey = dispatch $ callAPI method $ target ++ auth ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getTags"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+        auth = case b of
+                 Left user        -> ["user" ?< user]
+                 Right sessionKey -> ["sk" ?< sessionKey]
+
+-- | Get the top fans for this track on Last.fm, based on listening data.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getTopFans>
+getTopFans :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
+getTopFans a autocorrect apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getTopFans"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Get the top tags for this track on Last.fm, ordered by tag count.
+--
+-- More: <http://www.lastfm.ru/api/show/track.getTopTags>
+getTopTags :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
+getTopTags a autocorrect apiKey = dispatch $ callAPI method $ target ++
+  [ "autocorrect" ?< autocorrect
+  , "api_key" ?< apiKey
+  ]
+  where method = "track.getTopTags"
+        target = case a of
+                   Left (artist, track) -> ["artist" ?< artist, "track" ?< track]
+                   Right mbid           -> ["mbid" ?< mbid]
+
+-- | Love a track for a user profile.
+--
+-- More: <http://www.lastfm.ru/api/show/track.love>
+love :: Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+love artist track apiKey sessionKey = dispatch $ void $ callAPI "track.love"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Remove a user's tag from a track.
+--
+-- More: <http://www.lastfm.ru/api/show/track.removeTag>
+removeTag :: Artist -> Track -> Tag -> APIKey -> SessionKey -> Lastfm ()
+removeTag artist track tag apiKey sessionKey = dispatch $ void $ callAPI "track.removeTag"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "tag" ?< tag
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Used to add a track-play to a user's profile.
+--
+-- More; <http://www.lastfm.ru/api/show/track.scrobble>
+scrobble :: ( Timestamp, Maybe Album, Artist, Track, Maybe AlbumArtist
+           , Maybe Duration, Maybe StreamId, Maybe ChosenByUser
+           , Maybe Context, Maybe TrackNumber, Maybe Mbid )
+         -> APIKey
+         -> SessionKey
+         -> Lastfm ()
+scrobble (timestamp, album, artist, track, albumArtist, duration, streamId, chosenByUser, context, trackNumber, mbid) apiKey sessionKey = dispatch $ void $ callAPI "track.scrobble"
+  [ "timestamp" ?< timestamp
+  , "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  , "album" ?< album
+  , "albumArtist" ?< albumArtist
+  , "duration" ?< duration
+  , "streamId" ?< streamId
+  , "chosenByUser" ?< chosenByUser
+  , "context" ?< context
+  , "trackNumber" ?< trackNumber
+  , "mbid" ?< mbid
+  ]
+
+-- | Search for a track by track name. Returns track matches sorted by relevance.
+--
+-- More: <http://www.lastfm.ru/api/show/track.search>
+search :: Track -> Maybe Page -> Maybe Limit -> Maybe Artist -> APIKey -> Lastfm Response
+search limit page track artist apiKey = dispatch $ callAPI "track.search"
+  [ "track" ?< track
+  , "page" ?< page
+  , "limit" ?< limit
+  , "artist" ?< artist
+  , "api_key" ?< apiKey
+  ]
+
+-- | Share a track twith one or more Last.fm users or other friends.
+--
+-- More: <http://www.lastfm.ru/api/show/track.share>
+share :: Artist -> Track -> [Recipient] -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Lastfm ()
+share artist track recipients message public apiKey sessionKey = dispatch go
+  where go
+          | null recipients        = throw $ WrapperCallError method "empty recipient list."
+          | length recipients > 10 = throw $ WrapperCallError method "recipient list length has exceeded maximum."
+          | otherwise              = void $ callAPI method
+            [ "artist" ?< artist
+            , "track" ?< track
+            , "recipient" ?< recipients
+            , "api_key" ?< apiKey
+            , "sk" ?< sessionKey
+            , "public" ?< public
+            , "message" ?< message
+            ]
+            where method = "track.share"
+
+-- | Unban a track for a user profile.
+--
+-- More: <http://www.lastfm.ru/api/show/track.unban>
+unban :: Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+unban artist track apiKey sessionKey = dispatch $ void $ callAPI "track.unban"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Unlove a track for a user profile.
+--
+-- More: <http://www.lastfm.ru/api/show/track.unlove>
+unlove :: Artist -> Track -> APIKey -> SessionKey -> Lastfm ()
+unlove artist track apiKey sessionKey = dispatch $ void $ callAPI "track.unlove"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+
+-- | Used to notify Last.fm that a user has started listening to a track. Parameter names are case sensitive.
+--
+-- More: <http://www.lastfm.ru/api/show/track.updateNowPlaying>
+updateNowPlaying :: Artist
+                 -> Track
+                 -> Maybe Album
+                 -> Maybe AlbumArtist
+                 -> Maybe Context
+                 -> Maybe TrackNumber
+                 -> Maybe Mbid
+                 -> Maybe Duration
+                 -> APIKey
+                 -> SessionKey
+                 -> Lastfm ()
+updateNowPlaying artist track album albumArtist context trackNumber mbid duration apiKey sessionKey = dispatch $ void $ callAPI "track.updateNowPlaying"
+  [ "artist" ?< artist
+  , "track" ?< track
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  , "album" ?< album
+  , "albumArtist" ?< albumArtist
+  , "context" ?< context
+  , "trackNumber" ?< trackNumber
+  , "mbid" ?< mbid
+  , "duration" ?< duration
+  ]
diff --git a/Network/Lastfm/API/User.hs b/Network/Lastfm/API/User.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/User.hs
@@ -0,0 +1,303 @@
+-- | User API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.User
+  ( getArtistTracks, getBannedTracks, getEvents, getFriends, getInfo, getLovedTracks
+  , getNeighbours, getNewReleases, getPastEvents, getPersonalTags, getPlaylists, getRecentStations
+  , getRecentTracks, getRecommendedArtists, getRecommendedEvents, getShouts, getTopAlbums
+  , getTopArtists, getTopTags, getTopTracks, getWeeklyAlbumChart, getWeeklyArtistChart
+  , getWeeklyChartList, getWeeklyTrackChart, shout
+  ) where
+
+import Control.Monad (void)
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ( (?<), APIKey, Artist, FestivalsOnly, From, Limit, Message, Page
+                            , Period, RecentTracks, SessionKey, Tag, TaggingType, To, User, UseRecs
+                            )
+
+-- | Get a list of tracks by a given artist scrobbled by this user, including scrobble time. Can be limited to specific timeranges, defaults to all time.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getArtistTracks>
+getArtistTracks :: User
+                -> Artist
+                -> Maybe From
+                -> Maybe To
+                -> Maybe Page
+                -> APIKey
+                -> Lastfm Response
+getArtistTracks user artist startTimestamp endTimestamp page apiKey = dispatch $ callAPI "user.getArtistTracks"
+  [ "user" ?< user
+  , "artist" ?< artist
+  , "startTimestamp" ?< startTimestamp
+  , "page" ?< page
+  , "endTimestamp" ?< endTimestamp
+  , "api_key" ?< apiKey
+  ]
+
+-- | Returns the tracks banned by the user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getBannedTracks>
+getBannedTracks :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getBannedTracks user page limit apiKey = dispatch $ callAPI "user.getBannedTracks"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of upcoming events that this user is attending.
+--
+-- Mpre: <http://www.lastfm.ru/api/show/user.getEvents>
+getEvents :: User -> Maybe Page -> Maybe Limit -> Maybe FestivalsOnly -> APIKey -> Lastfm Response
+getEvents user page limit festivalsOnly apiKey = dispatch $ callAPI "user.getEvents"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "festivalsonly" ?< festivalsOnly
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of the user's friends on Last.fm.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getFriends>
+getFriends :: User -> Maybe RecentTracks -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getFriends user recentTracks page limit apiKey = dispatch $ callAPI "user.getFriends"
+  [ "user" ?< user
+  , "recenttracks" ?< recentTracks
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get information about a user profile.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getInfo>
+getInfo :: Maybe User -> APIKey -> Lastfm Response
+getInfo user apiKey = dispatch $ callAPI "user.getInfo"
+  [ "user" ?< user
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get tracks loved by a user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getLovedTracks>
+getLovedTracks :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getLovedTracks user page limit apiKey = dispatch $ callAPI "user.getLovedTracks"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of a user's neighbours on Last.fm.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getNeighbours>
+getNeighbours :: User -> Maybe Limit -> APIKey -> Lastfm Response
+getNeighbours user limit apiKey = dispatch $ callAPI "user.getNeighbours"
+  [ "user" ?< user
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Gets a list of forthcoming releases based on a user's musical taste.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getNewReleases>
+getNewReleases :: User -> Maybe UseRecs -> APIKey -> Lastfm Response
+getNewReleases user useRecs apiKey = dispatch $ callAPI "user.getNewReleases"
+  [ "user" ?< user
+  , "userecs" ?< useRecs
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a paginated list of all events a user has attended in the past.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getPastEvents>
+getPastEvents :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getPastEvents user page limit apiKey = dispatch $ callAPI "user.getPastEvents"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the user's personal tags.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getPersonalTags>
+getPersonalTags :: User
+                -> Tag
+                -> TaggingType
+                -> Maybe Page
+                -> Maybe Limit
+                -> APIKey
+                -> Lastfm Response
+getPersonalTags user tag taggingType page limit apiKey = dispatch $ callAPI "user.getPersonalTags"
+  [ "user" ?< user
+  , "tag" ?< tag
+  , "taggingtype" ?< taggingType
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of a user's playlists on Last.fm.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getPlaylists>
+getPlaylists :: User -> APIKey -> Lastfm Response
+getPlaylists user apiKey = dispatch $ callAPI "user.getPlaylists"
+  [ "user" ?< user
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of the recent Stations listened to by this user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getRecentStations>
+getRecentStations :: User -> Maybe Page -> Maybe Limit -> APIKey -> SessionKey -> Lastfm Response
+getRecentStations user page limit apiKey sessionKey = dispatch $ callAPI "user.getRecentStations"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Get a list of the recent tracks listened to by this user. Also includes the currently playing track with the nowplaying="true" attribute if the user is currently listening.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getRecentTracks>
+getRecentTracks :: User -> Maybe Page -> Maybe Limit -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getRecentTracks user page limit from to apiKey = dispatch $ callAPI "user.getRecentTracks"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "from" ?< from
+  , "to" ?< to
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get Last.fm artist recommendations for a user.
+--
+-- Mpre: <http://www.lastfm.ru/api/show/user.getRecommendedArtists>
+getRecommendedArtists :: Maybe Page -> Maybe Limit -> APIKey -> SessionKey -> Lastfm Response
+getRecommendedArtists page limit apiKey sessionKey = dispatch $ callAPI "user.getRecommendedArtists"
+  [ "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Get a paginated list of all events recommended to a user by Last.fm, based on their listening profile.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getRecommendedEvents>
+getRecommendedEvents :: Maybe Page -> Maybe Limit -> APIKey -> SessionKey -> Lastfm Response
+getRecommendedEvents page limit apiKey sessionKey = dispatch $ callAPI "user.getRecommendedEvents"
+  [ "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
+
+-- | Get shouts for this user. Also available as an rss feed.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getShouts>
+getShouts :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getShouts user page limit apiKey = dispatch $ callAPI "user.getShouts"
+  [ "user" ?< user
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the top albums listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getTopAlbums>
+getTopAlbums :: User -> Maybe Period -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopAlbums user period page limit apiKey = dispatch $ callAPI "user.getTopAlbums"
+  [ "user" ?< user
+  , "period" ?< period
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the top artists listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getTopArtists>
+getTopArtists :: User -> Maybe Period -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopArtists user period page limit apiKey = dispatch $ callAPI "user.getTopArtists"
+  [ "user" ?< user
+  , "period" ?< period
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the top tags used by this user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getTopTags>
+getTopTags :: User -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTags user limit apiKey = dispatch $ callAPI "user.getTopTags"
+  [ "user" ?< user
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get the top tracks listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getTopTracks>
+getTopTracks :: User -> Maybe Period -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getTopTracks user period page limit apiKey = dispatch $ callAPI "user.getTopTracks"
+  [ "user" ?< user
+  , "period" ?< period
+  , "page" ?< page
+  , "limit" ?< limit
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get an album chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent album chart for this user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getWeeklyAlbumChart>
+getWeeklyAlbumChart :: User -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getWeeklyAlbumChart user from to apiKey = dispatch $ callAPI "user.getWeeklyAlbumChart"
+  [ "user" ?< user
+  , "from" ?< from
+  , "to" ?< to
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get an artist chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent artist chart for this user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getWeeklyArtistChart>
+getWeeklyArtistChart :: User -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getWeeklyArtistChart user from to apiKey = dispatch $ callAPI "user.getWeeklyArtistChart"
+  [ "user" ?< user
+  , "from" ?< from
+  , "to" ?< to
+  , "api_key" ?< apiKey
+  ]
+
+-- | Get a list of available charts for this user, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getWeeklyChartList>
+getWeeklyChartList :: User -> APIKey -> Lastfm Response
+getWeeklyChartList user apiKey = dispatch $ callAPI "user.getWeeklyChartList" ["user" ?< user, "api_key" ?< apiKey]
+
+-- | Get a track chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent track chart for this user.
+--
+-- More: <http://www.lastfm.ru/api/show/user.getWeeklyTrackChart>
+getWeeklyTrackChart :: User -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
+getWeeklyTrackChart user from to apiKey = dispatch $ callAPI "user.getWeeklyTrackChart"
+  [ "user" ?< user
+  , "from" ?< from
+  , "to" ?< to
+  , "api_key" ?< apiKey
+  ]
+
+-- | Shout on this user's shoutbox.
+--
+-- More: <http://www.lastfm.ru/api/show/user.shout>
+shout :: User -> Message -> APIKey -> SessionKey -> Lastfm ()
+shout user message apiKey sessionKey = dispatch $ void $ callAPI "user.shout"
+  [ "user" ?< user
+  , "message" ?< message
+  , "api_key" ?< apiKey
+  , "sk" ?< sessionKey
+  ]
diff --git a/Network/Lastfm/API/Venue.hs b/Network/Lastfm/API/Venue.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/API/Venue.hs
@@ -0,0 +1,42 @@
+-- | Venue API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.API.Venue
+  ( getEvents, getPastEvents, search
+  ) where
+
+import Network.Lastfm.Response
+import Network.Lastfm.Types ((?<), APIKey, Country, FestivalsOnly, Limit, Name, Page, Venue)
+
+-- | Get a list of upcoming events at this venue.
+--
+-- More: <http://www.lastfm.ru/api/show/venue.getEvents>
+getEvents :: Venue -> Maybe FestivalsOnly -> APIKey -> Lastfm Response
+getEvents venue festivalsOnly apiKey = dispatch $ callAPI "venue.getEvents"
+  [ "venue" ?< venue
+  , "api_key" ?< apiKey
+  , "festivalsonly" ?< festivalsOnly
+  ]
+
+-- | Get a paginated list of all the events held at this venue in the past.
+--
+-- More: <http://www.lastfm.ru/api/show/venue.getPastEvents>
+getPastEvents :: Venue -> Maybe FestivalsOnly -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
+getPastEvents venue festivalsOnly page limit apiKey = dispatch $ callAPI "venue.getPastEvents"
+  [ "venue" ?< venue
+  , "api_key" ?< apiKey
+  , "festivalsonly" ?< festivalsOnly
+  , "page" ?< page
+  , "limit" ?< limit
+  ]
+
+-- | Search for a venue by venue name.
+--
+-- More: <http://www.lastfm.ru/api/show/venue.search>
+search :: Name -> Maybe Page -> Maybe Limit -> Maybe Country -> APIKey -> Lastfm Response
+search venue page limit country apiKey = dispatch $ callAPI "venue.search"
+  [ "venue" ?< venue
+  , "api_key" ?< apiKey
+  , "page" ?< page
+  , "limit" ?< limit
+  , "country" ?< country
+  ]
diff --git a/Network/Lastfm/Response.hs b/Network/Lastfm/Response.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/Response.hs
@@ -0,0 +1,143 @@
+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}
+-- | Response module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.Response
+  ( Lastfm, Response, LastfmError(WrapperCallError), dispatch
+  , withSecret
+  , callAPI
+  ) where
+
+import Codec.Binary.UTF8.String (encodeString)
+import Control.Applicative ((<$>))
+import Control.Arrow (second)
+import Control.Exception (Exception, handle, throw)
+import Control.Monad ((<=<), liftM)
+import Data.Digest.Pure.MD5 (md5)
+import Data.Function (on)
+import Data.IORef
+import Data.List (sortBy)
+import Data.Typeable (Typeable)
+import Data.URLEncoded (urlEncode, export)
+import Network.Curl hiding (Content)
+import System.IO.Unsafe (unsafePerformIO)
+import Text.XML.Light
+
+import qualified Data.ByteString.Lazy.Char8 as BS
+
+data APIError
+  = DoesntExist
+  | InvalidService
+  | InvalidMethod
+  | AuthenticationFailed
+  | InvalidFormat
+  | InvalidParameters
+  | InvalidResource
+  | OperationFailed
+  | InvalidSessionKey
+  | InvalidAPIKey
+  | ServiceOffline
+  | SubscribersOnly
+  | InvalidMethodSignature
+  | TokenHasNotAuthorized
+  | NotForStreaming
+  | TemporaryUnavailable
+  | LoginRequired
+  | TrialExpired
+  | DoesntExistAgain
+  | NotEnoughContent
+  | NotEnoughMembers
+  | NotEnoughFans
+  | NotEnoughNeighbours
+  | NoPeakRadio
+  | RadioNotFound
+  | SuspendedAPIKey
+  | Deprecated
+  | RateLimitExceeded
+    deriving (Enum)
+
+instance Show APIError where
+  show DoesntExist = "DoesntExist: This error does not exist"
+  show InvalidService = "InvalidService: This service does not exist"
+  show InvalidMethod = "InvalidMethod: No method with that name in this package"
+  show AuthenticationFailed = "AuthenticationFailed: You do not have permissions to access the service"
+  show InvalidFormat = "InvalidFormat: This service doesn't exist in that format"
+  show InvalidParameters = "InvalidParameters: Your request is missing a required parameter"
+  show InvalidResource = "InvalidResource: Invalid resource specified"
+  show OperationFailed = "OperationFailed: Something else went wrong"
+  show InvalidSessionKey = "InvalidSessionKey: Please re-authenticate"
+  show InvalidAPIKey = "InvalidAPIKey: You must be granted a valid key by last.fm"
+  show ServiceOffline = "ServiceOffline: This service is temporarily offline. Try again later."
+  show SubscribersOnly  = "SubscribersOnly : This station is only available to paid last.fm subscribers"
+  show InvalidMethodSignature = "InvalidMethodSignature: Invalid method signature supplied"
+  show TokenHasNotAuthorized = "TokenHasNotAuthorized: This token has not been authorized"
+  show NotForStreaming = "NotForStreaming: This item is not available for streaming."
+  show TemporaryUnavailable = "TemporaryUnavailable: The service is temporarily unavailable, please try again."
+  show LoginRequired = "LoginRequired: Login: User requires to be logged in"
+  show TrialExpired = "TrialExpired: This user has no free radio plays left. Subscription required."
+  show DoesntExistAgain = "DoesntExistAgain: This error does not exist"
+  show NotEnoughContent = "NotEnoughContent: There is not enough content to play this station"
+  show NotEnoughMembers = "NotEnoughMembers: This group does not have enough members for radio"
+  show NotEnoughFans = "NotEnoughFans: This artist does not have enough fans for for radio"
+  show NotEnoughNeighbours = "NotEnoughNeighbours: There are not enough neighbours for radio"
+  show NoPeakRadio = "NoPeakRadio: This user is not allowed to listen to radio during peak usage"
+  show RadioNotFound = "RadioNotFound: Radio station not found"
+  show SuspendedAPIKey = "SuspendedAPIKey: Access for your account has been suspended, please contact Last.fm"
+  show Deprecated = "Deprecated: This type of request is no longer supported"
+  show RateLimitExceeded = "RateLimitExceeded: Your IP has made too many requests in a short period"
+
+-- Various Lastfm errors.
+data LastfmError
+  = LastfmAPIError APIError -- ^ Internal Lastfm errors
+  | WrapperCallError Method Message -- ^ Wrapper errors
+    deriving (Show, Typeable)
+
+instance Exception LastfmError
+
+-- | Type synonym for Lastfm response or error.
+type Lastfm a = IO (Either LastfmError a)
+-- | Type synonym for Lastfm response
+type Response = String
+type Key = String
+type Value = String
+type Secret = String
+type Sign = String
+type Method = String
+type Message = String
+
+secret :: IORef Secret
+secret = unsafePerformIO $ newIORef ""
+
+-- | All authentication requiring functions should be wrapped into 'withSecret'
+withSecret :: Secret -> IO a -> IO a
+withSecret s f = writeIORef secret s >> f
+
+url :: String
+url = "http://ws.audioscrobbler.com/2.0/?"
+
+-- | Low level function. Captures all exceptions and transform them into Either Error type.
+dispatch :: IO a -> Lastfm a
+dispatch f = handle (\(e :: LastfmError) -> return (Left e)) (liftM Right f)
+
+-- | Low level function. Sends POST query to Lastfm API.
+callAPI :: Method -> [(Key, Value)] -> IO Response
+callAPI m xs = withCurlDo $ do
+                 s <- readIORef secret
+                 let ys = ("method", m) : (map (second encodeString) . filter (not . null . snd) $ xs)
+                 let zs = if not $ null s then ("api_sig", sign s ys) : ys else ys
+                 response <- respBody <$> (curlGetResponse_ url
+                                            [ CurlPostFields . map (export . urlEncode) $ zs
+                                            , CurlFailOnError False
+                                            , CurlUserAgent "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 Iceweasel/10.0"
+                                            ]
+                                            :: IO CurlResponse)
+                 case isError response of
+                   Just n  -> throw $ LastfmAPIError (toEnum $ n - 1)
+                   Nothing -> return response
+
+  where -- | Some API calls should be signed. (http://www.lastfm.ru/api/authspec Section 8)
+        sign :: Secret -> [(Key, Value)] -> Sign
+        sign s = show . md5 . BS.pack . (++ s) . concatMap (uncurry (++)) . sortBy (compare `on` fst)
+
+        isError :: String -> Maybe Int
+        isError response = do xml <- parseXMLDoc response
+                              read <$> (findAttr (unqual "code") <=< findChild (unqual "error")) xml
diff --git a/Network/Lastfm/Types.hs b/Network/Lastfm/Types.hs
new file mode 100644
--- /dev/null
+++ b/Network/Lastfm/Types.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE FlexibleInstances, OverlappingInstances, TypeSynonymInstances, GeneralizedNewtypeDeriving #-}
+module Network.Lastfm.Types where
+
+import Data.List (intercalate)
+
+newtype Album = Album String deriving (Show, LastfmValue)
+newtype AlbumArtist = AlbumArtist String deriving (Show, LastfmValue)
+newtype APIKey = APIKey String deriving (Show, LastfmValue)
+newtype Artist = Artist String deriving (Show, LastfmValue)
+newtype AuthToken = AuthToken String deriving (Show, LastfmValue)
+newtype Autocorrect = Autocorrect Bool deriving (Show, LastfmValue)
+newtype Bitrate = Bitrate Int deriving (Show, LastfmValue)
+newtype BuyLinks = BuyLinks Bool deriving (Show, LastfmValue)
+newtype ChosenByUser = ChosenByUser String deriving (Show, LastfmValue)
+newtype Context = Context String deriving (Show, LastfmValue)
+newtype Country = Country String deriving (Show, LastfmValue)
+newtype Description = Description String deriving (Show, LastfmValue)
+newtype Discovery = Discovery Bool deriving (Show, LastfmValue)
+newtype Distance = Distance Int deriving (Show, LastfmValue)
+newtype Duration = Duration String deriving (Show, LastfmValue)
+newtype Event = Event Int deriving (Show, LastfmValue)
+newtype FestivalsOnly = FestivalsOnly Bool deriving (Show, LastfmValue)
+newtype Fingerprint = Fingerprint Integer deriving (Show, LastfmValue)
+newtype From = From Integer deriving (Show, LastfmValue)
+newtype Group = Group String deriving (Show, LastfmValue)
+newtype Language = Language String deriving (Show, LastfmValue)
+newtype Latitude = Latitude String deriving (Show, LastfmValue)
+newtype Limit = Limit Int deriving (Show, LastfmValue)
+newtype Location = Location String deriving (Show, LastfmValue)
+newtype Longitude = Longitude String deriving (Show, LastfmValue)
+newtype Mbid = Mbid String deriving (Show, LastfmValue)
+newtype Message = Message String deriving (Show, LastfmValue)
+newtype Metro = Metro String deriving (Show, LastfmValue)
+newtype Multiplier = Multiplier Double deriving (Show, LastfmValue)
+newtype Name = Name String deriving (Show, LastfmValue)
+newtype Page = Page Int deriving (Show, LastfmValue)
+newtype Playlist = Playlist Int deriving (Show, LastfmValue)
+newtype Public = Public Bool deriving (Show, LastfmValue)
+newtype RecentTracks = RecentTracks Bool deriving (Show, LastfmValue)
+newtype Recipient = Recipient String deriving (Show, LastfmValue)
+newtype RTP = RTP Bool deriving (Show, LastfmValue)
+newtype SessionKey = SessionKey String deriving (Show, LastfmValue)
+newtype Station = Station String deriving (Show, LastfmValue)
+newtype StreamId = StreamId String deriving (Show, LastfmValue)
+newtype Tag = Tag String deriving (Show, LastfmValue)
+newtype TaggingType = TaggingType String deriving (Show, LastfmValue)
+newtype Timestamp = Timestamp Integer deriving (Show, LastfmValue)
+newtype Title = Title String deriving (Show, LastfmValue)
+newtype To = To Integer deriving (Show, LastfmValue)
+newtype Token = Token String deriving (Show, LastfmValue)
+newtype Track = Track String deriving (Show, LastfmValue)
+newtype TrackNumber = TrackNumber String deriving (Show, LastfmValue)
+newtype User = User String deriving (Show, LastfmValue)
+newtype UseRecs = UseRecs Bool deriving (Show, LastfmValue)
+newtype Venue = Venue Int deriving (Show, LastfmValue)
+
+data Order = Popularity | DateAdded deriving Show
+
+instance LastfmValue Order where
+  unpack Popularity = "popularity"
+  unpack DateAdded  = "dateadded"
+
+data Status = Yes | Maybe | No deriving Show
+
+instance LastfmValue Status where
+  unpack Yes = "0"
+  unpack Maybe = "1"
+  unpack No = "2"
+
+class LastfmValue a where
+  unpack :: a -> String
+
+data Value = ValueUser User
+           | ValueArtists [Artist]
+
+instance Show Value where
+  show (ValueUser _)    = "user"
+  show (ValueArtists _) = "artists"
+
+instance LastfmValue Value where
+  unpack (ValueUser u)     = unpack u
+  unpack (ValueArtists as) = unpack as
+
+data Period = Week | Quater | HalfYear | Year | Overall
+              deriving (Show)
+
+instance LastfmValue Period where
+  unpack Week     = "7day"
+  unpack Quater   = "3month"
+  unpack HalfYear = "6month"
+  unpack Year     = "12month"
+  unpack Overall  = "overall"
+
+instance LastfmValue Bool where
+  unpack True = "1"
+  unpack False = "0"
+instance LastfmValue Int where
+  unpack = show
+instance LastfmValue Integer where
+  unpack = show
+instance LastfmValue Double where
+  unpack = show
+instance LastfmValue String where
+  unpack = id
+instance LastfmValue a => LastfmValue [a] where
+  unpack = intercalate "," . map unpack
+instance LastfmValue a => LastfmValue (Maybe a) where
+  unpack (Just a) = unpack a
+  unpack Nothing  = ""
+
+(?<) :: LastfmValue a => String -> a -> (String, String)
+a ?< b = (a, unpack b)
+
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/liblastfm.cabal b/liblastfm.cabal
new file mode 100644
--- /dev/null
+++ b/liblastfm.cabal
@@ -0,0 +1,25 @@
+Name:		liblastfm
+Version:	0.0.1.0
+Description:	Wrapper to Lastfm API
+License:	MIT
+License-file:	LICENSE
+Author:		Matvey Aksenov, Dmitry Malikov
+Maintainer:	Matvey Aksenov <matvey.aksenov@gmail.com>
+Category:	Network
+Synopsis:	Wrapper to Lastfm API
+Cabal-Version:	>= 1.6
+Build-Type:	Simple
+
+Library
+  Build-Depends:	base >= 3 && < 5, bytestring, curl, pureMD5, urlencoded, xml, utf8-string
+  Exposed-Modules:	Network.Lastfm.Response, Network.Lastfm.Types, Network.Lastfm.API.Album, Network.Lastfm.API.Artist, Network.Lastfm.API.Auth, Network.Lastfm.API.Chart, Network.Lastfm.API.Event, Network.Lastfm.API.Geo, Network.Lastfm.API.Group, Network.Lastfm.API.Library, Network.Lastfm.API.Playlist, Network.Lastfm.API.Radio, Network.Lastfm.API.Tag, Network.Lastfm.API.Tasteometer, Network.Lastfm.API.Track, Network.Lastfm.API.User, Network.Lastfm.API.Venue
+  Extensions:		FlexibleInstances, OverlappingInstances, GeneralizedNewtypeDeriving, ScopedTypeVariables, TypeSynonymInstances
+
+source-repository head
+  type:     git
+  location: https://github.com/supki/haskell-liblastfm
+
+source-repository this
+  type:     git
+  location: https://github.com/supki/haskell-liblastfm
+  tag:      v0.0.1.0
