diff --git a/process-listlike.cabal b/process-listlike.cabal
--- a/process-listlike.cabal
+++ b/process-listlike.cabal
@@ -1,16 +1,16 @@
 Name:               process-listlike
-Version:            0.10
+Version:            1.0
 Synopsis:           Process extras
 Description:        Extra functionality for the Process library
                     <http://hackage.haskell.org/package/process>.
 Homepage:           https://github.com/ddssff/process-listlike
 License:            MIT
 License-file:       LICENSE
-Author:             David Lazar, Bas van Dijk
-Maintainer:         David Lazar <lazar6@illinois.edu>
+Author:             David Lazar, Bas van Dijk, David Fox
+Maintainer:         David Fox <dsf@seereason.com>
 Category:           System
 Build-type:         Simple
-Cabal-version:      >= 1.8
+Cabal-version:      >=1.6
 Extra-source-files:
   README.md
 
@@ -26,15 +26,8 @@
   Exposed-modules:
     System.Process.ByteString
     System.Process.ByteString.Lazy
-    System.Process.Chunks
+    System.Process.Extras
     System.Process.ListLike
-    System.Process.ListLike.Classes
-    System.Process.ListLike.Instances
-    System.Process.ListLike.LazyString
-    System.Process.ListLike.Read
-    System.Process.ListLike.ReadNoThreads
-    System.Process.ListLike.StrictString
-    System.Process.String
     System.Process.Text
     System.Process.Text.Lazy
 
@@ -43,18 +36,8 @@
 
   Build-depends:
     base >= 4 && < 5,
+    ListLike >= 4,
     process,
     bytestring,
-    ListLike >= 4,
-    mtl,
     text,
     deepseq
-
-Executable process-listlike-tests
-  Main-Is: tests/Main.hs
-  Build-depends: base >= 4, bytestring, deepseq, process, process-listlike, utf8-string, unix, text, HUnit, ListLike, regex-posix
-
-Executable process-listlike-interactive-tests
-  Main-Is: tests/Interactive.hs
-  GHC-Options: -Wall -O2 -threaded -rtsopts
-  Build-Depends: base >= 4, bytestring, deepseq, HUnit, ListLike, mtl, process, process-listlike, text, utf8-string, unix
diff --git a/src/System/Process/ByteString.hs b/src/System/Process/ByteString.hs
--- a/src/System/Process/ByteString.hs
+++ b/src/System/Process/ByteString.hs
@@ -1,28 +1,27 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 module System.Process.ByteString where
 
+import Control.Exception
+import Control.Monad
 import Data.ByteString (ByteString)
+import Data.ListLike (null)
+import Data.ListLike.IO (hGetContents, hPutStr)
+import Data.Word (Word8)
+import Prelude hiding (null)
 import System.Process
-import System.Process.ListLike.Classes (ProcessOutput)
-import qualified System.Process.ListLike.Read as LL (readCreateProcess, readProcess)
+import qualified System.Process.ListLike as LL
 import System.Exit (ExitCode)
-
-readCreateProcess :: ProcessOutput ByteString b => CreateProcess -> ByteString -> IO b
-readCreateProcess = LL.readCreateProcess
-
--- | Like 'System.Process.readProcessWithExitCode', but takes a
--- CreateProcess instead of a command and argument list, and reads and
--- writes type 'ByteString'
-readCreateProcessWithExitCode
-    :: CreateProcess            -- ^ command to run
-    -> ByteString               -- ^ standard input
-    -> IO (ExitCode, ByteString, ByteString) -- ^ exitcode, stdout, stderr
-readCreateProcessWithExitCode = LL.readCreateProcess
+import System.IO (hClose, hFlush)
+import Utils (forkWait)
 
 -- | Like 'System.Process.readProcessWithExitCode', but using 'ByteString'
+instance LL.ListLikeProcessIO ByteString Word8 where
+    forceOutput = return
+
+-- | Specialized version for backwards compatibility.
 readProcessWithExitCode :: FilePath -> [String] -> ByteString -> IO (ExitCode, ByteString, ByteString)
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
+readProcessWithExitCode = LL.readProcessWithExitCode
 
--- | Like 'System.Process.readProcess', but using 'ByteString'
-readProcess :: FilePath -> [String] -> ByteString -> IO ByteString
-readProcess = LL.readProcess
+readCreateProcessWithExitCode :: CreateProcess -> ByteString -> IO (ExitCode, ByteString, ByteString)
+readCreateProcessWithExitCode = LL.readCreateProcessWithExitCode
diff --git a/src/System/Process/ByteString/Lazy.hs b/src/System/Process/ByteString/Lazy.hs
--- a/src/System/Process/ByteString/Lazy.hs
+++ b/src/System/Process/ByteString/Lazy.hs
@@ -1,28 +1,29 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 module System.Process.ByteString.Lazy where
 
+import Control.DeepSeq (force)
+import Control.Exception
+import qualified Control.Exception as C (evaluate)
+import Control.Monad
 import Data.ByteString.Lazy (ByteString)
-import System.Exit (ExitCode)
+import Data.ListLike (null)
+import Data.ListLike.IO (hGetContents, hPutStr)
+import Data.Word (Word8)
+import Prelude hiding (null)
 import System.Process
-import qualified System.Process.ListLike.Read as LL (readCreateProcess, readProcess)
-import System.Process.ListLike.Classes (ProcessOutput)
-
-readCreateProcess :: ProcessOutput ByteString b => CreateProcess -> ByteString -> IO b
-readCreateProcess = LL.readCreateProcess
-
--- | Like 'System.Process.readProcessWithExitCode', but takes a
--- CreateProcess instead of a command and argument list, and reads and
--- writes type 'ByteString'
-readCreateProcessWithExitCode
-    :: CreateProcess            -- ^ command to run
-    -> ByteString               -- ^ standard input
-    -> IO (ExitCode, ByteString, ByteString) -- ^ exitcode, stdout, stderr
-readCreateProcessWithExitCode = LL.readCreateProcess
+import qualified System.Process.ListLike as LL
+import System.Exit (ExitCode)
+import System.IO (hClose, hFlush)
+import Utils (forkWait)
 
 -- | Like 'System.Process.readProcessWithExitCode', but using 'ByteString'
+instance LL.ListLikeProcessIO ByteString Word8 where
+    forceOutput = C.evaluate . force
+
+-- | Specialized version for backwards compatibility.
 readProcessWithExitCode :: FilePath -> [String] -> ByteString -> IO (ExitCode, ByteString, ByteString)
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
+readProcessWithExitCode = LL.readProcessWithExitCode
 
