diff --git a/.ghci b/.ghci
new file mode 100644
--- /dev/null
+++ b/.ghci
@@ -0,0 +1,1 @@
+:set -isrc -idist/build/autogen -optP-include -optPdist/build/autogen/cabal_macros.h
diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+dist
+docs
+wiki
+TAGS
+tags
+wip
+.DS_Store
+.*.swp
+.*.swo
+*.o
+*.hi
+*~
+*#
diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,1 +1,8 @@
 language: haskell
+notifications:
+  irc:
+    channels:
+      - "irc.freenode.org#haskell-lens"
+    skip_join: true
+    template:
+      - "\x0313compressed\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
diff --git a/.vim.custom b/.vim.custom
new file mode 100644
--- /dev/null
+++ b/.vim.custom
@@ -0,0 +1,31 @@
+" Add the following to your .vimrc to automatically load this on startup
+
+" if filereadable(".vim.custom")
+"     so .vim.custom
+" endif
+
+function StripTrailingWhitespace()
+  let myline=line(".")
+  let mycolumn = col(".")
+  silent %s/  *$//
+  call cursor(myline, mycolumn)
+endfunction
+
+" enable syntax highlighting
+syntax on
+
+" search for the tags file anywhere between here and /
+set tags=TAGS;/
+
+" highlight tabs and trailing spaces
+set listchars=tab:‗‗,trail:‗
+set list
+
+" f2 runs hasktags
+map <F2> :exec ":!hasktags -x -c --ignore src"<CR><CR>
+
+" strip trailing whitespace before saving
+" au BufWritePre *.hs,*.markdown silent! cal StripTrailingWhitespace()
+
+" rebuild hasktags after saving
+au BufWritePost *.hs silent! :exec ":!hasktags -x -c --ignore src"
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.markdown
@@ -0,0 +1,6 @@
+3.0.1
+-----
+* Refactored the build system
+* IRC buildbot notification
+* Started the CHANGELOG
+* Added `README.markdown`
diff --git a/Data/Compressed/Internal/LZ78.hs b/Data/Compressed/Internal/LZ78.hs
deleted file mode 100644
--- a/Data/Compressed/Internal/LZ78.hs
+++ /dev/null
@@ -1,235 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE ParallelListComp #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Generator.LZ78
--- Copyright   :  (c) Edward Kmett 2009-2012
--- License     :  BSD-style
--- Maintainer  :  ekmett@gmail.com
--- Stability   :  experimental
--- Portability :  non-portable (type families)
---
--- Compression algorithms are all about exploiting redundancy. When applying
--- an expensive 'Reducer' to a redundant source, it may be better to
--- extract the structural redundancy that is present. 'LZ78' is a compression
--- algorithm that does so, without requiring the dictionary to be populated
--- with all of the possible values of a data type unlike its later
--- refinement LZW, and which has fewer comparison reqirements during encoding
--- than its earlier counterpart LZ77.
------------------------------------------------------------------------------
-
-module Data.Compressed.Internal.LZ78
-    (
-    -- * Lempel-Ziv 78
-      Token(..)
-    , LZ78(..)
-    -- * Encoding
-    , encode    -- /O(n)/
-    , encodeOrd -- /O(n log n)/
-    , encodeEq  -- /O(n^2)/
-    -- * Decoding (reduce)
-    , decode
-    -- * Recoding
-    , recode    -- /O(n)/
-    , recodeOrd -- /O(n log n)/
-    , recodeEq  -- /O(n^2)/
-    -- * Unsafe (exposes internal structure)
-    , Entry(..)
-    , entries
-    ) where
-
-import Control.Applicative
-import qualified Data.Sequence as Seq
-import Data.Sequence ((|>))
-import qualified Data.Map as Map
-import qualified Data.HashMap.Lazy as HashMap
-import qualified Data.List as List
-import Data.Functor.Extend
-import Data.Generator
-import Data.Function (on)
-import Data.Key as Key
-import Data.Foldable
-import Data.Traversable
-import Data.Semigroup
-import Data.Pointed
-import Text.Read
-import Control.Comonad
-import Data.Hashable
-import Data.Semigroup.Reducer (Reducer(..), Count(..))
-
-data Token a = Token {-# UNPACK #-} !Int a deriving (Eq, Ord)
-
-instance Functor Token where
-  fmap f (Token i a) = Token i (f a)
-
-instance Foldable Token where
-  foldMap f (Token _ a) = f a
-
-instance Traversable Token where
-  traverse f (Token i a) = Token i <$> f a
-
-instance Extend Token where
-  extended = extend
-
-instance Comonad Token where
-  extend f t@(Token i _) = Token i (f t)
-  duplicate t@(Token i _) = Token i t
-  extract (Token _ a) = a
-
-instance Hashable a => Hashable (Token a) where
-  hashWithSalt s (Token i a) = s `hashWithSalt` i `hashWithSalt` a
-
--- | An LZ78 compressed 'Generator'.
-data LZ78 a
-  = Cons {-# UNPACK #-} !(Token a) (LZ78 a)
-  | Nil
-
-instance Show a => Show (LZ78 a) where
-  showsPrec d xs = showParen (d > 10) $
-    showString "encode " . showsPrec 11 (toList xs)
-
-instance Eq a => Eq (LZ78 a) where
-  (==) = (==) `on` decode
-
-instance Ord a => Ord (LZ78 a) where
-  compare = compare `on` decode
-
-instance (Read a, Hashable a, Eq a) => Read (LZ78 a) where
-  readPrec = parens $ prec 10 $ do
-    Ident "encode" <- lexP
-    encode <$> step readPrec
-
-instance Generator (LZ78 a) where
-  type Elem (LZ78 a) = a
-  mapTo = go (Seq.singleton mempty) where
-    go _ _ m Nil = m
-    go s f m (Cons (Token w c) ws) = m `mappend` go (s |> v) f v ws where
-      v = Seq.index s w `mappend`  unit (f c)
-
-instance Functor LZ78 where
-  fmap f (Cons (Token i a) as) = Cons (Token i (f a)) (fmap f as)
-  fmap _ Nil = Nil
-  a <$ xs = go 0 (getCount (reduce xs)) where
-     go !_ 0 = Nil
-     go k  n | n > k = Cons (Token k a) (go (k + 1) (n - k - 1))
-             | otherwise = Cons (Token (n - 1) a) Nil
-
-instance Pointed LZ78 where
-  point a = Cons (Token 0 a) Nil
-
-instance Foldable LZ78 where
-  foldMap f = unwrapMonoid . mapReduce f
-  fold      = unwrapMonoid . reduce
-
--- | /O(n)/ Construct an LZ78-compressed 'Generator' using a 'HashMap' internally.
-encode :: (Hashable a, Eq a) => [a] -> LZ78 a
-encode = go HashMap.empty 1 0 where
-  go _ _ _ [] = Nil
-  go _ _ p [c] = Cons (Token p c) Nil
-  go d f p (c:cs) = let t = Token p c in case HashMap.lookup t d of
-    Just p' -> go d f p' cs
-    Nothing -> Cons t (go (HashMap.insert t f d) (succ f) 0 cs)
-
--- | /O(n log n)/ Contruct an LZ78-compressed 'Generator' using a 'Map' internally.
-encodeOrd :: Ord a => [a] -> LZ78 a
-encodeOrd = go Map.empty 1 0 where
-  go _ _ _ [] = Nil
-  go _ _ p [c] = Cons (Token p c) Nil
-  go d f p (c:cs) = let t = Token p c in case Map.lookup t d of
-    Just p' -> go d f p' cs
-    Nothing -> Cons t (go (Map.insert t f d) (succ f) 0 cs)
-
--- | /O(n^2)/ Contruct an LZ78-compressed 'Generator' using a list internally, requires an instance of Eq,
--- less efficient than encode.
-encodeEq :: Eq a => [a] -> LZ78 a
-encodeEq = go [] 1 0 where
-  go _ _ _ [] = Nil
-  go _ _ p [c] = Cons (Token p c) Nil
-  go d f p (c:cs) = let t = Token p c in case List.lookup t d of
-    Just p' -> go d f p' cs
-    Nothing -> Cons t (go ((t, f):d) (succ f) 0 cs)
-
--- | A type-constrained 'reduce' operation
-decode :: LZ78 a -> [a]
-decode = reduce
-
--- | /O(n)/. Recompress with 'Hashable'
-recode :: (Eq a, Hashable a) => LZ78 a -> LZ78 a
-recode = encode . decode
-
--- | /O(n log n)/. Recompress with 'Ord'
-recodeOrd :: Ord a => LZ78 a -> LZ78 a
-recodeOrd = encodeOrd . decode
-
--- | /O(n^2)/. Recompress with 'Eq'
-recodeEq :: Eq a => LZ78 a -> LZ78 a
-recodeEq = encodeEq . decode
-
-data Entry i a = Entry !i a deriving (Show,Read)
-
-instance Functor (Entry i) where
-  fmap f (Entry i a) = Entry i (f a)
-
-instance Extend (Entry i) where
-  extended = extend
-
-instance Comonad (Entry i) where
-  extend f e@(Entry i _) = Entry i (f e)
-  duplicate e@(Entry i _) = Entry i e
-  extract (Entry _ a) = a
-
-instance Eq i => Eq (Entry i a) where
-  Entry i _ == Entry j _ = i == j
-
-instance Ord i => Ord (Entry i a) where
-  compare (Entry i _) (Entry j _) = compare i j
-
-instance Hashable i => Hashable (Entry i a) where
-  hashWithSalt n (Entry i _) = hashWithSalt n i
-
--- | exposes internal structure
-entries :: LZ78 a -> LZ78 (Entry Int a)
-entries = go 0 where
-  go k (Cons (Token i t) xs) = Cons (Token i (Entry k t)) $ (go $! k + 1) xs
-  go _ Nil = Nil
-
-instance Applicative LZ78 where
-  pure a = Cons (Token 0 a) Nil
-  fs <*> as = fmap extract $ encode $ do
-    Entry i f <- decode (entries fs)
-    Entry j a <- decode (entries as)
-    return $ Entry (i,j) (f a)
-  as *> bs = fmap extract $ encode $ Prelude.concat $ replicate (reduceWith getCount as)  $  decode (entries bs)
-  as <* bs = fmap extract $ encode $ Prelude.concat $ replicate (reduceWith getCount bs) <$> decode (entries as)
-
-instance Monad LZ78 where
-  return a = Cons (Token 0 a) Nil
-  (>>) = (*>)
-  as >>= k = fmap extract $ encode $ do
-    Entry i a <- decode (entries as)
-    Entry j b <- decode (entries (k a))
-    return $ Entry (i,j) b
-
-instance Adjustable LZ78 where
-  adjust f i = fmap extract . encode . adjust (Entry (-1) . f . extract) i . decode . entries
-
-type instance Key LZ78 = Int
-
-instance Lookup LZ78 where
-  lookup i xs = Key.lookup i (decode xs)
-
-instance Indexable LZ78 where
-  index xs i = index (decode xs) i
-
-instance FoldableWithKey LZ78 where
-  foldMapWithKey f xs = foldMapWithKey f (decode xs)
-
-instance Zip LZ78 where
-  zipWith f as bs = extract <$> encode
-    [ Entry (i,j) (f a b)
-    | Entry i a <- decode (entries as)
-    | Entry j b <- decode (entries bs)
-    ]
-
-
diff --git a/Data/Compressed/LZ78.hs b/Data/Compressed/LZ78.hs
deleted file mode 100644
--- a/Data/Compressed/LZ78.hs
+++ /dev/null
@@ -1,35 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Compressed.LZ78
--- Copyright   :  (c) Edward Kmett 2009-2011
--- License     :  BSD-style
--- Maintainer  :  ekmett@gmail.com
--- Stability   :  experimental
--- Portability :  non-portable (type families)
---
--- Compression algorithms are all about exploiting redundancy. When applying
--- an expensive 'Reducer' to a redundant source, it may be better to 
--- extract the structural redundancy that is present. 'LZ78' is a compression
--- algorithm that does so, without requiring the dictionary to be populated
--- with all of the possible values of a data type unlike its later 
--- refinement LZW, and which has fewer comparison reqirements during encoding
--- than its earlier counterpart LZ77. 
------------------------------------------------------------------------------
-
-module Data.Compressed.LZ78 
-    ( 
-    -- * Lempel-Ziv 78 
-      LZ78
-    -- * Encoding
-    , encode    -- /O(n)/
-    , encodeOrd -- /O(n log n)/
-    , encodeEq  -- /O(n^2)/
-    -- * Decoding (reduce)
-    , decode
-    -- * Recoding
-    , recode    -- /O(n)/
-    , recodeOrd -- /O(n log n)/
-    , recodeEq  -- /O(n^2)/
-    ) where
-
-import Data.Compressed.Internal.LZ78
diff --git a/Data/Compressed/RunLengthEncoding.hs b/Data/Compressed/RunLengthEncoding.hs
deleted file mode 100644
--- a/Data/Compressed/RunLengthEncoding.hs
+++ /dev/null
@@ -1,273 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE BangPatterns #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Compressed.RunLengthEncoding
--- Copyright   :  (c) Edward Kmett 2009-2012
--- License     :  BSD-style
--- Maintainer  :  ekmett@gmail.com
--- Stability   :  experimental
--- Portability :  portable
---
--- Compression algorithms are all about exploiting redundancy. When applying
--- an expensive 'Reducer' to a redundant source, it may be better to 
--- extract the structural redundancy that is present. Run length encoding
--- can do so for long runs of identical inputs.
------------------------------------------------------------------------------
-module Data.Compressed.RunLengthEncoding
-    ( RLE(..)
-    , Run
-    , runLength
-    , decode
-    , encode
-    , recode
-    , toRuns
-    , fromRuns
-    ) where
-
-import Data.Foldable
-import Data.Semigroup
-import Data.Semigroup.Reducer
-import Data.Semigroup.Foldable
-import Data.Hashable
-import Data.Function (on)
-import Data.Functor.Bind
-import Data.Functor.Extend
-import Control.Comonad
-import Data.FingerTree (FingerTree,(|>),(<|),ViewL(..),ViewR(..),(><),viewl,viewr, Measured(..), split)
-import qualified Data.FingerTree as F
-import Data.Generator
-import Data.Pointed
-import Data.Key
-import Control.Applicative
-
--- | A single run with a strict length
-data Run a = Run {-# UNPACK #-} !Int a deriving (Eq,Show)
-
-runLength :: Run a -> Int
-runLength (Run n _) = n
-
--- lexicographical order
-instance Ord a => Ord (Run a) where
-  compare (Run n a) (Run m b) = case compare a b of
-    LT -> LT
-    GT -> GT
-    EQ -> compare n m
-
-instance Extend Run where
-  extended = extend
-
-instance Comonad Run where
-  duplicate r@(Run i _) = Run i r
-  extend f r@(Run i _) = Run i (f r)
-  extract (Run _ a) = a
-
-instance Functor Run where
-  fmap f (Run n a) = Run n (f a)
-  a <$ Run n _ = Run n a
-
-instance Pointed Run where
-  point = Run 1
-
-instance Apply Run where
-  Run n f <.> Run m a = Run (n * m) (f a)
-  Run n _  .> Run m a = Run (n * m) a
-  Run n a <.  Run m _ = Run (n * m) a
-
-instance ComonadApply Run where
-  Run n f <@> Run m a = Run (n * m) (f a)
-  Run n _  @> Run m a = Run (n * m) a
-  Run n a <@  Run m _ = Run (n * m) a
-
-instance Applicative Run where
-  pure = Run 1
-  Run n f <*> Run m a = Run (n * m) (f a)
-  Run n _  *> Run m a = Run (n * m) a
-  Run n a <*  Run m _ = Run (n * m) a
-
-instance Bind Run where
-  Run n a >>- f = case f a of
-    Run m b -> Run (n * m) b
- 
-instance Monad Run where
-  return = Run 1
-  Run n _ >> Run m b = Run (n * m) b
-  Run n a >>= f = case f a of
-    Run m b -> Run (n * m) b
-
-instance Foldable Run where
-  foldMap k (Run y0 x0) = f (k x0) y0 where
-    f x y
-      | even y = f (x `mappend` x) (y `quot` 2)
-      | y == 1 = x
-      | otherwise = g (x `mappend` x) ((y - 1) `quot` 2) x
-    g x y z
-      | even y = g (x `mappend` x) (y `quot` 2) z
-      | y == 1 = x `mappend` z
-      | otherwise = g (x `mappend` x) ((y - 1) `quot` 2) (x `mappend` z)
-  {-# INLINE foldMap #-}
-
-instance Foldable1 Run where
-  foldMap1 k (Run y0 x0) = f (k x0) y0 where
-    f x y
-      | even y = f (x <> x) (y `quot` 2)
-      | y == 1 = x
-      | otherwise = g (x <> x) ((y - 1) `quot` 2) x
-    g x y z
-      | even y = g (x <> x) (y `quot` 2) z
-      | y == 1 = x <> z
-      | otherwise = g (x <> x) ((y - 1) `quot` 2) (x <> z)
-  {-# INLINE foldMap1 #-}
-
-instance Measured Count (Run a) where
-  measure (Run n _) = Count n
-
--- | A 'Generator' which supports efficient 'mapReduce' operations over run-length encoded data.
-newtype RLE a = RLE { getRLE :: FingerTree Count (Run a) } 
-
-toRuns :: RLE a -> [Run a]
-toRuns = toList . getRLE
-
-fromRuns :: [Run a] -> RLE a
-fromRuns = RLE . F.fromList 
-
-instance Eq a => Semigroup (RLE a) where
-  RLE l <> RLE r = go (viewr l) (viewl r) where
-    go EmptyR  _ = RLE r
-    go _  EmptyL = RLE l
-    go (l' :> Run m a) (Run n b :< r')
-      | a == b     = RLE ((l' |> Run (m+n) a) >< r')
-      | otherwise  = RLE (l >< r)
-
-instance Functor RLE where
-  fmap f = RLE . F.fmap' (fmap f) . getRLE
-
-instance Pointed RLE where
-  point = RLE . F.singleton . pure
-
-instance Apply RLE where
-  (<.>) = (<*>)
-  (<. ) = (<* )
-  ( .>) = ( *>)
-
-instance Applicative RLE where
-  pure = RLE . F.singleton . pure
-  RLE fs <*> RLE as = RLE $ F.fromList $ do
-    Run n f <- toList fs
-    Run m a <- toList as
-    return $ Run (n * m) (f a)
-  RLE as <* RLE bs = RLE $ F.fmap' (\(Run n a) -> Run (n * m) a) as where
-    m = reduceWith getCount bs
-  RLE as *> RLE bs = RLE $ mconcat $ replicate (reduceWith getCount as) bs
-
-instance Bind RLE where
-  (>>-) = (>>=)
-
-instance Monad RLE where
-  return = RLE . F.singleton . pure 
-  (>>) = (*>)
-  RLE xs >>= f = RLE $ mconcat [ mconcat $ replicate n (getRLE (f a)) | Run n a <- toList xs ]
- 
-instance Eq a => Reducer a (RLE a) where
-  unit = pure
-  cons a (RLE r) = case viewl r of
-    EmptyL -> pure a
-    Run n b :< r' 
-      | a == b    -> RLE (Run (n+1) a <| r')
-      | otherwise -> RLE (Run 1     a <| r )
-  snoc (RLE l) a = case viewr l of
-    EmptyR -> pure a
-    l' :> Run n b 
-      | a == b    -> RLE (l' |> Run (n+1) b)
-      | otherwise -> RLE (l  |> Run 1 a   )
-
-instance Eq a => Monoid (RLE a) where
-  mempty = RLE mempty
-  mappend = (<>)
-
-instance Foldable RLE where
-  foldMap f = foldMap (foldMap f) . getRLE
-
-instance Generator (RLE a) where
-  type Elem (RLE a) = a
-  mapReduce f = foldMap (unit . f)
-
-instance Hashable a => Hashable (RLE a) where
-  hashWithSalt n = hashWithSalt n . toList
-
-instance Eq a => Eq (RLE a) where
-  (==) = (==) `on` toList  -- todo stride through aligning
-
-instance Zip RLE where
-  zipWith f (RLE xs0) (RLE ys0) = RLE $ case toList xs0 of
-    [] -> mempty
-    (Run n0 a0:as0) -> case toList ys0 of 
-      [] -> mempty
-      (Run m0 b0:bs0) -> go n0 a0 as0 m0 b0 bs0 
-    where
-      go !n !a !as !m !b !bs = case compare n m of 
-        LT -> Run n (f a b) <| case as of
-          [] -> mempty
-          (Run n' a':as') -> go n' a' as' (m - n) b bs
-        EQ -> Run n (f a b) <| case as of
-          [] -> mempty
-          (Run n' a':as') -> case bs of
-             [] -> mempty
-             (Run m' b':bs') -> go n' a' as' m' b' bs'
-        GT -> Run m (f a b) <| case bs of
-          [] -> mempty
-          (Run m' b':bs') -> go (n - m) a as m' b' bs'
-          
-type instance Key RLE = Int
-
-instance Lookup RLE where
-  lookup i (RLE xs) 
-    | i < 0 = Nothing
-    | otherwise = case viewl $ snd $ split (\n -> getCount n > i) xs of
-      Run _ a :< _ -> Just a
-      EmptyL       -> Nothing 
-
-instance Adjustable RLE where
-  adjust f i (RLE xs) = RLE $ case viewl r of
-    EmptyL -> xs
-    Run n a :< r' -> 
-      let 
-        k = i - getCount (measure l)
-        infixr 4 <?
-        Run 0 _ <? ys = ys
-        Run m b <? ys = Run m b <| ys
-     in l >< (Run k a <? Run 1 (f a) <? Run (n - k - 1) a <? r')
-    where 
-      (l,r) = split (\n -> getCount n > i) xs
-
-
-encode :: (Generator c, Eq (Elem c)) => c -> RLE (Elem c)
-encode = reduce
-{-# RULES "encode/recode"     encode = recode #-}
-{-# RULES "encode/encodeList" encode = encodeList #-}
-
-decode :: RLE a -> [a]
-decode = reduce
-
-recode :: Eq a => RLE a -> RLE a
-recode (RLE xs0) = case toList xs0 of 
-  [] -> RLE mempty
-  (Run n0 a0:as0) -> RLE $ go n0 a0 as0
-  where
-    go n a [] = F.singleton (Run n a)
-    go n a (Run m b:bs)
-      | a == b = go (n + m) a bs
-      | otherwise = Run n a <| go m b bs
-
-encodeList :: Eq a => [a] -> RLE a
-encodeList []       = RLE mempty
-encodeList (a0:as0) = RLE $ go 1 a0 as0
-  where
-    go n a [] = F.singleton (Run n a)
-    go n a (b:bs) 
-      | a == b    = go (n + 1) a bs
-      | otherwise = Run n a <| go 1 b bs
diff --git a/README.markdown b/README.markdown
new file mode 100644
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,16 @@
+compressed
+==========
+
+[![Build Status](https://secure.travis-ci.org/ekmett/compressed.png?branch=master)](http://travis-ci.org/ekmett/compressed)
+
+This package provides compressed data structures for LZ78 and run length encoding. Their primary benefit is that if you go
+to decompress them you can decompress them in an arbitrary `Monoid`.
+
+Contact Information
+-------------------
+
+Contributions and bug reports are welcome!
+
+Please feel free to contact me through github or on the #haskell IRC channel on irc.freenode.net.
+
+-Edward Kmett
diff --git a/compressed.cabal b/compressed.cabal
--- a/compressed.cabal
+++ b/compressed.cabal
@@ -1,6 +1,6 @@
 name:          compressed
 category:      Data, Compression, MapReduce
-version:       3.0.0.1
+version:       3.0.1
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -13,7 +13,13 @@
 synopsis:      Compressed containers and reducers
 description:   Compressed containers and reducers
 build-type:    Simple
-extra-source-files: .travis.yml
+extra-source-files:
+  .ghci
+  .gitignore
+  .vim.custom
+  .travis.yml
+  CHANGELOG.markdown
+  README.markdown
 
 source-repository head
   type: git
@@ -27,12 +33,12 @@
     fingertree             >= 0.0.1    && < 0.1,
     hashable               >= 1.1.2.1  && < 1.3,
     unordered-containers   >= 0.2.1    && < 0.3,
-    semigroups             >= 0.8.3.1  && < 0.9,
-    semigroupoids          >= 3.0      && < 3.1,
-    comonad                >= 3.0      && < 3.1,
-    pointed                >= 3.0      && < 3.1,
-    keys                   >= 3.0      && < 3.1,
-    reducers               >= 3.0      && < 3.1
+    semigroups             >= 0.8.3.1,
+    semigroupoids          >= 3,
+    comonad                >= 3,
+    pointed                >= 3,
+    keys                   >= 3,
+    reducers               >= 3
 
   exposed-modules:
     Data.Compressed.LZ78
@@ -40,3 +46,4 @@
     Data.Compressed.Internal.LZ78
 
   ghc-options: -Wall
+  hs-source-dirs: src
diff --git a/src/Data/Compressed/Internal/LZ78.hs b/src/Data/Compressed/Internal/LZ78.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Compressed/Internal/LZ78.hs
@@ -0,0 +1,235 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE ParallelListComp #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Generator.LZ78
+-- Copyright   :  (c) Edward Kmett 2009-2012
+-- License     :  BSD-style
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  experimental
+-- Portability :  non-portable (type families)
+--
+-- Compression algorithms are all about exploiting redundancy. When applying
+-- an expensive 'Reducer' to a redundant source, it may be better to
+-- extract the structural redundancy that is present. 'LZ78' is a compression
+-- algorithm that does so, without requiring the dictionary to be populated
+-- with all of the possible values of a data type unlike its later
+-- refinement LZW, and which has fewer comparison reqirements during encoding
+-- than its earlier counterpart LZ77.
+-----------------------------------------------------------------------------
+
+module Data.Compressed.Internal.LZ78
+    (
+    -- * Lempel-Ziv 78
+      Token(..)
+    , LZ78(..)
+    -- * Encoding
+    , encode    -- /O(n)/
+    , encodeOrd -- /O(n log n)/
+    , encodeEq  -- /O(n^2)/
+    -- * Decoding (reduce)
+    , decode
+    -- * Recoding
+    , recode    -- /O(n)/
+    , recodeOrd -- /O(n log n)/
+    , recodeEq  -- /O(n^2)/
+    -- * Unsafe (exposes internal structure)
+    , Entry(..)
+    , entries
+    ) where
+
+import Control.Applicative
+import qualified Data.Sequence as Seq
+import Data.Sequence ((|>))
+import qualified Data.Map as Map
+import qualified Data.HashMap.Lazy as HashMap
+import qualified Data.List as List
+import Data.Functor.Extend
+import Data.Generator
+import Data.Function (on)
+import Data.Key as Key
+import Data.Foldable
+import Data.Traversable
+import Data.Semigroup
+import Data.Pointed
+import Text.Read
+import Control.Comonad
+import Data.Hashable
+import Data.Semigroup.Reducer (Reducer(..), Count(..))
+
+data Token a = Token {-# UNPACK #-} !Int a deriving (Eq, Ord)
+
+instance Functor Token where
+  fmap f (Token i a) = Token i (f a)
+
+instance Foldable Token where
+  foldMap f (Token _ a) = f a
+
+instance Traversable Token where
+  traverse f (Token i a) = Token i <$> f a
+
+instance Extend Token where
+  extended = extend
+
+instance Comonad Token where
+  extend f t@(Token i _) = Token i (f t)
+  duplicate t@(Token i _) = Token i t
+  extract (Token _ a) = a
+
+instance Hashable a => Hashable (Token a) where
+  hashWithSalt s (Token i a) = s `hashWithSalt` i `hashWithSalt` a
+
+-- | An LZ78 compressed 'Generator'.
+data LZ78 a
+  = Cons {-# UNPACK #-} !(Token a) (LZ78 a)
+  | Nil
+
+instance Show a => Show (LZ78 a) where
+  showsPrec d xs = showParen (d > 10) $
+    showString "encode " . showsPrec 11 (toList xs)
+
+instance Eq a => Eq (LZ78 a) where
+  (==) = (==) `on` decode
+
+instance Ord a => Ord (LZ78 a) where
+  compare = compare `on` decode
+
+instance (Read a, Hashable a, Eq a) => Read (LZ78 a) where
+  readPrec = parens $ prec 10 $ do
+    Ident "encode" <- lexP
+    encode <$> step readPrec
+
+instance Generator (LZ78 a) where
+  type Elem (LZ78 a) = a
+  mapTo = go (Seq.singleton mempty) where
+    go _ _ m Nil = m
+    go s f m (Cons (Token w c) ws) = m `mappend` go (s |> v) f v ws where
+      v = Seq.index s w `mappend`  unit (f c)
+
+instance Functor LZ78 where
+  fmap f (Cons (Token i a) as) = Cons (Token i (f a)) (fmap f as)
+  fmap _ Nil = Nil
+  a <$ xs = go 0 (getCount (reduce xs)) where
+     go !_ 0 = Nil
+     go k  n | n > k = Cons (Token k a) (go (k + 1) (n - k - 1))
+             | otherwise = Cons (Token (n - 1) a) Nil
+
+instance Pointed LZ78 where
+  point a = Cons (Token 0 a) Nil
+
+instance Foldable LZ78 where
+  foldMap f = unwrapMonoid . mapReduce f
+  fold      = unwrapMonoid . reduce
+
+-- | /O(n)/ Construct an LZ78-compressed 'Generator' using a 'HashMap' internally.
+encode :: (Hashable a, Eq a) => [a] -> LZ78 a
+encode = go HashMap.empty 1 0 where
+  go _ _ _ [] = Nil
+  go _ _ p [c] = Cons (Token p c) Nil
+  go d f p (c:cs) = let t = Token p c in case HashMap.lookup t d of
+    Just p' -> go d f p' cs
+    Nothing -> Cons t (go (HashMap.insert t f d) (succ f) 0 cs)
+
+-- | /O(n log n)/ Contruct an LZ78-compressed 'Generator' using a 'Map' internally.
+encodeOrd :: Ord a => [a] -> LZ78 a
+encodeOrd = go Map.empty 1 0 where
+  go _ _ _ [] = Nil
+  go _ _ p [c] = Cons (Token p c) Nil
+  go d f p (c:cs) = let t = Token p c in case Map.lookup t d of
+    Just p' -> go d f p' cs
+    Nothing -> Cons t (go (Map.insert t f d) (succ f) 0 cs)
+
+-- | /O(n^2)/ Contruct an LZ78-compressed 'Generator' using a list internally, requires an instance of Eq,
+-- less efficient than encode.
+encodeEq :: Eq a => [a] -> LZ78 a
+encodeEq = go [] 1 0 where
+  go _ _ _ [] = Nil
+  go _ _ p [c] = Cons (Token p c) Nil
+  go d f p (c:cs) = let t = Token p c in case List.lookup t d of
+    Just p' -> go d f p' cs
+    Nothing -> Cons t (go ((t, f):d) (succ f) 0 cs)
+
+-- | A type-constrained 'reduce' operation
+decode :: LZ78 a -> [a]
+decode = reduce
+
+-- | /O(n)/. Recompress with 'Hashable'
+recode :: (Eq a, Hashable a) => LZ78 a -> LZ78 a
+recode = encode . decode
+
+-- | /O(n log n)/. Recompress with 'Ord'
+recodeOrd :: Ord a => LZ78 a -> LZ78 a
+recodeOrd = encodeOrd . decode
+
+-- | /O(n^2)/. Recompress with 'Eq'
+recodeEq :: Eq a => LZ78 a -> LZ78 a
+recodeEq = encodeEq . decode
+
+data Entry i a = Entry !i a deriving (Show,Read)
+
+instance Functor (Entry i) where
+  fmap f (Entry i a) = Entry i (f a)
+
+instance Extend (Entry i) where
+  extended = extend
+
+instance Comonad (Entry i) where
+  extend f e@(Entry i _) = Entry i (f e)
+  duplicate e@(Entry i _) = Entry i e
+  extract (Entry _ a) = a
+
+instance Eq i => Eq (Entry i a) where
+  Entry i _ == Entry j _ = i == j
+
+instance Ord i => Ord (Entry i a) where
+  compare (Entry i _) (Entry j _) = compare i j
+
+instance Hashable i => Hashable (Entry i a) where
+  hashWithSalt n (Entry i _) = hashWithSalt n i
+
+-- | exposes internal structure
+entries :: LZ78 a -> LZ78 (Entry Int a)
+entries = go 0 where
+  go k (Cons (Token i t) xs) = Cons (Token i (Entry k t)) $ (go $! k + 1) xs
+  go _ Nil = Nil
+
+instance Applicative LZ78 where
+  pure a = Cons (Token 0 a) Nil
+  fs <*> as = fmap extract $ encode $ do
+    Entry i f <- decode (entries fs)
+    Entry j a <- decode (entries as)
+    return $ Entry (i,j) (f a)
+  as *> bs = fmap extract $ encode $ Prelude.concat $ replicate (reduceWith getCount as)  $  decode (entries bs)
+  as <* bs = fmap extract $ encode $ Prelude.concat $ replicate (reduceWith getCount bs) <$> decode (entries as)
+
+instance Monad LZ78 where
+  return a = Cons (Token 0 a) Nil
+  (>>) = (*>)
+  as >>= k = fmap extract $ encode $ do
+    Entry i a <- decode (entries as)
+    Entry j b <- decode (entries (k a))
+    return $ Entry (i,j) b
+
+instance Adjustable LZ78 where
+  adjust f i = fmap extract . encode . adjust (Entry (-1) . f . extract) i . decode . entries
+
+type instance Key LZ78 = Int
+
+instance Lookup LZ78 where
+  lookup i xs = Key.lookup i (decode xs)
+
+instance Indexable LZ78 where
+  index xs i = index (decode xs) i
+
+instance FoldableWithKey LZ78 where
+  foldMapWithKey f xs = foldMapWithKey f (decode xs)
+
+instance Zip LZ78 where
+  zipWith f as bs = extract <$> encode
+    [ Entry (i,j) (f a b)
+    | Entry i a <- decode (entries as)
+    | Entry j b <- decode (entries bs)
+    ]
+
+
diff --git a/src/Data/Compressed/LZ78.hs b/src/Data/Compressed/LZ78.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Compressed/LZ78.hs
@@ -0,0 +1,35 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Compressed.LZ78
+-- Copyright   :  (c) Edward Kmett 2009-2011
+-- License     :  BSD-style
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  experimental
+-- Portability :  non-portable (type families)
+--
+-- Compression algorithms are all about exploiting redundancy. When applying
+-- an expensive 'Reducer' to a redundant source, it may be better to 
+-- extract the structural redundancy that is present. 'LZ78' is a compression
+-- algorithm that does so, without requiring the dictionary to be populated
+-- with all of the possible values of a data type unlike its later 
+-- refinement LZW, and which has fewer comparison reqirements during encoding
+-- than its earlier counterpart LZ77. 
+-----------------------------------------------------------------------------
+
+module Data.Compressed.LZ78 
+    ( 
+    -- * Lempel-Ziv 78 
+      LZ78
+    -- * Encoding
+    , encode    -- /O(n)/
+    , encodeOrd -- /O(n log n)/
+    , encodeEq  -- /O(n^2)/
+    -- * Decoding (reduce)
+    , decode
+    -- * Recoding
+    , recode    -- /O(n)/
+    , recodeOrd -- /O(n log n)/
+    , recodeEq  -- /O(n^2)/
+    ) where
+
+import Data.Compressed.Internal.LZ78
diff --git a/src/Data/Compressed/RunLengthEncoding.hs b/src/Data/Compressed/RunLengthEncoding.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Compressed/RunLengthEncoding.hs
@@ -0,0 +1,273 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE BangPatterns #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Compressed.RunLengthEncoding
+-- Copyright   :  (c) Edward Kmett 2009-2012
+-- License     :  BSD-style
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Compression algorithms are all about exploiting redundancy. When applying
+-- an expensive 'Reducer' to a redundant source, it may be better to 
+-- extract the structural redundancy that is present. Run length encoding
+-- can do so for long runs of identical inputs.
+-----------------------------------------------------------------------------
+module Data.Compressed.RunLengthEncoding
+    ( RLE(..)
+    , Run
+    , runLength
+    , decode
+    , encode
+    , recode
+    , toRuns
+    , fromRuns
+    ) where
+
+import Data.Foldable
+import Data.Semigroup
+import Data.Semigroup.Reducer
+import Data.Semigroup.Foldable
+import Data.Hashable
+import Data.Function (on)
+import Data.Functor.Bind
+import Data.Functor.Extend
+import Control.Comonad
+import Data.FingerTree (FingerTree,(|>),(<|),ViewL(..),ViewR(..),(><),viewl,viewr, Measured(..), split)
+import qualified Data.FingerTree as F
+import Data.Generator
+import Data.Pointed
+import Data.Key
+import Control.Applicative
+
+-- | A single run with a strict length
+data Run a = Run {-# UNPACK #-} !Int a deriving (Eq,Show)
+
+runLength :: Run a -> Int
+runLength (Run n _) = n
+
+-- lexicographical order
+instance Ord a => Ord (Run a) where
+  compare (Run n a) (Run m b) = case compare a b of
+    LT -> LT
+    GT -> GT
+    EQ -> compare n m
+
+instance Extend Run where
+  extended = extend
+
+instance Comonad Run where
+  duplicate r@(Run i _) = Run i r
+  extend f r@(Run i _) = Run i (f r)
+  extract (Run _ a) = a
+
+instance Functor Run where
+  fmap f (Run n a) = Run n (f a)
+  a <$ Run n _ = Run n a
+
+instance Pointed Run where
+  point = Run 1
+
+instance Apply Run where
+  Run n f <.> Run m a = Run (n * m) (f a)
+  Run n _  .> Run m a = Run (n * m) a
+  Run n a <.  Run m _ = Run (n * m) a
+
+instance ComonadApply Run where
+  Run n f <@> Run m a = Run (n * m) (f a)
+  Run n _  @> Run m a = Run (n * m) a
+  Run n a <@  Run m _ = Run (n * m) a
+
+instance Applicative Run where
+  pure = Run 1
+  Run n f <*> Run m a = Run (n * m) (f a)
+  Run n _  *> Run m a = Run (n * m) a
+  Run n a <*  Run m _ = Run (n * m) a
+
+instance Bind Run where
+  Run n a >>- f = case f a of
+    Run m b -> Run (n * m) b
+ 
+instance Monad Run where
+  return = Run 1
+  Run n _ >> Run m b = Run (n * m) b
+  Run n a >>= f = case f a of
+    Run m b -> Run (n * m) b
+
+instance Foldable Run where
+  foldMap k (Run y0 x0) = f (k x0) y0 where
+    f x y
+      | even y = f (x `mappend` x) (y `quot` 2)
+      | y == 1 = x
+      | otherwise = g (x `mappend` x) ((y - 1) `quot` 2) x
+    g x y z
+      | even y = g (x `mappend` x) (y `quot` 2) z
+      | y == 1 = x `mappend` z
+      | otherwise = g (x `mappend` x) ((y - 1) `quot` 2) (x `mappend` z)
+  {-# INLINE foldMap #-}
+
+instance Foldable1 Run where
+  foldMap1 k (Run y0 x0) = f (k x0) y0 where
+    f x y
+      | even y = f (x <> x) (y `quot` 2)
+      | y == 1 = x
+      | otherwise = g (x <> x) ((y - 1) `quot` 2) x
+    g x y z
+      | even y = g (x <> x) (y `quot` 2) z
+      | y == 1 = x <> z
+      | otherwise = g (x <> x) ((y - 1) `quot` 2) (x <> z)
+  {-# INLINE foldMap1 #-}
+
+instance Measured Count (Run a) where
+  measure (Run n _) = Count n
+
+-- | A 'Generator' which supports efficient 'mapReduce' operations over run-length encoded data.
+newtype RLE a = RLE { getRLE :: FingerTree Count (Run a) } 
+
+toRuns :: RLE a -> [Run a]
+toRuns = toList . getRLE
+
+fromRuns :: [Run a] -> RLE a
+fromRuns = RLE . F.fromList 
+
+instance Eq a => Semigroup (RLE a) where
+  RLE l <> RLE r = go (viewr l) (viewl r) where
+    go EmptyR  _ = RLE r
+    go _  EmptyL = RLE l
+    go (l' :> Run m a) (Run n b :< r')
+      | a == b     = RLE ((l' |> Run (m+n) a) >< r')
+      | otherwise  = RLE (l >< r)
+
+instance Functor RLE where
+  fmap f = RLE . F.fmap' (fmap f) . getRLE
+
+instance Pointed RLE where
+  point = RLE . F.singleton . pure
+
+instance Apply RLE where
+  (<.>) = (<*>)
+  (<. ) = (<* )
+  ( .>) = ( *>)
+
+instance Applicative RLE where
+  pure = RLE . F.singleton . pure
+  RLE fs <*> RLE as = RLE $ F.fromList $ do
+    Run n f <- toList fs
+    Run m a <- toList as
+    return $ Run (n * m) (f a)
+  RLE as <* RLE bs = RLE $ F.fmap' (\(Run n a) -> Run (n * m) a) as where
+    m = reduceWith getCount bs
+  RLE as *> RLE bs = RLE $ mconcat $ replicate (reduceWith getCount as) bs
+
+instance Bind RLE where
+  (>>-) = (>>=)
+
+instance Monad RLE where
+  return = RLE . F.singleton . pure 
+  (>>) = (*>)
+  RLE xs >>= f = RLE $ mconcat [ mconcat $ replicate n (getRLE (f a)) | Run n a <- toList xs ]
+ 
+instance Eq a => Reducer a (RLE a) where
+  unit = pure
+  cons a (RLE r) = case viewl r of
+    EmptyL -> pure a
+    Run n b :< r' 
+      | a == b    -> RLE (Run (n+1) a <| r')
+      | otherwise -> RLE (Run 1     a <| r )
+  snoc (RLE l) a = case viewr l of
+    EmptyR -> pure a
+    l' :> Run n b 
+      | a == b    -> RLE (l' |> Run (n+1) b)
+      | otherwise -> RLE (l  |> Run 1 a   )
+
+instance Eq a => Monoid (RLE a) where
+  mempty = RLE mempty
+  mappend = (<>)
+
+instance Foldable RLE where
+  foldMap f = foldMap (foldMap f) . getRLE
+
+instance Generator (RLE a) where
+  type Elem (RLE a) = a
+  mapReduce f = foldMap (unit . f)
+
+instance Hashable a => Hashable (RLE a) where
+  hashWithSalt n = hashWithSalt n . toList
+
+instance Eq a => Eq (RLE a) where
+  (==) = (==) `on` toList  -- todo stride through aligning
+
+instance Zip RLE where
+  zipWith f (RLE xs0) (RLE ys0) = RLE $ case toList xs0 of
+    [] -> mempty
+    (Run n0 a0:as0) -> case toList ys0 of 
+      [] -> mempty
+      (Run m0 b0:bs0) -> go n0 a0 as0 m0 b0 bs0 
+    where
+      go !n !a !as !m !b !bs = case compare n m of 
+        LT -> Run n (f a b) <| case as of
+          [] -> mempty
+          (Run n' a':as') -> go n' a' as' (m - n) b bs
+        EQ -> Run n (f a b) <| case as of
+          [] -> mempty
+          (Run n' a':as') -> case bs of
+             [] -> mempty
+             (Run m' b':bs') -> go n' a' as' m' b' bs'
+        GT -> Run m (f a b) <| case bs of
+          [] -> mempty
+          (Run m' b':bs') -> go (n - m) a as m' b' bs'
+          
+type instance Key RLE = Int
+
+instance Lookup RLE where
+  lookup i (RLE xs) 
+    | i < 0 = Nothing
+    | otherwise = case viewl $ snd $ split (\n -> getCount n > i) xs of
+      Run _ a :< _ -> Just a
+      EmptyL       -> Nothing 
+
+instance Adjustable RLE where
+  adjust f i (RLE xs) = RLE $ case viewl r of
+    EmptyL -> xs
+    Run n a :< r' -> 
+      let 
+        k = i - getCount (measure l)
+        infixr 4 <?
+        Run 0 _ <? ys = ys
+        Run m b <? ys = Run m b <| ys
+     in l >< (Run k a <? Run 1 (f a) <? Run (n - k - 1) a <? r')
+    where 
+      (l,r) = split (\n -> getCount n > i) xs
+
+
+encode :: (Generator c, Eq (Elem c)) => c -> RLE (Elem c)
+encode = reduce
+{-# RULES "encode/recode"     encode = recode #-}
+{-# RULES "encode/encodeList" encode = encodeList #-}
+
+decode :: RLE a -> [a]
+decode = reduce
+
+recode :: Eq a => RLE a -> RLE a
+recode (RLE xs0) = case toList xs0 of 
+  [] -> RLE mempty
+  (Run n0 a0:as0) -> RLE $ go n0 a0 as0
+  where
+    go n a [] = F.singleton (Run n a)
+    go n a (Run m b:bs)
+      | a == b = go (n + m) a bs
+      | otherwise = Run n a <| go m b bs
+
+encodeList :: Eq a => [a] -> RLE a
+encodeList []       = RLE mempty
+encodeList (a0:as0) = RLE $ go 1 a0 as0
+  where
+    go n a [] = F.singleton (Run n a)
+    go n a (b:bs) 
+      | a == b    = go (n + 1) a bs
+      | otherwise = Run n a <| go 1 b bs
