diff --git a/Language/Lojban/CLL.hs b/Language/Lojban/CLL.hs
--- a/Language/Lojban/CLL.hs
+++ b/Language/Lojban/CLL.hs
@@ -11,6 +11,8 @@
 import Network.HTTP
 import Text.HTML.TagSoup
 
+-- | Queries the CLL page on jbotcan.org using Google.
+cll :: String -> IO (Maybe [(String,String)])
 cll query = do
   (code,body) <- curlGetString url [CurlUserAgent "Mozilla"]
   if code == CurlOK
diff --git a/Language/Lojban/Camxes/Parse.hs b/Language/Lojban/Camxes/Parse.hs
new file mode 100644
--- /dev/null
+++ b/Language/Lojban/Camxes/Parse.hs
@@ -0,0 +1,61 @@
+module Language.Lojban.Camxes.Parse 
+    (parse
+    ,LojbanTree
+    ,Expr
+    ,Type
+    ,Value) where
+
+import Data.Char
+import Data.List
+import Data.Tree
+import Text.ParserCombinators.Parsec hiding (parse)
+import qualified Text.ParserCombinators.Parsec as P
+import Control.Monad.Reader
+
+sample = " text=(  text1=(  paragraphs=(  paragraph=(  statement=(  statement1=(  statement2=(  statement3=(  sentence=(  terms=(  terms1=(  terms2=(  term=(  term1=(  sumti=(  sumti1=(  sumti2=(  sumti3=(  sumti4=(  sumti5=(  sumti6=(  KOhAClause=(  KOhAPre=(  KOhA=(  CMAVO=(  KOhA=( mi )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  bridiTail=(  bridiTail1=(  bridiTail2=(  bridiTail3=(  selbri=(  selbri1=(  selbri2=(  selbri3=(  selbri4=(  selbri5=(  selbri6=(  tanruUnit=(  tanruUnit1=(  tanruUnit2=(  BRIVLAClause=(  BRIVLAPre=(  BRIVLA=(  BRIVLA=(  gismu=( dansu )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  )  ) "
+
+parse :: String -> Either ParseError LojbanTree
+parse = P.parse expr ""
+
+expr = do skipMany space
+          sym <- symbol
+          char '='
+          char '('
+          inner <- try innerExprs <|> fmap return lojbanic
+          char ')'
+          skipMany space
+          return $ Node (Left sym) inner
+
+innerExprs :: Parser [LojbanTree]
+innerExprs = many1 (do e <- expr; skipMany space; return e)
+
+lojbanic :: Parser LojbanTree
+lojbanic = do skipMany space
+              string <- many1 (letter <|> digit <|> oneOf "'")
+              skipMany space
+              return $ Node (Right (map toLower string)) []
+
+symbol :: Parser Type
+symbol = fmap (map toLower) $ many1 (letter <|> digit)
+
+type LojbanTree = Tree Expr
+type Expr = Either Type Value
+type Type = String
+type Value = String
+
+prettyPrint :: LojbanTree -> String
+prettyPrint tree = runReader (go tree) "" where
+    go (Node (Right value) []) = out value
+    go (Node (Left value) [])  = out value
+    go (Node (Left label) (x:xs)) 
+        | isTree x = do indent <- ask
+                        inner <- local (' ':) $ mapM go (x:xs)
+                        return $ "\n" ++ indent ++ "(" ++ label ++ "" ++ concat inner ++ ")"
+        | otherwise = do indent <- ask
+                         in' <- go x
+                         return $ "\n" ++ indent ++ "(" ++ label ++ " " ++ in' ++ ")"
+
+isTree (Node (Left _) (_:_)) = True
+isTree _                     = False
+
+out = return
diff --git a/Language/Lojban/Jbobau.hs b/Language/Lojban/Jbobau.hs
new file mode 100644
--- /dev/null
+++ b/Language/Lojban/Jbobau.hs
@@ -0,0 +1,89 @@
+module Language.Lojban.Jbobau
+    (newJbobau
+    ,jbobauLine
+    ,Jbobau)
+ where
+
+import Control.Concurrent
+import Control.Monad
+import Data.Char
+import Data.List
+import Data.MarkovChain
+import Language.Lojban.Util
+import System.Directory
+import System.IO
+import System.IO.Strict (readFile)
+import System.Random
+import System.Process
+
+-- | Creates a new jbobau handle.
+newJbobau :: FilePath -> IO (Either String Jbobau)
+newJbobau path = do
+  does <- doesFileExist path
+  if does
+     then connectJbobau path
+     else return $ Left "Couldn't find jbobau training data."
+
+connectJbobau :: FilePath -> IO (Either String Jbobau)
+connectJbobau path = do
+  pipe <- catch (Right `fmap` runInteractiveCommand "java -jar ~/camxes.jar -t")
+                (const $ return $ Left "Broken pipe.")
+  case pipe of
+    Left e -> return $ Left e
+    Right (inp,out,err,_) -> do
+      hSetBuffering inp LineBuffering
+      file <- System.IO.Strict.readFile path
+      rg <- newStdGen
+      let words' = intercalate ["\n"] $ map words $ lines file
+
+          lines' = lines $ unwords $ run 3 words' 0 rg
+      var <- newMVar (Jbobau_ inp out err lines')
+      hGetLine out
+      return $ Right $ Jbobau var
+
+-- | Returns a random, grammatical, lojbanic sentence.
+jbobauLine :: Jbobau -> IO String
+jbobauLine (Jbobau jbobau) = do
+  jbobau' <- takeMVar jbobau
+  (line,lines) <- findM jbobau' (jboLines jbobau')
+  putMVar jbobau jbobau' { jboLines = lines }
+  return (clean line)
+    where
+    findM jbobau' (line:lines) = do
+      if length (words line) >= 4
+         then do line <- validLojban jbobau' line
+                 if length (words line) >= 4
+                    then do line <- jbofihe line
+                            case line of
+                              Just line -> return (line,lines)
+                              Nothing   -> findM jbobau' lines
+                    else findM jbobau' lines
+         else findM jbobau' lines
+
+jbofihe :: String -> IO (Maybe String)
+jbofihe line = do
+  out <- grammar line
+  case out of
+    Right ("",good) | good /= [] -> return $ Just (extract good)
+    _                            -> return $ Nothing
+  where extract = map toLower . unwords . words . filter good
+        good c = isLetter c || c == '\'' || c == ' '
+
+validLojban :: Jbobau_ -> String -> IO String
+validLojban jbobau line = do
+  let stdin  = jboIn jbobau
+      stdout = jboOut jbobau
+  hPutStrLn stdin line
+  hGetLine stdout
+
+newtype Jbobau = Jbobau (MVar Jbobau_)
+
+data Jbobau_ = Jbobau_
+    { jboIn    :: Handle
+    , jboOut   :: Handle
+    , jboErr   :: Handle
+    , jboLines :: [String]
+    }
+
+clean = unwords . words . filter good where
+    good c = c /= '.' && c /= '-'
diff --git a/Language/Lojban/Jbovlaste.hs b/Language/Lojban/Jbovlaste.hs
--- a/Language/Lojban/Jbovlaste.hs
+++ b/Language/Lojban/Jbovlaste.hs
@@ -27,6 +27,7 @@
     )
     where
 
