diff --git a/Data/Conduit/Binary.hs b/Data/Conduit/Binary.hs
--- a/Data/Conduit/Binary.hs
+++ b/Data/Conduit/Binary.hs
@@ -3,25 +3,50 @@
 -- | Functions for interacting with bytes.
 module Data.Conduit.Binary
     ( sourceFile
+    , sourceHandle
     , sourceFileRange
     , sinkFile
+    , sinkHandle
     , conduitFile
     , isolate
+    , openFile
+    , head
+    , takeWhile
+    , dropWhile
     ) where
 
+import Prelude hiding (head, takeWhile, dropWhile)
 import qualified Data.ByteString as S
 import Data.Conduit
 import Control.Exception (assert)
 import Control.Monad.IO.Class (liftIO)
 import qualified System.IO as IO
-import Control.Monad.Trans.Resource (withIO, release, newRef, readRef, writeRef)
+import Control.Monad.Trans.Resource
+    ( withIO, release, newRef, readRef, writeRef
+    )
+import Data.Word (Word8)
 #if CABAL_OS_WINDOWS
 import qualified System.Win32File as F
 #elif NO_HANDLES
 import qualified System.PosixFile as F
 #endif
 
+-- | Open a file 'IO.Handle' safely by automatically registering a release
+-- action.
+--
+-- While you are not required to call @hClose@ on the resulting handle, you
+-- should do so as early as possible to free scarce resources.
+--
+-- Since 0.0.2
+openFile :: ResourceIO m
+         => FilePath
+         -> IO.IOMode
+         -> ResourceT m IO.Handle
+openFile fp mode = fmap snd $ withIO (IO.openBinaryFile fp mode) IO.hClose
+
 -- | Stream the contents of a file as binary data.
+--
+-- Since 0.0.0
 sourceFile :: ResourceIO m
            => FilePath
            -> Source m S.ByteString
@@ -31,7 +56,7 @@
     F.close
     (liftIO . F.read)
 #else
-    (IO.openFile fp IO.ReadMode)
+    (IO.openBinaryFile fp IO.ReadMode)
     IO.hClose
     (\handle -> do
         bs <- liftIO $ S.hGetSome handle 4096
@@ -40,15 +65,46 @@
             else return $ Open bs)
 #endif
 
+-- | Stream the contents of a 'IO.Handle' as binary data. Note that this
+-- function will /not/ automatically close the @Handle@ when processing
+-- completes, since it did not acquire the @Handle@ in the first place.
+--
+-- Since 0.0.2.
+sourceHandle :: ResourceIO m
+             => IO.Handle
+             -> Source m S.ByteString
+sourceHandle h = Source $ return $ PreparedSource
+    { sourcePull = do
+        bs <- liftIO (S.hGetSome h 4096)
+        if S.null bs
+            then return Closed
+            else return (Open bs)
+    , sourceClose = return ()
+    }
+
+-- | Stream all incoming data to the given 'IO.Handle'. Note that this function
+-- will /not/ automatically close the @Handle@ when processing completes.
+--
+-- Since 0.0.2.
+sinkHandle :: ResourceIO m
+           => IO.Handle
+           -> Sink S.ByteString m ()
+sinkHandle h = Sink $ return $ SinkData
+    { sinkPush = \input -> liftIO (S.hPut h input) >> return Processing
+    , sinkClose = return ()
+    }
+
 -- | Stream the contents of a file as binary data, starting from a certain
 -- offset and only consuming up to a certain number of bytes.
+--
+-- Since 0.0.0
 sourceFileRange :: ResourceIO m
                 => FilePath
                 -> Maybe Integer -- ^ Offset
                 -> Maybe Integer -- ^ Maximum count
                 -> Source m S.ByteString
 sourceFileRange fp offset count = Source $ do
-    (key, handle) <- withIO (IO.openFile fp IO.ReadMode) IO.hClose
+    (key, handle) <- withIO (IO.openBinaryFile fp IO.ReadMode) IO.hClose
     case offset of
         Nothing -> return ()
         Just off -> liftIO $ IO.hSeek handle IO.AbsoluteSeek off
@@ -84,22 +140,26 @@
                     return $ Open bs
 
 -- | Stream all incoming data to the given file.
+--
+-- Since 0.0.0
 sinkFile :: ResourceIO m
          => FilePath
          -> Sink S.ByteString m ()
 sinkFile fp = sinkIO
