diff --git a/Pipes/Text.hs b/Pipes/Text.hs
--- a/Pipes/Text.hs
+++ b/Pipes/Text.hs
@@ -128,8 +128,16 @@
     words,
     writeFile )
 
+-- $setup
+-- >>> :set -XOverloadedStrings
+-- >>> import Data.Text (Text)
+-- >>> import qualified Data.Text as T
+-- >>> import qualified Data.Text.Lazy.IO as TL
+-- >>> import Data.Char
 
--- | Convert a lazy 'TL.Text' into a 'Producer' of strict 'Text's
+-- | Convert a lazy 'TL.Text' into a 'Producer' of strict 'Text's. Producers in 
+-- IO can be found in 'Pipes.Text.IO' or in pipes-bytestring, employed with the
+-- decoding lenses in 'Pipes.Text.Encoding'
 fromLazy :: (Monad m) => TL.Text -> Producer' Text m ()
 fromLazy  = TL.foldrChunks (\e a -> yield e >> a) (return ())
 {-# INLINE fromLazy #-}
@@ -138,11 +146,17 @@
 a ^. lens = getConstant (lens Constant a)
 
 -- | Apply a transformation to each 'Char' in the stream
+
+-- >>> let margaret =  ["Margaret, are you grieving\nOver Golde","ngrove unleaving?":: Text]
+-- >>> TL.putStrLn . toLazy $ each margaret >-> map Data.Char.toUpper
+-- MARGARET, ARE YOU GRIEVING
+-- OVER GOLDENGROVE UNLEAVING?
 map :: (Monad m) => (Char -> Char) -> Pipe Text Text m r
 map f = P.map (T.map f)
 {-# INLINABLE map #-}
 
 -- | Map a function over the characters of a text stream and concatenate the results
+
 concatMap
     :: (Monad m) => (Char -> Text) -> Pipe Text Text m r
 concatMap f = P.map (T.concatMap f)
@@ -154,7 +168,7 @@
 take n0 = go n0 where
     go n
         | n <= 0    = return ()
-        | otherwise = do
+        | otherwise = do 
             txt <- await
             let len = fromIntegral (T.length txt)
             if (len > n)
@@ -184,6 +198,11 @@
 {-# INLINABLE filter #-}
 
 -- | Strict left scan over the characters
+-- >>> let margaret = ["Margaret, are you grieving\nOver Golde","ngrove unleaving?":: Text]
+-- >>> let title_caser a x = case a of ' ' -> Data.Char.toUpper x; _ -> x
+-- >>> toLazy $ each margaret >-> scan title_caser ' ' 
+-- " Margaret, Are You Grieving\nOver Goldengrove Unleaving?"
+
 scan
     :: (Monad m)
     => (Char -> Char -> Char) -> Char -> Pipe Text Text m r
@@ -771,4 +790,4 @@
 -}
 
 
-type Lens' a b = forall f . Functor f => (b -> f b) -> (a -> f a)
+type Lens' a b =  forall f . Functor f => (b -> f b) -> (a -> f a)
diff --git a/Pipes/Text/Encoding.hs b/Pipes/Text/Encoding.hs
--- a/Pipes/Text/Encoding.hs
+++ b/Pipes/Text/Encoding.hs
@@ -1,19 +1,25 @@
 {-# LANGUAGE RankNTypes, BangPatterns #-}
 
--- | This module uses the stream decoding functions from Michael Snoyman's new
---  <http://hackage.haskell.org/package/text-stream-decode text-stream-decode> 
+-- | This module uses the stream decoding functions from
+--  <http://hackage.haskell.org/package/streaming-commons streaming-commons> 
 --  package to define decoding functions and lenses.  The exported names
---  conflict with names in @Data.Text.Encoding@ but the module can otherwise be 
---  imported unqualified. 
+--  conflict with names in @Data.Text.Encoding@ but not with the @Prelude@ 
 
 module Pipes.Text.Encoding
     ( 
-    -- * The Lens or Codec type
+    -- * Decoding ByteStrings and Encoding Texts
+    -- ** Simple usage
+    -- $usage
+    
+    -- ** Lens usage
     -- $lenses
+  
+    
+    -- * Basic lens operations
     Codec
     , decode
-    -- * \'Viewing\' the Text in a byte stream
-    -- $codecs
+    , eof
+    -- * Decoding lenses
     , utf8
     , utf8Pure
     , utf16LE
@@ -54,71 +60,87 @@
 import qualified Data.Text.Encoding as TE 
 import qualified Data.Streaming.Text as Stream
 import Data.Streaming.Text (DecodeResult(..))
-import Control.Monad (join)
+import Control.Monad (join, liftM)
 import Data.Word (Word8)
 import Pipes
 
-type Lens' a b = forall f . Functor f => (b -> f b) -> (a -> f a)
 
-{- $lenses
-    The 'Codec' type is a simple specializion of 
-    the @Lens'@ type synonymn used by the standard lens libraries, 
-    <http://hackage.haskell.org/package/lens lens> and 
-    <http://hackage.haskell.org/package/lens-family lens-family>. That type, 
-    
->   type Lens' a b = forall f . Functor f => (b -> f b) -> (a -> f a)
 
-    is just an alias for a Prelude type. Thus you use any particular codec with
-    the @view@ / @(^.)@ , @zoom@ and @over@ functions from either of those libraries;
-    we presuppose neither since we already have access to the types they require.
+{- $usage
+    Given 
 
-    -}
+>   text :: Producer Text IO ()
 
-type Codec
-    =  forall m r
-    .  Monad m
-    => Lens' (Producer ByteString m r)
-             (Producer Text m (Producer ByteString m r))
+    we can encode it with @Data.Text.Encoding@ and ordinary pipe operations:
 
-{- | 'decode' is just the ordinary @view@ or @(^.)@ of the lens libraries;
-      exported here under a name appropriate to the material. All of these are
-      the same: 
+>   text >-> P.map TE.encodeUtf8 :: Producer.ByteString IO ()
 
->    decode utf8 p = decodeUtf8 p = view utf8 p = p ^. utf8
+    or, using this module, with
 
--}
+>   for text encodeUtf8 :: Producer.ByteString IO ()
 
-decode :: ((b -> Constant b b) -> (a -> Constant b a)) -> a -> b
-decode codec a = getConstant (codec Constant a)
+    Given 
 
+>   bytes :: Producer ByteString Text IO ()
 
-{- $codecs
+    we can apply a decoding function from this module:
+
+>   decodeUtf8 bytes :: Producer Text IO (Producer ByteString IO ())
+
+    The Text producer ends wherever decoding first fails. Thus we can re-encode
+    as uft8 as much of our byte stream as is decodeUtf16BE decodable, with, e.g.
+
+>   for (decodeUtf16BE bytes) encodeUtf8 :: Producer ByteString IO (Producer ByteString IO ())
     
-    Each Codec-lens looks into a byte stream that is supposed to contain text.
-    The particular \'Codec\' lenses are named in accordance with the expected 
-    encoding, 'utf8', 'utf16LE' etc. To turn a Codec into an ordinary function, 
-    use @view@ / @(^.)@ -- here also called 'decode':
+    The bytestring producer that is returned begins with where utf16BE decoding
+    failed; it it didn't fail the producer is empty. 
 
+-}
+
+{- $lenses
+    We get a bit more flexibility, though, if we use a lens like @utf8@ or @utf16BE@ 
+    that looks for text in an appropriately encoded byte stream.
+
+>   type Lens' a b = forall f . Functor f => (b -> f b) -> (a -> f a)
+
+    is just an alias for a Prelude type.   We abbreviate this further, for our use case, as
+
+>   type Codec
+>     =  forall m r .  Monad m => Lens' (Producer ByteString m r) (Producer Text m (Producer ByteString m r))
+
+    and call the decoding lenses @utf8@, @utf16BE@ \"codecs\", since they can 
+    re-encode what they have decoded.  Thus you use any particular codec with
+    the @view@ / @(^.)@ , @zoom@ and @over@ functions from the standard lens libraries;
+    we presuppose neither <http://hackage.haskell.org/package/lens lens> 
+    nor  <http://hackage.haskell.org/package/lens-family lens-family> 
+    since we already have access to the types they require.             
+
+    Each decoding lens looks into a byte stream that is supposed to contain text.
+    The particular lenses are named in accordance with the expected 
+    encoding, 'utf8', 'utf16LE' etc. To turn a such a lens or @Codec@ 
+    into an ordinary function, use @view@ / @(^.)@ -- here also called 'decode':
+
 >   view utf8 :: Producer ByteString m r -> Producer Text m (Producer ByteString m r)
 >   decode utf8 Byte.stdin :: Producer Text IO (Producer ByteString IO r)
 >   Bytes.stdin ^. utf8 ::  Producer Text IO (Producer ByteString IO r)
 
-    Uses of a codec with @view@ or @(^.)@ or 'decode' can always be replaced by the specialized 
-    decoding functions exported here, e.g. 
+    These simple uses of a codec with @view@ or @(^.)@ or 'decode' can always be replaced by 
+    the specialized decoding functions exported here, e.g. 
 
 >   decodeUtf8 ::  Producer ByteString m r -> Producer Text m (Producer ByteString m r)
 >   decodeUtf8 Byte.stdin :: Producer Text IO (Producer ByteString IO r)
 
-    The stream of text that a @Codec@ \'sees\' in the stream of bytes begins at its head. 
+    As with these functions, the stream of text that a @Codec@ \'sees\' 
+    in the stream of bytes begins at its head. 
     At any point of decoding failure, the stream of text ends and reverts to (returns) 
     the original byte stream. Thus if the first bytes are already
     un-decodable, the whole ByteString producer will be returned, i.e.
 
->   view utf8 bytestream 
+>   view utf8 bad_bytestream 
 
     will just come to the same as 
 
->   return bytestream
+>   return bad_bytestream
 
     Where there is no decoding failure, the return value of the text stream will be
     an empty byte stream followed by its own return value.  In all cases you must
@@ -126,7 +148,21 @@
     it can be thrown away with @Control.Monad.void@
 
 >   void (Bytes.stdin ^. utf8) :: Producer Text IO ()
+
+    The @eof@ lens permits you to pattern match: if there is a Right value,
+    it is the leftover bytestring producer, if there is a Right value, it 
+    is the return value of the original bytestring producer:
+
+>   Bytes.stdin ^. utf8 . eof :: Producer Text IO (Either (Producer ByteString IO IO) ())
     
+    Thus for the stream of un-decodable bytes mentioned above,
+
+>   view (utf8 . eof) bad_bytestream
+
+    will be the same as 
+
+>   return (Left bad_bytestream)
+
     @zoom@ converts a Text parser into a ByteString parser:
 
 >   zoom utf8 drawChar :: Monad m => StateT (Producer ByteString m r) m (Maybe Char)
@@ -135,24 +171,81 @@
     
 >   zoom utf8 drawChar :: Monad m => Parser ByteString m (Maybe Char)
 
-    Thus we can define a ByteString parser like this:
+    Thus we can define a ByteString parser (in the pipes-parse sense) like this:
     
->   withNextByte :: Parser ByteString m (Maybe Char, Maybe Word8))) 
->   withNextByte = do char_ <- zoom utf8 Text.drawChar
+>   charPlusByte :: Parser ByteString m (Maybe Char, Maybe Word8))) 
+>   charPlusByte = do char_ <- zoom utf8 Text.drawChar
 >                     byte_ <- Bytes.peekByte
 >                     return (char_, byte_)
 
-     Though @withNextByte@ is partly defined with a Text parser 'drawChar'; 
+     Though @charPlusByte@ is partly defined with a Text parser 'drawChar'; 
      but it is a ByteString parser; it will return the first valid utf8-encoded 
-     Char in a ByteString, whatever its length, 
-     and the first byte of the next character, if they exist. Because 
+     Char in a ByteString, whatever its byte-length, 
+     and the first byte following, if both exist. Because 
      we \'draw\' one and \'peek\' at the other, the parser as a whole only 
      advances one Char's length along the bytestring, whatever that length may be.
      See the slightly more complex example \'decode.hs\' in the 
-     <http://www.haskellforall.com/2014/02/pipes-parse-30-lens-based-parsing.html#batteries-included haskellforall> 
-     discussion of this type of byte stream parsing.
+     <http://www.haskellforall.com/2014/02/pipes-parse-30-lens-based-parsing.html#batteries-included haskellforall blog> 
+     discussion of this type of byte stream parsing. 
     -}
 
+type Lens' a b = forall f . Functor f => (b -> f b) -> (a -> f a)
+
+type Codec
+    =  forall m r
+    .  Monad m
+    => Lens' (Producer ByteString m r)
+             (Producer Text m (Producer ByteString m r))
+
+
+{- | @decode@ is just the ordinary @view@ or @(^.)@ of the lens libraries;
+   exported here under a name appropriate to the material. Thus
+
+>    decode utf8 bytes :: Producer Text IO (Producer ByteString IO ())
+
+    All of these are thus the same:
+
+>    decode utf8 bytes = view utf8 bytes = bytes ^. utf8 = decodeUtf8 bytes
+
+
+-}
+
+decode :: ((b -> Constant b b) -> (a -> Constant b a)) -> a -> b
+decode codec a = getConstant (codec Constant a)
+
+{- | @eof@ tells you explicitly when decoding stops due to bad bytes or 
+    instead reaches end-of-file happily. (Without it one just makes an explicit 
+    test for emptiness of the resulting bytestring production using next) Thus
+
+>    decode (utf8 . eof) bytes :: Producer T.Text IO (Either (Producer B.ByteString IO ()) ())
+
+    If we hit undecodable bytes, the remaining bytestring producer will be 
+    returned as a Left value; in the happy case, a Right value is returned 
+    with the anticipated return value for the original bytestring producer.
+
+    Again, all of these are the same
+
+>    decode (utf8 . eof) bytes = view (utf8 . eof) p = p^.utf8.eof
+
+-}
+
+eof :: Monad m => Lens' (Producer Text m (Producer ByteString m r))
+                       (Producer Text m (Either (Producer ByteString m r) r))
+eof k p = fmap fromEither (k (toEither p)) where
+
+ fromEither = liftM (either id return)
+
+ toEither pp = do p <- pp
+                  check p
+
+ check p = do e <- lift (next p)
+              case e of 
+                Left r -> return (Right r)
+                Right (bs,pb) ->  if B.null bs 
+                                    then check pb
+                                    else return (Left (do yield bs
+                                                          pb))
+
 utf8 :: Codec
 utf8 = mkCodec decodeUtf8 TE.encodeUtf8
 
@@ -185,6 +278,7 @@
                                                       return (do yield bs 
                                                                  p')
 {-# INLINABLE decodeStream#-}
+
 
 {- $decoders
    These are functions with the simple type:
diff --git a/Pipes/Text/IO.hs b/Pipes/Text/IO.hs
--- a/Pipes/Text/IO.hs
+++ b/Pipes/Text/IO.hs
@@ -169,9 +169,6 @@
 toHandle h = for cat (liftIO . T.hPutStr h)
 {-# INLINABLE toHandle #-}
 
-{-# RULES "p >-> toHandle h" forall p h .
-        p >-> toHandle h = for p (\txt -> liftIO (T.hPutStr h txt))
-  #-}
 
 
 -- | Stream text into a file. Uses @pipes-safe@.
diff --git a/Pipes/Text/Tutorial.hs b/Pipes/Text/Tutorial.hs
--- a/Pipes/Text/Tutorial.hs
+++ b/Pipes/Text/Tutorial.hs
@@ -3,12 +3,19 @@
 module Pipes.Text.Tutorial (
     -- * Effectful Text
     -- $intro
+    
     -- ** @Pipes.Text@
     -- $pipestext
+    
     -- ** @Pipes.Text.IO@
     -- $pipestextio
+    
     -- ** @Pipes.Text.Encoding@
     -- $pipestextencoding
+    
+    -- ** Implicit chunking
+    -- $chunks
+    
     -- * Lenses
     -- $lenses
 
@@ -20,23 +27,28 @@
 
     -- ** @zoom@
     -- $zoom
+    
 
+
+
     -- * Special types: @Producer Text m (Producer Text m r)@ and @FreeT (Producer Text m) m r@
     -- $special
     ) where
-      
+
 import Pipes
 import Pipes.Text
 import Pipes.Text.IO
 import Pipes.Text.Encoding
-      
+
 {- $intro
     This package provides @pipes@ utilities for /character streams/,
     realized as streams of 'Text' chunks. The individual chunks are uniformly /strict/,
     and thus the @Text@ type we are using is the one from @Data.Text@, not @Data.Text.Lazy@ 
     But the type @Producer Text m r@, as we are using it, is a sort of /pipes/ equivalent of 
     the lazy @Text@ type.
+-}
 
+{- $pipestext
     The main @Pipes.Text@ module provides many functions equivalent 
     in one way or another to the pure functions in
     <https://hackage.haskell.org/package/text-1.1.0.0/docs/Data-Text-Lazy.html Data.Text.Lazy> 
@@ -44,17 +56,28 @@
     divide, group and fold text streams. Though @Producer Text m r@
     is the type of \'effectful Text\', the functions in @Pipes.Text@ are \'pure\'
     in the sense that they are uniformly monad-independent.
+-}
+
+{- $pipestextencoding 
+    In the @text@ library, @Data.Text.Lazy.Encoding@ 
+    handles inter-operation with @Data.ByteString.Lazy@. Here, @Pipes.Text.Encoding@ 
+    provides for interoperation with the \'effectful ByteStrings\' of @Pipes.ByteString@.
+-}
+
+{- $pipestextio
     Simple /IO/ operations are defined in @Pipes.Text.IO@ - as lazy IO @Text@
-    operations are in @Data.Text.Lazy.IO@. Similarly, as @Data.Text.Lazy.Encoding@ 
-    handles inter-operation with @Data.ByteString.Lazy@, @Pipes.Text.Encoding@ provides for
-    interoperation with the \'effectful ByteStrings\' of @Pipes.ByteString@.
+    operations are in @Data.Text.Lazy.IO@. It is generally 
+-} 
 
+
+{- $chunks
     Remember that the @Text@ type exported by @Data.Text.Lazy@ is basically 
     that of a lazy list of strict @Text@: the implementation is arranged so that 
     the individual strict 'Text' chunks are kept to a reasonable size; the user 
     is not aware of the divisions between the connected 'Text' chunks, but uses
     operations akin to those for strict text.
-    So also here: the functions in this module are designed to operate on character streams that
+    
+    So also here: the operations in @Pipes.Text@ are designed to operate on character streams that
     in a way that is independent of the boundaries of the underlying @Text@ chunks. 
     This means that they may freely split text into smaller texts and /discard empty texts/.  
     The objective, though, is that they should not /concatenate texts/ in order to provide strict upper
@@ -67,16 +90,20 @@
 > import qualified Pipes.Text as Text
 > import qualified Pipes.Text.IO as Text
 > import Pipes.Group (takes')
-> import Lens.Family (view)
+> import Lens.Family (view, (%~)) -- or, Control.Lens
 >
 > main = runEffect $ takeLines 3 Text.stdin >-> Text.stdout
->   where
+>   where 
 >     takeLines n = view Text.unlines . takes' n . view Text.lines
+> -- or equivalently: Text.unlines %~ takes' n
 
-     This program will never bring more into memory than what @Text.stdin@ considers
-     one chunk of text (~ 32 KB), even if individual lines are split across many chunks.
+     This program will not bring more into memory than what @Text.stdin@ considers
+     one chunk of text (~ 32 KB), even if individual lines are split 
+     across many chunks.  The division into lines does not join Text fragments.
 
 -}
+
+
 {- $lenses
     As the use of @view@ in this example shows, one superficial difference from @Data.Text.Lazy@
     is that many of the operations, like 'lines', are \'lensified\'; this has a
@@ -90,7 +117,7 @@
 
     > splitAt 17 producer
 
-    as we would with the Prelude or Text functions, we write
+    as we would with the Prelude or Text functions called @splitAt@, we write
 
     > view (splitAt 17) producer
 
@@ -110,7 +137,7 @@
     they don't admit all the operations of an ideal lens, but only /getting/ and /focusing/.
     Just for this reason, though, the magnificent complexities of the lens libraries
     are a distraction. The lens combinators to keep in mind, the ones that make sense for
-    our lenses, are @view@ \/ @(^.)@), @over@ \/ @(%~)@ , and @zoom@.
+    our lenses, are @view@, @over@, and @zoom@.
 
     One need only keep in mind that if @l@ is a @Lens' a b@, then:
 
@@ -120,7 +147,6 @@
     is the corresponding @b@; as was said above, this function will typically be 
     the pipes equivalent of the function you think it is, given its name. So for example 
     
-    > view (Text.drop)
     > view (Text.splitAt 300) :: Producer Text m r -> Producer Text (Producer Text m r)
     > Text.stdin ^. splitAt 300 :: Producer Text IO (Producer Text IO r) 
     
@@ -128,23 +154,29 @@
     Thus to uppercase the first n characters
     of a Producer, leaving the rest the same, we could write:
 
-
     > upper n p = do p' <- p ^. Text.splitAt n >-> Text.toUpper
     >                p'
+    
+    or equivalently:
+    
+    > upper n p = join (p ^. Text.splitAt n >-> Text.toUpper)
+    
 -}
 {- $over
-    @over l@ is a function @(b -> b) -> a -> a@.  Thus, given a function that modifies
+    If @l@ is a @Lens a b@, @over l@ is a function @(b -> b) -> a -> a@.  
+    Thus, given a function that modifies
     @b@s, the lens lets us modify an @a@ by applying @f :: b -> b@ to
-    the @b@ that we can \"see\" through the lens. So  @over l f :: a -> a@
+    the @b@ that we \"see\" in the @a@ through the lens. 
+    So the type of @over l f@ is @a -> a@ for the concrete type @a@
     (it can also be written @l %~ f@).
     For any particular @a@, then, @over l f a@ or @(l %~ f) a@ is a revised @a@.
     So above we might have written things like these:
 
-    > stripLines = Text.lines %~ maps (>-> Text.stripStart)
     > stripLines = over Text.lines (maps (>-> Text.stripStart))
+    > stripLines = Text.lines %~ maps (>-> Text.stripStart)
     > upper n    =  Text.splitAt n %~ (>-> Text.toUpper)
-
 -}
+
 {- $zoom
     @zoom l@, finally, is a function from a @Parser b m r@
     to a @Parser a m r@ (or more generally a @StateT (Producer b m x) m r@).
@@ -169,9 +201,9 @@
 >                                    p'
 
 
-> >>> let doc = each ["toU","pperTh","is document.\n"]
-> >>> runEffect $ obey doc >-> Text.stdout
-> THIS DOCUMENT.
+> -- > let doc = each ["toU","pperTh","is document.\n"]
+> -- > runEffect $ obey doc >-> Text.stdout
+> -- THIS DOCUMENT.
 
     The purpose of exporting lenses is the mental economy achieved with this three-way
     applicability. That one expression, e.g. @lines@ or @splitAt 17@ can have these
@@ -187,8 +219,9 @@
     and to some extent in the @Pipes.Text.Encoding@ module here.
 
 -}
+
 {- $special
-    These simple 'lines' examples reveal a more important difference from @Data.Text.Lazy@ .
+    The simple programs using the 'lines' lens reveal a more important difference from @Data.Text.Lazy@ .
     This is in the types that are most closely associated with our central text type,
     @Producer Text m r@.  In @Data.Text@ and @Data.Text.Lazy@ we find functions like
 
diff --git a/pipes-text.cabal b/pipes-text.cabal
--- a/pipes-text.cabal
+++ b/pipes-text.cabal
@@ -1,5 +1,5 @@
 name:                pipes-text
-version:             0.0.0.15
+version:             0.0.0.16
 synopsis:            Text pipes.
 description:         * This package will be in a draft, or testing, phase until version 0.0.1. Please report any installation difficulties, or any wisdom about the api, on the github page or the <https://groups.google.com/forum/#!forum/haskell-pipes pipes list>
                      .
@@ -9,7 +9,7 @@
                      .
                      Familiarity with the other three packages should give one an idea what to expect where. The package has three modules, @Pipes.Text@ , @Pipes.Text.Encoding@ and @Pipes.Text.IO@; the division has more or less the significance it has in the @text@ library. 
                      .
-                     Note that the module @Pipes.Text.IO@ is present as a convenience (as is @Data.Text.IO@).  Official pipes IO would use @Pipes.ByteString@ together with the bytestring decoding functions present here, based on Michael Snoyman's excellent @streaming-commons@ package.  In particular, the @Pipes.Text.IO@ functions use Text exceptions. 
+                     Note that the module @Pipes.Text.IO@ is present as a convenience (as is @Data.Text.IO@).  Official pipes IO would use @Pipes.ByteString@ together with the bytestring decoding functions in @Pipes.Text.Encoding@.  In particular, the @Pipes.Text.IO@ functions use Text exceptions. 
                      .
                      @Pipes.Text.IO@ uses version 0.11.3 or later of the @text@ library. It thus works with the version of @text@ that came with the 2013 Haskell Platform. To use an older @text@, install with the flag @-fnoio@
 
