diff --git a/HandsomeSoup.cabal b/HandsomeSoup.cabal
new file mode 100644
--- /dev/null
+++ b/HandsomeSoup.cabal
@@ -0,0 +1,61 @@
+-- HandsomeSoup.cabal auto-generated by cabal init. For additional
+-- options, see
+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
+-- The name of the package.
+Name:                HandsomeSoup
+
+-- The package version. See the Haskell package versioning policy
+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
+-- standards guiding when and how versions should be incremented.
+Version:             0.1
+
+-- A short (one-line) description of the package.
+Synopsis:            Work with HTML more easily in HXT
+
+-- A longer description of the package.
+Description: See examples and full readme on the Github page: https:\/\/github.com\/egonSchiele\/HandsomeSoup
+
+-- URL for the project homepage or repository.
+Homepage:            https://github.com/egonSchiele/HandsomeSoup
+
+-- The license under which the package is released.
+License:             BSD3
+
+-- The file containing the license text.
+License-file:        LICENSE
+
+-- The package author(s).
+Author:              Aditya Bhargava
+
+-- An email address to which users can send suggestions, bug reports,
+-- and patches.
+Maintainer:          bluemangroupie@gmail.com
+
+-- A copyright notice.
+-- Copyright:           
+
+Category:            Text
+
+Build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or
+-- a README.
+Extra-source-files: README.markdown
+
+-- Constraint on the version of Cabal needed to build this package.
+Cabal-version:       >=1.2
+
+
+Library
+  -- Modules exported by the library.
+  Exposed-modules:     Text.HandsomeSoup, Text.CSS.Parser
+  
+  -- Packages needed in order to build this package.
+  Build-depends: base < 5, transformers, HTTP, parsec, containers, mtl, MaybeT, hxt, network
+  
+  -- Modules not exported by this package.
+  Other-modules: Text.CSS.Utils
+  
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  -- Build-tools:         
+  
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2012, Aditya Bhargava
+
+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 Aditya Bhargava 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.markdown b/README.markdown
new file mode 100644
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,48 @@
+# HandsomeSoup
+
+Current Status: very very pre-alpha. Usable but buggy.
+
+HandsomeSoup is the library I wish I had when I started parsing HTML in Haskell.
+
+It is built on top of [HXT](http://www.fh-wedel.de/~si/HXmlToolbox/) and adds a few functions that make is easier to work with HTML.
+
+Most importantly, it adds CSS selectors to HXT. The goal of HandsomeSoup is to be a complete CSS2 parser for HXT (it is very close to this right now).
+
+## Example
+
+[Nokogiri](http://nokogiri.org/), the HTML parser for Ruby, has an example showing how to scrape Google search results. This is easy in HandsomeSoup:
+
+    main = do
+        doc <- fromUrl "http://www.google.com/search?q=egon+schiele"
+        links <- runX $ doc >>> css "h3.r a" ! "href"
+        mapM_ putStrLn links
+
+## What can HandsomeSoup do for you?
+
+### Easily parse an online page using `fromUrl`
+
+    doc <- fromUrl "http://example.com"
+
+### Or a local page using `parseHtml`
+
+    contents <- readFile [filename]
+    doc <- parseHtml contents
+
+### Easily extract elements using `css`
+
+Here are some valid selectors:
+
+    doc <<< css "a"
+    doc <<< css "*"
+    doc <<< css "a#link1"
+    doc <<< css "a.foo"
+    doc <<< css "p > a"
+    doc <<< css "#container h1"
+    doc <<< css "img[width]"
+    doc <<< css "img[width=400]"
+    doc <<< css "a[class~=bar]"
+
+### Easily get attributes using `(!)`
+
+    doc <<< css "img" ! "src"
+    doc <<< css "a" ! "href"
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/Text/CSS/Parser.hs b/Text/CSS/Parser.hs
new file mode 100644
--- /dev/null
+++ b/Text/CSS/Parser.hs
@@ -0,0 +1,106 @@
+module Text.CSS.Parser where
+
+import Text.Parsec
+import qualified Data.Functor.Identity as I
+import Data.List
+import Text.CSS.Utils
+
+-- if no tag name was given, sName will be set to '*'
+-- attrs are (attr name, attr value).
+-- if attr value is the empty string, we just check to
+-- make sure that the element has that attribute.
+-- if the attr value is prefixed with a '~', we treat
+-- that attribute as a list of words separated by a space
+-- and make sure that at least one of those words matches.
+data Selector = Selector { sName :: String, sAttrs :: [(String,String)], spseudoSelectores :: [String] } | Space | ChildOf | FollowedBy deriving (Show)
+
+-- pretty printers for debugging
+pp Space = "<space>"
+pp ChildOf = "<child of>"
+pp FollowedBy = "<followed by>"
+pp (Selector name attrs pseudo) = show name ++ ":" ++ showMap attrs ++ ", " ++ show pseudo
+    where showMap m = ("{" ++ (foldl (\acc (k,v) -> acc ++ (show k) ++ ":" ++ (show v) ++ ", ") "" m)) ++ "}"
+
+{- TYPE SELECTORS FOLLOW -}
+
+-- | selects a tag name, like @ h1 @
+typeSelector :: ParsecT [Char] u I.Identity [Char]
+typeSelector = many1 alphaNum
+
+-- | universal selector, selects @ * @
+universalSelector :: ParsecT [Char] u I.Identity String
+universalSelector = string "*"
+
+{- SECONDARY SELECTORS FOLLOW -}
+
+-- | selects a pseudo-element or pseudo-class, like @ :link @, @ :first-child @ etc.
+pseudoSelector :: ParsecT [Char] u I.Identity [Char]
+pseudoSelector = char ':' >> many1 (alphaNum <|> oneOf "-()")
+
+-- | class selector, selects @ .foo @
+classSelector :: ParsecT [Char] u I.Identity ([Char], [Char])
+classSelector = do
+    val <- char '.' >> many1 alphaNum
+    return ("class", '~':val)
+
+-- | id selector, selects @ #foo @
+idSelector :: ParsecT [Char] u I.Identity ([Char], [Char])
+idSelector = do
+    val <- char '#' >> many1 alphaNum
+    return ("id", val)
+
+-- | selects attributes, like @ [id] @ (element must have id) or @ [id=foo] @ (element must have id foo).
+attributeSelector :: ParsecT [Char] u I.Identity ([Char], [Char])
+attributeSelector = do
+      contents <- between (char '[') (char ']') (many1 (alphaNum <|> oneOf "~="))
+      if "~=" `isInfixOf` contents 
+          then return $ (\(a, b) -> (a, '~':b)) $ splitOn "~=" contents
+          else if '=' `elem` contents
+               then return $ splitOn "=" contents
+               else return (contents, "")
+
+-- | selector for everything after the type except pseudoSelectores
+secondarySelector = many1 (classSelector <|> idSelector <|> attributeSelector)
+
+{- COMBINATOR SELECTORS FOLLOW -}
+
+space_ = do
+    many1 $ string " "
+    return Space
+
+childOf = do
+    spaces >> string ">" >> spaces
+    return ChildOf
+
+followedBy = do
+    spaces >> string "+" >> spaces
+    return FollowedBy
+
+{- SIMPLE SELECTORS FOLLOW -}
+
+-- | selects a tagname followed by one or more secondary selectors
+-- example: @ a.foo @, @ *#hello @, @ h1 @ etc
+simpleSelectorTag :: ParsecT [Char] u I.Identity Selector
+simpleSelectorTag = do
+    tagName <- typeSelector <|> universalSelector
+    attrs <- secondarySelector <|> return []
+    pseudo <- many1 pseudoSelector <|> return []
+    return $ Selector tagName attrs pseudo
+
+-- | selects one or more secondary selectors
+-- and automatically prepends the universal selector to them.
+-- example: @ .foo @, @ #hello @ etc
+simpleSelectorNoTag = do
+    attrs <- secondarySelector
+    pseudo <- many1 pseudoSelector <|> return []
+    return $ Selector "*" attrs pseudo
+
+-- | A simple selector is either a type selector or universal selector followed immediately by zero or more attribute selectors, ID selectors, or pseudo-classes, in any order.
+simpleSelector :: ParsecT [Char] u I.Identity Selector
+simpleSelector = simpleSelectorTag <|> simpleSelectorNoTag <|> try childOf <|> try followedBy <|> space_
+
+-- | One or more simple selectors separated by combinators. 
+selector :: ParsecT [Char] u I.Identity [[Selector]]
+selector = many1 simpleSelector `sepBy` (spaces >> string "," >> spaces)
+
+css = parse selector ""
diff --git a/Text/CSS/Utils.hs b/Text/CSS/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Text/CSS/Utils.hs
@@ -0,0 +1,12 @@
+module Text.CSS.Utils where
+import Data.List
+
+-- like break, except don't keep the element you broke on.
+-- and it takes a list as the thing to break on.
+splitOn a xs = _splitOn a "" xs
+
+_splitOn _ begin [] = (begin, [])
+_splitOn a begin end@(x:xs)
+  | a `isPrefixOf` end = (begin, drop (length a) end)
+  | otherwise = _splitOn a (begin ++ [x]) xs
+
diff --git a/Text/HandsomeSoup.hs b/Text/HandsomeSoup.hs
new file mode 100644
--- /dev/null
+++ b/Text/HandsomeSoup.hs
@@ -0,0 +1,70 @@
+module Text.HandsomeSoup (openUrl, fromUrl, parseHtml, (!), css) where
+
+import Text.XML.HXT.Core
+import Network.HTTP
+import Network.URI
+import Data.Tree.NTree.TypeDefs
+import Control.Monad.Maybe
+import Control.Monad.Trans
+import Data.Maybe
+import Text.Parsec
+import qualified Data.Map as M
+import Data.Monoid (mconcat)
+import qualified Data.Functor.Identity as I
+import qualified Debug.Trace as D
+import Data.List
+import Control.Monad
+import Text.CSS.Parser hiding (css)
+
+-- | Helper function for getting page content. Example:
+--
+-- > contents <- runMaybeT $ openUrl "http://foo.com"
+openUrl :: String -> MaybeT IO String
+openUrl url = case parseURI url of
+    Nothing -> fail "couldn't parse url"
+    Just u  -> liftIO (getResponseBody =<< simpleHTTP (mkRequest GET u))
+
+-- | Given a url, returns a document. Example:
+--
+-- > doc <- fromUrl "http://foo.com"
+fromUrl :: String -> IO (IOSArrow XmlTree (NTree XNode))
+fromUrl url = do
+  contents <- runMaybeT $ openUrl url
+  return $ parseHtml (fromMaybe "" contents)
+
+-- | Given a string, parses it and returns a document. Example:
+--
+-- > doc = parseHtml "<h1>hello!</h1>"
+parseHtml :: String -> IOSArrow XmlTree (NTree XNode)
+parseHtml = readString [withParseHTML yes, withWarnings no]
+
+-- | Shortcut for getting attributes. Example:
+--
+-- > doc >>> css "a" ! "href"
+(!) :: ArrowXml cat => cat a XmlTree -> String -> cat a String
+(!) a str = a >>> getAttrValue str
+
+-- | A css selector for getting elements from a document. Example:
+--
+-- > doc >>> css "#menu li"
+css :: ArrowXml a => [Char] -> a (NTree XNode) (NTree XNode)
+css tag = case (parse selector "" tag) of
+       Left err -> D.trace (show err) this
+       Right x  -> fromSelectors x
+
+-- | Used internally. works on a selector (i.e a list of simple selectors)
+fromSelectors sel@(s:selectors) = foldl (\acc selector -> acc <+> _fromSelectors selector) (_fromSelectors s) selectors
+
+-- | Used internally. works on simple selectors and their combinators
+_fromSelectors (s:selectors) = foldl (\acc selector -> make acc selector) (make this s) selectors
+  where 
+        make acc sel@(Selector name attrs pseudo)
+          | name == "*" = acc >>> (multi this >>> makeAttrs attrs)
+          | otherwise = acc >>> (multi $ hasName name >>> makeAttrs attrs)
+        make acc Space = acc >>> multi getChildren
+        make acc ChildOf = acc >>> getChildren
+        makeAttrs (a:attrs) = foldl (\acc attr -> acc >>> makeAttr attr) (makeAttr a) attrs
+        makeAttrs [] = this
+        makeAttr (name, "") = hasAttr name
+        makeAttr (name, '~':value) = hasAttrValue name (elem value . words)
+        makeAttr (name, value) = hasAttrValue name (==value)
