diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Michal J. Gajda
+
+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 Michal J. Gajda 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+WordPass
+========
+
+Dictionary-based password generator.
+
+Uses dictionaries from /usr/share/dict by default.
+You might want to look and change the code, since it is not intended as CLI yet :-).
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/WordPass.hs b/WordPass.hs
new file mode 100644
--- /dev/null
+++ b/WordPass.hs
@@ -0,0 +1,101 @@
+-- | Main module generating passwords.
+module Main where
+
+import           System.Directory(getDirectoryContents)
+import qualified Data.Text    as Text
+import qualified Data.Text.IO as Text
+import           Data.Text(Text)
+import qualified Data.Set     as Set
+import           Data.Char           (isAlpha, isPunctuation, isSymbol)
+import           Data.Random.RVar
+import           Data.Random.Sample
+import           Data.Random.RVar.Enum
+import           Data.Random.Distribution
+import           Data.Random.Distribution.Uniform
+import           Data.Random.Source.IO
+import qualified Data.Vector  as V
+import           Control.Applicative
+import           Control.Monad       (replicateM, foldM)
+
+-- | Reads a dict format to get a list of unique words without any special
+--   chars.
+readDict ::  FilePath -> IO (V.Vector Text)
+readDict filename = do
+    input <- Text.readFile filename
+    return $! V.fromList . Set.toList . Set.fromList . map stripTails . Text.lines $! input
+  where
+    stripTails = head . Text.split (not . isAlpha)
+
+-- | Find all plausible dictionaries in a given directory
+dictFiles dir = postprocess `fmap`
+                  getDirectoryContents dir
+  where
+    postprocess = map ((dir ++ "/") ++) . filter (not . (=='.') . head)
+
+-- | Default directory where to look for the word lists.
+defaultDictDir :: FilePath
+defaultDictDir = "/usr/share/dict"
+
+-- | Read a set of dictionaries and put the together.
+readDicts filenames = (V.fromList . Set.toList) `fmap` foldM action Set.empty filenames
+  where
+    action currentSet filename = do newSet <- readDict filename
+                                    return $! Set.fromList (V.toList newSet) `Set.union` currentSet
+
+-- | Read all dictionaries from a given directory.
+readDictDir dirname = dictFiles dirname >>= readDicts
+
+-- | Filename for default dictionary (should be command line argument or default glob.)
+defaultDictionary ::  FilePath
+defaultDictionary = "/usr/share/dict/british-english"
+
+-- | Take a random element of a vector.
+randomElement :: V.Vector a -> RVar a
+randomElement words = (words V.!) <$> uniform 0 (V.length words - 1)
+
+-- | Pick a random password, given a words list, and a number of words it will contain.
+randomPassword :: V.Vector Text -> Int -> RVar Text
+randomPassword words numWords = do ws   <- replicateM numWords $ randomElement words
+                                   seps <- replicateM numWords randomSeparator
+                                   return $ Text.concat $ zipWith Text.append ws seps
+
+-- | Estimate strength of random password with given inputs.
+randomPasswordStrength words numWords = fromIntegral numWords * logBase 2 wordStrength
+  where
+    wordStrength = fromIntegral $ V.length words * (32 + 100)
+
+-- * Random separators
+-- | Randomly pick a word separator as a two-digit number, or a symbol
+--   character.
+randomSeparator ::  RVar Text
+randomSeparator = do b <- uniform False True
+                     if b then symbolSeparator
+                          else numericSeparator
+
+-- | Two-digit number as a separator 10^2 = 6.6 bits of entropy.
+numericSeparator ::  RVar Text
+numericSeparator = Text.pack <$> show <$> uniform 0 (99 :: Int)
+
+-- | Conjunction of two unary predicates
+(|||) ::  (t -> Bool) -> (t -> Bool) -> t -> Bool
+(|||) f g x = f x || g x
+
+-- | List of symbol and punctuation characters in ASCII
+--   Should be 5 bits of entropy
+symbolChars ::  V.Vector Char
+symbolChars = V.fromList $ filter (isSymbol ||| isPunctuation) $ map toEnum [0..127]
+
+-- | Text with random symbol character, 5 bits of entropy
+symbolSeparator ::  RVar Text
+symbolSeparator = Text.singleton <$> randomElement symbolChars
+
+main = do dictWords <- readDictDir defaultDictDir
+          --print $ V.length dictWords
+          putStr "Estimated password strength (bits): "
+          print $ randomPasswordStrength dictWords numWs
+          replicateM 5 $ do 
+            rv <- sample $ randomPassword dictWords numWs
+            Text.putStrLn rv
+  where
+    numWs = 5
+  
diff --git a/wordpass.cabal b/wordpass.cabal
new file mode 100644
--- /dev/null
+++ b/wordpass.cabal
@@ -0,0 +1,25 @@
+-- Initial wordpass.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                wordpass
+version:             0.1.0.0
+synopsis:            Dictionary-based password generator
+-- description:         
+homepage:            https://github.com/mjgajda/wordpass
+license:             BSD3
+license-file:        LICENSE
+author:              Michal J. Gajda
+maintainer:          mjgajda@gmail.com
+-- copyright:           
+category:            System
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+executable wordpass
+  main-is:             WordPass.hs
+  -- other-modules:    Data.Random.RVar.Enum   
+  other-extensions:    OverlappingInstances, MultiParamTypeClasses, FlexibleInstances
+  build-depends:       base >=4.6 && <4.7, text >=1.1 && <1.2, containers >=0.5 && <0.6, random-fu >=0.2 && <0.3, random-source >=0.3 && <0.4, vector >=0.10 && <0.11, directory >= 1.2 && < 1.4
+  -- hs-source-dirs:      
+  default-language:    Haskell2010