-    (IO.openFile fp IO.WriteMode)
+    (IO.openBinaryFile fp IO.WriteMode)
     IO.hClose
     (\handle bs -> liftIO (S.hPut handle bs) >> return Processing)
     (const $ return ())
 
 -- | Stream the contents of the input to a file, and also send it along the
 -- pipeline. Similar in concept to the Unix command @tee@.
+--
+-- Since 0.0.0
 conduitFile :: ResourceIO m
             => FilePath
             -> Conduit S.ByteString m S.ByteString
 conduitFile fp = conduitIO
-    (IO.openFile fp IO.WriteMode)
+    (IO.openBinaryFile fp IO.WriteMode)
     IO.hClose
     (\handle bs -> do
         liftIO $ S.hPut handle bs
@@ -109,6 +169,8 @@
 -- | Ensure that only up to the given number of bytes are consume by the inner
 -- sink. Note that this does /not/ ensure that all of those bytes are in fact
 -- consumed.
+--
+-- Since 0.0.0
 isolate :: Resource m
         => Int
         -> Conduit S.ByteString m S.ByteString
@@ -126,3 +188,45 @@
                 then Finished (if S.null b then Nothing else Just b) (if S.null a then [] else [a])
                 else assert (S.null b) $ Producing [a])
     close _ = return []