--- | Like 'System.Process.readProcess', but using 'ByteString'
-readProcess :: FilePath -> [String] -> ByteString -> IO ByteString
-readProcess = LL.readProcess
+readCreateProcessWithExitCode :: CreateProcess -> ByteString -> IO (ExitCode, ByteString, ByteString)
+readCreateProcessWithExitCode = LL.readCreateProcessWithExitCode
diff --git a/src/System/Process/Chunks.hs b/src/System/Process/Chunks.hs
deleted file mode 100644
--- a/src/System/Process/Chunks.hs
+++ /dev/null
@@ -1,230 +0,0 @@
--- | Support for using the 'Chunk' list returned by 'readProcessChunks'.
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}
-module System.Process.Chunks
-    ( Chunk(..)
-    , readCreateProcessChunks
-    , discardEmptyChunks
-    , fuseChunks
-    , collectProcessTriple
-    , collectProcessResult
-    , collectProcessOutput
-    , indentChunks
-    , dotifyChunks
-    , putChunk
-    , putMappedChunks
-    , putIndented
-    , putIndentedShowCommand
-    , putDots
-    , putDotsLn
-    , insertCommandStart
-    , insertCommandResult
-    , insertCommandDisplay
-    , showCreateProcessForUser
-    , showCmdSpecForUser
-    ) where
-
-import Control.Applicative ((<$>), (<*>))
-import Control.DeepSeq (NFData)
-import Control.Exception (SomeException)
-import Control.Monad.State (StateT, evalState, evalStateT, get, put)
-import Control.Monad.Trans (lift)
-import Data.ListLike (ListLike(..), ListLikeIO(hPutStr, putStr))
-import Data.Monoid (Monoid, (<>), mempty)
-import Data.String (IsString(fromString))
-import Prelude hiding (mapM, putStr, null, tail, break, sequence, length, replicate, rem)
-import System.Exit (ExitCode)
-import System.IO (stderr)
-import System.Process (ProcessHandle, CreateProcess(cmdspec, cwd), CmdSpec(..), showCommandForUser)
-import System.Process.ListLike.Classes (ListLikeLazyIO, ProcessOutput(pidf, outf, errf, intf, codef))
-import System.Process.ListLike.Read (readCreateProcess)
-
--- | A concrete representation of the methods in ProcessOutput.
-data Chunk a
-    = ProcessHandle ProcessHandle -- ^ This will always come first
-    | Stdout a
-    | Stderr a
-    | Exception SomeException
-    | Result ExitCode
-
-instance ListLikeLazyIO a c => ProcessOutput a [Chunk a] where
-    pidf p = [ProcessHandle p]
-    outf x = [Stdout x]
-    errf x = [Stderr x]
-    intf e = [Exception e]
-    codef c = [Result c]
-
-instance ListLikeLazyIO a c => ProcessOutput a (ExitCode, [Chunk a]) where
-    pidf p = (mempty, [ProcessHandle p])
-    codef c = (c, mempty)
-    outf x = (mempty, [Stdout x])
-    errf x = (mempty, [Stderr x])
-    intf e = (mempty, [Exception e])
-
--- | This lets us use DeepSeq's 'Control.DeepSeq.force' on a stream
--- of Chunks.
-instance NFData ExitCode
-
--- | A concrete use of 'readCreateProcess' - build a list containing
--- chunks of process output, any exceptions that get thrown, and
--- finally an exit code.  If a is a lazy type the returned list will
--- be lazy.
-readCreateProcessChunks :: (ListLikeLazyIO a c) => CreateProcess -> a -> IO [Chunk a]
-readCreateProcessChunks = readCreateProcess
-
--- | Eliminate empty Stdout or Stderr chunks.
-discardEmptyChunks :: ListLikeLazyIO a c => [Chunk a] -> [Chunk a]
-discardEmptyChunks [] = []
-discardEmptyChunks (Stdout a : more) | null a = discardEmptyChunks more
-discardEmptyChunks (Stderr a : more) | null a = discardEmptyChunks more
-discardEmptyChunks (a : more) = a : discardEmptyChunks more
-
--- | Merge adjacent Stdout or Stderr chunks.  This may be undesirable
--- if you want to get your input as soon as it becomes available, it
--- has the effect of making the result "less lazy".
-fuseChunks :: ListLikeLazyIO a c => [Chunk a] -> [Chunk a]
-fuseChunks [] = []
-fuseChunks (Stdout a : Stdout b : more) = fuseChunks (Stdout (a <> b) : more)
-fuseChunks (Stderr a : Stderr b : more) = fuseChunks (Stderr (a <> b) : more)
-fuseChunks (Stdout a : more) | null a = fuseChunks more
-fuseChunks (Stderr a : more) | null a = fuseChunks more
-fuseChunks (a : more) = a : fuseChunks more
-
-collectProcessTriple :: Monoid a => [Chunk a] -> (ExitCode, a, a)
-collectProcessTriple [] = mempty
-collectProcessTriple (Result x : xs) = (x, mempty, mempty) <> collectProcessTriple xs
-collectProcessTriple (Stdout x : xs) = (mempty, x, mempty) <> collectProcessTriple xs
-collectProcessTriple (Stderr x : xs) = (mempty, mempty, x) <> collectProcessTriple xs
-collectProcessTriple (_ : xs) = collectProcessTriple xs
-
-collectProcessResult :: Monoid a => [Chunk a] -> (ExitCode, [Chunk a])
-collectProcessResult [] = mempty
-collectProcessResult (Result x : xs) = (x, mempty) <> collectProcessResult xs
-collectProcessResult (x : xs) = (mempty, [x]) <> collectProcessResult xs
-
-collectProcessOutput :: Monoid a => [Chunk a] -> (ExitCode, a)
-collectProcessOutput [] = mempty
-collectProcessOutput (Result x : xs) = (x, mempty) <> collectProcessOutput xs
-collectProcessOutput (Stdout x : xs) = (mempty, x) <> collectProcessOutput xs
-collectProcessOutput (Stderr x : xs) = (mempty, x) <> collectProcessOutput xs
-collectProcessOutput (_ : xs) = mempty <> collectProcessOutput xs
-
--- | Pure function to indent the text of a chunk list.
-indentChunks :: forall a c. (ListLikeLazyIO a c, Eq c, IsString a) => String -> String -> [Chunk a] -> [Chunk a]
-indentChunks outp errp chunks =
-    evalState (Prelude.concat <$> mapM (indentChunk nl (fromString outp) (fromString errp)) chunks) BOL
-    where
-      nl :: c
-      nl = Data.ListLike.head (fromString "\n" :: a)
-
--- | The monad state, are we at the beginning of a line or the middle?
-data BOL = BOL | MOL deriving (Eq)
-
--- | Indent the text of a chunk with the prefixes given for stdout and
--- stderr.  The state monad keeps track of whether we are at the
--- beginning of a line - when we are and more text comes we insert one
--- of the prefixes.
-indentChunk :: forall a c m. (Monad m, Functor m, ListLikeLazyIO a c, Eq c) => c -> a -> a -> Chunk a -> StateT BOL m [Chunk a]
-indentChunk nl outp errp chunk =
-    case chunk of
-      Stdout x -> doText Stdout outp x
-      Stderr x -> doText Stderr errp x
-      _ -> return [chunk]
-    where
-      doText :: (a -> Chunk a) -> a -> a -> StateT BOL m [Chunk a]
-      doText con pre x = do
-        let (hd, tl) = break (== nl) x
-        (<>) <$> doHead con pre hd <*> doTail con pre tl
-      doHead :: (a -> Chunk a) -> a -> a -> StateT BOL m [Chunk a]
-      doHead _ _ x | null x = return []
-      doHead con pre x = do
-        bol <- get
-        case bol of
-          BOL -> put MOL >> return [con (pre <> x)]
-          MOL -> return [con x]
-      doTail :: (a -> Chunk a) -> a -> a -> StateT BOL m [Chunk a]
-      doTail _ _ x | null x = return []
-      doTail con pre x = do
-        bol <- get
-        put BOL
-        tl <- doText con pre (tail x)
-        return $ (if bol == BOL then [con pre] else []) <> [con (singleton nl)] <> tl
-
-dotifyChunks :: forall a c. (ListLikeLazyIO a c) => Int -> c -> [Chunk a] -> [Chunk a]
-dotifyChunks charsPerDot dot chunks =
-    evalState (Prelude.concat <$> mapM (dotifyChunk charsPerDot dot) chunks) 0
-
--- | dotifyChunk charsPerDot dot chunk - Replaces every charsPerDot
--- characters in the Stdout and Stderr chunks with one dot.  Runs in
--- the state monad to keep track of how many characters had been seen
--- when the previous chunk finished.  chunks.
-dotifyChunk :: forall a c m. (Monad m, Functor m, ListLikeLazyIO a c) => Int -> c -> Chunk a -> StateT Int m [Chunk a]
-dotifyChunk charsPerDot dot chunk =
-    case chunk of
-      Stdout x -> doChars (length x)
-      Stderr x -> doChars (length x)
-      _ -> return [chunk]
-    where
-      doChars count = do
-        rem <- get
-        let (count', rem') = divMod (rem + count) (fromIntegral charsPerDot)
-        put rem'
-        if (count' > 0) then return [Stderr (replicate count' dot)] else return []
-
--- | Write the Stdout chunks to stdout and the Stderr chunks to stderr.
-putChunk :: ListLikeLazyIO a c => Chunk a -> IO ()
-putChunk (Stdout x) = putStr x
-putChunk (Stderr x) = hPutStr stderr x
-putChunk _ = return ()
-
--- | Apply a function to the chunk list and output the result,
--- return the original (unmodified) chunk list.
-putMappedChunks :: ListLikeLazyIO a c => ([Chunk a] -> [Chunk a]) -> [Chunk a] -> IO [Chunk a]
-putMappedChunks f chunks = mapM_ putChunk (f chunks) >> return chunks
-
--- | Output the indented text of a chunk list, but return the original
--- unindented list.
-putIndented :: (ListLikeLazyIO a c, Eq c, IsString a) => String -> String -> [Chunk a] -> IO [Chunk a]
-putIndented outp errp chunks = putMappedChunks (indentChunks outp errp) chunks
-
-putIndentedShowCommand :: (ListLikeLazyIO a c, Eq c, IsString a) =>
-                          CreateProcess -> String -> String -> [Chunk a] -> IO [Chunk a]
-putIndentedShowCommand p outp errp chunks =
-    putMappedChunks (insertCommandDisplay p . indentChunks outp errp) chunks
-
--- | Output the dotified text of a chunk list. Returns the original
--- (undotified) list.
-putDots :: (ListLikeLazyIO a c) => Int -> c -> [Chunk a] -> IO [Chunk a]
-putDots charsPerDot dot chunks =
-    evalStateT (mapM (\ x -> dotifyChunk charsPerDot dot x >>= mapM_ (lift . putChunk) >> return x) chunks) 0
-
--- | Output the dotified text of a chunk list with a newline at EOF.
--- Returns the original list.
-putDotsLn :: forall a c. (IsString a, ListLikeLazyIO a c) => Int -> c -> [Chunk a] -> IO [Chunk a]
-putDotsLn cpd dot chunks = putDots cpd dot chunks >>= \ r -> hPutStr stderr (fromString "\n" :: a) >> return r
-
--- | Insert a chunk displaying the command and its arguments at the
--- beginning of the chunk list.
-insertCommandStart :: (IsString a, ListLikeLazyIO a c, Eq c) =>
-                      CreateProcess -> [Chunk a] -> [Chunk a]
-insertCommandStart p chunks = [Stderr (fromString (" -> " ++ showCreateProcessForUser p ++ "\n"))] <> chunks
-
--- | Insert a chunk displaying the command and the result code.
-insertCommandResult :: (IsString a, ListLikeLazyIO a c, Eq c) =>
-                       CreateProcess -> [Chunk a] -> [Chunk a]
-insertCommandResult _ [] = []
-insertCommandResult p (Result code : xs) =
-    Stderr (fromString (" <- " ++ show code ++ " <- " ++ showCmdSpecForUser (cmdspec p) ++ "\n")) :
-    Result code :
-    xs
-insertCommandResult p (x : xs) = x : insertCommandResult p xs
-
-insertCommandDisplay :: (IsString a, ListLikeLazyIO a c, Eq c) => CreateProcess -> [Chunk a] -> [Chunk a]
-insertCommandDisplay p = insertCommandResult p . insertCommandStart p
-
-showCreateProcessForUser :: CreateProcess -> String
-showCreateProcessForUser p =
-    showCmdSpecForUser (cmdspec p) ++ maybe "" (\ d -> " (in " ++ d ++ ")") (cwd p)
-
-showCmdSpecForUser :: CmdSpec -> String
-showCmdSpecForUser (ShellCommand s) = s
-showCmdSpecForUser (RawCommand p args) = showCommandForUser p args
diff --git a/src/System/Process/Extras.hs b/src/System/Process/Extras.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Process/Extras.hs
@@ -0,0 +1,40 @@
+-- | Re-export all symbols and instances of the process-extras package.
+{-# LANGUAGE FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, UndecidableInstances #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+module System.Process.Extras
+    ( ListLikeProcessIO(forceOutput)
+    , readCreateProcessWithExitCode
+    , readProcessWithExitCode
+    , showCreateProcessForUser
+    , showCmdSpecForUser
+    ) where
+
+import Control.DeepSeq (force)
+import qualified Control.Exception as C (evaluate)
+-- import Data.Text (pack, unpack)
+import System.Process (CmdSpec(..), CreateProcess(..), showCommandForUser)
+import System.Process.ByteString ()
+import System.Process.ByteString.Lazy ()
+import System.Process.ListLike (ListLikeProcessIO(forceOutput), readCreateProcessWithExitCode, readProcessWithExitCode)
+import System.Process.Text ()
+import System.Process.Text.Lazy ()
+
+-- | System.Process utility functions.
+showCreateProcessForUser :: CreateProcess -> String
+showCreateProcessForUser p =
+    showCmdSpecForUser (cmdspec p) ++ maybe "" (\ d -> " (in " ++ d ++ ")") (cwd p)
+
+showCmdSpecForUser :: CmdSpec -> String
+showCmdSpecForUser (ShellCommand s) = s
+showCmdSpecForUser (RawCommand p args) = showCommandForUser p args
+
+-- | Like 'System.Process.readProcessWithExitCode' that takes a 'CreateProcess'.
+instance ListLikeProcessIO String Char where
+    -- This is required because strings are magically lazy.  Without it
+    -- processes get exit status 13 - file read failures.
+    forceOutput = C.evaluate . force
+{-
+  readCreateProcessWithExitCode p input = do
+    (code, out, err) <- readCreateProcessWithExitCode p (pack input)
+    return (code, unpack out, unpack err)
+-}
diff --git a/src/System/Process/ListLike.hs b/src/System/Process/ListLike.hs
--- a/src/System/Process/ListLike.hs
+++ b/src/System/Process/ListLike.hs
@@ -1,8 +1,56 @@
-module System.Process.ListLike
-    ( module System.Process.ListLike.Classes
-    , module System.Process.ListLike.Read
-    ) where
+{-# LANGUAGE MultiParamTypeClasses #-}
+module System.Process.ListLike where
 
-import System.Process.ListLike.Classes
-import System.Process.ListLike.Instances ()
-import System.Process.ListLike.Read
+import Control.Exception
+import Control.Monad
+import Data.ListLike (null)
+import Data.ListLike.IO (ListLikeIO, hGetContents, hPutStr)
+import Prelude hiding (null)
+import System.Exit (ExitCode)
+import System.IO (hClose, hFlush)
+import System.Process
+import Utils (forkWait)
+
+class ListLikeIO a c => ListLikeProcessIO a c where
+    forceOutput :: a -> IO a
+
+-- | Like 'System.Process.readProcessWithExitCode', but with generalized input and output type.
+readProcessWithExitCode
+    :: ListLikeProcessIO a c =>
+       FilePath                 -- ^ command to run
+    -> [String]                 -- ^ any arguments
+    -> a               -- ^ standard input
+    -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr
+readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
+
+readCreateProcessWithExitCode :: ListLikeProcessIO a c => CreateProcess -> a -> IO (ExitCode, a, a)
+readCreateProcessWithExitCode p input = mask $ \restore -> do
+    (Just inh, Just outh, Just errh, pid) <-
+        createProcess p{ std_in  = CreatePipe,
+                                       std_out = CreatePipe,
+                                       std_err = CreatePipe }
+    flip onException
+      (do terminateProcess pid; hClose inh; hClose outh; hClose errh;
+          waitForProcess pid) $ restore $ do
+
+      -- fork off a thread to start consuming stdout
+      waitOut <- forkWait $ hGetContents outh >>= forceOutput
+
+      -- fork off a thread to start consuming stderr
+      waitErr <- forkWait $ hGetContents errh >>= forceOutput
+
+      -- now write and flush any input
+      unless (null input) $ do hPutStr inh input; hFlush inh
+      hClose inh -- done with stdin
+
+      -- wait on the output
+      out <- waitOut
+      err <- waitErr
+
+      hClose outh
+      hClose errh
+
+      -- wait on the process
+      ex <- waitForProcess pid
+
+      return (ex, out, err)
diff --git a/src/System/Process/ListLike/Classes.hs b/src/System/Process/ListLike/Classes.hs
deleted file mode 100644
--- a/src/System/Process/ListLike/Classes.hs
+++ /dev/null
@@ -1,38 +0,0 @@
-{-# LANGUAGE FunctionalDependencies, MultiParamTypeClasses #-}
-module System.Process.ListLike.Classes
-    ( ListLikeLazyIO(..)
-    , ProcessOutput(..)
-    ) where
-
-import Control.Exception (SomeException)
-import Data.ListLike (ListLikeIO(..))
-import Data.ListLike.Text.Text ()
-import Data.ListLike.Text.TextLazy ()
-import Data.Monoid (Monoid(mempty, mappend))
-import Prelude hiding (null, length, rem)
-import System.Exit (ExitCode(ExitFailure))
-import System.IO hiding (hPutStr, hGetContents)
-import System.Process (ProcessHandle)
-
--- | Methods for turning the output of a process into a monoid.
-class Monoid b => ProcessOutput a b | b -> a where
-    pidf :: ProcessHandle -> b
-    outf :: a -> b
-    errf :: a -> b
-    intf :: SomeException -> b
-    codef :: ExitCode -> b
-
--- | A process usually has one 'ExitCode' at the end of its output, this 'Monoid'
--- instance lets us build the type returned by 'System.Process.readProcessWithExitCode'.
-instance Monoid ExitCode where
-    mempty = ExitFailure 0
-    mappend x (ExitFailure 0) = x
-    mappend _ x = x
-
--- | Class of types which can be used as the input and outputs of
--- these process functions.
-class ListLikeIO a c => ListLikeLazyIO a c where
-  readChunks :: Handle -> IO [a]
-  -- ^ Read the list of chunks from this handle.  For lazy types this
-  -- is just a call to 'hGetContents' followed by 'toChunks'.  For strict
-  -- types it might return a singleton list.  Strings are trickier.
diff --git a/src/System/Process/ListLike/Instances.hs b/src/System/Process/ListLike/Instances.hs
deleted file mode 100644
--- a/src/System/Process/ListLike/Instances.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeSynonymInstances, UndecidableInstances #-}
-
--- | ListLikeLazyIO instances for strict and lazy types.  If you start a
--- long running process with a strict type it will block until the
--- process finishes.  Why not try a lazy type?
-
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module System.Process.ListLike.Instances where
-
-import Control.DeepSeq (force)
-import Control.Exception as E (evaluate, throw)
-import Data.ByteString.Char8 as B (ByteString)
-import qualified Data.ByteString.Lazy as L
-import Data.ListLike.IO (hGetContents)
-import Data.Monoid (mempty)
-import Data.Text as T (Text)
-import qualified Data.Text.Lazy as LT
-import Data.Word (Word8)
-import System.Exit (ExitCode)
-import System.Process.ListLike.Classes (ListLikeLazyIO(..), ProcessOutput(..))
-
-instance ListLikeLazyIO B.ByteString Word8 where
-  --setModes _ (inh, outh, errh, _) = f inh >> f outh >> f errh where f = maybe (return ()) (\ h -> hSetBinaryMode h True)
-  readChunks h = hGetContents h >>= return . force . (: [])
-
-instance ListLikeLazyIO T.Text Char where
-  --setModes _ _  = return ()
-  readChunks h = hGetContents h >>= return . force . (: [])
-
-instance ListLikeLazyIO L.ByteString Word8 where
-  --setModes _ (inh, outh, errh, _) = f inh >> f outh >> f errh where f = maybe (return ()) (\ h -> hSetBinaryMode h True)
-  readChunks h = hGetContents h >>= evaluate . Prelude.map (L.fromChunks . (: [])) . L.toChunks
-
-instance ListLikeLazyIO LT.Text Char where
-  --setModes _ _  = return ()
-  readChunks h = hGetContents h >>= evaluate . Prelude.map (LT.fromChunks . (: [])) . LT.toChunks
-
-instance ListLikeLazyIO a c => ProcessOutput a (ExitCode, a, a) where
-    pidf _ = mempty
-    codef c = (c, mempty, mempty)
-    outf x = (mempty, x, mempty)
-    errf x = (mempty, mempty, x)
-    intf e = throw e
diff --git a/src/System/Process/ListLike/LazyString.hs b/src/System/Process/ListLike/LazyString.hs
deleted file mode 100644
--- a/src/System/Process/ListLike/LazyString.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
-module System.Process.ListLike.LazyString where
-
-import Data.Text as T (unpack)
-import Data.Text.Lazy as LT (toChunks)
-import System.Process.ListLike.Classes (ListLikeLazyIO(readChunks))
-import System.Process.ListLike.Instances ()
-
--- | This String instance is implemented using the Lazy Text instance.
--- Otherwise (without some serious coding) String would be a strict
--- instance .  Note that the 'System.Process.readProcess' in the
--- process library is strict, while our equivalent is not - see test4
--- in Tests/Dots.hs.
-instance ListLikeLazyIO String Char where
-  readChunks h = readChunks h >>= return . map T.unpack . concat . map LT.toChunks
diff --git a/src/System/Process/ListLike/Read.hs b/src/System/Process/ListLike/Read.hs
deleted file mode 100644
--- a/src/System/Process/ListLike/Read.hs
+++ /dev/null
@@ -1,165 +0,0 @@
--- | Generalized versions of the functions
--- 'System.Process.readProcess', and
--- 'System.Process.readProcessWithExitCode'.
-{-# LANGUAGE FlexibleContexts, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, ScopedTypeVariables, TupleSections, TypeFamilies, UndecidableInstances #-}
-module System.Process.ListLike.Read
-    ( readCreateProcess,
-      readCreateProcess',
-      readInterleaved,
-      readCreateProcessWithExitCode,
-      readProcessWithExitCode,
-      StdoutWrapper(..),
-      readProcess
-    ) where
-
-import Control.Applicative ((<$>), (<*>), pure)
-import Control.Concurrent
-import Control.Exception as E (SomeException, onException, catch, mask, throw)
-import Control.Monad
-import Data.ListLike (ListLike(..), ListLikeIO(..))
-import Data.ListLike.Text.Text ()
-import Data.ListLike.Text.TextLazy ()
-import Data.Maybe (maybeToList)
-import Data.Monoid (Monoid(mempty, mappend), (<>))
-import GHC.IO.Exception (IOErrorType(OtherError, ResourceVanished), IOException(ioe_type))
-import Prelude hiding (null, length, rem)
-import System.Exit (ExitCode(ExitSuccess))
-import System.IO hiding (hPutStr, hGetContents)
-import qualified System.IO.Error as IO
-import System.IO.Unsafe (unsafeInterleaveIO)
-import System.Process (CreateProcess(..), StdStream(CreatePipe, Inherit), proc,
-                       createProcess, waitForProcess, terminateProcess)
-import System.Process.ListLike.Classes (ListLikeLazyIO(..), ProcessOutput(..))
-import System.Process.ListLike.Instances ()
-import Utils (forkWait)
-
--- | Read the output of a process and use the argument functions to
--- convert it into a Monoid, preserving the order of appearance of the
--- different chunks of output from standard output and standard error.
-readCreateProcess :: (ListLikeLazyIO a c, ProcessOutput a b) => CreateProcess -> a -> IO b
-readCreateProcess  p input =
-    readCreateProcess' (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe }) input
-
-readCreateProcess' :: (ListLikeLazyIO a c, ProcessOutput a b) => CreateProcess -> a -> IO b
-readCreateProcess'  p input = mask $ \ restore -> do
-  (Just inh, maybe_outh, maybe_errh, pid) <- createProcess p
-
-  onException
-    (restore $
-     do -- Without unsafeIntereleaveIO the pid messsage gets stuck
-        -- until some additional output arrives from the process.
-        waitOut <- forkWait $ (<>) <$> pure (pidf pid)
-                                   <*> unsafeInterleaveIO (readInterleaved (maybeToList (fmap (outf,) maybe_outh) <> maybeToList (fmap (errf,) maybe_errh))
-                                                                           (codef <$> waitForProcess pid))
-        writeInput inh input
-        waitOut)
-    (do terminateProcess pid
-        hClose inh
-        maybe (return ()) hClose maybe_outh
-        maybe (return ()) hClose maybe_errh
-        waitForProcess pid)
-
--- | Simultaneously read the output from several file handles, using
--- the associated functions to add them to a Monoid b in the order
--- they appear.  This closes each handle on EOF, because AFAIK it is
--- the only useful thing to do with a file handle that has reached
--- EOF.
-readInterleaved :: forall a b c. (ListLikeLazyIO a c, ProcessOutput a b) =>
-                   [(a -> b, Handle)] -> IO b -> IO b
-readInterleaved pairs finish = newEmptyMVar >>= readInterleaved' pairs finish
-
-readInterleaved' :: forall a b c. (ListLikeLazyIO a c, ProcessOutput a b) =>
-                    [(a -> b, Handle)] -> IO b -> MVar (Either Handle b) -> IO b
-readInterleaved' pairs finish res = do
-  mapM_ (forkIO . uncurry readHandle) pairs
-  takeChunks (length pairs)
-    where
-      -- Forked thread to read the input and send it to takeChunks via
-      -- the MVar.
-      readHandle :: (a -> b) -> Handle -> IO ()
-      readHandle f h = do
-        cs <- readChunks h
-        -- If the type returned as stdout and stderr is lazy we need
-        -- to force it here in the producer thread - I'm not exactly
-        -- sure why.  And why is String lazy?
-        -- when (lazy (undefined :: a)) (void cs)
-        mapM_ (\ c -> putMVar res (Right (f c))) cs
-        hClose h
-        putMVar res (Left h)
-      takeChunks :: Int -> IO b
-      takeChunks 0 = finish
-      takeChunks openCount = takeChunk >>= takeMore openCount
-      takeMore :: Int -> Either Handle b -> IO b
-      takeMore openCount (Left h) = hClose h >> takeChunks (openCount - 1)
-      takeMore openCount (Right x) =
-          do xs <- unsafeInterleaveIO $ takeChunks openCount
-             return (x <> xs)
-      takeChunk = takeMVar res `catch` (\ (e :: SomeException) -> return $ Right $ intf e)
-
--- | An implementation of 'System.Process.readProcessWithExitCode'
--- with a two generalizations: (1) The input and outputs can be any
--- instance of 'ListLikeLazyIO', and (2) The CreateProcess is passes an
--- argument, so you can use either 'System.Process.proc' or
--- 'System.Process.rawSystem' and you can modify its fields such as
--- 'System.Process.cwd' before the process starts
-readCreateProcessWithExitCode :: ListLikeLazyIO a c =>
-                                 CreateProcess       -- ^ process to run
-                              -> a                   -- ^ standard input
-                              -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr
-readCreateProcessWithExitCode p input = readCreateProcess p input
-
--- | A version of 'System.Process.readProcessWithExitCode' that uses
--- any instance of 'ListLikeLazyIO' instead of 'String', implemented
--- using 'readCreateProcessWithExitCode'.
-readProcessWithExitCode :: ListLikeLazyIO a c =>
-                           FilePath            -- ^ command to run
-                        -> [String]            -- ^ any arguments
-                        -> a                   -- ^ standard input
-                        -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
-
--- | Implementation of 'System.Process.readProcess' that uses any
--- instance of 'ListLikeLazyIO' instead of 'String', implemented using
--- 'readCreateProcess'.  As with 'System.Process.readProcess', Stderr
--- goes directly to the console, only stdout is returned.  Also like
--- 'System.Process.readProcess', an IO error of type OtherError is
--- thrown when the result code is not ExitSuccess.
-readProcess :: ListLikeLazyIO a c =>
-               FilePath        -- ^ command to run
-            -> [String]        -- ^ any arguments
-            -> a               -- ^ standard input
-            -> IO a            -- ^ stdout
-readProcess cmd args input =
-    unStdoutWrapper <$> readCreateProcess' ((proc cmd args) {std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit}) input
-
--- | For the 'readProcess' function, we need to wrap a newtype around
--- the output type so we can build a ProcessOutput instance for it.
--- Otherwise it would overlap everything.
-newtype StdoutWrapper a = StdoutWrapper {unStdoutWrapper :: a}
-
-instance Monoid a => Monoid (StdoutWrapper a) where
-    mempty = StdoutWrapper mempty
-    mappend (StdoutWrapper a) (StdoutWrapper b) = StdoutWrapper (a <> b)
-
-instance (ListLikeLazyIO a c, Monoid a) => ProcessOutput a (StdoutWrapper a) where
-    pidf _ = mempty
-    codef ExitSuccess = mempty
-    codef failure = throw $ IO.mkIOError OtherError ("Process exited with " ++ show failure) Nothing Nothing
-    outf x = StdoutWrapper x
-    errf _ = mempty
-    intf e = throw e
-
--- | Write and flush process input, closing the handle when done.
--- Catch and ignore Resource Vanished exceptions, they just mean the
--- process exited before all of its output was read.
-writeInput :: ListLikeLazyIO a c => Handle -> a -> IO ()
-writeInput inh input = do
-  (do unless (null input) (hPutStr inh input >> hFlush inh)
-      hClose inh) `E.catch` resourceVanished (\ _ -> return ())
-
--- | Wrapper for a process that provides a handler for the
--- ResourceVanished exception.  This is frequently an exception we
--- wish to ignore, because many processes will deliberately exit
--- before they have read all of their input.
-resourceVanished :: (IOError -> IO a) -> IOError -> IO a
-resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e
diff --git a/src/System/Process/ListLike/ReadNoThreads.hs b/src/System/Process/ListLike/ReadNoThreads.hs
deleted file mode 100644
--- a/src/System/Process/ListLike/ReadNoThreads.hs
+++ /dev/null
@@ -1,173 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses, PackageImports, ScopedTypeVariables #-}
-{-# OPTIONS -Wwarn -Wall -fno-warn-name-shadowing -fno-warn-missing-signatures #-}
-
--- | This is an alternative version of the module
---   "System.Process.ListLike.Read" that doesn't use forkIO.  I don't
---   know of any advantages, I'm just including it because it is derived
---   from old code I had developed, it is kinda badass, and maybe
---   someone has a use for it.
---
---   Function to run a process and return a lazy list of chunks from
---   standard output, standard error, and at the end of the list an
---   object indicating the process result code.  If neither output
---   handle is ready for reading the process sleeps and tries again,
---   with the sleep intervals increasing from 8 microseconds to a
---   maximum of 0.1 seconds.
-module System.Process.ListLike.ReadNoThreads
-    ( ListLikeIOPlus(..)
-    , readCreateProcess
-    , readCreateProcessWithExitCode
-    , readProcessWithExitCode
-    ) where
-
-import Control.Applicative ((<$>), (<*>), pure)
-import Control.Concurrent (threadDelay)
-import Control.Exception (catch, mask, onException, try)
-import Data.ListLike (ListLike(length, null), ListLikeIO(hGetNonBlocking))
-import Data.Maybe (mapMaybe)
-import Data.Monoid (Monoid(mempty), (<>), mconcat)
-import qualified Data.Text.Lazy as LT
-import Data.Text.Lazy.Encoding (encodeUtf8)
-import qualified GHC.IO.Exception as E
-import Prelude hiding (length, null)
-import System.Exit (ExitCode)
-import System.Process (ProcessHandle, CreateProcess(..), waitForProcess, proc, createProcess, StdStream(CreatePipe), terminateProcess)
-import System.IO (Handle, hReady, hClose)
-import System.IO.Unsafe (unsafeInterleaveIO)
-import System.Process.ListLike.Classes (ProcessOutput(..), ListLikeLazyIO(..))
-import System.Process.ListLike.Instances ()
-
--- For the ListLikeIOPlus instance
-import qualified Data.ByteString.Lazy as L
-import Data.Word (Word8)
-
--- | For the unthreaded implementation we need a more powerful
--- ListLikeLazyIO class.
-class ListLikeLazyIO a c => ListLikeIOPlus a c where
-    hPutNonBlocking :: Handle -> a -> IO a
-    chunks :: a -> [a]
-
-instance ListLikeIOPlus L.ByteString Word8 where
-    hPutNonBlocking = L.hPutNonBlocking
-    chunks = Prelude.map (L.fromChunks . (: [])) . L.toChunks
-
-instance ListLikeIOPlus LT.Text Char where
-    hPutNonBlocking h text = L.hPutNonBlocking h (encodeUtf8 text) >> return text
-    chunks = map (LT.fromChunks . (: [])) . LT.toChunks
-
-bufSize = 65536		-- maximum chunk size
-uSecs = 8		-- minimum wait time, doubles each time nothing is ready
-maxUSecs = 100000	-- maximum wait time (microseconds)
-
-readCreateProcess :: forall a b c. (ListLikeIOPlus a c, ProcessOutput a b) => CreateProcess -> a -> IO b
-readCreateProcess p input = mask $ \ restore -> do
-    (Just inh, Just outh, Just errh, pid) <-
-        createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe})
-
-    -- setModes input hs
-
-    -- The uses of unsafeInterleaveIO here and below are required to
-    -- keep the output from blocking waiting for process exit.
-    onException
-      (restore $ (<>) <$> pure (pidf pid)
-                      <*> (unsafeInterleaveIO $ elements pid (chunks input, Just inh, [(outf, outh), (errf, errh)], Nothing)))
-      (do terminateProcess pid; hClose inh; hClose outh; hClose errh;
-          waitForProcess pid)
-    where
-      elements :: ProcessHandle -> ([a], Maybe Handle, [(a -> b, Handle)], Maybe b) -> IO b
-      -- EOF on both output descriptors, get exit code.  It can be
-      -- argued that the list will always contain exactly one exit
-      -- code if traversed to its end, because the only case of
-      -- elements that does not recurse is the one that adds a Result,
-      -- and nowhere else is a Result added.  However, the process
-      -- doing the traversing might die before that end is reached.
-      elements pid tuple@(_, _, [], elems) =
-          do result <- try (waitForProcess pid)
-             case result of
-               Left exn -> (<>) <$> pure (maybe mempty id elems <> intf exn) <*> elements pid tuple
-               Right code -> pure (maybe mempty id elems <> codef code)
-      -- The available output has been processed, send input and read
-      -- from the ready handles
-      elements pid tuple@(_, _, _, Nothing) =
-          do result <- try (ready uSecs tuple)
-             case result of
-               Left exn -> (<>) <$> pure (intf exn) <*> elements pid tuple
-               Right tuple' -> elements pid tuple'
-      -- Add some output to the result value
-      elements pid (input, inh, pairs, Just elems) =
-          (<>) <$> pure elems
-               <*> (unsafeInterleaveIO $ elements pid (input, inh, pairs, Nothing))
-
--- A quick fix for the issue where hWaitForInput has actually started
--- raising the isEOFError exception in ghc 6.10.
-data Readyness = Ready | Unready | EndOfFile deriving Eq
-
-hReady' :: Handle -> IO Readyness
-hReady' h = (hReady h >>= (\ flag -> return (if flag then Ready else Unready))) `catch` (\ (e :: IOError) ->
-                                                                                             case E.ioe_type e of
-                                                                                               E.EOF -> return EndOfFile
-                                                                                               _ -> error (show e))
-
--- | Wait until at least one handle is ready and then write input or
--- read output.  Note that there is no way to check whether the input
--- handle is ready except to try to write to it and see if any bytes
--- are accepted.  If no input is accepted, or the input handle is
--- already closed, and none of the output descriptors are ready for
--- reading the function sleeps and tries again.
-ready :: (ListLikeIOPlus a c, ProcessOutput a b) =>
-         Int -> ([a], Maybe Handle, [(a -> b, Handle)], Maybe b)
-      -> IO ([a], Maybe Handle, [(a -> b, Handle)], Maybe b)
-ready waitUSecs (input, inh, pairs, elems) =
-    do
-      anyReady <- mapM (hReady' . snd) pairs
-      case (input, inh, anyReady) of
-        -- Input exhausted, close the input handle.
-        ([], Just handle, _) | all (== Unready) anyReady ->
-            do hClose handle
-               ready  waitUSecs ([], Nothing, pairs, elems)
-        -- Input handle closed and there are no ready output handles,
-        -- wait a bit
-        ([], Nothing, _) | all (== Unready) anyReady ->
-            do threadDelay waitUSecs
-               --ePut0 ("Slept " ++ show uSecs ++ " microseconds\n")
-               ready (min maxUSecs (2 * waitUSecs)) (input, inh, pairs, elems)
-        -- Input is available and there are no ready output handles
-        (input : etc, Just handle, _)
-            -- Discard a zero byte input
-            | all (== Unready) anyReady && null input -> ready waitUSecs (etc, inh, pairs, elems)
-            -- Send some input to the process
-            | all (== Unready) anyReady ->
-                do input' <- hPutNonBlocking handle input
-                   case null input' of
-                     -- Input buffer is full too, sleep.
-                     True -> do threadDelay uSecs
-                                ready (min maxUSecs (2 * waitUSecs)) (input : etc, inh, pairs, elems)
-                     -- We wrote some input, discard it and continue
-                     False -> return (input' : etc, Just handle, pairs, elems)
-        -- One or both output handles are ready, try to read from them
-        _ ->
-            do allOutputs <- mapM (\ ((f, h), r) -> nextOut h r f) (zip pairs anyReady)
-               let newPairs = mapMaybe (\ ((_, mh), (f, _)) -> maybe Nothing (\ h -> Just (f, h)) mh) (zip allOutputs pairs)
-               return (input, inh, newPairs, elems <> mconcat (map fst allOutputs))
-
--- | Return the next output element and the updated handle
--- from a handle which is assumed ready.
-nextOut :: (ListLikeIO a c, ProcessOutput a b) => Handle -> Readyness -> (a -> b) -> IO (Maybe b, Maybe Handle)
-nextOut _ EndOfFile _ = return (Nothing, Nothing)	-- Handle is closed
-nextOut handle Unready _ = return (Nothing, Just handle)	-- Handle is not ready
-nextOut handle Ready constructor =	-- Perform a read
-    do
-      a <- hGetNonBlocking handle bufSize
-      case length a of
-        -- A zero length read, unlike a zero length write, always
-        -- means EOF.
-        0 -> do hClose handle
-                return (Nothing, Nothing)
-        -- Got some input
-        _n -> return (Just (constructor a), Just handle)
-
-readCreateProcessWithExitCode :: (ListLikeIOPlus a c) => CreateProcess -> a -> IO (ExitCode, a, a)
-readCreateProcessWithExitCode p input = readCreateProcess p input
-
-readProcessWithExitCode :: (ListLikeIOPlus a c) => FilePath -> [String] -> a -> IO (ExitCode, a, a)
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
diff --git a/src/System/Process/ListLike/StrictString.hs b/src/System/Process/ListLike/StrictString.hs
deleted file mode 100644
--- a/src/System/Process/ListLike/StrictString.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
-module System.Process.ListLike.StrictString where
-
-import Control.DeepSeq (force)
-import Data.ListLike (hGetContents)
-import System.Process.ListLike.Classes (ListLikeLazyIO(readChunks))
-
-instance ListLikeLazyIO String Char where
-  readChunks h = hGetContents h >>= return . force . (: [])
diff --git a/src/System/Process/String.hs b/src/System/Process/String.hs
deleted file mode 100644
--- a/src/System/Process/String.hs
+++ /dev/null
@@ -1,19 +0,0 @@
-{-# LANGUAGE FlexibleContexts #-}
-module System.Process.String where
-
-import System.Exit (ExitCode)
-import System.Process (CreateProcess(..), CmdSpec(..), readProcessWithExitCode)
-import System.Process.ListLike.Classes (ProcessOutput, ListLikeLazyIO)
-import System.Process.ListLike.Read as LL (readCreateProcess)
-
--- No ListLikeLazyIO instance is imported here because we have two and
--- naturally they conflict.
-readCreateProcess :: (ListLikeLazyIO String Char, ProcessOutput String b) => CreateProcess -> String -> IO b
-readCreateProcess = LL.readCreateProcess
-
-readCreateProcessWithExitCode
-    :: ListLikeLazyIO String Char =>
-       CreateProcess                 -- ^ command to run
-    -> String                        -- ^ standard input
-    -> IO (ExitCode, String, String) -- ^ exitcode, stdout, stderr
-readCreateProcessWithExitCode = LL.readCreateProcess
diff --git a/src/System/Process/Text.hs b/src/System/Process/Text.hs
--- a/src/System/Process/Text.hs
+++ b/src/System/Process/Text.hs
@@ -1,28 +1,26 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 module System.Process.Text where
 
+import Control.Exception
+import Control.Monad
 import Data.Text (Text)
+import Data.ListLike (null)
+import Data.ListLike.IO (hGetContents, hPutStr)
+import Prelude hiding (null)
 import System.Process
-import System.Process.ListLike.Classes (ProcessOutput)
-import qualified System.Process.ListLike.Read as LL (readCreateProcess, readProcess)
+import qualified System.Process.ListLike as LL
 import System.Exit (ExitCode)
-
-readCreateProcess :: ProcessOutput Text b => CreateProcess -> Text -> IO b
-readCreateProcess = LL.readCreateProcess
+import System.IO (hClose, hFlush)
+import Utils (forkWait)
 
--- | Like 'System.Process.readProcessWithExitCode', but takes a
--- CreateProcess instead of a command and argument list, and reads and
--- writes type 'ByteString'
-readCreateProcessWithExitCode
-    :: CreateProcess            -- ^ command to run
-    -> Text                     -- ^ standard input
-    -> IO (ExitCode, Text, Text) -- ^ exitcode, stdout, stderr
-readCreateProcessWithExitCode = LL.readCreateProcess
+-- | Like 'System.Process.readProcessWithExitCode', but using 'Text'
+instance LL.ListLikeProcessIO Text Char where
+    forceOutput = return
 
--- | Like 'System.Process.readProcessWithExitCode', but using 'ByteString'
+-- | Specialized version for backwards compatibility.
 readProcessWithExitCode :: FilePath -> [String] -> Text -> IO (ExitCode, Text, Text)
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
+readProcessWithExitCode = LL.readProcessWithExitCode
 
--- | Like 'System.Process.readProcess', but using 'Text'
-readProcess :: FilePath -> [String] -> Text -> IO Text
-readProcess = LL.readProcess
+readCreateProcessWithExitCode :: CreateProcess -> Text -> IO (ExitCode, Text, Text)
+readCreateProcessWithExitCode = LL.readCreateProcessWithExitCode
diff --git a/src/System/Process/Text/Lazy.hs b/src/System/Process/Text/Lazy.hs
--- a/src/System/Process/Text/Lazy.hs
+++ b/src/System/Process/Text/Lazy.hs
@@ -1,26 +1,28 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 module System.Process.Text.Lazy where
 
+import Control.DeepSeq (force)
+import Control.Exception
+import qualified Control.Exception as C (evaluate)
+import Control.Monad
+import Data.ListLike (null)
+import Data.ListLike.IO (hGetContents, hPutStr)
 import Data.Text.Lazy (Text)
-import System.Exit (ExitCode)
+import Prelude hiding (null)
 import System.Process
-import System.Process.ListLike.Classes (ProcessOutput)
-import qualified System.Process.ListLike.Read as LL (readCreateProcess, readProcess)
-
-readCreateProcess :: ProcessOutput Text b => CreateProcess -> Text -> IO b
-readCreateProcess = LL.readCreateProcess
+import qualified System.Process.ListLike as LL
+import System.Exit (ExitCode)
+import System.IO (hClose, hFlush)
+import Utils (forkWait)
 
 -- | Like 'System.Process.readProcessWithExitCode', but using 'Text'
-readCreateProcessWithExitCode
-    :: CreateProcess             -- ^ command to run
-    -> Text                      -- ^ standard input
-    -> IO (ExitCode, Text, Text) -- ^ exitcode, stdout, stderr
-readCreateProcessWithExitCode = LL.readCreateProcess
+instance LL.ListLikeProcessIO Text Char where
+    forceOutput = C.evaluate . force
 
--- | Like 'System.Process.readProcessWithExitCode', but using 'ByteString'
+-- | Specialized version for backwards compatibility.
 readProcessWithExitCode :: FilePath -> [String] -> Text -> IO (ExitCode, Text, Text)
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
+readProcessWithExitCode = LL.readProcessWithExitCode
 
--- | Like 'System.Process.readProcess', but using 'Text'
-readProcess :: FilePath -> [String] -> Text -> IO Text
-readProcess = LL.readProcess
+readCreateProcessWithExitCode :: CreateProcess -> Text -> IO (ExitCode, Text, Text)
+readCreateProcessWithExitCode = LL.readCreateProcessWithExitCode
diff --git a/tests/Interactive.hs b/tests/Interactive.hs
deleted file mode 100644
--- a/tests/Interactive.hs
+++ /dev/null
@@ -1,74 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables, StandaloneDeriving #-}
--- | Tests that require a user to send a keyboard interrupt.
-module Main where
-
-import Control.Exception (SomeException)
-import qualified Data.Text.Lazy
-import qualified Data.ByteString.Lazy
-import Data.Monoid
-import System.Process
-import System.Process.Chunks (Chunk(..))
-import System.Process.ListLike.Instances ()
-import qualified System.Process.ListLike.ReadNoThreads as NoThreads
-import qualified System.Process.ListLike.Read as Threads
-import System.Environment
-import System.IO
-import Text.Read (readMaybe)
-
-instance Show ProcessHandle where
-    show _ = "<processhandle>"
-
-instance Eq ProcessHandle where
-    _ == _ = False
-
-instance Eq SomeException where
-    _ == _ = False
-
-deriving instance Show a => Show (Chunk a)
-
-deriving instance Eq a => Eq (Chunk a)
-
-main :: IO ()
-main = do
-  args <- getArgs
-  case readArgs args of
-    Nothing ->
-        hPutStrLn stderr $
-          unlines ([ "usage: interactive-tests test# runner#"
-                   , "tests: " ] ++
-                   map (\ (n, test) -> " " ++ show n ++ ". " ++ test) (zip ([1..] :: [Int]) tests) ++
-                   [ "runners: " ] ++
-                   map (\ (n, (runner, _)) -> " " ++ show n ++ ". " ++ runner) (zip ([1..] :: [Int]) runners))
-    Just (test, (s, runner)) ->
-        do hPutStrLn stderr (test ++ " -> " ++ s)
-           runner (shell test)
-    where
-      readArgs :: [String] -> Maybe (String, (String, CreateProcess -> IO ()))
-      readArgs [t, r] =
-          case (readMaybe t, readMaybe r) of
-            (Just t', Just r')
-                | t' >= 1 && t' <= length tests && r' >= 1 && r' <= length runners ->
-                    Just (tests !! (t' - 1), runners !! (r' - 1))
-            _ -> Nothing
-      readArgs _ = Nothing
-
-tests :: [String]
-tests = [ "ls -l /tmp"
-        , "yes | cat -n | while read i; do echo $i; sleep 1; done"
-        , "oneko"
-        , "yes | cat -n" ]
-
-runners  :: [(String, CreateProcess -> IO ())]
-runners = [ ("NoThreads.readCreateProcess Lazy.Text",
-             \ p -> NoThreads.readCreateProcess p mempty >>= \ (b :: [Chunk Data.Text.Lazy.Text]) ->
-                    mapM_ (hPutStrLn stderr . show) b)
-          , ("NoThreads.readCreateProcess Lazy.ByteString",
-             \ p -> NoThreads.readCreateProcess p mempty >>= \ (b :: [Chunk Data.ByteString.Lazy.ByteString]) ->
-                    mapM_ (hPutStrLn stderr . show) b)
-          , ("Threads.readCreateProcess Lazy.Text",
-             \ p -> Threads.readCreateProcess p mempty >>= \ (b :: [Chunk Data.Text.Lazy.Text]) ->
-                    mapM_ (hPutStrLn stderr . show) b)
-          , ("Threads.readCreateProcess Lazy.ByteString",
-             \ p -> Threads.readCreateProcess p mempty >>= \ (b :: [Chunk Data.ByteString.Lazy.ByteString]) ->
-                    mapM_ (hPutStrLn stderr . show) b)
-          ]
diff --git a/tests/Main.hs b/tests/Main.hs
deleted file mode 100644
--- a/tests/Main.hs
+++ /dev/null
@@ -1,252 +0,0 @@
-{-# LANGUAGE CPP, FlexibleInstances, OverloadedStrings, RankNTypes, ScopedTypeVariables, StandaloneDeriving #-}
-module Main where
-
-import Codec.Binary.UTF8.String (encode)
-import Control.Applicative ((<$>))
-import Control.DeepSeq (NFData, force)
-import Control.Exception (SomeException, try)
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Lazy as LB
-import Data.Char (chr, ord)
-import Data.List (isSuffixOf)
-import Data.ListLike as ListLike (ListLike(length, concat, null, groupBy, head, toList, dropWhile, takeWhile, drop, length), ListLikeIO(readFile))
-import Data.Maybe (mapMaybe)
-import Data.Monoid (Monoid(..), (<>))
-import Data.String (IsString(fromString))
-import qualified Data.Text as T
-import qualified Data.Text.Lazy as LT
-import Prelude hiding (length, readFile, head)
-import GHC.IO.Exception
-import System.Exit
-import System.IO (hPutStrLn, stderr)
-import System.Posix.Files (getFileStatus, fileMode, setFileMode, unionFileModes, ownerExecuteMode, groupExecuteMode, otherExecuteMode)
-import System.Process (CreateProcess, proc, ProcessHandle, shell, readProcessWithExitCode)
-import System.Process.ByteString as B
-import System.Process.ByteString.Lazy as LB
-import System.Process.String as S
-import System.Process.Text as T
-import System.Process.Text.Lazy as LT
-import System.Process.Chunks as Chunks
-import System.Process.ListLike.Classes (ListLikeLazyIO, ProcessOutput)
-import System.Process.ListLike.Instances
-import System.Process.ListLike.StrictString () -- the lazy one is the same as lazy text, the strict one is more interesting to test
-import System.Process.ListLike.Read as LL
-import System.Timeout
-import Test.HUnit hiding (path)
-import Text.Regex.Posix ((=~))
-import Text.Printf
-
-instance Show ProcessHandle where
-    show _ = "<processhandle>"
-
-instance Eq ProcessHandle where
-    _ == _ = False
-
-instance Eq SomeException where
-    _ == _ = False
-
-deriving instance Show a => Show (Chunk a)
-
-deriving instance Eq a => Eq (Chunk a)
-
-instance Monoid Test where
-    mempty = TestList []
-    mappend (TestList a) (TestList b) = TestList (a <> b)
-    mappend (TestList a) b = TestList (a <> [b])
-    mappend a (TestList b) = TestList ([a] <> b)
-    mappend a b = TestList [a, b]
-
-type MkTest = forall a c. (Show a, ListLikeLazyIO a c, IsString a, Eq a, Enum c) => String -> a -> Test
-
-testInstances :: MkTest -> Test
-testInstances mkTest = mappend (testCharInstances mkTest) (testWord8Instances mkTest)
-
-testStrictInstances :: MkTest -> Test
-testStrictInstances mkTest = mappend (testStrictCharInstances mkTest) (testStrictWord8Instances mkTest)
-
-testLazyInstances :: MkTest -> Test
-testLazyInstances mkTest = mappend (testLazyCharInstances mkTest) (testLazyWord8Instances mkTest)
-
-testCharInstances :: MkTest -> Test
-testCharInstances mkTest = mappend (testLazyCharInstances mkTest) (testStrictCharInstances mkTest)
-
-testLazyCharInstances :: MkTest -> Test
-testLazyCharInstances mkTest = mkTest "Lazy Text" LT.empty
-
-testStrictCharInstances :: MkTest -> Test
-testStrictCharInstances mkTest = mappend (mkTest "Strict Text" T.empty) (mkTest "String" ("" :: String))
-
-testWord8Instances :: MkTest -> Test
-testWord8Instances mkTest = mappend (testLazyWord8Instances mkTest) (testStrictWord8Instances mkTest)
-
-testLazyWord8Instances :: MkTest -> Test
-testLazyWord8Instances mkTest = mkTest "Lazy ByteString" LB.empty
-
-testStrictWord8Instances :: MkTest -> Test
-testStrictWord8Instances mkTest = mkTest "Strict ByteString" B.empty
-
-main :: IO ()
-main =
-    do chmod "tests/script1.hs"
-       chmod "tests/script4.hs"
-       (c,st) <- runTestText putTextToShowS test1 -- (TestList (versionTests ++ sourcesListTests ++ dependencyTests ++ changesTests))
-       putStrLn (st "")
-       case (failures c) + (errors c) of
-         0 -> return ()
-         _ -> exitFailure
-
-chmod :: FilePath -> IO ()
-chmod path =
-    getFileStatus path >>= \ status ->
-    setFileMode path (foldr unionFileModes (fileMode status) [ownerExecuteMode, groupExecuteMode, otherExecuteMode])
-
-cps :: [CreateProcess]
-cps = [ proc "true" []
-      , proc "false" []
-      , shell "foo"
-      , proc "foo" []
-      , shell "yes | cat -n | head 100"
-      , shell "yes | cat -n"
-      , proc "cat" ["tests/text"]
-      , proc "cat" ["tests/houseisclean.jpg"]
-      , proc "tests/script1.hs" []
-      ]
-
-test1 :: Test
-test1 =
-    TestLabel "test1"
-      (TestList
-       [ TestLabel "[Output]" $
-         TestList
-         [ testInstances
-           (\ s i -> TestLabel s $ TestCase $ do -- We can use a string for the input because the process I/O types
-                       -- are instances of IsString.
-                       result <- LL.readCreateProcessWithExitCode (proc "tests/script4.hs" []) ("a" <> i)
-                       assertEqual "file closed 1" (ExitSuccess, "a", "Read one character: 'a'\n") result)
-         , testInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       result <- LL.readCreateProcessWithExitCode (proc "tests/script4.hs" []) i
-                       assertEqual "file closed 2" (ExitFailure 1, "", "script4.hs: <stdin>: hGetChar: end of file\n") result)
-         , testInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       result <- LL.readCreateProcessWithExitCode (proc "tests/script4.hs" []) ("abcde" <> i)
-                       assertEqual "file closed 3" (ExitSuccess, "a", "Read one character: 'a'\n") result)
-         , testCharInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       b <- LL.readCreateProcessWithExitCode (proc "cat" ["tests/text"]) i
-                       assertEqual
-                         "Unicode"
-                         (ExitSuccess,
-                          -- For Text, assuming your locale is set to utf8, the result is unicode.
-                          "Signed: Baishi laoren \30333\30707\32769\20154, painted in the artist\8217s 87th year.\n",
-                          "")
-                         b)
-         , testWord8Instances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       b <- LL.readCreateProcessWithExitCode (proc "cat" ["tests/text"]) i
-                       assertEqual
-                         "UTF8"
-                         (ExitSuccess,
-                          -- For ByteString we get utf8 encoded text
-                          "Signed: Baishi laoren \231\153\189\231\159\179\232\128\129\228\186\186, painted in the artist\226\128\153s 87th year.\n",
-                          "")
-                         b)
-         , testInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       b <- LL.readCreateProcessWithExitCode (proc "tests/script1.hs" []) i
-                       assertEqual
-                         "ExitFailure"
-                         (ExitFailure 123,
-                          "",
-                          "This is an error message.\n")
-                         b)
-         , testWord8Instances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       (ex, out, err) <- LL.readCreateProcessWithExitCode (proc "cat" ["tests/houseisclean.jpg"]) i
-                       assertEqual "Length" (ExitSuccess, 68668, 0) (ex, length out, length err))
-         , testInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       l <- LL.readCreateProcessWithExitCode (proc "tests/script1.hs" []) i
-                       assertEqual "Error 123" (ExitFailure 123, "", "This is an error message.\n") l)
-         , testWord8Instances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       jpg <- readFile "tests/penguin.jpg"
-                       (code1, pnm, err1) <- LL.readCreateProcessWithExitCode (proc "djpeg" []) (i <> jpg) -- force the return type of readFile to match i
-                       (code2, out2, err2) <- LL.readCreateProcessWithExitCode (proc "pnmfile" []) pnm
-                       assertEqual "pnmfile1"
-                                   (ExitSuccess, mempty, 2192, 27661, "stdin:\tPPM raw, 96 by 96  maxval 255\n")
-                                   (code1, err1, length jpg, length pnm, out2))
-         , testCharInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                     Left e <- try $ do jpg <- readFile "tests/penguin.jpg"
-                                        (code1, pnm, err1) <- LL.readCreateProcessWithExitCode (proc "djpeg" []) (i <> jpg)
-                                        LL.readCreateProcessWithExitCode (proc "pnmfile" []) pnm
-                     assertEqual "pnmfile2" (IOError {ioe_handle = ioe_handle e,
-                                                      ioe_type = InvalidArgument,
-                                                      ioe_location = "hGetContents",
-                                                      ioe_description = "invalid byte sequence",
-                                                      ioe_errno = Nothing,
-                                                      ioe_filename = Just "tests/penguin.jpg"})
-                                      (e :: IOError))
-         , testInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       let n = case isSuffixOf "ByteString" s of
-                                 True -> (50000000 :: Int)
-                                 False -> (5000000 :: Int)
-                           l :: Int
-                           l = case isSuffixOf "ByteString" s of
-                                 True -> (539000002 :: Int)
-                                 False -> (49000001 :: Int)
-                       (ex, out, err) <- LL.readCreateProcessWithExitCode (proc "time" ["bash", "-c", "yes | cat -n | head -n " <> show n]) i
-                       let t = parseTimeOutput err
-                           v = fromInteger (toEnum l) / t
-                       hPutStrLn stderr (printf "%7.2f million chars/second for " (v / 1000000.00) <> s <> " (" <> percentMessage v (expected s) <> ")")
-                       let r = v `about` expected s
-                       assertEqual "5M lines" (ExitSuccess, l, "Within 30% of usual speed") (ex, length out, r))
-         -- This demonstrates lazy generation of process output.  If
-         -- you try this with a strict instance the call to
-         -- readCreateProcessChunks will block indefinitely.
-         , let expected "Lazy Text" = [Stderr "..",Stderr "..",Stderr "..",Stderr "..",Stderr "..",Stderr "..",Stderr "..",Stderr "..",Stderr ".."]
-               expected "Lazy ByteString" = [Stderr "................................",Stderr ".................................",
-                                             Stderr ".................................",Stderr ".................................",
-                                             Stderr "................................",Stderr ".................................",
-                                             Stderr ".................................",Stderr ".................................",
-                                             Stderr "................................"]
-               expected _ = error "unexpected" in
-           testLazyInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       (ProcessHandle _ : chunks) <- LL.readCreateProcess (proc "bash" ["-c", "yes | cat -n"]) i >>= return . take 10 . dotifyChunks 1000 (head (i <> "."))
-                       assertEqual "ten chunks" (expected s) chunks)
-         , testInstances
-           (\ s i -> TestLabel s $ TestCase $ do
-                       hPutStrLn stderr $ "deadlock test for " ++ s
-                       result <- timeout 1000000 $ print =<< LL.readProcessWithExitCode "sleep" ["2h"] i
-                       assertEqual "takano-akio deadlock test" Nothing result)
-         ]
-       ])
-
-expected :: String -> Double
-expected "String" =             23000000.0
-expected "Strict ByteString" = 760000000.0
-expected "Lazy ByteString" =   760000000.0
-expected "Strict Text" =        44000000.0
-expected "Lazy Text" =          47000000.0
-expected s = error $ "Unexpected instance: " <> show s
-
-percentMessage v expected =
-    case v / expected of
-      r | r < 1.0 -> printf "%01.2f pct slower than usual" (100.0 - 100.0 * r)
-      r -> printf "%01.2f pct faster than usual" (100.0 * r - 100.0)
-
-about :: Double -> Double -> String
-about v expected =
-    case v / expected of
-      r | r >= 0.7 && r <= 1.3 -> "Within 30% of usual speed"
-      _ -> percentMessage v expected
-
-parseTimeOutput :: forall a c. (ListLike a c, Enum c) => a -> Double
-parseTimeOutput a =
-    case s =~ ("^(.*)system ([0-9]*):([0-9]*).([0-9]*)elapsed(.*)$" :: String) :: (String, String, String, [String]) of
-      (_, _, _, [_, m, s, h, _]) -> (read m :: Double) * 60.0 + (read s :: Double) + (read ("0." <> h) :: Double)
-    where
-      s = map (chr . fromEnum) $ toList a
