diff --git a/Konf.cabal b/Konf.cabal
new file mode 100644
--- /dev/null
+++ b/Konf.cabal
@@ -0,0 +1,21 @@
+name:                Konf
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+synopsis:            A configuration language and a parser.
+description:         Konf is a minimal konfiguration language, and ``Text.Konf'' is an implementation of this language.
+category:            Unix, Configuration
+homepage:            http://www.gkayaalp.com/p/konf.html
+license:             OtherLicense
+license-file:        LICENSE
+author:              Göktuğ Kayaalp
+maintainer:          self@gkayaalp.com
+category:            Text
+build-type:          Simple
+cabal-version:       >=1.8
+library
+  hs-source-dirs:      Src
+  exposed-modules:     Text.Konf
+  build-depends:       base ==4.6.*, parsec ==3.1.*, containers ==0.5.*
+  
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2013 Göktuğ Kayaalp <self@gkayaalp.com>
+
+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.
+
+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 HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/Src/Text/Konf.hs b/Src/Text/Konf.hs
new file mode 100644
--- /dev/null
+++ b/Src/Text/Konf.hs
@@ -0,0 +1,171 @@
+--------------------------------------------------------------------------------
+-- |
+-- Module      : Text.Konf
+-- Copyright   : (C) 2013 Göktuğ Kayaalp
+-- License     : Two Clause BSD License (see file LICENSE)
+--
+-- Maintainer  : Göktuğ Kayaalp <self@gkayaalp.com>
+-- Stability   : Experimental
+-- Portability : Not known
+--------------------------------------------------------------------------------
+
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- |
+-- @Text.Konf@ is an implementation of the Konf language.
+module Text.Konf
+( Konf
+, KonfValue(..)
+, KonfException(..)
+, konf
+, konfFile
+, lookup ) where
+
+import Prelude hiding (lookup)
+import Text.ParserCombinators.Parsec
+import Text.Parsec.Error
+import qualified Control.Exception as CE
+import qualified Control.Monad as CM
+import qualified Data.Map.Lazy as DML
+import qualified Data.Typeable as DT
+
+-- |
+-- This data type enumerates the possible types a returned value may be.
+-- Any value will be returned as a @KonfValue value@.
+data KonfValue = KonfString String
+               | KonfNumber Float
+               | KonfComplex Float Float
+               | KonfBoolean Bool
+               | KonfIdentifier String
+               | KonfList [KonfValue]
+               | KonfUndefined
+               deriving Show
+
+-- |
+-- The @Konf@ data type, a map from strings to values. This is actually a
+-- parameterized @Data.Map.Lazy.Map@ and it is possible to use method in that
+-- module on this type.
+type Konf = DML.Map String KonfValue
+
+data KonfException = SyntaxError String
+                     deriving (Show, DT.Typeable)
+
+instance CE.Exception KonfException
+
+parseIdentifier :: Parser String
+parseIdentifier = letter >>= \initial -> 
+                    many alphaNum >>= \rest -> return (initial : rest)
+
+parseFloat :: Parser KonfValue
+parseFloat = many1 digit >>= \d ->
+               -- `optionMaybe p' tries `p', if fails w/o consuming input,
+               -- returns `Nothing'.  If a number lacks a decimal part (this
+               -- parser return `Nothing'), it is appended `.0', thus
+               -- combining the parsing of numbers in one parser and making it
+               -- possible the complex number literal include integers w/o
+               -- modifying it.
+               optionMaybe decimalPart >>= \f ->
+                 return $ KonfNumber $ read
+                   (case f of
+                     Just dp -> (d ++ "." ++ dp)
+                     Nothing -> (d ++ ".0"))
+        -- Parse `.' here to let the parser fail w/o consuming input if the
+        -- literal has no decimal part.
+  where decimalPart = char '.' >> many1 digit --  >>= return
+
+parseComplex :: Parser KonfValue
+parseComplex = parseFloat >>= \ (KonfNumber r) ->
+                 skip >> char '+' >> skip >> parseFloat >>= \ (KonfNumber i) ->
+                   (char 'i' <|> char 'j') >> return (KonfComplex r i)
+  where skip = skipMany $ oneOf " \t"
+
+parseNumber :: Parser KonfValue
+parseNumber = try parseComplex <|> try parseFloat
+               
+parseBoolean :: Parser KonfValue
+parseBoolean = true <|> false
+  where
+    true  = string "true"  >> return (KonfBoolean True)
+    false = string "false" >> return (KonfBoolean False)
+
+parseString :: Parser KonfValue
+parseString = begin >>= \open ->
+                many (noneOf "\\\"'" <|> escape) >>= \str ->
+                  end open >> (return . KonfString) str
+  where begin = oneOf "\"'"
+        end character = char character
+        escapeChar 'n' = '\n'
+        escapeChar 't' = '\t'
+        escapeChar 'r' = '\r'
+        escapeChar 'b' = '\b'
+        escapeChar  e  =  e
+        escape = char '\\' >> letter >>= return . escapeChar
+
+parseIdentifierRValue :: Parser KonfValue
+parseIdentifierRValue = return . KonfIdentifier =<< parseIdentifier
+
+parseList :: Parser KonfValue
+parseList = open >> sepBy value comma >>= \l ->
+              close >> return (KonfList l)
+  where skip = skipMany $ oneOf " \t\n"
+        open = char '(' >> skip >> optional comment >> skip
+        close = skip >> optional comment >> skip >> char ')'
+        value = parseValue >>= \v ->
+                  skip >> optional comment >> skip >> return v
+        comma = char ',' >> skip >> optional comment >> skip
+
+comment :: Parser ()
+comment = CM.void (char '#' >> manyTill anyChar newline)
+
+parseValue :: Parser KonfValue
+parseValue = parseList <|> parseString <|> parseNumber <|> try parseBoolean <|> parseIdentifierRValue
+
+parsePair :: Parser (String, KonfValue)
+parsePair = identifier >>= \key -> 
+              equals >> parseValue >>= \value ->
+                skip >> return (key, value)
+  where skip = many $ oneOf " \t"
+        equals = skip >> char '=' >> skip
+        identifier = skip >> parseIdentifier
+
+parsePairs :: Parser [(String, KonfValue)]
+parsePairs = many getPair
+  where skip = comment <|> CM.void newline
+        terminate = (comment <|> CM.void (many1 newline)) >> optional eof
+        getPair = many skip >> parsePair >>= \pair ->
+                    terminate >> return pair
+
+showErr :: ParseError -> String
+showErr = show
+
+-- |
+-- Parse the string and return the resulting @Konf@ object, that can be
+-- looked up for keys by using the @lookup@ function.
+konf :: String -- ^ A string in the language of Konf.
+     -> Konf   -- ^ A specialized map, as the result of parsing.
+konf file = DML.fromList pairs
+  -- HACK: I bet appending a newline to the end of the string is the silliest hack ever.
+  where pairs = case parse parsePairs "konf" (file ++ "\n") of
+                  -- TODO: Don't `show' here, build the string by the error resources of parsec.
+                  Left err -> CE.throw $ SyntaxError ("Syntax error: " ++ showErr err)
+                  Right kvlist -> kvlist
+
+-- |
+-- Read a file and parse; then return the result as a @Konf@ object in the IO monad.
+konfFile :: FilePath -> IO Konf
+konfFile f = do str <- readFile f
+                return $ konf str
+
+
+-- |
+-- Lookup keys in the Konf object.
+--
+-- This is actually @Data.Map.Lazy.lookup@, but it additionally handles
+-- mapped to other identifiers, by recursively looking those keys up
+-- until it finds a value.
+lookup :: Konf -> String -> KonfValue
+lookup k key = case DML.lookup key k of
+                 Just (KonfIdentifier i) -> lookup k i
+                 Just value              -> value
+                 Nothing                 -> KonfUndefined
+