+import Utils
 import qualified System.IO.Strict as StrictIO
 import Text.XML.Light.Input
 import Text.XML.Light.Types
@@ -53,12 +54,13 @@
 -- | Find valsi(s) by definition substring.
 defSub :: JboDB -> String -> [JboValsi]
 defSub db s = filterValsi db match where
-    match e = isInfixOf s (valsiDef e) 
+    match = any ((==lower s) . lower) . splitBy (not . isLetter) . valsiDef
+--    match = isInfixOf s . valsiDef
 
 -- | Find valsi(s) by definition wild card string.
 defWildCard :: JboDB -> String -> [JboValsi]
 defWildCard db s = filterValsi db match where
-    match e = isNothing $ wildcard s (valsiDef e) 
+    match = isNothing . wildcard s . valsiDef
 
 -- | Filter valsi(s) by a predicate.
 filterValsi :: JboDB -> (JboValsi -> Bool) -> [JboValsi]
@@ -106,7 +108,7 @@
 
 elemToValsi :: Element -> [Element] -> Map String JboValsi -> JboValsi
 elemToValsi e es m | type' == "gismu"         = makeGismu e es
-                   | type' == "fu'ivla"       = makeGismu e es
+                   | type' == "fu'ivla"       = makeFu'ivla e es
                    | type' == "cmavo cluster" = makeCmavo True e es
                    | type' == "cmavo"         = makeCmavo False e es
                    | type' == "lujvo"         = makeLujvo e es m
@@ -134,7 +136,7 @@
 selrafsi :: String -> Map String JboValsi -> Maybe JboValsi
 selrafsi s = fmap snd . find sel . M.assocs where
     sel (w,v) = case valsiType v of
-                  GismuType -> isPrefixOf s w || any (==s) rafsis
+                  GismuType -> (isPrefixOf s w && length s >= 4) || any (==s) rafsis
                   CmavoType -> any (==s) rafsis
                   _         -> False
        where rafsis = valsiRafsis v
