diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2010, Sam Anklesaria
+
+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 Sam Anklesaria 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/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/SmartGroup.hs b/SmartGroup.hs
new file mode 100644
--- /dev/null
+++ b/SmartGroup.hs
@@ -0,0 +1,81 @@
+module SmartGroup (groupAll, groupNum, groupLog) where
+import Data.Heap as Heap
+import Data.Set as Set
+import Data.Map as Map
+import Data.Monoid
+import Data.Ord
+
+data StringL = StringL {str :: String, count :: Int} deriving (Eq, Show)
+instance Ord StringL where compare (StringL i a) (StringL x b) = compare a b `mappend` compare i x
+data SizeMap = Unsplittable (Set String) | Splittable (Map StringL (Set String)) deriving (Eq, Show)
+instance Ord SizeMap where
+         compare (Splittable a) (Splittable b) = compare (Map.size a) (Map.size b)
+         compare (Unsplittable a) (Unsplittable b) = compare a b
+         compare (Unsplittable _) (Splittable _) = LT
+         compare (Splittable _) (Unsplittable _) = GT
+type WordAssoc = MaxHeap SizeMap
+
+toSet (Unsplittable x) = x
+toSet (Splittable x) = Set.unions (Map.elems x)
+
+intLog :: Int -> Int
+intLog = truncate . logBase 2 . fromIntegral
+
+groupWith :: (Int -> WordAssoc -> WordAssoc) -> Int -> [String] -> [[String]]
+groupWith f i = mkList . f i . mkAssoc . mkMap
+
+-- | Divide list into as many groups as possible
+groupAll :: Int -> [String] -> [[String]]
+groupAll = groupWith $ \i x->
+         let cycleSplit n = case splitIt i n of
+                  (Just a) -> cycleSplit a
+                  Nothing -> n
+         in cycleSplit x
+
+-- | Divide list into about n different groups
+groupNum :: Int -> Int -> [String] -> [[String]]
+groupNum i = groupWith $ \x->
+         let splitTimes n m =
+                if Heap.size m >= n then m else
+                   case splitIt x m of
+                     (Just a) -> splitTimes n a
+                     Nothing -> m
+         in splitTimes i
+
+-- | Divide list into groups such that the amount of groups
+--   equals the log of the number of elements
+groupLog :: Int -> [String] -> [[String]]
+groupLog i s = groupNum (intLog (length s)) i s
+
+mkMap :: [String] -> Map String (Set String)
+mkMap = foldl (\m x->
+        foldl (\m' i-> if length i > 3
+              then Map.alter (Just . maybe (Set.singleton x) (Set.insert x)) i m' else m')
+        m (words x)) Map.empty
+
+mkAssoc :: Map String (Set String) -> MaxHeap SizeMap
+mkAssoc m = Heap.singleton . Splittable . Map.mapKeys (\k-> StringL k (Set.size (m Map.! k))) $ m
+
+splitIt :: Int -> WordAssoc -> Maybe WordAssoc
+splitIt i s = case Heap.view s of
+         (Just ((Unsplittable _),_)) -> Nothing
+         (Just ((Splittable x),xs)) ->
+               let
+                  (Just (as,b)) = Map.maxView x
+                  x1 = sizeMap i $ flip Map.mapMaybe b $ \n->
+                      let m = Set.difference n as
+                      in if Set.null m then Nothing else Just m
+                  x2 = sizeMap i $ flip Map.mapMaybe b $ \n->
+                      let m = Set.intersection n as
+                      in if Set.null m then Nothing else Just m
+                  x3 = as Set.\\ (Set.unions (Map.elems b))
+               in Just $ (if Set.null x3 then id else Heap.insert (Unsplittable x3)) $
+                   Heap.insert x1 $ Heap.insert x2 xs
+
+sizeMap :: Int -> (Map StringL (Set String)) -> SizeMap
+sizeMap i m = case Map.findMax m of
+        (StringL _ c,_) -> if c >= i then Splittable m
+                 else Unsplittable (Set.unions (Map.elems m))
+
+mkList :: WordAssoc -> [[String]]
+mkList = Prelude.map (Set.toList . toSet) . Heap.toList
diff --git a/smartGroup.cabal b/smartGroup.cabal
new file mode 100644
--- /dev/null
+++ b/smartGroup.cabal
@@ -0,0 +1,62 @@
+-- smartGroup.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:                smartGroup
+
+-- 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.0.0
+
+-- A short (one-line) description of the package.
+Synopsis:            group strings by words in common
+
+-- A longer description of the package.
+Description:         Given a list of strings, smartGroup provides a set of functions
+                     to group them into smaller lists based on the most common words of the set.
+
+-- URL for the project homepage or repository.
+Homepage:            http://patch-tag.com/r/salazar/smartgroup
+
+-- The license under which the package is released.
+License:             BSD3
+
+-- The file containing the license text.
+License-file:        LICENSE
+
+-- The package author(s).
+Author:              Sam Anklesaria
+
+-- An email address to which users can send suggestions, bug reports,
+-- and patches.
+Maintainer:          amsay@amsay.net
+
+-- A copyright notice.
+-- Copyright:           
+
+Category:            Algorithms
+
+Build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or
+-- a README.
+-- Extra-source-files:  
+
+-- Constraint on the version of Cabal needed to build this package.
+Cabal-version:       >=1.2
+
+
+Library
+  -- Modules exported by the library.
+  Exposed-modules:     SmartGroup
+  
+  -- Packages needed in order to build this package.
+  Build-depends:       base >= 3 && < 5, containers < 1, heap < 1.1
+  
+  -- Modules not exported by this package.
+  -- Other-modules:       
+  
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  -- Build-tools:         
+  
