diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,9 @@
+0.10.8.0 Duncan Coutts <duncan@community.haskell.org> May 2016
+
+ * Use Rabin-Karp substring search for `breakSubstring` and `findSubstring`
+ * Improve the performance of `partition` for lazy and strict bytestrings
+ * Added `stripPrefix` and `stripSuffix` for lazy and strict bytestrings
+ * Fix building with ghc 8.0 & base 4.9 (Semigroup etc)
 
 0.10.6.0 Duncan Coutts <duncan@community.haskell.org> Mar 2015
 
diff --git a/Data/ByteString.hs b/Data/ByteString.hs
--- a/Data/ByteString.hs
+++ b/Data/ByteString.hs
@@ -1,8 +1,6 @@
 {-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__
 {-# LANGUAGE MagicHash, UnboxedTuples,
             NamedFieldPuns, BangPatterns #-}
-#endif
 {-# OPTIONS_HADDOCK prune #-}
 #if __GLASGOW_HASKELL__ >= 701
 {-# LANGUAGE Trustworthy #-}
@@ -21,7 +19,7 @@
 -- Maintainer  : dons00@gmail.com, duncan@community.haskell.org
 -- Stability   : stable
 -- Portability : portable
--- 
+--
 -- A time and space-efficient implementation of byte vectors using
 -- packed Word8 arrays, suitable for high performance use, both in terms
 -- of large data quantities, or high speed requirements. Byte vectors
@@ -124,6 +122,8 @@
         groupBy,                -- :: (Word8 -> Word8 -> Bool) -> ByteString -> [ByteString]
         inits,                  -- :: ByteString -> [ByteString]
         tails,                  -- :: ByteString -> [ByteString]
+        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString
+        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString
 
         -- ** Breaking into many substrings
         split,                  -- :: Word8 -> ByteString -> [ByteString]
@@ -219,20 +219,21 @@
                                 ,getContents,getLine,putStr,putStrLn,interact
                                 ,zip,zipWith,unzip,notElem)
 
+#if MIN_VERSION_base(4,7,0)
+import Data.Bits                (finiteBitSize, shiftL, (.|.), (.&.))
+#else
+import Data.Bits                (bitSize, shiftL, (.|.), (.&.))
+#endif
+
 import Data.ByteString.Internal
 import Data.ByteString.Unsafe
 
 import qualified Data.List as List
 
 import Data.Word                (Word8)
-import Data.Maybe               (isJust, listToMaybe)
+import Data.Maybe               (isJust)
 
--- Control.Exception.assert not available in yhc or nhc
-#ifndef __NHC__
 import Control.Exception        (finally, bracket, assert, throwIO)
-#else
-import Control.Exception	(bracket, finally)
-#endif
 import Control.Monad            (when)
 
 import Foreign.C.String         (CString, CStringLen)
@@ -258,15 +259,7 @@
 import Data.Monoid              (Monoid(..))
 #endif
 
-#if !defined(__GLASGOW_HASKELL__)
-import System.IO.Unsafe
-import qualified System.Environment
-import qualified System.IO      (hGetLine)
-import System.IO                (hIsEOF)
-#endif
 
-#if defined(__GLASGOW_HASKELL__)
-
 import System.IO                (hGetBufNonBlocking, hPutBufNonBlocking)
 
 #if MIN_VERSION_base(4,3,0)
@@ -275,7 +268,6 @@
 import System.IO                (hWaitForInput, hIsEOF)
 #endif
 
-#if __GLASGOW_HASKELL__ >= 611
 import Data.IORef
 import GHC.IO.Handle.Internals
 import GHC.IO.Handle.Types
@@ -284,38 +276,15 @@
 import GHC.IO                   (unsafePerformIO, unsafeDupablePerformIO)
 import Data.Char                (ord)
 import Foreign.Marshal.Utils    (copyBytes)
-#else
-import System.IO.Error          (isEOFError)
-import GHC.IOBase
-import GHC.Handle
-#endif
 
 import GHC.Prim                 (Word#)
 import GHC.Base                 (build)
 import GHC.Word hiding (Word8)
 
-#endif
-
--- An alternative to Control.Exception (assert) for nhc98
-#ifdef __NHC__
-
-import System.IO (Handle)
-
-#define assert  assertS "__FILE__ : __LINE__"
-assertS :: String -> Bool -> a -> a
-assertS _ True  = id
-assertS s False = error ("assertion failed at "++s)
-
--- An alternative to hWaitForInput
-hWaitForInput :: Handle -> Int -> IO ()
-hWaitForInput _ _ = return ()
-#endif
-
-#ifndef __GLASGOW_HASKELL__
-unsafeDupablePerformIO = unsafePerformIO
+#if !(MIN_VERSION_base(4,7,0))
+finiteBitSize = bitSize
 #endif
 
-
 -- -----------------------------------------------------------------------------
 -- Introducing and eliminating 'ByteString's
 
@@ -339,17 +308,17 @@
 --
 -- is compiled to:
 --
---  case mallocByteString 2 of 
---      ForeignPtr f internals -> 
---           case writeWord8OffAddr# f 0 255 of _ -> 
+--  case mallocByteString 2 of
+--      ForeignPtr f internals ->
+--           case writeWord8OffAddr# f 0 255 of _ ->
 --           case writeWord8OffAddr# f 0 127 of _ ->
---           case eqAddr# f f of 
---                  False -> case compare (GHC.Prim.plusAddr# f 0) 
+--           case eqAddr# f f of
+--                  False -> case compare (GHC.Prim.plusAddr# f 0)
 --                                        (GHC.Prim.plusAddr# f 0)
 --
 --
 
--- | /O(n)/ Convert a '[Word8]' into a 'ByteString'. 
+-- | /O(n)/ Convert a '[Word8]' into a 'ByteString'.
 --
 -- For applications with large numbers of string literals, pack can be a
 -- bottleneck. In such cases, consider using packAddress (GHC only).
@@ -358,10 +327,6 @@
 
 -- | /O(n)/ Converts a 'ByteString' to a '[Word8]'.
 unpack :: ByteString -> [Word8]
-#if !defined(__GLASGOW_HASKELL__)
-unpack = unpackBytes
-#else
-
 unpack bs = build (unpackFoldr bs)
 {-# INLINE unpack #-}
 
@@ -377,8 +342,6 @@
     unpackFoldr bs (:) [] = unpackBytes bs
  #-}
 
-#endif
-
 -- ---------------------------------------------------------------------
 -- Basic interface
 
@@ -792,11 +755,11 @@
     | otherwise = unsafeCreate w $ \ptr ->
                       memset ptr c (fromIntegral w) >> return ()
 
--- | /O(n)/, where /n/ is the length of the result.  The 'unfoldr' 
--- function is analogous to the List \'unfoldr\'.  'unfoldr' builds a 
--- ByteString from a seed value.  The function takes the element and 
--- returns 'Nothing' if it is done producing the ByteString or returns 
--- 'Just' @(a,b)@, in which case, @a@ is the next byte in the string, 
+-- | /O(n)/, where /n/ is the length of the result.  The 'unfoldr'
+-- function is analogous to the List \'unfoldr\'.  'unfoldr' builds a
+-- ByteString from a seed value.  The function takes the element and
+-- returns 'Nothing' if it is done producing the ByteString or returns
+-- 'Just' @(a,b)@, in which case, @a@ is the next byte in the string,
 -- and @b@ is the seed value for further production.
 --
 -- Examples:
@@ -887,23 +850,31 @@
 --
 break :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
 break p ps = case findIndexOrEnd p ps of n -> (unsafeTake n ps, unsafeDrop n ps)
-#if __GLASGOW_HASKELL__ 
 {-# INLINE [1] break #-}
-#endif
 
+-- See bytestring #70
+#if MIN_VERSION_base(4,9,0)
 {-# RULES
-"ByteString specialise break (x==)" forall x.
-    break ((==) x) = breakByte x
-"ByteString specialise break (==x)" forall x.
-    break (==x) = breakByte x
+"ByteString specialise break (x ==)" forall x.
+    break (x `eqWord8`) = breakByte x
+"ByteString specialise break (== x)" forall x.
+    break (`eqWord8` x) = breakByte x
   #-}
+#else
+{-# RULES
+"ByteString specialise break (x ==)" forall x.
+    break (x ==) = breakByte x
+"ByteString specialise break (== x)" forall x.
+    break (== x) = breakByte x
+  #-}
+#endif
 
 -- INTERNAL:
 
 -- | 'breakByte' breaks its ByteString argument at the first occurence
 -- of the specified byte. It is more efficient than 'break' as it is
 -- implemented with @memchr(3)@. I.e.
--- 
+--
 -- > break (=='c') "abcd" == breakByte 'c' "abcd"
 --
 breakByte :: Word8 -> ByteString -> (ByteString, ByteString)
@@ -914,7 +885,7 @@
 {-# DEPRECATED breakByte "It is an internal function and should never have been exported. Use 'break (== x)' instead. (There are rewrite rules that handle this special case of 'break'.)" #-}
 
 -- | 'breakEnd' behaves like 'break' but from the end of the 'ByteString'
--- 
+--
 -- breakEnd p == spanEnd (not.p)
 breakEnd :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
 breakEnd  p ps = splitAt (findFromEndUntil p ps) ps
@@ -923,9 +894,7 @@
 -- equivalent to @('takeWhile' p xs, 'dropWhile' p xs)@
 span :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
 span p ps = break (not . p) ps
-#if __GLASGOW_HASKELL__
 {-# INLINE [1] span #-}
-#endif
 
 -- | 'spanByte' breaks its ByteString argument at the first
 -- occurence of a byte other than its argument. It is more efficient
@@ -946,12 +915,22 @@
                                   else go p (i+1)
 {-# INLINE spanByte #-}
 
+-- See bytestring #70
+#if MIN_VERSION_base(4,9,0)
 {-# RULES
-"ByteString specialise span (x==)" forall x.
-    span ((==) x) = spanByte x
-"ByteString specialise span (==x)" forall x.
-    span (==x) = spanByte x
+"ByteString specialise span (x ==)" forall x.
+    span (x `eqWord8`) = spanByte x
+"ByteString specialise span (== x)" forall x.
+    span (`eqWord8` x) = spanByte x
   #-}
+#else
+{-# RULES
+"ByteString specialise span (x ==)" forall x.
+    span (x ==) = spanByte x
+"ByteString specialise span (== x)" forall x.
+    span (== x) = spanByte x
+  #-}
+#endif
 
 -- | 'spanEnd' behaves like 'span' but from the end of the 'ByteString'.
 -- We have
@@ -961,8 +940,8 @@
 -- and
 --
 -- > spanEnd (not . isSpace) ps
--- >    == 
--- > let (x,y) = span (not.isSpace) (reverse ps) in (reverse y, reverse x) 
+-- >    ==
+-- > let (x,y) = span (not.isSpace) (reverse ps) in (reverse y, reverse x)
 --
 spanEnd :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
 spanEnd  p ps = splitAt (findFromEndUntil (not.p) ps) ps
@@ -976,8 +955,6 @@
 -- > splitWith (=='a') []        == []
 --
 splitWith :: (Word8 -> Bool) -> ByteString -> [ByteString]
-
-#if defined(__GLASGOW_HASKELL__)
 splitWith _pred (PS _  _   0) = []
 splitWith pred_ (PS fp off len) = splitWith0 pred# off len fp
   where pred# c# = pred_ (W8# c#)
@@ -1003,27 +980,18 @@
                    else splitLoop pred' p (idx'+1) off' len' fp'
 {-# INLINE splitWith #-}
 
-#else
-splitWith _ (PS _ _ 0) = []
-splitWith p ps = loop p ps
-    where
-        loop !q !qs = if null rest then [chunk]
-                                   else chunk : loop q (unsafeTail rest)
-            where (chunk,rest) = break q qs
-#endif
-
 -- | /O(n)/ Break a 'ByteString' into pieces separated by the byte
 -- argument, consuming the delimiter. I.e.
 --
 -- > split '\n' "a\nb\nd\ne" == ["a","b","d","e"]
 -- > split 'a'  "aXaXaXa"    == ["","X","X","X",""]
 -- > split 'x'  "x"          == ["",""]
--- 
+--
 -- and
 --
 -- > intercalate [c] . split c == id
 -- > split == splitWith . (==)
--- 
+--
 -- As for all splitting functions in this library, this function does
 -- not copy the substrings, it just constructs new 'ByteStrings' that
 -- are slices of the original.
@@ -1053,7 +1021,7 @@
 -- > group "Mississippi" = ["M","i","ss","i","ss","i","pp","i"]
 --
 -- It is a special case of 'groupBy', which allows the programmer to
--- supply their own equality test. It is about 40% faster than 
+-- supply their own equality test. It is about 40% faster than
 -- /groupBy (==)/
 group :: ByteString -> [ByteString]
 group xs
@@ -1110,7 +1078,7 @@
 
 -- | /O(n)/ The 'elemIndex' function returns the index of the first
 -- element in the given 'ByteString' which is equal to the query
--- element, or 'Nothing' if there is no such element. 
+-- element, or 'Nothing' if there is no such element.
 -- This implementation uses memchr(3).
 elemIndex :: Word8 -> ByteString -> Maybe Int
 elemIndex c (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do
@@ -1124,7 +1092,7 @@
 -- element, or 'Nothing' if there is no such element. The following
 -- holds:
 --
--- > elemIndexEnd c xs == 
+-- > elemIndexEnd c xs ==
 -- > (-) (length xs - 1) `fmap` elemIndex c (reverse xs)
 --
 elemIndexEnd :: Word8 -> ByteString -> Maybe Int
@@ -1259,14 +1227,42 @@
 -- > partition p bs == (filter p xs, filter (not . p) xs)
 --
 partition :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
-partition p bs = (filter p bs, filter (not . p) bs)
---TODO: use a better implementation
+partition f s = unsafeDupablePerformIO $
+    do fp' <- mallocByteString len
+       withForeignPtr fp' $ \p ->
+           do let end = p `plusPtr` (len - 1)
+              mid <- sep 0 p end
+              rev mid end
+              let i = mid `minusPtr` p
+              return (PS fp' 0 i,
+                      PS fp' i (len - i))
+  where
+    len  = length s
+    incr = (`plusPtr` 1)
+    decr = (`plusPtr` (-1))
 
--- ---------------------------------------------------------------------
--- Searching for substrings
+    sep !i !p1 !p2
+       | i == len  = return p1
+       | f w       = do poke p1 w
+                        sep (i + 1) (incr p1) p2
+       | otherwise = do poke p2 w
+                        sep (i + 1) p1 (decr p2)
+      where
+        w = s `unsafeIndex` i
 
--- | /O(n)/ The 'isPrefixOf' function takes two ByteStrings and returns 'True'
--- iff the first is a prefix of the second.
+    rev !p1 !p2
+      | p1 >= p2  = return ()
+      | otherwise = do a <- peek p1
+                       b <- peek p2
+                       poke p1 b
+                       poke p2 a
+                       rev (incr p1) (decr p2)
+
+-- --------------------------------------------------------------------
+-- Sarching for substrings
+
+-- |/O(n)/ The 'isPrefixOf' function takes two ByteStrings and returns 'True'
+-- if the first is a prefix of the second.
 isPrefixOf :: ByteString -> ByteString -> Bool
 isPrefixOf (PS x1 s1 l1) (PS x2 s2 l2)
     | l1 == 0   = True
@@ -1276,9 +1272,17 @@
             i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2) (fromIntegral l1)
             return $! i == 0
 
+-- | /O(n)/ The 'stripPrefix' function takes two ByteStrings and returns 'Just'
+-- the remainder of the second iff the first is its prefix, and otherwise
+-- 'Nothing'.
+stripPrefix :: ByteString -> ByteString -> Maybe ByteString
+stripPrefix bs1@(PS _ _ l1) bs2
+   | bs1 `isPrefixOf` bs2 = Just (unsafeDrop l1 bs2)
+   | otherwise = Nothing
+
 -- | /O(n)/ The 'isSuffixOf' function takes two ByteStrings and returns 'True'
 -- iff the first is a suffix of the second.
--- 
+--
 -- The following holds:
 --
 -- > isSuffixOf x y == reverse x `isPrefixOf` reverse y
@@ -1294,6 +1298,14 @@
             i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2 `plusPtr` (l2 - l1)) (fromIntegral l1)
             return $! i == 0
 
+-- | /O(n)/ The 'stripSuffix' function takes two ByteStrings and returns 'Just'
+-- the remainder of the second iff the first is its suffix, and otherwise
+-- 'Nothing'.
+stripSuffix :: ByteString -> ByteString -> Maybe ByteString
+stripSuffix bs1@(PS _ _ l1) bs2@(PS _ _ l2)
+   | bs1 `isSuffixOf` bs2 = Just (unsafeTake (l2 - l1) bs2)
+   | otherwise = Nothing
+
 -- | Check whether one string is a substring of another. @isInfixOf
 -- p s@ is equivalent to @not (null (findSubstrings p s))@.
 isInfixOf :: ByteString -> ByteString -> Bool
@@ -1320,31 +1332,80 @@
 -- >     where (h,t) = breakSubstring x y
 --
 -- To skip to the first occurence of a string:
--- 
--- > snd (breakSubstring x y) 
 --
+-- > snd (breakSubstring x y)
+--
 -- To take the parts of a string before a delimiter:
 --
--- > fst (breakSubstring x y) 
+-- > fst (breakSubstring x y)
 --
+-- Note that calling `breakSubstring x` does some preprocessing work, so
+-- you should avoid unnecessarily duplicating breakSubstring calls with the same
+-- pattern.
+--
 breakSubstring :: ByteString -- ^ String to search for
                -> ByteString -- ^ String to search in
                -> (ByteString,ByteString) -- ^ Head and tail of string broken at substring
-
-breakSubstring pat src = search 0 src
+breakSubstring pat =
+  case lp of
+    0 -> \src -> (empty,src)
+    1 -> breakByte (unsafeHead pat)
+    _ -> if lp * 8 <= finiteBitSize (0 :: Word)
+             then shift
+             else karpRabin
   where
-    search !n !s
-        | null s             = (src,empty)      -- not found
-        | pat `isPrefixOf` s = (take n src,s)
-        | otherwise          = search (n+1) (unsafeTail s)
+    unsafeSplitAt i s = (unsafeTake i s, unsafeDrop i s)
+    lp                = length pat
+    karpRabin :: ByteString -> (ByteString, ByteString)
+    karpRabin src
+        | length src < lp = (src,empty)
+        | otherwise = search (rollingHash $ unsafeTake lp src) lp
+      where
+        k           = 2891336453 :: Word32
+        rollingHash = foldl' (\h b -> h * k + fromIntegral b) 0
+        hp          = rollingHash pat
+        m           = k ^ lp
+        get = fromIntegral . unsafeIndex src
+        search !hs !i
+            | hp == hs && pat == unsafeTake lp b = u
+            | length src <= i                    = (src,empty) -- not found
+            | otherwise                          = search hs' (i + 1)
+          where
+            u@(_, b) = unsafeSplitAt (i - lp) src
+            hs' = hs * k +
+                  get i -
+                  m * get (i - lp)
+    {-# INLINE karpRabin #-}
 
+    shift :: ByteString -> (ByteString, ByteString)
+    shift !src
+        | length src < lp = (src,empty)
+        | otherwise       = search (intoWord $ unsafeTake lp src) lp
+      where
+        intoWord :: ByteString -> Word
+        intoWord = foldl' (\w b -> (w `shiftL` 8) .|. fromIntegral b) 0
+        wp   = intoWord pat
+        mask = (1 `shiftL` (8 * lp)) - 1
+        search !w !i
+            | w == wp         = unsafeSplitAt (i - lp) src
+            | length src <= i = (src, empty)
+            | otherwise       = search w' (i + 1)
+          where
+            b  = fromIntegral (unsafeIndex src i)
+            w' = mask .&. ((w `shiftL` 8) .|. b)
+    {-# INLINE shift #-}
+
 -- | Get the first index of a substring in another string,
 --   or 'Nothing' if the string is not found.
 --   @findSubstring p s@ is equivalent to @listToMaybe (findSubstrings p s)@.
 findSubstring :: ByteString -- ^ String to search for.
               -> ByteString -- ^ String to seach in.
               -> Maybe Int
-findSubstring f i = listToMaybe (findSubstrings f i)
+findSubstring pat src
+    | null pat && null src = Just 0
+    | null b = Nothing
+    | otherwise = Just (length a)
+  where (a, b) = breakSubstring pat src
 
 {-# DEPRECATED findSubstring "findSubstring is deprecated in favour of breakSubstring." #-}
 
@@ -1354,14 +1415,18 @@
 findSubstrings :: ByteString -- ^ String to search for.
                -> ByteString -- ^ String to seach in.
                -> [Int]
-findSubstrings pat str
-    | null pat         = [0 .. length str]
-    | otherwise        = search 0 str
+findSubstrings pat src
+    | null pat        = [0 .. ls]
+    | otherwise       = search 0
   where
-    search !n !s
-        | null s             = []
-        | pat `isPrefixOf` s = n : search (n+1) (unsafeTail s)
-        | otherwise          =     search (n+1) (unsafeTail s)
+    lp = length pat
+    ls = length src
+    search !n
+        | (n > ls - lp) || null b = []
+        | otherwise = let k = n + length a
+                      in  k : search (k + lp)
+      where
+        (a, b) = breakSubstring pat (unsafeDrop n src)
 
 {-# DEPRECATED findSubstrings "findSubstrings is deprecated in favour of breakSubstring." #-}
 
@@ -1380,7 +1445,7 @@
 -- | 'zipWith' generalises 'zip' by zipping with the function given as
 -- the first argument, instead of a tupling function.  For example,
 -- @'zipWith' (+)@ is applied to two ByteStrings to produce the list of
--- corresponding sums. 
+-- corresponding sums.
 zipWith :: (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
 zipWith f ps qs
     | null ps || null qs = []
@@ -1507,12 +1572,12 @@
 
 ------------------------------------------------------------------------
 
--- | /O(n)/ Make a copy of the 'ByteString' with its own storage. 
+-- | /O(n)/ Make a copy of the 'ByteString' with its own storage.
 -- This is mainly useful to allow the rest of the data pointed
 -- to by the 'ByteString' to be garbage collected, for example
--- if a large string has been read in, and only a small part of it 
+-- if a large string has been read in, and only a small part of it
 -- is needed in the rest of the program.
--- 
+--
 copy :: ByteString -> ByteString
 copy (PS x s l) = unsafeCreate l $ \p -> withForeignPtr x $ \f ->
     memcpy p (f `plusPtr` s) (fromIntegral l)
@@ -1527,13 +1592,6 @@
 -- | Read a line from a handle
 
 hGetLine :: Handle -> IO ByteString
-
-#if !defined(__GLASGOW_HASKELL__)
-
-hGetLine h = System.IO.hGetLine h >>= return . pack . P.map c2w
-
-#elif __GLASGOW_HASKELL__ >= 611
-
 hGetLine h =
   wantReadableHandle_ "Data.ByteString.hGetLine" h $
     \ h_@Handle__{haByteBuffer} -> do
@@ -1588,72 +1646,6 @@
  where
    len = end - start
 
-#else
--- GHC 6.10 and older, pre-Unicode IO library
-
-hGetLine h = wantReadableHandle "Data.ByteString.hGetLine" h $ \ handle_ -> do
-    case haBufferMode handle_ of
-       NoBuffering -> error "no buffering"
-       _other      -> hGetLineBuffered handle_
-
- where
-    hGetLineBuffered handle_ = do
-        let ref = haBuffer handle_
-        buf <- readIORef ref
-        hGetLineBufferedLoop handle_ ref buf 0 []
-
-    hGetLineBufferedLoop handle_ ref
-            buf@Buffer{ bufRPtr=r, bufWPtr=w, bufBuf=raw } !len xss = do
-        off <- findEOL r w raw
-        let new_len = len + off - r
-        xs <- mkPS raw r off
-
-      -- if eol == True, then off is the offset of the '\n'
-      -- otherwise off == w and the buffer is now empty.
-        if off /= w
-            then do if (w == off + 1)
-                            then writeIORef ref buf{ bufRPtr=0, bufWPtr=0 }
-                            else writeIORef ref buf{ bufRPtr = off + 1 }
-                    mkBigPS new_len (xs:xss)
-            else do
-                 maybe_buf <- maybeFillReadBuffer (haFD handle_) True (haIsStream handle_)
-                                    buf{ bufWPtr=0, bufRPtr=0 }
-                 case maybe_buf of
-                    -- Nothing indicates we caught an EOF, and we may have a
-                    -- partial line to return.
-                    Nothing -> do
-                         writeIORef ref buf{ bufRPtr=0, bufWPtr=0 }
-                         if new_len > 0
-                            then mkBigPS new_len (xs:xss)
-                            else ioe_EOF
-                    Just new_buf ->
-                         hGetLineBufferedLoop handle_ ref new_buf new_len (xs:xss)
-
-    -- find the end-of-line character, if there is one
-    findEOL r w raw
-        | r == w = return w
-        | otherwise =  do
-            (c,r') <- readCharFromBuffer raw r
-            if c == '\n'
-                then return r -- NB. not r': don't include the '\n'
-                else findEOL r' w raw
-
-    maybeFillReadBuffer fd is_line is_stream buf = catch
-        (do buf' <- fillReadBuffer fd is_line is_stream buf
-            return (Just buf'))
-        (\e -> if isEOFError e then return Nothing else ioError e)
-
--- TODO, rewrite to use normal memcpy
-mkPS :: RawBuffer -> Int -> Int -> IO ByteString
-mkPS buf start end =
-    let len = end - start
-    in create len $ \p -> do
-        memcpy_ptr_baoff p buf (fromIntegral start) (fromIntegral len)
-        return ()
-
-memcpy_ptr_baoff dst src src_off sz = memcpy dst (src+src_off) sz
-#endif
-
 mkBigPS :: Int -> [ByteString] -> IO ByteString
 mkBigPS _ [ps] = return ps
 mkBigPS _ pss = return $! concat (P.reverse pss)
@@ -1675,15 +1667,11 @@
 -- function does not work correctly; it behaves identically to 'hPut'.
 --
 hPutNonBlocking :: Handle -> ByteString -> IO ByteString
-#if defined(__GLASGOW_HASKELL__)
 hPutNonBlocking h bs@(PS ps s l) = do
   bytesWritten <- withForeignPtr ps $ \p-> hPutBufNonBlocking h (p `plusPtr` s) l
   return $! drop bytesWritten bs
-#else
-hPutNonBlocking h bs = hPut h bs >> return empty
-#endif
 
--- | A synonym for @hPut@, for compatibility 
+-- | A synonym for @hPut@, for compatibility
 hPutStr :: Handle -> ByteString -> IO ()
 hPutStr = hPut
 
@@ -1713,7 +1701,7 @@
 
 -- | Read a 'ByteString' directly from the specified 'Handle'.  This
 -- is far more efficient than reading the characters into a 'String'
--- and then using 'pack'. First argument is the Handle to read from, 
+-- and then using 'pack'. First argument is the Handle to read from,
 -- and the second is the number of bytes to read. It returns the bytes
 -- read, up to n, or 'empty' if EOF has been reached.
 --
@@ -1737,14 +1725,10 @@
 -- function does not work correctly; it behaves identically to 'hGet'.
 --
 hGetNonBlocking :: Handle -> Int -> IO ByteString
-#if defined(__GLASGOW_HASKELL__)
 hGetNonBlocking h i
     | i >  0    = createAndTrim i $ \p -> hGetBufNonBlocking h p i
     | i == 0    = return empty
     | otherwise = illegalBufferSize h "hGetNonBlocking" i
-#else
-hGetNonBlocking = hGet
-#endif
 
 -- | Like 'hGet', except that a shorter 'ByteString' may be returned
 -- if there are not enough bytes immediately available to satisfy the
@@ -1884,12 +1868,7 @@
 {-# NOINLINE moduleError #-}
 
 moduleErrorIO :: String -> String -> IO a
-moduleErrorIO fun msg =
-#if MIN_VERSION_base(4,0,0)
-    throwIO . userError $ moduleErrorMsg fun msg
-#else
-    throwIO . IOException . userError $ moduleErrorMsg fun msg
-#endif
+moduleErrorIO fun msg = throwIO . userError $ moduleErrorMsg fun msg
 {-# NOINLINE moduleErrorIO #-}
 
 moduleErrorMsg :: String -> String -> String
diff --git a/Data/ByteString/Builder/ASCII.hs b/Data/ByteString/Builder/ASCII.hs
--- a/Data/ByteString/Builder/ASCII.hs
+++ b/Data/ByteString/Builder/ASCII.hs
@@ -85,7 +85,7 @@
 import           Foreign
 
 
-#if defined(__GLASGOW_HASKELL__) && defined(INTEGER_GMP)
+#if defined(INTEGER_GMP)
 
 #if !(MIN_VERSION_base(4,8,0))
 import           Data.Monoid (mappend)
@@ -304,7 +304,7 @@
 -- Fast decimal 'Integer' encoding.
 ------------------------------------------------------------------------------
 
-#if defined(__GLASGOW_HASKELL__) && defined(INTEGER_GMP)
+#if defined(INTEGER_GMP)
 -- An optimized version of the integer serialization code
 -- in blaze-textual (c) 2011 MailRank, Inc. Bryan O'Sullivan
 -- <bos@mailrank.com>. It is 2.5x faster on Int-sized integers and 4.5x faster
diff --git a/Data/ByteString/Builder/Internal.hs b/Data/ByteString/Builder/Internal.hs
--- a/Data/ByteString/Builder/Internal.hs
+++ b/Data/ByteString/Builder/Internal.hs
@@ -130,11 +130,13 @@
 
 import           Control.Arrow (second)
 
+#if MIN_VERSION_base(4,9,0)
+import           Data.Semigroup (Semigroup((<>)))
+#endif
 #if !(MIN_VERSION_base(4,8,0))
 import           Data.Monoid
-import           Control.Applicative (Applicative(..))
+import           Control.Applicative (Applicative(..),(<$>))
 #endif
-import           Control.Applicative ((<$>))
 
 import qualified Data.ByteString               as S
 import qualified Data.ByteString.Internal      as S
@@ -400,11 +402,21 @@
 append :: Builder -> Builder -> Builder
 append (Builder b1) (Builder b2) = Builder $ b1 . b2
 
+#if MIN_VERSION_base(4,9,0)
+instance Semigroup Builder where
+  {-# INLINE (<>) #-}
+  (<>) = append
+#endif
+
 instance Monoid Builder where
   {-# INLINE mempty #-}
   mempty = empty
   {-# INLINE mappend #-}
+#if MIN_VERSION_base(4,9,0)
+  mappend = (<>)
+#else
   mappend = append
+#endif
   {-# INLINE mconcat #-}
   mconcat = foldr mappend mempty
 
@@ -490,21 +502,18 @@
   pure x = Put $ \k -> k x
   {-# INLINE (<*>) #-}
   Put f <*> Put a = Put $ \k -> f (\f' -> a (\a' -> k (f' a')))
-#if MIN_VERSION_base(4,2,0)
   {-# INLINE (<*) #-}
   (<*) = ap_l
   {-# INLINE (*>) #-}
   (*>) = ap_r
-#endif
 
 instance Monad Put where
   {-# INLINE return #-}
-  return x = Put $ \k -> k x
+  return = pure
   {-# INLINE (>>=) #-}
   Put m >>= f = Put $ \k -> m (\m' -> unPut (f m') k)
   {-# INLINE (>>) #-}
-  (>>) = ap_r
-
+  (>>) = (*>)
 
 -- Conversion between Put and Builder
 -------------------------------------
diff --git a/Data/ByteString/Builder/Prim/Internal/UncheckedShifts.hs b/Data/ByteString/Builder/Prim/Internal/UncheckedShifts.hs
--- a/Data/ByteString/Builder/Prim/Internal/UncheckedShifts.hs
+++ b/Data/ByteString/Builder/Prim/Internal/UncheckedShifts.hs
@@ -18,7 +18,7 @@
 -- These functions are undefined when the amount being shifted by is
 -- greater than the size in bits of a machine Int#.-
 --
-#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
+#if !defined(__HADDOCK__)
 #include "MachDeps.h"
 #endif
 
@@ -32,7 +32,7 @@
   ) where
 
 
-#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
+#if !defined(__HADDOCK__)
 import GHC.Base
 import GHC.Word (Word32(..),Word16(..),Word64(..))
 
@@ -70,19 +70,12 @@
 shiftr_w w s = fromIntegral $ (`shiftr_w64` s) $ fromIntegral w
 #endif
 
-#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
+#if !defined(__HADDOCK__)
 shiftr_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftRL#`   i)
 shiftr_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftRL#`   i)
 
 #if WORD_SIZE_IN_BITS < 64
 shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL64#` i)
-
-#if __GLASGOW_HASKELL__ <= 606
--- Exported by GHC.Word in GHC 6.8 and higher
-foreign import ccall unsafe "stg_uncheckedShiftRL64"
-    uncheckedShiftRL64#     :: Word64# -> Int# -> Word64#
-#endif
-
 #else
 shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL#` i)
 #endif
diff --git a/Data/ByteString/Char8.hs b/Data/ByteString/Char8.hs
--- a/Data/ByteString/Char8.hs
+++ b/Data/ByteString/Char8.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE CPP, BangPatterns #-}
-#if __GLASGOW_HASKELL__
 {-# LANGUAGE MagicHash, UnboxedTuples #-}
-#endif
 {-# OPTIONS_HADDOCK prune #-}
 #if __GLASGOW_HASKELL__ >= 701
 {-# LANGUAGE Trustworthy #-}
@@ -24,9 +22,9 @@
 -- More specifically these byte strings are taken to be in the
 -- subset of Unicode covered by code points 0-255. This covers
 -- Unicode Basic Latin, Latin-1 Supplement and C0+C1 Controls.
--- 
--- See: 
 --
+-- See:
+--
 --  * <http://www.unicode.org/charts/>
 --
 --  * <http://www.unicode.org/charts/PDF/U0000.pdf>
@@ -126,6 +124,8 @@
         groupBy,                -- :: (Char -> Char -> Bool) -> ByteString -> [ByteString]
         inits,                  -- :: ByteString -> [ByteString]
         tails,                  -- :: ByteString -> [ByteString]
+        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString
+        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString
 
         -- ** Breaking into many substrings
         split,                  -- :: Char -> ByteString -> [ByteString]
@@ -135,7 +135,7 @@
         lines,                  -- :: ByteString -> [ByteString]
         words,                  -- :: ByteString -> [ByteString]
         unlines,                -- :: [ByteString] -> ByteString
-        unwords,                -- :: ByteString -> [ByteString]
+        unwords,                -- :: [ByteString] -> ByteString
 
         -- * Predicates
         isPrefixOf,             -- :: ByteString -> ByteString -> Bool
@@ -244,6 +244,7 @@
                        ,inits,tails,reverse,transpose
                        ,concat,take,drop,splitAt,intercalate
                        ,sort,isPrefixOf,isSuffixOf,isInfixOf
+                       ,stripPrefix,stripSuffix
                        ,findSubstring,findSubstrings,breakSubstring,copy,group
 
                        ,getLine, getContents, putStr, interact
@@ -256,14 +257,14 @@
 import Data.ByteString.Internal
 
 import Data.Char    ( isSpace )
+#if MIN_VERSION_base(4,9,0)
+-- See bytestring #70
+import GHC.Char (eqChar)
+#endif
 import qualified Data.List as List (intersperse)
 
 import System.IO    (Handle,stdout,openBinaryFile,hClose,hFileSize,IOMode(..))
-#ifndef __NHC__
 import Control.Exception        (bracket)
-#else
-import IO			(bracket)
-#endif
 import Foreign
 
 
@@ -462,11 +463,11 @@
 replicate w = B.replicate w . c2w
 {-# INLINE replicate #-}
 
--- | /O(n)/, where /n/ is the length of the result.  The 'unfoldr' 
--- function is analogous to the List \'unfoldr\'.  'unfoldr' builds a 
--- ByteString from a seed value.  The function takes the element and 
--- returns 'Nothing' if it is done producing the ByteString or returns 
--- 'Just' @(a,b)@, in which case, @a@ is the next character in the string, 
+-- | /O(n)/, where /n/ is the length of the result.  The 'unfoldr'
+-- function is analogous to the List \'unfoldr\'.  'unfoldr' builds a
+-- ByteString from a seed value.  The function takes the element and
+-- returns 'Nothing' if it is done producing the ByteString or returns
+-- 'Just' @(a,b)@, in which case, @a@ is the next character in the string,
 -- and @b@ is the seed value for further production.
 --
 -- Examples:
@@ -499,9 +500,7 @@
 -- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@.
 dropWhile :: (Char -> Bool) -> ByteString -> ByteString
 dropWhile f = B.dropWhile (f . w2c)
-#if defined(__GLASGOW_HASKELL__)
 {-# INLINE [1] dropWhile #-}
-#endif
 
 {-# RULES
 "ByteString specialise dropWhile isSpace -> dropSpace"
@@ -511,23 +510,31 @@
 -- | 'break' @p@ is equivalent to @'span' ('not' . p)@.
 break :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
 break f = B.break (f . w2c)
-#if defined(__GLASGOW_HASKELL__)
 {-# INLINE [1] break #-}
-#endif
 
+-- See bytestring #70
+#if MIN_VERSION_base(4,9,0)
 {-# RULES
 "ByteString specialise break (x==)" forall x.
-    break ((==) x) = breakChar x
+    break (x `eqChar`) = breakChar x
 "ByteString specialise break (==x)" forall x.
-    break (==x) = breakChar x
+    break (`eqChar` x) = breakChar x
   #-}
+#else
+{-# RULES
+"ByteString specialise break (x==)" forall x.
+    break (x ==) = breakChar x
+"ByteString specialise break (==x)" forall x.
+    break (== x) = breakChar x
+  #-}
+#endif
 
 -- INTERNAL:
 
 -- | 'breakChar' breaks its ByteString argument at the first occurence
 -- of the specified char. It is more efficient than 'break' as it is
 -- implemented with @memchr(3)@. I.e.
--- 
+--
 -- > break (=='c') "abcd" == breakChar 'c' "abcd"
 --
 breakChar :: Char -> ByteString -> (ByteString, ByteString)
@@ -550,54 +557,32 @@
 -- and
 --
 -- > spanEnd (not . isSpace) ps
--- >    == 
--- > let (x,y) = span (not.isSpace) (reverse ps) in (reverse y, reverse x) 
+-- >    ==
+-- > let (x,y) = span (not.isSpace) (reverse ps) in (reverse y, reverse x)
 --
 spanEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
 spanEnd f = B.spanEnd (f . w2c)
 {-# INLINE spanEnd #-}
 
 -- | 'breakEnd' behaves like 'break' but from the end of the 'ByteString'
--- 
+--
 -- breakEnd p == spanEnd (not.p)
 breakEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
 breakEnd f = B.breakEnd (f . w2c)
 {-# INLINE breakEnd #-}
 
-{-
--- | 'breakChar' breaks its ByteString argument at the first occurence
--- of the specified Char. It is more efficient than 'break' as it is
--- implemented with @memchr(3)@. I.e.
--- 
--- > break (=='c') "abcd" == breakChar 'c' "abcd"
---
-breakChar :: Char -> ByteString -> (ByteString, ByteString)
-breakChar = B.breakByte . c2w
-{-# INLINE breakChar #-}
-
--- | 'spanChar' breaks its ByteString argument at the first
--- occurence of a Char other than its argument. It is more efficient
--- than 'span (==)'
---
--- > span  (=='c') "abcd" == spanByte 'c' "abcd"
---
-spanChar :: Char -> ByteString -> (ByteString, ByteString)
-spanChar = B.spanByte . c2w
-{-# INLINE spanChar #-}
--}
-
 -- | /O(n)/ Break a 'ByteString' into pieces separated by the byte
 -- argument, consuming the delimiter. I.e.
 --
 -- > split '\n' "a\nb\nd\ne" == ["a","b","d","e"]
 -- > split 'a'  "aXaXaXa"    == ["","X","X","X",""]
 -- > split 'x'  "x"          == ["",""]
--- 
+--
 -- and
 --
 -- > intercalate [c] . split c == id
 -- > split == splitWith . (==)
--- 
+--
 -- As for all splitting functions in this library, this function does
 -- not copy the substrings, it just constructs new 'ByteStrings' that
 -- are slices of the original.
@@ -621,7 +606,7 @@
 {-
 -- | Like 'splitWith', except that sequences of adjacent separators are
 -- treated as a single separator. eg.
--- 
+--
 -- > tokens (=='a') "aabbaca" == ["bb","c"]
 --
 tokens :: (Char -> Bool) -> ByteString -> [ByteString]
@@ -650,7 +635,7 @@
 -- element, or 'Nothing' if there is no such element. The following
 -- holds:
 --
--- > elemIndexEnd c xs == 
+-- > elemIndexEnd c xs ==
 -- > (-) (length xs - 1) `fmap` elemIndex c (reverse xs)
 --
 elemIndexEnd :: Char -> ByteString -> Maybe Int
@@ -677,9 +662,9 @@
 -- | count returns the number of times its argument appears in the ByteString
 --
 -- > count = length . elemIndices
--- 
+--
 -- Also
---  
+--
 -- > count '\n' == length . lines
 --
 -- But more efficiently than using length on the intermediate list.
@@ -802,7 +787,7 @@
 
 -- | 'breakSpace' returns the pair of ByteStrings when the argument is
 -- broken at the first whitespace byte. I.e.
--- 
+--
 -- > break isSpace == breakSpace
 --
 breakSpace :: ByteString -> (ByteString,ByteString)
@@ -824,7 +809,7 @@
 -- | 'dropSpace' efficiently returns the 'ByteString' argument with
 -- white space Chars removed from the front. It is more efficient than
 -- calling dropWhile for removing whitespace. I.e.
--- 
+--
 -- > dropWhile isSpace == dropSpace
 --
 dropSpace :: ByteString -> ByteString
@@ -842,7 +827,7 @@
 {-
 -- | 'dropSpaceEnd' efficiently returns the 'ByteString' argument with
 -- white space removed from the end. I.e.
--- 
+--
 -- > reverse . (dropWhile isSpace) . reverse == dropSpaceEnd
 --
 -- but it is more efficient than using multiple reverses.
diff --git a/Data/ByteString/Internal.hs b/Data/ByteString/Internal.hs
--- a/Data/ByteString/Internal.hs
+++ b/Data/ByteString/Internal.hs
@@ -1,11 +1,9 @@
 {-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns #-}
-#if __GLASGOW_HASKELL__
 {-# LANGUAGE UnliftedFFITypes, MagicHash,
             UnboxedTuples, DeriveDataTypeable #-}
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-#endif
 {-# OPTIONS_HADDOCK hide #-}
 
 -- |
@@ -35,9 +33,7 @@
         packChars, packUptoLenChars, unsafePackLenChars,
         unpackBytes, unpackAppendBytesLazy, unpackAppendBytesStrict,
         unpackChars, unpackAppendCharsLazy, unpackAppendCharsStrict,
-#if defined(__GLASGOW_HASKELL__)
         unsafePackAddress,
-#endif
         checkedSum,
 
         -- * Low level imperative construction
@@ -93,35 +89,24 @@
 #endif
 import Foreign.C.String         (CString)
 
+#if MIN_VERSION_base(4,9,0)
+import Data.Semigroup           (Semigroup((<>)))
+#endif
 #if !(MIN_VERSION_base(4,8,0))
 import Data.Monoid              (Monoid(..))
 #endif
 import Control.DeepSeq          (NFData(rnf))
 
-#if MIN_VERSION_base(3,0,0)
 import Data.String              (IsString(..))
-#endif
 
-#ifndef __NHC__
 import Control.Exception        (assert)
-#endif
 
 import Data.Char                (ord)
 import Data.Word                (Word8)
 
 import Data.Typeable            (Typeable)
-#if MIN_VERSION_base(4,1,0)
-import Data.Data                (Data(..))
-#if MIN_VERSION_base(4,2,0)
-import Data.Data                (mkNoRepType)
-#else
-import Data.Data                (mkNorepType)
-#endif
-#else
-import Data.Generics            (Data(..), mkNorepType)
-#endif
+import Data.Data                (Data(..), mkNoRepType)
 
-#ifdef __GLASGOW_HASKELL__
 import GHC.Base                 (realWorld#,unsafeChr)
 #if MIN_VERSION_base(4,4,0)
 import GHC.CString              (unpackCString#)
@@ -139,43 +124,15 @@
 #else
 import GHC.IOBase               (unsafeDupablePerformIO)
 #endif
-#else
-import Data.Char                (chr)
-import System.IO.Unsafe         (unsafePerformIO)
-#endif
 
-#ifdef __GLASGOW_HASKELL__
-import GHC.ForeignPtr           (newForeignPtr_, mallocPlainForeignPtrBytes)
-import GHC.Ptr                  (Ptr(..), castPtr)
-#else
-import Foreign.ForeignPtr       (mallocForeignPtrBytes)
-#endif
-
-#ifdef __GLASGOW_HASKELL__
-import GHC.ForeignPtr           (ForeignPtr(ForeignPtr))
 import GHC.Base                 (nullAddr#)
-#else
-import Foreign.Ptr              (nullPtr)
-#endif
-
-#if __HUGS__
-import Hugs.ForeignPtr          (newForeignPtr_)
-#elif __GLASGOW_HASKELL__<=604
-import Foreign.ForeignPtr       (newForeignPtr_)
-#endif
+import GHC.ForeignPtr           (ForeignPtr(ForeignPtr)
+                                ,newForeignPtr_, mallocPlainForeignPtrBytes)
+import GHC.Ptr                  (Ptr(..), castPtr)
 
 -- CFILES stuff is Hugs only
 {-# CFILES cbits/fpstring.c #-}
 
--- An alternative to Control.Exception (assert) for nhc98
-#ifdef __NHC__
-#define assert	assertS "__FILE__ : __LINE__"
-assertS :: String -> Bool -> a -> a
-assertS _ True  = id
-assertS s False = error ("assertion failed at "++s)
-#endif
-
-
 -- -----------------------------------------------------------------------------
 
 -- | A space-efficient representation of a 'Word8' vector, supporting many
@@ -188,10 +145,7 @@
 data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                      {-# UNPACK #-} !Int                -- offset
                      {-# UNPACK #-} !Int                -- length
-
-#if defined(__GLASGOW_HASKELL__)
     deriving (Typeable)
-#endif
 
 instance Eq  ByteString where
     (==)    = eq
@@ -199,9 +153,18 @@
 instance Ord ByteString where
     compare = compareBytes
 
+#if MIN_VERSION_base(4,9,0)
+instance Semigroup ByteString where
+    (<>)    = append
+#endif
+
 instance Monoid ByteString where
     mempty  = PS nullForeignPtr 0 0
+#if MIN_VERSION_base(4,9,0)
+    mappend = (<>)
+#else
     mappend = append
+#endif
     mconcat = concat
 
 instance NFData ByteString where
@@ -213,20 +176,14 @@
 instance Read ByteString where
     readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ]
 
-#if MIN_VERSION_base(3,0,0)
 instance IsString ByteString where
     fromString = packChars
-#endif
 
 instance Data ByteString where
   gfoldl f z txt = z packBytes `f` (unpackBytes txt)
   toConstr _     = error "Data.ByteString.ByteString.toConstr"
   gunfold _ _    = error "Data.ByteString.ByteString.gunfold"
-#if MIN_VERSION_base(4,2,0)
   dataTypeOf _   = mkNoRepType "Data.ByteString.ByteString"
-#else
-  dataTypeOf _   = mkNorepType "Data.ByteString.ByteString"
-#endif
 
 ------------------------------------------------------------------------
 -- Packing and unpacking from lists
@@ -237,14 +194,12 @@
 packChars :: [Char] -> ByteString
 packChars cs = unsafePackLenChars (List.length cs) cs
 
-#if defined(__GLASGOW_HASKELL__)
 {-# INLINE [0] packChars #-}
 
 {-# RULES
 "ByteString packChars/packAddress" forall s .
    packChars (unpackCString# s) = accursedUnutterablePerformIO (unsafePackAddress s)
  #-}
-#endif
 
 unsafePackLenBytes :: Int -> [Word8] -> ByteString
 unsafePackLenBytes len xs0 =
@@ -260,7 +215,7 @@
     go !_ []     = return ()
     go !p (c:cs) = poke p (c2w c) >> go (p `plusPtr` 1) cs
 
-#if defined(__GLASGOW_HASKELL__)
+
 -- | /O(n)/ Pack a null-terminated sequence of bytes, pointed to by an
 -- Addr\# (an arbitrary machine address assumed to point outside the
 -- garbage-collected heap) into a @ByteString@. A much faster way to
@@ -291,8 +246,8 @@
     cstr :: CString
     cstr = Ptr addr#
 {-# INLINE unsafePackAddress #-}
-#endif
 
+
 packUptoLenBytes :: Int -> [Word8] -> (ByteString, [Word8])
 packUptoLenBytes len xs0 =
     unsafeCreateUptoN' len $ \p -> go p len xs0
@@ -373,12 +328,7 @@
 
 -- | The 0 pointer. Used to indicate the empty Bytestring.
 nullForeignPtr :: ForeignPtr Word8
-#ifdef __GLASGOW_HASKELL__
 nullForeignPtr = ForeignPtr nullAddr# (error "nullForeignPtr") --TODO: should ForeignPtrContents be strict?
-#else
-nullForeignPtr = unsafePerformIO $ newForeignPtr_ nullPtr
-{-# NOINLINE nullForeignPtr #-}
-#endif
 
 -- ---------------------------------------------------------------------
 -- Low level constructors
@@ -419,12 +369,6 @@
 unsafeCreateUptoN' l f = unsafeDupablePerformIO (createUptoN' l f)
 {-# INLINE unsafeCreateUptoN' #-}
 
-#ifndef __GLASGOW_HASKELL__
--- for Hugs, NHC etc
-unsafeDupablePerformIO :: IO a -> a
-unsafeDupablePerformIO = unsafePerformIO
-#endif
-
 -- | Create ByteString of size @l@ and use action @f@ to fill it's contents.
 create :: Int -> (Ptr Word8 -> IO ()) -> IO ByteString
 create l f = do
@@ -482,12 +426,7 @@
 -- | Wrapper of 'mallocForeignPtrBytes' with faster implementation for GHC
 --
 mallocByteString :: Int -> IO (ForeignPtr a)
-mallocByteString l = do
-#ifdef __GLASGOW_HASKELL__
-    mallocPlainForeignPtrBytes l
-#else
-    mallocForeignPtrBytes l
-#endif
+mallocByteString l = mallocPlainForeignPtrBytes l
 {-# INLINE mallocByteString #-}
 
 ------------------------------------------------------------------------
@@ -545,11 +484,7 @@
 
 -- | Conversion between 'Word8' and 'Char'. Should compile to a no-op.
 w2c :: Word8 -> Char
-#if !defined(__GLASGOW_HASKELL__)
-w2c = chr . fromIntegral
-#else
 w2c = unsafeChr . fromIntegral
-#endif
 {-# INLINE w2c #-}
 
 -- | Unsafe conversion between 'Char' and 'Word8'. This is a no-op and
@@ -615,11 +550,7 @@
 --
 {-# INLINE accursedUnutterablePerformIO #-}
 accursedUnutterablePerformIO :: IO a -> a
-#if defined(__GLASGOW_HASKELL__)
 accursedUnutterablePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
-#else
-accursedUnutterablePerformIO = unsafePerformIO
-#endif
 
 inlinePerformIO :: IO a -> a
 inlinePerformIO = accursedUnutterablePerformIO
diff --git a/Data/ByteString/Lazy.hs b/Data/ByteString/Lazy.hs
--- a/Data/ByteString/Lazy.hs
+++ b/Data/ByteString/Lazy.hs
@@ -137,6 +137,8 @@
         groupBy,                -- :: (Word8 -> Word8 -> Bool) -> ByteString -> [ByteString]
         inits,                  -- :: ByteString -> [ByteString]
         tails,                  -- :: ByteString -> [ByteString]
+        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString
+        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString
 
         -- ** Breaking into many substrings
         split,                  -- :: Word8 -> ByteString -> [ByteString]
@@ -233,11 +235,7 @@
                                 ,hClose)
 import System.IO.Error          (mkIOError, illegalOperationErrorType)
 import System.IO.Unsafe
-#ifndef __NHC__
 import Control.Exception        (bracket)
-#else
-import IO		        (bracket)
-#endif
 
 import Foreign.ForeignPtr       (withForeignPtr)
 import Foreign.Ptr
@@ -1017,8 +1015,11 @@
 -- > partition p bs == (filter p xs, filter (not . p) xs)
 --
 partition :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
-partition f p = (filter f p, filter (not . f) p)
---TODO: use a better implementation
+partition _ Empty = (Empty, Empty)
+partition p (Chunk x xs) = (chunk t ts, chunk f fs)
+  where
+    (t,   f) = S.partition p x
+    (ts, fs) = partition   p xs
 
 -- ---------------------------------------------------------------------
 -- Searching for substrings
@@ -1035,6 +1036,19 @@
   where (xh,xt) = S.splitAt (S.length y) x
         (yh,yt) = S.splitAt (S.length x) y
 
+-- | /O(n)/ The 'stripPrefix' function takes two ByteStrings and returns 'Just'
+-- the remainder of the second iff the first is its prefix, and otherwise
+-- 'Nothing'.
+stripPrefix :: ByteString -> ByteString -> Maybe ByteString
+stripPrefix Empty bs  = Just bs
+stripPrefix _ Empty  = Nothing
+stripPrefix (Chunk x xs) (Chunk y ys)
+    | S.length x == S.length y = if x == y then stripPrefix xs ys else Nothing
+    | S.length x <  S.length y = do yt <- S.stripPrefix x y
+                                    stripPrefix xs (Chunk yt ys)
+    | otherwise                = do xt <- S.stripPrefix y x
+                                    stripPrefix (Chunk xt xs) ys
+
 -- | /O(n)/ The 'isSuffixOf' function takes two ByteStrings and returns 'True'
 -- iff the first is a suffix of the second.
 --
@@ -1046,6 +1060,13 @@
 isSuffixOf x y = reverse x `isPrefixOf` reverse y
 --TODO: a better implementation
 
+-- | /O(n)/ The 'stripSuffix' function takes two ByteStrings and returns 'Just'
+-- the remainder of the second iff the first is its suffix, and otherwise
+-- 'Nothing'.
+stripSuffix :: ByteString -> ByteString -> Maybe ByteString
+stripSuffix x y = reverse <$> stripPrefix (reverse x) (reverse y)
+--TODO: a better implementation
+
 -- ---------------------------------------------------------------------
 -- Zipping
 
@@ -1169,7 +1190,6 @@
 -- is available. Chunks are read on demand, in @k@-sized chunks.
 --
 hGetNonBlockingN :: Int -> Handle -> Int -> IO ByteString
-#if defined(__GLASGOW_HASKELL__)
 hGetNonBlockingN k h n | n > 0= readChunks n
   where
     readChunks !i = do
@@ -1181,9 +1201,6 @@
 
 hGetNonBlockingN _ _ 0 = return Empty
 hGetNonBlockingN _ h n = illegalBufferSize h "hGetNonBlocking" n
-#else
-hGetNonBlockingN = hGetN
-#endif
 
 illegalBufferSize :: Handle -> String -> Int -> IO a
 illegalBufferSize handle fn sz =
@@ -1217,12 +1234,8 @@
 -- Note: on Windows and with Haskell implementation other than GHC, this
 -- function does not work correctly; it behaves identically to 'hGet'.
 --
-#if defined(__GLASGOW_HASKELL__)
 hGetNonBlocking :: Handle -> Int -> IO ByteString
 hGetNonBlocking = hGetNonBlockingN defaultChunkSize
-#else
-hGetNonBlocking = hGet
-#endif
 
 -- | Read an entire file /lazily/ into a 'ByteString'.
 -- The Handle will be held open until EOF is encountered.
diff --git a/Data/ByteString/Lazy/Char8.hs b/Data/ByteString/Lazy/Char8.hs
--- a/Data/ByteString/Lazy/Char8.hs
+++ b/Data/ByteString/Lazy/Char8.hs
@@ -116,6 +116,8 @@
         groupBy,                -- :: (Char -> Char -> Bool) -> ByteString -> [ByteString]
         inits,                  -- :: ByteString -> [ByteString]
         tails,                  -- :: ByteString -> [ByteString]
+        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString
+        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString
 
         -- ** Breaking into many substrings
         split,                  -- :: Char -> ByteString -> [ByteString]
@@ -199,6 +201,7 @@
         ,empty,null,length,tail,init,append,reverse,transpose,cycle
         ,concat,take,drop,splitAt,intercalate
         ,isPrefixOf,isSuffixOf,group,inits,tails,copy
+        ,stripPrefix,stripSuffix
         ,hGetContents, hGet, hPut, getContents
         ,hGetNonBlocking, hPutNonBlocking
         ,putStr, hPutStr, interact)
@@ -223,12 +226,7 @@
         ,zip,zipWith,unzip,notElem,repeat,iterate,interact,cycle)
 
 import System.IO            (Handle,stdout,hClose,openBinaryFile,IOMode(..))
-#ifndef __NHC__
 import Control.Exception    (bracket)
-#else
-import IO                   (bracket)
-#endif
-
 
 ------------------------------------------------------------------------
 
diff --git a/Data/ByteString/Lazy/Internal.hs b/Data/ByteString/Lazy/Internal.hs
--- a/Data/ByteString/Lazy/Internal.hs
+++ b/Data/ByteString/Lazy/Internal.hs
@@ -1,10 +1,8 @@
 {-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns #-}
-#if __GLASGOW_HASKELL__
 {-# LANGUAGE DeriveDataTypeable #-}
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-#endif
 {-# OPTIONS_HADDOCK hide #-}
 
 -- |
@@ -53,26 +51,18 @@
 import Data.Word        (Word8)
 import Foreign.Storable (Storable(sizeOf))
 
+#if MIN_VERSION_base(4,9,0)
+import Data.Semigroup   (Semigroup((<>)))
+#endif
 #if !(MIN_VERSION_base(4,8,0))
 import Data.Monoid      (Monoid(..))
 #endif
 import Control.DeepSeq  (NFData, rnf)
 
-#if MIN_VERSION_base(3,0,0)
 import Data.String      (IsString(..))
-#endif
 
 import Data.Typeable            (Typeable)
-#if MIN_VERSION_base(4,1,0)
-import Data.Data                (Data(..))
-#if MIN_VERSION_base(4,2,0)
-import Data.Data                (mkNoRepType)
-#else
-import Data.Data                (mkNorepType)
-#endif
-#else
-import Data.Generics            (Data(..), mkNorepType)
-#endif
+import Data.Data                (Data(..), mkNoRepType)
 
 -- | A space-efficient representation of a 'Word8' vector, supporting many
 -- efficient operations.
@@ -82,10 +72,7 @@
 -- 8-bit characters.
 --
 data ByteString = Empty | Chunk {-# UNPACK #-} !S.ByteString ByteString
-
-#if defined(__GLASGOW_HASKELL__)
     deriving (Typeable)
-#endif
 
 instance Eq  ByteString where
     (==)    = eq
@@ -93,9 +80,18 @@
 instance Ord ByteString where
     compare = cmp
 
+#if MIN_VERSION_base(4,9,0)
+instance Semigroup ByteString where
+    (<>)    = append
+#endif
+
 instance Monoid ByteString where
     mempty  = Empty
+#if MIN_VERSION_base(4,9,0)
+    mappend = (<>)
+#else
     mappend = append
+#endif
     mconcat = concat
 
 instance NFData ByteString where
@@ -108,20 +104,14 @@
 instance Read ByteString where
     readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ]
 
-#if MIN_VERSION_base(3,0,0)
 instance IsString ByteString where
     fromString = packChars
-#endif
 
 instance Data ByteString where
   gfoldl f z txt = z packBytes `f` unpackBytes txt
   toConstr _     = error "Data.ByteString.Lazy.ByteString.toConstr"
   gunfold _ _    = error "Data.ByteString.Lazy.ByteString.gunfold"
-#if MIN_VERSION_base(4,2,0)
   dataTypeOf _   = mkNoRepType "Data.ByteString.Lazy.ByteString"
-#else
-  dataTypeOf _   = mkNorepType "Data.ByteString.Lazy.ByteString"
-#endif
 
 ------------------------------------------------------------------------
 -- Packing and unpacking from lists
diff --git a/Data/ByteString/Short/Internal.hs b/Data/ByteString/Short/Internal.hs
--- a/Data/ByteString/Short/Internal.hs
+++ b/Data/ByteString/Short/Internal.hs
@@ -40,6 +40,9 @@
 
 import Data.Typeable    (Typeable)
 import Data.Data        (Data(..), mkNoRepType)
+#if MIN_VERSION_base(4,9,0)
+import Data.Semigroup   (Semigroup((<>)))
+#endif
 import Data.Monoid      (Monoid(..))
 import Data.String      (IsString(..))
 import Control.DeepSeq  (NFData(..))
@@ -131,9 +134,18 @@
 instance Ord ShortByteString where
     compare = compareBytes
 
+#if MIN_VERSION_base(4,9,0)
+instance Semigroup ShortByteString where
+    (<>)    = append
+#endif
+
 instance Monoid ShortByteString where
     mempty  = empty
+#if MIN_VERSION_base(4,9,0)
+    mappend = (<>)
+#else
     mappend = append
+#endif
     mconcat = concat
 
 instance NFData ShortByteString where
@@ -152,11 +164,7 @@
   gfoldl f z txt = z packBytes `f` (unpackBytes txt)
   toConstr _     = error "Data.ByteString.Short.ShortByteString.toConstr"
   gunfold _ _    = error "Data.ByteString.Short.ShortByteString.gunfold"
-#if MIN_VERSION_base(4,2,0)
   dataTypeOf _   = mkNoRepType "Data.ByteString.Short.ShortByteString"
-#else
-  dataTypeOf _   = mkNorepType "Data.ByteString.Short.ShortByteString"
-#endif
 
 ------------------------------------------------------------------------
 -- Simple operations
diff --git a/Data/ByteString/Unsafe.hs b/Data/ByteString/Unsafe.hs
--- a/Data/ByteString/Unsafe.hs
+++ b/Data/ByteString/Unsafe.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__
 {-# LANGUAGE MagicHash #-}
-#endif
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
@@ -43,12 +41,10 @@
         unsafePackMallocCString,-- :: CString -> IO ByteString
         unsafePackMallocCStringLen, -- :: CStringLen -> IO ByteString
 
-#if defined(__GLASGOW_HASKELL__)
         unsafePackAddress,          -- :: Addr# -> IO ByteString
         unsafePackAddressLen,       -- :: Int -> Addr# -> IO ByteString
         unsafePackCStringFinalizer, -- :: Ptr Word8 -> Int -> IO () -> IO ByteString
         unsafeFinalize,             -- :: ByteString -> IO ()
-#endif
 
   ) where
 
@@ -60,31 +56,16 @@
 import Foreign.Storable         (Storable(..))
 import Foreign.C.String         (CString, CStringLen)
 
-#ifndef __NHC__
 import Control.Exception        (assert)
-#endif
 
 import Data.Word                (Word8)
 
-#if defined(__GLASGOW_HASKELL__)
 import qualified Foreign.ForeignPtr as FC (finalizeForeignPtr)
 import qualified Foreign.Concurrent as FC (newForeignPtr)
 
---import Data.Generics            (Data(..), Typeable(..))
-
 import GHC.Prim                 (Addr#)
 import GHC.Ptr                  (Ptr(..))
-#endif
 
--- An alternative to Control.Exception (assert) for nhc98
-#ifdef __NHC__
-#define assert	assertS "__FILE__ : __LINE__"
-assertS :: String -> Bool -> a -> a
-assertS _ True  = id
-assertS s False = error ("assertion failed at "++s)
-#endif
-
-
 -- ---------------------------------------------------------------------
 --
 -- Extensions to the basic interface
@@ -142,7 +123,6 @@
 {-# INLINE unsafeDrop #-}
 
 
-#if defined(__GLASGOW_HASKELL__)
 -- | /O(1)/ 'unsafePackAddressLen' provides constant-time construction of
 -- 'ByteString's, which is ideal for string literals. It packs a sequence
 -- of bytes into a @ByteString@, given a raw 'Addr#' to the string, and
@@ -191,8 +171,6 @@
 --
 unsafeFinalize :: ByteString -> IO ()
 unsafeFinalize (PS p _ _) = FC.finalizeForeignPtr p
-
-#endif
 
 ------------------------------------------------------------------------
 -- Packing CStrings into ByteStrings
diff --git a/bytestring.cabal b/bytestring.cabal
--- a/bytestring.cabal
+++ b/bytestring.cabal
@@ -1,5 +1,5 @@
 Name:                bytestring
-Version:             0.10.6.0
+Version:             0.10.8.0
 Synopsis:            Fast, compact, strict and lazy byte strings with a list interface
 Description:
     An efficient compact, immutable byte string type (both strict and lazy)
@@ -153,7 +153,7 @@
   hs-source-dirs:   . tests
   build-depends:    base, ghc-prim, deepseq, random, directory,
                     test-framework, test-framework-quickcheck2,
-                    QuickCheck >= 2.3 && < 2.7
+                    QuickCheck >= 2.3
   c-sources:        cbits/fpstring.c
   include-dirs:     include
   ghc-options:      -fwarn-unused-binds
@@ -198,11 +198,11 @@
 
   build-depends:    base, ghc-prim,
                     deepseq,
-                    QuickCheck                 >= 2.4 && < 2.7,
+                    QuickCheck                 >= 2.4,
                     byteorder                  == 1.0.*,
-                    dlist                      == 0.5.*,
+                    dlist                      >= 0.5 && < 0.8,
                     directory,
-                    mtl                        >= 2.0 && < 2.2,
+                    mtl                        >= 2.0 && < 2.3,
                     HUnit,
                     test-framework,
                     test-framework-hunit,
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -91,6 +91,9 @@
 prop_findIndexCC    = D.findIndex             `eq2`  ((fmap toInt64 .) . C.findIndex)
 prop_findIndicesCC  = D.findIndices           `eq2`  ((fmap toInt64 .) . C.findIndices)
 prop_isPrefixOfCC   = D.isPrefixOf            `eq2`  C.isPrefixOf
+prop_stripPrefixCC  = D.stripPrefix           `eq2`  C.stripPrefix
+prop_isSuffixOfCC   = D.isSuffixOf            `eq2`  C.isSuffixOf
+prop_stripSuffixCC  = D.stripSuffix           `eq2`  C.stripSuffix
 prop_mapCC          = D.map                   `eq2`  C.map
 prop_replicateCC    = forAll arbitrarySizedIntegral $
                       (D.replicate . toInt64) `eq2`  C.replicate
@@ -175,6 +178,9 @@
 prop_findIndexBP    = L.findIndex            `eq2`  ((fmap toInt64 .) . P.findIndex)
 prop_findIndicesBP  = L.findIndices          `eq2`  ((fmap toInt64 .) . P.findIndices)
 prop_isPrefixOfBP   = L.isPrefixOf           `eq2`  P.isPrefixOf
+prop_stripPrefixBP  = L.stripPrefix          `eq2`  P.stripPrefix
+prop_isSuffixOfBP   = L.isSuffixOf           `eq2`  P.isSuffixOf
+prop_stripSuffixBP  = L.stripSuffix          `eq2`  P.stripSuffix
 prop_mapBP          = L.map                  `eq2`  P.map
 prop_replicateBP    = forAll arbitrarySizedIntegral $
                       (L.replicate. toInt64) `eq2`  P.replicate
@@ -356,6 +362,9 @@
 prop_findIndicesBL  = L.findIndices           `eq2` ((fmap toInt64 .) . findIndices:: (W -> Bool) -> [W] -> [Int64])
 prop_findIndexBL    = L.findIndex             `eq2` ((fmap toInt64 .) . findIndex :: (W -> Bool) -> [W] -> Maybe Int64)
 prop_isPrefixOfBL   = L.isPrefixOf            `eq2` (isPrefixOf:: [W] -> [W] -> Bool)
+prop_stripPrefixBL  = L.stripPrefix           `eq2` (stripPrefix:: [W] -> [W] -> Maybe [W])
+prop_isSuffixOfBL   = L.isSuffixOf            `eq2` (isSuffixOf:: [W] -> [W] -> Bool)
+prop_stripSuffixBL  = L.stripSuffix           `eq2` (stripSuffix :: [W] -> [W] -> Maybe [W])
 prop_mapBL          = L.map                   `eq2` (map       :: (W -> W) -> [W] -> [W])
 prop_replicateBL    = forAll arbitrarySizedIntegral $
                       (L.replicate . toInt64) `eq2` (replicate :: Int -> W -> [W])
@@ -457,7 +466,10 @@
 prop_findPL       = P.find      `eq2`    (find      :: (W -> Bool) -> [W] -> Maybe W)
 prop_findIndexPL  = P.findIndex `eq2`    (findIndex :: (W -> Bool) -> [W] -> Maybe Int)
 prop_isPrefixOfPL = P.isPrefixOf`eq2`    (isPrefixOf:: [W] -> [W] -> Bool)
+prop_isSuffixOfPL = P.isSuffixOf`eq2`    (isSuffixOf:: [W] -> [W] -> Bool)
 prop_isInfixOfPL  = P.isInfixOf `eq2`    (isInfixOf:: [W] -> [W] -> Bool)
+prop_stripPrefixPL = P.stripPrefix`eq2`  (stripPrefix:: [W] -> [W] -> Maybe [W])
+prop_stripSuffixPL = P.stripSuffix`eq2`  (stripSuffix:: [W] -> [W] -> Maybe [W])
 prop_mapPL        = P.map       `eq2`    (map       :: (W -> W) -> [W] -> [W])
 prop_replicatePL  = forAll arbitrarySizedIntegral $
                     P.replicate `eq2`    (replicate :: Int -> W -> [W])
@@ -764,7 +776,11 @@
                                 _      -> Nothing
 
 prop_isPrefixOf xs ys = isPrefixOf xs ys == (pack xs `L.isPrefixOf` pack ys)
+prop_stripPrefix xs ys = (pack <$> stripPrefix xs ys) == (pack xs `L.stripPrefix` pack ys)
 
+prop_isSuffixOf xs ys = isSuffixOf xs ys == (pack xs `L.isSuffixOf` pack ys)
+prop_stripSuffix xs ys = (pack <$> stripSuffix xs ys) == (pack xs `L.stripSuffix` pack ys)
+
 {-
 prop_sort1 xs = sort xs == (unpack . L.sort . pack) xs
 prop_sort2 xs = (not (null xs)) ==> (L.head . L.sort . pack $ xs) == minimum xs
@@ -1165,9 +1181,15 @@
     fn x = Just (x, chr (ord x + 1))
 
 prop_prefixBB xs ys = isPrefixOf xs ys == (P.pack xs `P.isPrefixOf` P.pack ys)
+prop_prefixLL xs ys = isPrefixOf xs ys == (L.pack xs `L.isPrefixOf` L.pack ys)
 prop_suffixBB xs ys = isSuffixOf xs ys == (P.pack xs `P.isSuffixOf` P.pack ys)
 prop_suffixLL xs ys = isSuffixOf xs ys == (L.pack xs `L.isSuffixOf` L.pack ys)
 
+prop_stripPrefixBB xs ys = (P.pack <$> stripPrefix xs ys) == (P.pack xs `P.stripPrefix` P.pack ys)
+prop_stripPrefixLL xs ys = (L.pack <$> stripPrefix xs ys) == (L.pack xs `L.stripPrefix` L.pack ys)
+prop_stripSuffixBB xs ys = (P.pack <$> stripSuffix xs ys) == (P.pack xs `P.stripSuffix` P.pack ys)
+prop_stripSuffixLL xs ys = (L.pack <$> stripSuffix xs ys) == (L.pack xs `L.stripSuffix` L.pack ys)
+
 prop_copyBB xs = let p = P.pack xs in P.copy p == p
 prop_copyLL xs = let p = L.pack xs in L.copy p == p
 
@@ -1611,6 +1633,8 @@
 prop_short_read xs =
     read (show (Short.pack xs)) == Short.pack xs
 
+stripSuffix :: [W] -> [W] -> Maybe [W]
+stripSuffix xs ys = reverse <$> stripPrefix (reverse xs) (reverse ys)
 
 short_tests =
     [ testProperty "pack/unpack"              prop_short_pack_unpack
@@ -1640,7 +1664,7 @@
 -- The entry point
 
 main :: IO ()
-main = defaultMain tests
+main = defaultMainWithArgs tests ["-o 3"] -- timeout if a test runs for >3 secs
 
 --
 -- And now a list of all the properties to test.
@@ -1762,6 +1786,9 @@
     , testProperty "head"        prop_headBL
     , testProperty "init"        prop_initBL
     , testProperty "isPrefixOf"  prop_isPrefixOfBL
+    , testProperty "isSuffixOf"  prop_isSuffixOfBL
+    , testProperty "stripPrefix" prop_stripPrefixBL
+    , testProperty "stripSuffix" prop_stripSuffixBL
     , testProperty "last"        prop_lastBL
     , testProperty "length"      prop_lengthBL
     , testProperty "map"         prop_mapBL
@@ -1820,7 +1847,10 @@
     , testProperty "prop_findCC"        prop_findCC
     , testProperty "prop_findIndexCC"   prop_findIndexCC
     , testProperty "prop_findIndicesCC" prop_findIndicesCC
-    , testProperty "prop_isPrefixOfCC"  prop_isPrefixOfCC
+    , testProperty "prop_isPrefixCC"    prop_isPrefixOfCC
+    , testProperty "prop_isSuffixCC"    prop_isSuffixOfCC
+    , testProperty "prop_stripPrefixCC" prop_stripPrefixCC
+    , testProperty "prop_stripSuffixCC" prop_stripSuffixCC
     , testProperty "prop_mapCC"         prop_mapCC
     , testProperty "prop_replicateCC"   prop_replicateCC
     , testProperty "prop_snocCC"        prop_snocCC
@@ -1887,6 +1917,9 @@
     , testProperty "head"        prop_headBP
     , testProperty "init"        prop_initBP
     , testProperty "isPrefixOf"  prop_isPrefixOfBP
+    , testProperty "isSuffixOf"  prop_isSuffixOfBP
+    , testProperty "stripPrefix" prop_stripPrefixBP
+    , testProperty "stripSuffix" prop_stripSuffixBP
     , testProperty "last"        prop_lastBP
     , testProperty "length"      prop_lengthBP
     , testProperty "readInt"     prop_readIntBP
@@ -1976,7 +2009,10 @@
 --  , testProperty "zipWith/zipWith'" prop_zipWithPL'
 
     , testProperty "isPrefixOf"  prop_isPrefixOfPL
+    , testProperty "isSuffixOf"  prop_isSuffixOfPL
     , testProperty "isInfixOf"   prop_isInfixOfPL
+    , testProperty "stripPrefix" prop_stripPrefixPL
+    , testProperty "stripSuffix" prop_stripSuffixPL
     , testProperty "length"      prop_lengthPL
     , testProperty "map"         prop_mapPL
     , testProperty "null"        prop_nullPL
@@ -2148,8 +2184,13 @@
 --  , testProperty "dropSpaceEnd"   prop_dropSpaceEndBB
     , testProperty "unfoldr"        prop_unfoldrBB
     , testProperty "prefix"         prop_prefixBB
+    , testProperty "prefix"         prop_prefixLL
     , testProperty "suffix"         prop_suffixBB
     , testProperty "suffix"         prop_suffixLL
+    , testProperty "stripPrefix"    prop_stripPrefixBB
+    , testProperty "stripPrefix"    prop_stripPrefixLL
+    , testProperty "stripSuffix"    prop_stripSuffixBB
+    , testProperty "stripSuffix"    prop_stripSuffixLL
     , testProperty "copy"           prop_copyBB
     , testProperty "copy"           prop_copyLL
     , testProperty "inits"          prop_initsBB
@@ -2271,7 +2312,7 @@
     , testProperty "reverse"            prop_reverse
     , testProperty "reverse1"           prop_reverse1
     , testProperty "reverse2"           prop_reverse2
-    , testProperty "transpose"          prop_transpose
+    --, testProperty "transpose"          prop_transpose
     , testProperty "foldl"              prop_foldl
     , testProperty "foldl/reverse"      prop_foldl_1
     , testProperty "foldr"              prop_foldr
@@ -2329,7 +2370,11 @@
 --  , testProperty "filterNotByte 1"    prop_filterNotByte
 --  , testProperty "filterNotByte 2"    prop_filterNotByte2
     , testProperty "isPrefixOf"         prop_isPrefixOf
+    , testProperty "isSuffixOf"         prop_isSuffixOf
+    , testProperty "stripPrefix"        prop_stripPrefix
+    , testProperty "stripSuffix"        prop_stripSuffix
     , testProperty "concatMap"          prop_concatMap
     , testProperty "isSpace"            prop_isSpaceWord8
     ]
+
 
diff --git a/tests/QuickCheckUtils.hs b/tests/QuickCheckUtils.hs
--- a/tests/QuickCheckUtils.hs
+++ b/tests/QuickCheckUtils.hs
@@ -32,24 +32,31 @@
                                          fromIntegral b :: Integer) g of
                             (x,g) -> (fromIntegral x, g)
 
-instance Arbitrary L.ByteString where
-  arbitrary = return . L.checkInvariant
-                     . L.fromChunks
-                     . filter (not. P.null)  -- maintain the invariant.
-                   =<< arbitrary
-
-instance CoArbitrary L.ByteString where
-  coarbitrary s = coarbitrary (L.unpack s)
+sizedByteString n = do m <- choose(0, n)
+                       fmap P.pack $ vectorOf m arbitrary
 
 instance Arbitrary P.ByteString where
   arbitrary = do
-    bs <- P.pack `fmap` arbitrary
+    bs <- sized sizedByteString
     n  <- choose (0, 2)
     return (P.drop n bs) -- to give us some with non-0 offset
 
 instance CoArbitrary P.ByteString where
   coarbitrary s = coarbitrary (P.unpack s)
 
+instance Arbitrary L.ByteString where
+  arbitrary = sized $ \n -> do numChunks <- choose (0, n)
+                               if numChunks == 0
+                                   then return L.empty
+                                   else fmap (L.checkInvariant .
+                                              L.fromChunks .
+                                              filter (not . P.null)) $
+                                            vectorOf numChunks
+                                                     (sizedByteString
+                                                          (n `div` numChunks))
+
+instance CoArbitrary L.ByteString where
+  coarbitrary s = coarbitrary (L.unpack s)
 
 newtype CByteString = CByteString P.ByteString
   deriving Show
diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs
--- a/tests/builder/Data/ByteString/Builder/Tests.hs
+++ b/tests/builder/Data/ByteString/Builder/Tests.hs
@@ -39,9 +39,7 @@
 
 import           Control.Exception (evaluate)
 import           System.IO (openTempFile, hPutStr, hClose, hSetBinaryMode)
-#if MIN_VERSION_base(4,2,0)
 import           System.IO (hSetEncoding, utf8)
-#endif
 import           System.Directory
 import           Foreign (ForeignPtr, withForeignPtr, castPtr)
 
@@ -61,9 +59,7 @@
 tests :: [Test]
 tests =
   [ testBuilderRecipe
-#if MIN_VERSION_base(4,2,0)
   , testHandlePutBuilder
-#endif
   , testHandlePutBuilderChar8
   , testPut
   , testRunBuilder
@@ -96,7 +92,6 @@
           , "diff  : " ++ show (dropWhile (uncurry (==)) $ zip x1 x2)
           ]
 
-#if MIN_VERSION_base(4,2,0)
 testHandlePutBuilder :: Test
 testHandlePutBuilder =
     testProperty "hPutBuilder" testRecipe
@@ -132,7 +127,6 @@
             success = lbs == lbsRef
         unless success (error msg)
         return success
-#endif
 
 testHandlePutBuilderChar8 :: Test
 testHandlePutBuilderChar8 =