@@ -253,6 +255,7 @@
           notes = list "" (" Notes: "++)
 
 instance Eq JboValsi where (==) = (==) `on` valsiWord
+instance Ord JboValsi where compare = compare `on` valsiType
 
 -- | Get the selrafsis of a lujvo.
 lujvoSelrafsis :: JboValsi -> [JboValsi]
@@ -276,7 +279,6 @@
 speech s = "\"" ++ s ++ "\""
 commas = intercalate ", " . filter (not . null)
 slashes = intercalate "/" . filter (not . null)
-list nil cons v = if v == [] then nil else cons v
 name n = QName n Nothing Nothing
 attr = findAttr . name
-trim = unwords . words
+lower = map toLower
diff --git a/Language/Lojban/Lujvo.hs b/Language/Lojban/Lujvo.hs
--- a/Language/Lojban/Lujvo.hs
+++ b/Language/Lojban/Lujvo.hs
@@ -1,9 +1,10 @@
 module Language.Lojban.Lujvo (rafsis,fixClusters) where
 
-import Prelude hiding ((^),(*),(/),(+))
-import Text.ParserCombinators.Parsec hiding (notFollowedBy)
 import Control.Monad
 import Control.Applicative ((<$>))
+import Data.Maybe
+import Prelude hiding ((^),(*),(/),(+))
+import Text.ParserCombinators.Parsec hiding (notFollowedBy)
 
 data Rafsi = ShortRafsi [Char] | Rafsi4Let [Char] | Rafsi5Let [Char]
 instance Show Rafsi where
@@ -11,31 +12,52 @@
     show (Rafsi4Let e) = e
     show (Rafsi5Let e) = e
 
+-- | Fix clusters in lojbanic words, consonants, vowels, hyphens, etc. Might not be accurate sometimes.
 fixClusters :: String -> String
 fixClusters xs = go xs [] where
+    go stream acc | stream == xs && isJust broken = go rest (acc++cmavo++[hyphen])
+                  where broken = breakCmavo stream
+                        Just (cmavo,hyphen,rest) = broken
     go (x:y:xs) acc | validCluster (x:y:[]) = go (y:xs) (acc++[x])
                     | otherwise             = go (y:xs) (acc++[x]++"y")
     go [x] acc = go [] (acc++[x])
     go [] acc = acc
 
