diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2012 Matvey Aksenov
+
+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/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/librandomorg.cabal b/librandomorg.cabal
new file mode 100644
--- /dev/null
+++ b/librandomorg.cabal
@@ -0,0 +1,19 @@
+name:                librandomorg
+version:             0.0.1.0
+synopsis:            Wrapper to Random.org API
+description:         Simple but complete wrapper to Random.org API
+homepage:            https://github.com/supki/haskell-random.org
+license:             MIT
+license-file:        LICENSE
+author:              Matvey Aksenov
+maintainer:          matvey.aksenov@gmail.com
+category:            Network APIs
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  build-depends:       base >= 3 && < 5, curl == 1.3.7, bytestring == 0.9.*
+  hs-source-dirs:      src
+  exposed-modules:     Network.Randomorg
+  GHC-options:         -Wall
+                       -fno-warn-unused-do-bind
diff --git a/src/Network/Randomorg.hs b/src/Network/Randomorg.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Randomorg.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE UnicodeSyntax #-}
+{-# LANGUAGE ViewPatterns #-}
+-- | Random.org API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Randomorg
+  ( RNG(..)
+  , integers, shuffle, strings, quota
+  ) where
+
+import Control.Applicative ((<$>))
+import Data.ByteString.Char8 (ByteString, readInteger, readInt)
+import Data.List (intercalate)
+import Data.Maybe (fromMaybe)
+import Data.Word (Word8)
+import Network.Curl
+import Prelude hiding (max, min)
+import qualified Data.ByteString.Char8 as B
+
+-- | Specify the randomization method
+data RNG = New -- ^ Truly random bitstream
+         | Id String -- ^ Determine randomization from a large pool of pregenerated bits
+         | Date String -- ^ Determine randomization based on one of the daily pregenerated files. The date must be in YYYY-MM-DD format or one of the two shorthand strings `today' or `yesterday'.
+
+class Get α where
+  get ∷ α → String
+  getF ∷ (Functor μ, Get α) ⇒ μ α → μ String
+  getF = fmap get
+
+instance Get Int where
+  get = show
+instance Get Bool where
+  get True = "on"
+  get False = "off"
+instance Get (Word8,Word8,Word8,Word8) where
+  get (α,β,γ,δ) = intercalate "." . map show $ [α,β,γ,δ]
+instance Get RNG where
+  get New = "new"
+  get (Id s) = "id." ++ s
+  get (Date s) = "date." ++ s
+
+-- | Generate random integers in configurable intervals
+integers ∷ Int -- ^ Number of integers to generate ([1,1e4])
+         → Int -- ^ Minimum value (-1e9,1e9)
+         → Int -- ^ Maximum value (-1e9,1e9)
+         → RNG
+         → IO (Maybe [Int])
+integers (get → n)
+         (get → min)
+         (get → max)
+         (get → rng) =
+  let url = "http://www.random.org/integers/?col=1&base=10&format=plain&"
+      params = zip ["num","min","max","rnd"] [n, min, max, rng]
+  in mapM (\l → fst <$> readInt l) . B.lines . respBody <$> query url params
+
+-- | Shuffle integers in given interval
+--
+-- NOTE: Maintains the invariant `max - min + 1 <= 1e4'
+--
+-- NOTE: Doesn't maintain the invariant `max >= min'
+shuffle ∷ Int -- ^ Minimum value (-1e9,1e9)
+        → Int -- ^ Maximum value (-1e9,1e9)
+        → RNG
+        → IO (Maybe [Int])
+shuffle min
+        max
+        (get → rng)
+  | max - min + 1 <= 10000 =
+    let url = "http://www.random.org/sequences/?col=1&format=plain&"
+        params = zip ["min","max","rnd"] [get min, get max, rng]
+    in mapM (\l → fst <$> readInt l) . B.lines . respBody <$> query url params
+  | otherwise = return Nothing
+
+-- | Generate random strings of various length and composition
+strings ∷ Int -- ^ Number of strings to generate ([1,1e4])
+        → Int -- ^ Length of each string ([1,20])
+        → Bool -- ^ Allow digits
+        → Bool -- ^ Allow uppercase alphabetic characters
+        → Bool -- ^ Allow lowercase alphabetic characters
+        → Bool -- ^ Whether all string should be unique
+        → RNG
+        → IO [String]
+strings (get → n)
+        (get → l)
+        (get → digits)
+        (get → upper)
+        (get → lower)
+        (get → unique)
+        (get → rng) =
+  let url = "http://www.random.org/strings/?format=plain&"
+      params = zip ["num","len","digits","upperalpha","loweralpha","unique","rnd"] [n, l, digits, upper, lower, unique, rng]
+  in map B.unpack . B.lines . respBody <$> query url params
+
+-- | Examine quota for given IP address
+quota ∷ Maybe (Word8, Word8, Word8, Word8)-- ^ Optional IP address. If not provided use IP of the caller
+      → IO (Maybe Integer)
+quota (getF → ip) =
+  let url = "http://www.random.org/quota/?format=plain&"
+      params = zip ["ip"] [fromMaybe "" ip]
+  in (fst <$>) . readInteger . respBody <$> query url params
+
+query ∷ String → [(String,String)] → IO (CurlResponse_ [(String, String)] ByteString)
+query url (filter (not . null . snd) → params) =
+  let ua = "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 Iceweasel/10.0"
+  in withCurlDo $ curlGetResponse_ (url ++ intercalate "&" (map (\(k,v) → k ++ "=" ++ v) params))
+       [ CurlFailOnError False
+       , CurlUserAgent ua
+       ]
