diff --git a/clustertools.cabal b/clustertools.cabal
--- a/clustertools.cabal
+++ b/clustertools.cabal
@@ -1,5 +1,5 @@
 Name:                clustertools
-Version:             0.1.1
+Version:             0.1.2
 License:             GPL
 License-file:        LICENSE
 Author:              Ketil Malde
@@ -72,7 +72,7 @@
 Executable clusterlibs
            Hs-source-dirs: src
            Main-Is:     ClusterLibs.hs
-           Build-depends: regex-compat
+           Build-depends: regex-compat, QuickCheck
 
 Executable xcerpt
            Hs-source-dirs: src
diff --git a/src/ClusterLibs.hs b/src/ClusterLibs.hs
--- a/src/ClusterLibs.hs
+++ b/src/ClusterLibs.hs
@@ -2,34 +2,51 @@
 -- calculate clusters by library, using the lib table
 -- read patterns from a table, first line is header
 
-{-
-import qualified Data.ByteString.Char8.Lazy as B
-import Data.Map (Map)
-import qualified Data.Map as M
-
-
-type Str = B.ByteString
-type Clusters = Map Str [Str]
-
-insert1 m k v = M.insertWith (flip (++)) k [v] m
--}
-
 import System.Environment (getArgs)
 import Text.Regex
 import Data.List (elemIndex,sortBy,intersperse)
+import Data.Map hiding (map)
+import Numeric (showFFloat)
 
+import Statistics
+
+type LibTable = [(Regex,String)]
 type Cluster = (String,[String])
 
 main :: IO ()
 main = do
    [ps,cs] <- do [xs,ys] <- getArgs 
                  return [xs,ys] 
-             `catch` error "Usage: clusterlibs ps cs"
+             `catch` error "Usage: clusterlibs <libtable> <clusters>"
    pat <- readPatternTable ps
+   counts <- totalsByLib pat cs
+   writeTable [("","sum":map snd pat++["significance"])]
+   writeTable . map (decorate counts) . countClusters pat =<< readClusters cs
+
+-- counts is 
+decorate :: (String,[Int]) -> (String,[Int]) -> (String,[String])
+decorate counts (x,ys) = 
+    let fractions = [ fromIntegral x / fromIntegral (sum $ snd counts) | x <- snd counts]
+        clustersize = sum ys
+        significance = unwords $ zipWith isSignificant ys fractions
+        isSignificant obs frac = showFFloat (Just 3) (pvalue (1-frac) clustersize (clustersize-obs)) ""
+    in (x,map show (clustersize:ys) ++ [significance])
+
+{-
    clus <- classClusters pat cs
-   writeClusters clus
+   writeTable clus
+-}
 
-readPatternTable :: FilePath -> IO [(Regex,String)]
+-- --------------------------------------------------
+-- | Calculate the p value of observing k sequences
+--   from a library, given an a priori background distribution. 
+pvalue :: Double -> Int -> Int -> Double
+pvalue fraction tot obs = cumbin fraction tot obs
+
+-- --------------------------------------------------
+-- | Read a LibTable from a file of wsp-separated columns, first line is
+--   a header, and only columns "Pattern" and "Name" are used.
+readPatternTable :: FilePath -> IO LibTable
 readPatternTable f = do
   (h:ls) <- return . map words . lines =<< readFile f
   let (p,n) = case (elemIndex "Pattern" h, elemIndex "Name" h) of
@@ -39,34 +56,49 @@
           | otherwise          = (mkRegex (l!!p),l!!n)
   return $ map z ls
 
--- will need to match against all, to check for multiple matches
--- tag names with library
-classClusters :: [(Regex,String)] -> FilePath -> IO [Cluster]
-classClusters ps f = return . getClusters (classify ps) . lines =<< readFile f
+-- --------------------------------------------------
+-- | Acquire total counts by library from a clustering
+totalsByLib :: LibTable -> FilePath -> IO (String,[Int])
+totalsByLib lt f = do 
+  cs <- readClusters f
+  let unify cs = [("total", concatMap snd cs)]
+  case countClusters lt (unify cs) of
+    [x] -> return x
+    _   -> error "totalsByLib: this is impossible"
 
-classify :: [(Regex,String)] -> String -> String
+-- --------------------------------------------------
+-- | Parse clusters
+readClusters :: FilePath -> IO [Cluster]
+readClusters f = readFile f >>= return . rc . lines
+    where rc []          = []
+          rc [_]         = error "odd number of cluster lines!"
+          rc (c:ss:rest) = case head $ words c of
+                              ('>':name) -> (name,words ss) : rc rest
+                              _          -> error ("Cluster '"++c++"' didn't start with '>'")
+
+classify :: LibTable -> String -> String
 classify ps str = case concatMap (class1 str) ps of
                     [] -> error ("no match for "++str++" in library table")
-                    [x] -> x++":"++str
+                    [x] -> x
                     s@(_:_) -> error ("multiple matches for "++str++": "++show s)
     where class1 st (r,s) = maybe [] (const [s]) (matchRegex r st)
 
-getClusters :: (String -> String) -> [String] -> [(String,[String])]
-getClusters _ []          = []
-getClusters _ [_]         = error "odd number of cluster lines!"
-getClusters f (c:ss:rest) = case head $ words c of
-                              ('>':name) -> (name,map f $ words ss) : getClusters f rest
-                              _          -> error ("Cluster '"++c++"' didn't start with '>'")
 
--- transpose and print
-writeClusters :: [Cluster] -> IO ()
-writeClusters cs = do
-  let cs' = map (\(h,s) -> (h:s)) cs
-      cs'' = sortBy (\x y -> compare (length y) (length x)) cs'
-      unwords' = concat . intersperse ","
-  putStrLn $ unlines $ map unwords' $ transpose cs''
+-- --------------------------------------------------
+-- will need to match against all, to check for multiple matches
+-- tag names with library
+classClusters :: LibTable -> FilePath -> IO [Cluster]
+classClusters ps f = return . map class1 =<< readClusters f
+    where class1 (l,ss) = (l, map (\s -> classify ps s++":"++s) ss)
 
-transpose :: [[String]] -> [[String]]
-transpose []  = []
-transpose ls' = let ls = filter (not . null) ls'
-                in map head ls : transpose (map tail ls)
+-- | Output the clusters to stdout
+writeTable :: [(String,[String])] -> IO ()
+writeTable = putStrLn . unlines . map show1 
+    where
+      show1 (name,stuff) = concat $ intersperse "\t" (name:stuff)
+
+-- count by classification
+countClusters :: LibTable -> [Cluster] -> [(String,[Int])]
+countClusters lt = map count1
+    where count1 (c,ss) = (c,map (\k -> findWithDefault 0 k (counts ss)) (map snd lt))
+          counts ss = fromListWith (+) $ zip (map (classify lt) ss) $ repeat 1