+breakCmavo :: String -> Maybe (String,Char,String)
+breakCmavo stream = either (const Nothing) Just $ parse break "" stream where
+    break = do cmavo' <- cmavo
+               rest <- ccv!> (lujvoRest / gismu / cmavo)
+               let hyphen = if head rest == 'r' then 'n' else 'r'               
+               return (cmavo',hyphen,rest)
+        where lujvoRest = (concat . map show) `fmap` lujvo
+
 validCluster :: [Char] -> Bool
 validCluster = either (const False) (const True) . parse cluster ""
 
-cluster = do diphthong / (do consonant / vowel; consonant / vowel)
+cluster = diphthong 
+        / vt & string "'"
+        / string "'" & vt 
+        / (ct / vowel) & (ct / vt)
+        / ct & string "y"
+        / string "y" & ct
 
+-- | The rafsis of a lujvo. (Empty list for invalid parse.)
 rafsis :: String -> [String]
 rafsis s = 
     case parse lujvo "" s of
       Right rs -> map show rs
       Left _ -> []
 
-lujvo = ((rafsi5 <!anyChar / rafsi3 / rafsi4)+) <!anyChar
+cmavo = ct & (diphthong / vt & h & vt / vt)
+lujvo = (do r1 <- raf; rs <- (raf+); return (r1:rs)) <!anyChar
+               where raf = rafsi5 <!anyChar / rafsi3 / rafsi4
 rafsi3 = ShortRafsi <$> ((cvc / ccv / cvv) <!y <!(anyChar >> y))
 rafsi4 = Rafsi4Let <$> (ct & (vt & ct / ct & vt) & ct <&anyChar <&!(y?))
-rafsi5 = do (Rafsi4Let ls) <- rafsi4; v <- vowel; return $ Rafsi5Let (ls++v)
+rafsi5 = do (Rafsi4Let ls) <- rafsi4; v <- vt; return $ Rafsi5Let (ls++v)
+gismu = do (Rafsi4Let ls) <- rafsi4; v <- vt; return (ls++v)
 cvc = ct & vt & ct <&anyChar <&!(y?)
-ccv = ct & ct & vt <&!(((r / n) <& consonant)?)
-cvv = ct & (diphthong / vt & h & vt) <&!(((r / n) <& consonant)?)
+ccv = ct & ct & vt <&!(((r / n) <& ct)?)
+cvv = ct & (diphthong / vt & h & vt) <&!(((r / n) <& ct)?)
 ct = consonant
 vt = vowel
 syllabic = l / m / n / r
@@ -77,6 +99,8 @@
 oneOf' p = oneOf p >>= return . (:[])
 (+) p = many1 (try p)
 (*) p = many (try p)
+(!>) a a1 = (do r <- try a; unexpected $ show r) <|> a1
+infixr 3 !>
 (<!) a a1 = do r <- a; ((try a1 >>= unexpected . show) <|> return r)
 infixl 2 <!
 (/) a a1 = (try a <|> a1)
diff --git a/Language/Lojban/Mlismu.hs b/Language/Lojban/Mlismu.hs
new file mode 100644
--- /dev/null
+++ b/Language/Lojban/Mlismu.hs
@@ -0,0 +1,80 @@
+module Language.Lojban.Mlismu 
+    (newMlismu
+    ,isValidFatci
+    ,addFatci
+    ,readFatci
+    ,randomBridi
+    ,randomBridiRel
+    ,Mlismu)
+    where
+
+import Data.Maybe
+import Data.Char
+import Language.Lojban.Util
+import System.Directory
+import System.IO
+import System.Process
+import Utils
+
+-- | Create a new mlismu handle.
+newMlismu :: FilePath -> IO (Either String Mlismu)
+newMlismu path = do
+  is <- doesFileExist path
+  if is
+     then do db <- openFile path AppendMode
+             hSetBuffering db LineBuffering
+             return $ Right $ Mlismu path db
+     else return $ Left $ "\"" ++ path ++ "\" does not exist"
+
+-- | Is a fatci valid?
+isValidFatci :: String -> IO Bool
+isValidFatci text = do
+  validLojban <- isValidLojban text
+  if validLojban
+     then isJust `fmap` mlismuBridi (Right text) Nothing 1
+     else return False
+
+mlismuBridi :: (Either FilePath String) -> Maybe String -> Int -> IO (Maybe [String])
+mlismuBridi path selbri lines' = do
+  out <- run ("mlismu -n " ++ show lines' ++  " -f " ++ path' ++ selbri') input
+  case out of
+    Right (_,good@(_:_)) 
+        | Just good' /= selbri -> return $ Just $ lines $ good 
+        where good' = list "" (head . lines) good
+    _                         -> return Nothing
+  where selbri' = maybe "" (" "++) selbri
+        path' = either id (const "/dev/stdin") path
+        input = either (const "") (++"\n") path
+
+-- | Return a random bridi for a (maybe) given selbri.
+randomBridi :: Mlismu -> Maybe String -> IO (Maybe String)
+randomBridi mli bridi = start `fmap` mlismuBridi (Left $ mliFile mli) bridi 1
+    where start = (>>= list Nothing (Just . head))
+
+-- | Try to return a random bridi for one of the given selbri.
+randomBridiRel :: Mlismu -> [String] -> IO (Maybe String)
+randomBridiRel mli bridis = findM bridis where
+    findM []     = randomBridi mli Nothing
+    findM (x:xs) = do
+      randomBridi mli (Just x) >>= maybe (findM xs) (return . Just)
+
+-- | Add a new fatci.
+addFatci :: Mlismu -> String -> IO Bool
+addFatci mli fatci = do
+  is <- isValidFatci fatci
+  if is
+     then do hPutStrLn (mliDB mli) fatci
+             return True
+     else return False
+
+-- | Add any valid fatci from a set of utterances.
+readFatci :: Mlismu -> String -> IO ()
+readFatci mli = mapM_ (addFatci mli) . splitBridis
+
+splitBridis :: String -> [String]
+splitBridis = map unwords . splitBy ((=="i") . filter isLetter) . words
+
+data Mlismu = Mlismu
+    { mliFile   :: FilePath
+    , mliDB     :: Handle
+    }
diff --git a/Language/Lojban/Util.hs b/Language/Lojban/Util.hs
--- a/Language/Lojban/Util.hs
+++ b/Language/Lojban/Util.hs
@@ -13,7 +13,8 @@
     ,translate
     ,wordType
     ,lujvoAndRate
-    ,selma'oInfo)
+    ,selma'oInfo
+    ,isValidLojban)
     where
 
 import Utils
@@ -68,7 +69,8 @@
 filterSelma'o :: JboDB -> String -> [JboValsi]
 filterSelma'o db s = filterValsi db selma'o where
     selma'o v = valsiType v == CmavoType && fmap format (valsiSelma'o v) == Just (format s)