+
+-- | Return the next byte from the stream, if available.
+--
+-- Since 0.0.2
+head :: Resource m => Sink S.ByteString m (Maybe Word8)
+head = Sink $ return $ SinkData
+    { sinkPush = \bs ->
+        case S.uncons bs of
+            Nothing -> return Processing
+            Just (w, bs') -> do
+                let lo = if S.null bs' then Nothing else Just bs'
+                return $ Done lo (Just w)
+    , sinkClose = return Nothing
+    }
+
+-- | Return all bytes while the predicate returns @True@.
+--
+-- Since 0.0.2
+takeWhile :: Resource m => (Word8 -> Bool) -> Conduit S.ByteString m S.ByteString
+takeWhile p = Conduit $ return $ PreparedConduit
+    { conduitPush = \bs -> do
+        let (x, y) = S.span p bs
+        return $
+            if S.null y
+                then Producing [x]
+                else Finished (Just y) (if S.null x then [] else [x])
+    , conduitClose = return []
+    }
+
+-- | Ignore all bytes while the predicate returns @True@.
+--
+-- Since 0.0.2
+dropWhile :: Resource m => (Word8 -> Bool) -> Sink S.ByteString m ()
+dropWhile p = Sink $ return $ SinkData
+    { sinkPush = \bs -> do
+        let bs' = S.dropWhile p bs
+        return $
+            if S.null bs'
+                then Processing
+                else Done (Just bs') ()
+    , sinkClose = return ()
+    }
diff --git a/Data/Conduit/Lazy.hs b/Data/Conduit/Lazy.hs
--- a/Data/Conduit/Lazy.hs
+++ b/Data/Conduit/Lazy.hs
@@ -10,6 +10,9 @@
 import System.IO.Unsafe (unsafeInterleaveIO)
 import Control.Monad.Trans.Control
 
+-- | Use lazy I\/O to consume all elements from a @Source@.
+--
+-- Since 0.0.0
 lazyConsume :: MonadBaseControl IO m => Source m a -> ResourceT m [a]
 lazyConsume (Source msrc) = do
     src <- msrc
diff --git a/Data/Conduit/List.hs b/Data/Conduit/List.hs
--- a/Data/Conduit/List.hs
+++ b/Data/Conduit/List.hs
@@ -27,6 +27,7 @@
       -- ** Pure
     , map
     , concatMap
+    , groupBy
     , isolate
     , filter
       -- ** Monadic
@@ -45,6 +46,8 @@
 import Control.Monad.Trans.Class (lift)
 
 -- | A strict left fold.
+--
+-- Since 0.0.0
 fold :: Resource m
      => (b -> a -> b)
      -> b
@@ -55,6 +58,8 @@
     return
 
 -- | A monadic strict left fold.
+--
+-- Since 0.0.0
 foldM :: Resource m
       => (b -> a -> m b)
       -> b
@@ -68,6 +73,8 @@
     return
 
 -- | Apply the action to all values in the stream.
+--
+-- Since 0.0.0
 mapM_ :: Resource m
       => (a -> m ())
       -> Sink a m ()
@@ -76,6 +83,8 @@
     (return ())
 
 -- | Convert a list into a source.
+--
+-- Since 0.0.0
 sourceList :: Resource m => [a] -> Source m a
 sourceList l0 =
     sourceState l0 go
@@ -90,6 +99,8 @@
 --
 -- However, @drop@ is more efficient as it does not need to hold values in
 -- memory.
+--
+-- Since 0.0.0
 drop :: Resource m
      => Int
      -> Sink a m ()
@@ -111,6 +122,8 @@
 -- This function is semantically equivalent to:
 --
 -- > take i = isolate i =$ consume
+--
+-- Since 0.0.0
 take :: Resource m
      => Int
      -> Sink a m [a]
@@ -130,6 +143,8 @@
     close (_, front) = return $ front []
 
 -- | Take a single value from the stream, if available.
+--
+-- Since 0.0.0
 head :: Resource m => Sink a m (Maybe a)
 head =
     Sink $ return $ SinkData push close
@@ -139,6 +154,8 @@
 
 -- | Look at the next value in the stream, if available. This function will not
 -- change the state of the stream.
+--
+-- Since 0.0.0
 peek :: Resource m => Sink a m (Maybe a)
 peek =
     Sink $ return $ SinkData push close
@@ -147,6 +164,8 @@
     close = return Nothing
 
 -- | Apply a transformation to all values in a stream.
+--
+-- Since 0.0.0
 map :: Monad m => (a -> b) -> Conduit a m b
 map f = Conduit $ return $ PreparedConduit
     { conduitPush = return . Producing . return . f
@@ -157,6 +176,8 @@
 --
 -- If you do not need the transformed values, and instead just want the monadic
 -- side-effects of running the action, see 'mapM_'.
+--
+-- Since 0.0.0
 mapM :: Monad m => (a -> m b) -> Conduit a m b
 mapM f = Conduit $ return $ PreparedConduit
     { conduitPush = fmap (Producing . return) . lift . f
@@ -165,6 +186,8 @@
 
 -- | Apply a transformation to all values in a stream, concatenating the output
 -- values.
+--
+-- Since 0.0.0
 concatMap :: Monad m => (a -> [b]) -> Conduit a m b
 concatMap f = Conduit $ return $ PreparedConduit
     { conduitPush = return . Producing . f
@@ -173,6 +196,8 @@
 
 -- | Apply a monadic transformation to all values in a stream, concatenating
 -- the output values.
+--
+-- Since 0.0.0
 concatMapM :: Monad m => (a -> m [b]) -> Conduit a m b
 concatMapM f = Conduit $ return $ PreparedConduit
     { conduitPush = fmap Producing . lift . f
@@ -182,12 +207,31 @@
 -- | Consume all values from the stream and return as a list. Note that this
 -- will pull all values into memory. For a lazy variant, see
 -- "Data.Conduit.Lazy".
+--
+-- Since 0.0.0
 consume :: Resource m => Sink a m [a]
 consume = sinkState
     id
     (\front input -> return (front . (input :), Processing))
     (\front -> return $ front [])
 
+-- | Grouping input according to an equality function.
+--
+-- Since 0.0.2
+groupBy :: Resource m => (a -> a -> Bool) -> Conduit a m [a]
+groupBy f = conduitState
+    []
+    push
+    close
+  where
+    push []      v = return ([v], Producing [])
+    push s@(x:_) v =
+      if f x v then
+        return (v:s, Producing [])
+      else
+        return ([v], Producing [s])
+    close s = return [s]
+
 -- | Ensure that the inner sink consumes no more than the given number of
 -- values. Note this this does /not/ ensure that the sink consumes all of those
 -- values. To get the latter behavior, combine with 'sinkNull', e.g.:
@@ -199,6 +243,8 @@
 -- >         return x
 -- >     someOtherSink
 -- >     ...
+--
+-- Since 0.0.0
 isolate :: Resource m => Int -> Conduit a m a
 isolate count0 = conduitState
     count0
@@ -217,6 +263,8 @@
                         else Producing [x])
 
 -- | Keep only values in the stream passing a given predicate.
+--
+-- Since 0.0.0
 filter :: Resource m => (a -> Bool) -> Conduit a m a
 filter f = Conduit $ return $ PreparedConduit
     { conduitPush = return . Producing . Prelude.filter f . return
@@ -225,6 +273,8 @@
 
 -- | Ignore the remainder of values in the source. Particularly useful when
 -- combined with 'isolate'.
+--
+-- Since 0.0.0
 sinkNull :: Resource m => Sink a m ()
 sinkNull = Sink $ return $ SinkData
     (\_ -> return Processing)
diff --git a/Data/Conduit/Text.hs b/Data/Conduit/Text.hs
--- a/Data/Conduit/Text.hs
+++ b/Data/Conduit/Text.hs
@@ -46,6 +46,8 @@
 import Control.Monad.Trans.Resource (ResourceThrow (..))
 
 -- | A specific character encoding.
+--
+-- Since 0.0.0
 data Codec = Codec
     { codecName :: T.Text
     , codecEncode
@@ -64,6 +66,8 @@
 
 -- | Convert text into bytes, using the provided codec. If the codec is
 -- not capable of representing an input character, an exception will be thrown.
+--
+-- Since 0.0.0
 encode :: ResourceThrow m => Codec -> C.Conduit T.Text m B.ByteString
 encode codec = CL.mapM $ \t -> do
     let (bs, mexc) = codecEncode codec t
@@ -72,6 +76,8 @@
 
 -- | Convert bytes into text, using the provided codec. If the codec is
 -- not capable of decoding an input byte sequence, an exception will be thrown.
+--
+-- Since 0.0.0
 decode :: ResourceThrow m => Codec -> C.Conduit B.ByteString m T.Text
 decode codec = C.conduitState
     Nothing
@@ -108,6 +114,8 @@
         (text, extra) = codecDecode codec x
         front' = front . (text:)
 
+-- |
+-- Since 0.0.0
 data TextException = DecodeException Codec Word8
                    | EncodeException Codec Char
     deriving (Show, Typeable)
@@ -139,6 +147,8 @@
             -- is only called when parsing failed somewhere
             Right _ -> Right B.empty)
 
+-- |
+-- Since 0.0.0
 utf8 :: Codec
 utf8 = Codec name enc dec where
     name = T.pack "UTF-8"
@@ -170,6 +180,8 @@
                     then Just tooLong
                     else decodeMore
 
+-- |
+-- Since 0.0.0
 utf16_le :: Codec
 utf16_le = Codec name enc dec where
     name = T.pack "UTF-16-LE"
@@ -195,6 +207,8 @@
         decodeTo n = first TE.decodeUtf16LE (B.splitAt n bytes)
         decodeAll = (TE.decodeUtf16LE bytes, B.empty)
 
+-- |
+-- Since 0.0.0
 utf16_be :: Codec
 utf16_be = Codec name enc dec where
     name = T.pack "UTF-16-BE"
@@ -228,6 +242,8 @@
     x :: Word16
     x = (fromIntegral x1 `shiftL` 8) .|. fromIntegral x0
 
+-- |
+-- Since 0.0.0
 utf32_le :: Codec
 utf32_le = Codec name enc dec where
     name = T.pack "UTF-32-LE"
@@ -236,6 +252,8 @@
         Just (text, extra) -> (text, Right extra)
         Nothing -> splitSlowly TE.decodeUtf32LE bs
 
+-- |
+-- Since 0.0.0
 utf32_be :: Codec
 utf32_be = Codec name enc dec where
     name = T.pack "UTF-32-BE"
@@ -257,6 +275,8 @@
         then (bytes, B.empty)
         else B.splitAt lenToDecode bytes
 
+-- |
+-- Since 0.0.0
 ascii :: Codec
 ascii = Codec name enc dec where
     name = T.pack "ASCII"
@@ -274,6 +294,8 @@
             then Right B.empty
             else Left (DecodeException ascii (B.head unsafe), unsafe)
 
+-- |
+-- Since 0.0.0
 iso8859_1 :: Codec
 iso8859_1 = Codec name enc dec where
     name = T.pack "ISO-8859-1"
diff --git a/Data/Conduit/Types/Conduit.hs b/Data/Conduit/Types/Conduit.hs
--- a/Data/Conduit/Types/Conduit.hs
+++ b/Data/Conduit/Types/Conduit.hs
@@ -13,6 +13,8 @@
 -- still producing output and provide some, or indicate that it is finished
 -- producing output, in which case it returns optional leftover input and some
 -- final output.
+--
+-- Since 0.0.0
 data ConduitResult input output = Producing [output] | Finished (Maybe input) [output]
 
 instance Functor (ConduitResult input) where
@@ -26,6 +28,8 @@
 --
 -- * Neither a push nor close may be performed after a conduit returns a
 -- 'Finished' from a push, or after a close is performed.
+--
+-- Since 0.0.0
 data PreparedConduit input m output = PreparedConduit
     { conduitPush :: input -> ResourceT m (ConduitResult input output)
     , conduitClose :: ResourceT m [output]
@@ -39,6 +43,8 @@
 
 -- | A monadic action generating a 'PreparedConduit'. See @Source@ and @Sink@
 -- for more motivation.
+--
+-- Since 0.0.0
 newtype Conduit input m output =
     Conduit { prepareConduit :: ResourceT m (PreparedConduit input m output) }
 
diff --git a/Data/Conduit/Types/Sink.hs b/Data/Conduit/Types/Sink.hs
--- a/Data/Conduit/Types/Sink.hs
+++ b/Data/Conduit/Types/Sink.hs
@@ -21,6 +21,8 @@
 -- pushed to it, a @Sink@ may indicate that it is still processing data, or
 -- that it is done, in which case it returns some optional leftover input and
 -- an output value.
+--
+-- Since 0.0.0
 data SinkResult input output = Processing | Done (Maybe input) output
 instance Functor (SinkResult input) where
     fmap _ Processing = Processing
@@ -52,6 +54,8 @@
 -- it must do so whenever it returns a result, either via @sinkPush@ or
 -- @sinkClose@. Note that, due to usage of @ResourceT@, this is merely an
 -- optimization.
+--
+-- Since 0.0.0
 data PreparedSink input m output =
     SinkNoData output
   | SinkData
@@ -73,6 +77,8 @@
 --
 -- Note that this type provides a 'Monad' instance, allowing you to easily
 -- compose @Sink@s together.
+--
+-- Since 0.0.0
 newtype Sink input m output = Sink { prepareSink :: ResourceT m (PreparedSink input m output) }
 
 instance Monad m => Functor (Sink input m) where
diff --git a/Data/Conduit/Types/Source.hs b/Data/Conduit/Types/Source.hs
--- a/Data/Conduit/Types/Source.hs
+++ b/Data/Conduit/Types/Source.hs
@@ -19,6 +19,8 @@
 
 -- | Result of pulling from a source. Either a new piece of data (@Open@), or
 -- indicates that the source is now @Closed@.
+--
+-- Since 0.0.0
 data SourceResult a = Open a | Closed
     deriving (Show, Eq, Ord)
 
@@ -42,6 +44,8 @@
 -- * A 'PreparedSource' is responsible to free any resources when either 'sourceClose'
 -- is called or a 'Closed' is returned. However, based on the usage of
 -- 'ResourceT', this is simply an optimization.
+--
+-- Since 0.0.0
 data PreparedSource m a = PreparedSource
     { sourcePull :: ResourceT m (SourceResult a)
     , sourceClose :: ResourceT m ()
@@ -66,6 +70,8 @@
 -- Note that each time you \"call\" a @Source@, it is started from scratch. If
 -- you want a resumable source (e.g., one which can be passed to multiple
 -- @Sink@s), you likely want to use a 'BufferedSource'.
+--
+-- Since 0.0.0
 newtype Source m a = Source { prepareSource :: ResourceT m (PreparedSource m a) }
 
 instance Monad m => Functor (Source m) where
@@ -133,17 +139,23 @@
 -- while the types will allow you to use the buffered source in multiple
 -- threads, there is no guarantee that all @BufferedSource@s will handle this
 -- correctly.
+--
+-- Since 0.0.0
 data BufferedSource m a = BufferedSource
     { bsourcePull :: ResourceT m (SourceResult a)
     , bsourceUnpull :: a -> ResourceT m ()
     , bsourceClose :: ResourceT m ()
     }
 
+-- |
+-- Since 0.0.0
 data SourceInvariantException = PullAfterEOF String
     deriving (Show, Typeable)
 instance Exception SourceInvariantException
 
 -- | This typeclass allows us to unify operators on 'Source' and 'BufferedSource'.
+--
+-- Since 0.0.0
 class BufferSource s where
     bufferSource :: Resource m => s m a -> ResourceT m (BufferedSource m a)
 
@@ -211,6 +223,10 @@
 -- mean your original 'BufferedSource' will be closed. Additionally, all
 -- leftover data from usage of the returned @Source@ will be discarded. In
 -- other words: this is a no-going-back move.
+--
+-- Note: @bufferSource@ . @unbufferSource@ is /not/ the identity function.
+--
+-- Since 0.0.1
 unbufferSource :: Monad m
                => BufferedSource m a
                -> Source m a
diff --git a/Data/Conduit/Util/Conduit.hs b/Data/Conduit/Util/Conduit.hs
--- a/Data/Conduit/Util/Conduit.hs
+++ b/Data/Conduit/Util/Conduit.hs
@@ -22,6 +22,8 @@
 
 -- | Construct a 'Conduit' with some stateful functions. This function address
 -- all mutable state for you.
+--
+-- Since 0.0.0
 conduitState
     :: Resource m
     => state -- ^ initial state
@@ -56,6 +58,8 @@
         }
 
 -- | Construct a 'Conduit'.
+--
+-- Since 0.0.0
 conduitIO :: ResourceIO m
            => IO state -- ^ resource and/or state allocation
            -> (state -> IO ()) -- ^ resource and/or state cleanup
@@ -92,6 +96,8 @@
         }
 
 -- | Transform the monad a 'Conduit' lives in.
+--
+-- Since 0.0.0
 transConduit :: (Monad m, Base m ~ Base n)
               => (forall a. m a -> n a)
               -> Conduit input m output
@@ -105,6 +111,8 @@
         }
 
 -- | Return value from a 'SequencedSink'.
+--
+-- Since 0.0.0
 data SequencedSinkResponse state input m output =
     Emit state [output] -- ^ Set a new state, and emit some new output.
   | Stop -- ^ End the conduit.
@@ -113,6 +121,8 @@
 -- | Helper type for constructing a @Conduit@ based on @Sink@s. This allows you
 -- to write higher-level code that takes advantage of existing conduits and
 -- sinks, and leverages a sink's monadic interface.
+--
+-- Since 0.0.0
 type SequencedSink state input m output =
     state -> Sink input m (SequencedSinkResponse state input m output)
 
@@ -123,6 +133,8 @@
            (ResourceT m (SequencedSinkResponse state input m output))
 
 -- | Convert a 'SequencedSink' into a 'Conduit'.
+--
+-- Since 0.0.0
 sequenceSink
     :: Resource m
     => state -- ^ initial state
diff --git a/Data/Conduit/Util/Sink.hs b/Data/Conduit/Util/Sink.hs
--- a/Data/Conduit/Util/Sink.hs
+++ b/Data/Conduit/Util/Sink.hs
@@ -17,6 +17,8 @@
 
 -- | Construct a 'Sink' with some stateful functions. This function address
 -- all mutable state for you.
+--
+-- Since 0.0.0
 sinkState
     :: Resource m
     => state -- ^ initial state
@@ -52,6 +54,8 @@
 
 -- | Construct a 'Sink'. Note that your push and close functions need not
 -- explicitly perform any cleanup.
+--
+-- Since 0.0.0
 sinkIO :: ResourceIO m
         => IO state -- ^ resource and/or state allocation
         -> (state -> IO ()) -- ^ resource and/or state cleanup
@@ -88,6 +92,8 @@
         }
 
 -- | Transform the monad a 'Sink' lives in.
+--
+-- Since 0.0.0
 transSink :: (Base m ~ Base n, Monad m)
            => (forall a. m a -> n a)
            -> Sink input m output
diff --git a/Data/Conduit/Util/Source.hs b/Data/Conduit/Util/Source.hs
--- a/Data/Conduit/Util/Source.hs
+++ b/Data/Conduit/Util/Source.hs
@@ -18,6 +18,8 @@
 
 -- | Construct a 'Source' with some stateful functions. This function address
 -- all mutable state for you.
+--
+-- Since 0.0.0
 sourceState
     :: Resource m
     => state -- ^ Initial state
@@ -54,6 +56,8 @@
         }
 
 -- | Construct a 'Source' based on some IO actions for alloc/release.
+--
+-- Since 0.0.0
 sourceIO :: ResourceIO m
           => IO state -- ^ resource and/or state allocation
           -> (state -> IO ()) -- ^ resource and/or state cleanup
@@ -87,6 +91,8 @@
         }
 
 -- | Transform the monad a 'Source' lives in.
+--
+-- Since 0.0.0
 transSource :: (Base m ~ Base n, Monad m)
              => (forall a. m a -> n a)
              -> Source m output
diff --git a/conduit.cabal b/conduit.cabal
--- a/conduit.cabal
+++ b/conduit.cabal
@@ -1,5 +1,5 @@
 Name:                conduit
-Version:             0.0.1.1
+Version:             0.0.2
 Synopsis:            A pull-based approach to streaming data.
 Description:         Conduits are an approach to the streaming data problem. It is meant as an alternative to enumerators\/iterators, hoping to address the same issues with different trade-offs based on real-world experience with enumerators. For more information, see <http://www.yesodweb.com/blog/2011/12/conduits>.
 License:             BSD3
@@ -10,7 +10,7 @@
 Build-type:          Simple
 Cabal-version:       >=1.8
 Homepage:            http://github.com/snoyberg/conduit
-extra-source-files:  test/main.hs
+extra-source-files:  test/main.hs, test/random
 
 flag debug
 
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -11,6 +11,7 @@
 import qualified Data.Conduit.Binary as CB
 import qualified Data.Conduit.Text as CT
 import Data.Conduit (runResourceT)
+import qualified Data.List as DL
 import Control.Monad.ST (runST)
 import Data.Monoid
 import qualified Data.ByteString as S
@@ -159,6 +160,20 @@
                     C.=$ CL.fold (+) 0
             x @?= 2 * sum [1..10 :: Int]
 
+        it "groupBy" $ do
+            let input = [1::Int, 1, 2, 3, 3, 3, 4, 5, 5]
+            x <- runResourceT $ CL.sourceList input
+                    C.$$ CL.groupBy (==)
+                    C.=$ CL.consume
+            x @?= DL.groupBy (==) input
+
+        it "groupBy (nondup begin/end)" $ do
+            let input = [1::Int, 2, 3, 3, 3, 4, 5]
+            x <- runResourceT $ CL.sourceList input
+                    C.$$ CL.groupBy (==)
+                    C.=$ CL.consume
+            x @?= DL.groupBy (==) input
+
         it "concatMap" $ do
             let input = [1, 11, 21]
             x <- runResourceT $ CL.sourceList input
@@ -304,6 +319,41 @@
                 let src = C.unbufferSource bsrc
                 src C.$$ CL.fold (+) 0
             x @?= sum [6..10]
+
+    describe "properly using binary file reading" $ do
+        it "sourceFile" $ do
+            x <- runResourceT $ CB.sourceFile "test/random" C.$$ CL.consume
+            lbs <- L.readFile "test/random"
+            L.fromChunks x @?= lbs
+
+    describe "binary head" $ do
+        let go lbs = do
+                x <- CB.head
+                case (x, L.uncons lbs) of
+                    (Nothing, Nothing) -> return True
+                    (Just y, Just (z, lbs'))
+                        | y == z -> go lbs'
+                    _ -> return False
+
+        prop "works" $ \bss' ->
+            let bss = map S.pack bss'
+             in runST $ runResourceT $
+                CL.sourceList bss C.$$ go (L.fromChunks bss)
+    describe "binary takeWhile" $ do
+        prop "works" $ \bss' ->
+            let bss = map S.pack bss'
+             in runST $ runResourceT $ do
+                bss2 <- CL.sourceList bss C.$$ CB.takeWhile (>= 5) C.=$ CL.consume
+                return $ L.fromChunks bss2 == L.takeWhile (>= 5) (L.fromChunks bss)
+
+    describe "binary dropWhile" $ do
+        prop "works" $ \bss' ->
+            let bss = map S.pack bss'
+             in runST $ runResourceT $ do
+                bss2 <- CL.sourceList bss C.$$ do
+                    CB.dropWhile (< 5)
+                    CL.consume
+                return $ L.fromChunks bss2 == L.dropWhile (< 5) (L.fromChunks bss)
 
 it' :: String -> IO () -> Writer [Spec] ()
 it' = it
diff --git a/test/random b/test/random
new file mode 100644
Binary files /dev/null and b/test/random differ