-        where format = filter isLetter . lower
+        where format | any isDigit s = lower
+                     | otherwise     = filter isLetter . lower
 
 -- | Shows the grammar of a lojban utterance using jbofihe.
 grammar :: String                              -- ^ The lojban utterance
@@ -113,6 +115,14 @@
   where format = flip (subRegex r1) "\n" . flip (subRegex r) "\\1 \\2"
         r = mkRegex "([^\n])\n([^\n])"
         r1 = mkRegex "\n\n"
+
+-- | Just checks with jbofihe if some lojban is grammatically valid.
+isValidLojban :: String -> IO Bool
+isValidLojban line = do
+  out <- grammar line
+  case out of
+    Right (_,"") -> return $ False
+    _            -> return $ True
 
 lojbanic = filter good where
     good c = isLetter c || c == '\'' || c == ' '
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,4 @@
 import Distribution.Simple
+
+main :: IO ()
 main = defaultMain
diff --git a/Utils.hs b/Utils.hs
--- a/Utils.hs
+++ b/Utils.hs
@@ -1,28 +1,50 @@
 module Utils
     (list
     ,run
-    ,trim)
+    ,trim
+    ,splitBy)
     where
 
+import Prelude hiding (catch)
+import Control.Exception
+import Control.Concurrent
 import System.Process
 import System.IO
 import System.Exit
-import qualified System.IO.Strict as StrictIO
 
 list :: Eq a => b -> ([a] -> b) -> [a] -> b
 list nil cons v = if v == [] then nil else cons v
 
 run :: String -> String -> IO (Either String (String,String))
 run cmd input = do
-  Right (inp,out,err,pid) <- catch (Right `fmap` runInteractiveCommand cmd)
-                                   (const $ return $ Left "Broken pipe")
-  catch (do hPutStr inp input; hClose inp
-            output <- StrictIO.hGetContents out
-            errput <- StrictIO.hGetContents err
-            e <- catch (waitForProcess pid)
-                       (const $ return ExitSuccess)
-            return $ Right (errput,output))
-        (const $ return $ Left "Broken pipe")
+  pipe <- catch (Right `fmap` runInteractiveCommand ("ulimit -t 1 && " ++ cmd))
+                (const $ return $ Left "Broken pipe")
+  case pipe of
+    Right (inp,out,err,pid) -> do
+                  catch (do hSetBuffering inp NoBuffering
+                            hPutStr inp input 
+                            hClose inp
+                            errv <- newEmptyMVar
+                            outv <- newEmptyMVar
+                            output <- hGetContents out
+                            errput <- hGetContents err
+                            forkIO $ evaluate (length output) >> putMVar outv ()
+                            forkIO $ evaluate (length errput) >> putMVar errv ()
+                            takeMVar errv
+                            takeMVar outv
+                            e <- catch (waitForProcess pid)
+                                       (const $ return ExitSuccess)
+                            return $ Right (errput,output))
+                        (const $ return $ Left "Broken pipe")
+    _ -> return $ Left "Unable to launch process"
 
 trim :: String -> String
 trim = unwords . words
+
+splitBy :: (a -> Bool) -> [a] -> [[a]]
+splitBy f = go [] where
+    go ac xs = case break f xs of
+                 ([],[]) -> reverse ac
+                 ([],ys) -> go ac      (skip ys)
+                 (xs,ys) -> go (xs:ac) (skip ys)
+    skip = dropWhile f
diff --git a/lojban.cabal b/lojban.cabal
--- a/lojban.cabal
+++ b/lojban.cabal
@@ -1,5 +1,5 @@
 name:                lojban
-version:             0.1
+version:             0.2
 synopsis:            Useful utilities for the Lojban language
 description:         Some utilities such as querying Jbovlaste XML 
                      exports for gismu, gloss, rafsi, etc. and 
@@ -14,8 +14,8 @@
 build-type:          Simple
 
 library
-  build-depends: base,xml,strict,parsec,process,regex-compat,containers,tagsoup,HTTP,curl
-  exposed-modules: Language.Lojban.Jbovlaste,Language.Lojban.Lujvo,Language.Lojban.Util,Language.Lojban.CLL
+  build-depends: base,xml,strict,parsec,process,regex-compat,containers,tagsoup,HTTP,curl,random,directory,markov-chain
+  exposed-modules: Language.Lojban.Jbovlaste,Language.Lojban.Lujvo,Language.Lojban.Util,Language.Lojban.CLL,Language.Lojban.Jbobau,Language.Lojban.Mlismu,Language.Lojban.Camxes.Parse
   other-modules: WildCard, Utils
   ghc-options: -O2
 
