diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
 # hw-balancedparens
 
-[![CircleCI](https://circleci.com/gh/haskell-works/hw-balancedparens.svg?style=svg)](https://circleci.com/gh/haskell-works/hw-balancedparens)
+[![Binaries](https://github.com/haskell-works/hw-balancedparens/actions/workflows/haskell.yml/badge.svg)](https://github.com/haskell-works/hw-balancedparens/actions/workflows/haskell.yml)
+
+For documentation, see the week [wiki](https://github.com/haskell-works/hw-balancedparens/wiki) and
+[API docs](https://hackage.haskell.org/package/hw-balancedparens).
diff --git a/app/App/Commands.hs b/app/App/Commands.hs
new file mode 100644
--- /dev/null
+++ b/app/App/Commands.hs
@@ -0,0 +1,14 @@
+module App.Commands where
+
+import App.Commands.BitsToParens
+import App.Commands.ParensToBits
+import App.Commands.Positions
+import Options.Applicative
+
+{- HLINT ignore "Monoid law, left identity" -}
+
+cmdOpts :: Parser (IO ())
+cmdOpts = subparser $ mempty
+  <>  cmdParensToBits
+  <>  cmdBitsToParens
+  <>  cmdPositions
diff --git a/app/App/Commands/BitsToParens.hs b/app/App/Commands/BitsToParens.hs
new file mode 100644
--- /dev/null
+++ b/app/App/Commands/BitsToParens.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE DataKinds           #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
+
+module App.Commands.BitsToParens
+  ( cmdBitsToParens
+  ) where
+
+import Control.Lens
+import Data.Generics.Product.Any
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import Options.Applicative            hiding (columns)
+
+import qualified App.Commands.Options.Type as Z
+import qualified App.IO                    as IO
+import qualified Data.ByteString.Builder   as B
+import qualified Data.ByteString.Lazy      as LBS
+
+bitString :: Word8 -> B.Builder
+bitString w =
+  go ((w .>. 0) .&. 1) <>
+  go ((w .>. 1) .&. 1) <>
+  go ((w .>. 2) .&. 1) <>
+  go ((w .>. 3) .&. 1) <>
+  go ((w .>. 4) .&. 1) <>
+  go ((w .>. 5) .&. 1) <>
+  go ((w .>. 6) .&. 1) <>
+  go ((w .>. 7) .&. 1)
+  where go :: Word8 -> B.Builder
+        go 1 = B.word8 40
+        go _ = B.word8 41
+
+parensBuilder :: LBS.ByteString -> B.Builder
+parensBuilder lbs = case LBS.uncons lbs of
+  Just (w, rs) -> bitString w <> parensBuilder rs
+  Nothing      -> mempty
+
+parens :: LBS.ByteString -> LBS.ByteString
+parens = B.toLazyByteString . parensBuilder
+
+runBitsToParens :: Z.BitsToParensOptions -> IO ()
+runBitsToParens opts = do
+  let inputFile   = opts ^. the @"inputFile"
+  let outputFile  = opts ^. the @"outputFile"
+
+  lbs <- IO.readInputFile inputFile
+
+  IO.writeOutputFile outputFile $ parens lbs
+
+  return ()
+
+optsBitsToParens :: Parser Z.BitsToParensOptions
+optsBitsToParens = Z.BitsToParensOptions
+  <$> strOption
+      (   long "input"
+      <>  help "Input file"
+      <>  metavar "FILE"
+      <>  value "-"
+      )
+  <*> strOption
+      (   long "output"
+      <>  help "Output file"
+      <>  metavar "FILE"
+      <>  value "-"
+      )
+
+cmdBitsToParens :: Mod CommandFields (IO ())
+cmdBitsToParens = command "bits-to-parens"  $ flip info idm $ runBitsToParens <$> optsBitsToParens
diff --git a/app/App/Commands/Options/Type.hs b/app/App/Commands/Options/Type.hs
new file mode 100644
--- /dev/null
+++ b/app/App/Commands/Options/Type.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE DeriveGeneric         #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module App.Commands.Options.Type where
+
+import GHC.Generics
+
+newtype PositionsOptions = PositionsOptions
+  { inputFile :: FilePath
+  } deriving (Eq, Show, Generic)
+
+data BitsToParensOptions = BitsToParensOptions
+  { inputFile  :: FilePath
+  , outputFile :: FilePath
+  } deriving (Eq, Show, Generic)
+
+data ParensToBitsOptions = ParensToBitsOptions
+  { inputFile  :: FilePath
+  , outputFile :: FilePath
+  } deriving (Eq, Show, Generic)
diff --git a/app/App/Commands/ParensToBits.hs b/app/App/Commands/ParensToBits.hs
new file mode 100644
--- /dev/null
+++ b/app/App/Commands/ParensToBits.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE DataKinds           #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections       #-}
+{-# LANGUAGE TypeApplications    #-}
+
+module App.Commands.ParensToBits
+  ( cmdParensToBits
+  ) where
+
+import Control.Lens
+import Data.Generics.Product.Any
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Positioning
+import Options.Applicative            hiding (columns)
+
+import qualified App.Commands.Options.Type as Z
+import qualified App.IO                    as IO
+import qualified Data.ByteString.Lazy      as LBS
+
+{- HLINT ignore "Redundant do"      -}
+{- HLINT ignore "Redundant return"  -}
+
+unparens :: LBS.ByteString -> LBS.ByteString
+unparens = LBS.unfoldr go . (0, 0, )
+  where go :: (Word8, Count, LBS.ByteString) -> Maybe (Word8, (Word8, Count, LBS.ByteString))
+        go (w, c, lbs) = case LBS.uncons lbs of
+          Nothing -> if c > 0
+            then Just (w, (0, 0, LBS.empty))
+            else Nothing
+          Just (a, as) -> case a of
+            40 -> if c < 8
+              then go (w .|. (1 .<. c), c + 1, as)
+              else Just (w, (1, 1, as))
+            41 -> if c < 8
+              then go (w, c + 1, as)
+              else Just (w, (0, 1, as))
+            _ -> go (w, c, as)
+
+runParensToBits :: Z.ParensToBitsOptions -> IO ()
+runParensToBits opts = do
+  let inputFile   = opts ^. the @"inputFile"
+  let outputFile  = opts ^. the @"outputFile"
+
+  lbs <- IO.readInputFile inputFile
+
+  IO.writeOutputFile outputFile (unparens lbs)
+
+optsParensToBits :: Parser Z.ParensToBitsOptions
+optsParensToBits = Z.ParensToBitsOptions
+  <$> strOption
+      (   long "input"
+      <>  help "Input file"
+      <>  metavar "FILE"
+      <>  value "-"
+      )
+  <*> strOption
+      (   long "output"
+      <>  help "Output file"
+      <>  metavar "FILE"
+      <>  value "-"
+      )
+
+cmdParensToBits :: Mod CommandFields (IO ())
+cmdParensToBits = command "parens-to-bits"  $ flip info idm $ runParensToBits <$> optsParensToBits
diff --git a/app/App/Commands/Positions.hs b/app/App/Commands/Positions.hs
new file mode 100644
--- /dev/null
+++ b/app/App/Commands/Positions.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE DataKinds           #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
+
+module App.Commands.Positions
+  ( cmdPositions
+  ) where
+
+import Control.Lens
+import Control.Monad
+import Data.Generics.Product.Any
+import Data.Word
+import HaskellWorks.Data.BalancedParens.FindClose
+import HaskellWorks.Data.BalancedParens.OpenAt
+import HaskellWorks.Data.Positioning
+import Options.Applicative                        hiding (columns)
+
+import qualified App.Commands.Options.Type           as Z
+import qualified Data.Vector.Storable                as DVS
+import qualified HaskellWorks.Data.FromForeignRegion as IO
+import qualified System.IO                           as IO
+
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+
+openCloses :: (FindClose v, OpenAt v) => v -> [(Count, Count)]
+openCloses v = go 1 v []
+  where go :: (FindClose v, OpenAt v) => Count -> v -> [(Count, Count)] -> [(Count, Count)]
+        go p w = if openAt w p
+          then case findClose w p of
+            Just q  -> ((p, q):) . go (p + 1) w . go (q + 1) w
+            Nothing -> id
+          else id
+
+runPositions :: Z.PositionsOptions -> IO ()
+runPositions opts = do
+  let inputFile   = opts ^. the @"inputFile"
+
+  v :: DVS.Vector Word64 <- IO.mmapFromForeignRegion inputFile
+
+  forM_ (openCloses v) $ \(o, c) -> do
+    IO.putStrLn $ show o <> "," <> show c
+
+  return ()
+
+optsPositions :: Parser Z.PositionsOptions
+optsPositions = Z.PositionsOptions
+  <$> strOption
+      (   long "input"
+      <>  help "Input file"
+      <>  metavar "FILE"
+      )
+
+cmdPositions :: Mod CommandFields (IO ())
+cmdPositions = command "positions"  $ flip info idm $ runPositions <$> optsPositions
diff --git a/app/App/IO.hs b/app/App/IO.hs
new file mode 100644
--- /dev/null
+++ b/app/App/IO.hs
@@ -0,0 +1,12 @@
+module App.IO where
+
+import qualified Data.ByteString.Lazy as LBS
+import qualified System.IO            as IO
+
+readInputFile :: FilePath -> IO LBS.ByteString
+readInputFile "-"      = LBS.hGetContents IO.stdin
+readInputFile filePath = LBS.readFile filePath
+
+writeOutputFile :: FilePath -> LBS.ByteString -> IO ()
+writeOutputFile "-"      bs = LBS.hPut IO.stdout bs
+writeOutputFile filePath bs = LBS.writeFile filePath bs
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import App.Commands
+import Control.Monad
+import Options.Applicative
+
+main :: IO ()
+main = join $ customExecParser
+  (prefs $ showHelpOnEmpty <> showHelpOnError)
+  (info (cmdOpts <**> helper) idm)
diff --git a/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -1,32 +1,54 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds           #-}
+{-# LANGUAGE DeriveAnyClass      #-}
+{-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
 
 module Main where
 
+import Control.DeepSeq
+import Control.Lens                                 ((^.))
+import Control.Monad
 import Criterion.Main
-import Data.Semigroup                               ((<>))
+import Data.Generics.Product.Any
+import Data.Maybe
 import Data.Word
+import GHC.Generics
 import HaskellWorks.Data.BalancedParens.FindClose
-import HaskellWorks.Data.Bits.Broadword
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Type
 import HaskellWorks.Data.Bits.FromBitTextByteString
 import HaskellWorks.Data.Naive
 import HaskellWorks.Data.Ops
 
-import qualified Data.Vector.Storable                          as DVS
-import qualified HaskellWorks.Data.BalancedParens.Gen          as G
-import qualified HaskellWorks.Data.BalancedParens.ParensSeq    as PS
-import qualified HaskellWorks.Data.BalancedParens.RangeMinMax  as RMM
-import qualified HaskellWorks.Data.BalancedParens.RangeMinMax2 as RMM2
-import qualified Hedgehog.Gen                                  as G
-import qualified Hedgehog.Range                                as R
+import qualified Data.List                                                                        as L
+import qualified Data.Vector.Storable                                                             as DVS
+import qualified HaskellWorks.Data.BalancedParens.FindClose                                       as CLS
+import qualified HaskellWorks.Data.BalancedParens.Gen                                             as G
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64           as BWV64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64 as BW64
+import qualified HaskellWorks.Data.BalancedParens.Internal.IO                                     as IO
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word64      as SW64
+import qualified HaskellWorks.Data.BalancedParens.ParensSeq                                       as PS
+import qualified HaskellWorks.Data.BalancedParens.RangeMin                                        as RM
+import qualified HaskellWorks.Data.BalancedParens.RangeMin2                                       as RM2
+import qualified HaskellWorks.Data.FromForeignRegion                                              as IO
+import qualified HaskellWorks.Data.Length                                                         as HW
+import qualified Hedgehog.Gen                                                                     as G
+import qualified Hedgehog.Range                                                                   as R
 
+{- HLINT ignore "Monoid law, left identity" -}
+
 setupEnvVector :: Int -> IO (DVS.Vector Word64)
 setupEnvVector n = return $ DVS.fromList (take n (cycle [maxBound, 0]))
 
-setupEnvRmmVector :: Int -> IO (RMM.RangeMinMax (DVS.Vector Word64))
-setupEnvRmmVector n = return $ RMM.mkRangeMinMax $ DVS.fromList (take n (cycle [maxBound, 0]))
+setupEnvRmVector :: Int -> IO (RM.RangeMin (DVS.Vector Word64))
+setupEnvRmVector n = return $ RM.mkRangeMin $ DVS.fromList (take n (cycle [maxBound, 0]))
 
-setupEnvRmm2Vector :: Int -> IO (RMM2.RangeMinMax2 (DVS.Vector Word64))
-setupEnvRmm2Vector n = return $ RMM2.mkRangeMinMax2 $ DVS.fromList (take n (cycle [maxBound, 0]))
+setupEnvRm2Vector :: Int -> IO (RM2.RangeMin2 (DVS.Vector Word64))
+setupEnvRm2Vector n = return $ RM2.mkRangeMin2 $ DVS.fromList (take n (cycle [maxBound, 0]))
 
 setupEnvBP2 :: IO Word64
 setupEnvBP2 = return $ DVS.head (fromBitTextByteString "10")
@@ -46,6 +68,17 @@
 setupEnvBP64 :: IO Word64
 setupEnvBP64 = return $ DVS.head (fromBitTextByteString "11111000 11101000 11101000 11101000 11101000 11101000 11101000 11100000")
 
+benchWord64 :: [Benchmark]
+benchWord64 = foldMap mkBenchWord64Group [0 .. 64]
+  where mkBenchWord64Group :: Word64 -> [Benchmark]
+        mkBenchWord64Group r = let w = (1 .<. r) - 1 in
+          [ bgroup "Word64"
+            [ bench ("Broadword   find close " <> bitShow w) (whnf (BW64.findUnmatchedCloseFar 0 0) w)
+            , bench ("Naive       find close " <> bitShow w) (whnf (SW64.findUnmatchedCloseFar 0 0) w)
+            , bench ("Super naive find close " <> bitShow w) (whnf ((`findClose` 1) . Naive       ) w)
+            ]
+          ]
+
 benchVector :: [Benchmark]
 benchVector =
   [ bgroup "Vector"
@@ -79,25 +112,25 @@
     ]
   ]
 
-benchRmm :: [Benchmark]
-benchRmm =
-  [ bgroup "Rmm"
+benchRm :: [Benchmark]
+benchRm =
+  [ bgroup "Rm"
     [ env (G.sample (G.storableVector (R.singleton 1000) (G.word64 R.constantBounded))) $ \v -> bgroup "Vector64"
-      [ bench "mkRangeMinMax"     (nf   RMM.mkRangeMinMax v)
+      [ bench "mkRangeMin"        (nf   RM.mkRangeMin v)
       ]
-    , env (setupEnvRmmVector 1000000) $ \bv -> bgroup "RangeMinMax"
+    , env (setupEnvRmVector 1000000) $ \bv -> bgroup "RangeMin"
       [ bench "findClose"         (nf   (map (findClose bv)) [0, 1000..10000000])
       ]
     ]
   ]
 
-benchRmm2 :: [Benchmark]
-benchRmm2 =
-  [ bgroup "Rmm2"
+benchRm2 :: [Benchmark]
+benchRm2 =
+  [ bgroup "Rm2"
     [ env (G.sample (G.storableVector (R.singleton 1000) (G.word64 R.constantBounded))) $ \v -> bgroup "Vector64"
-      [ bench "mkRangeMinMax2"    (nf   RMM2.mkRangeMinMax2 v)
+      [ bench "mkRangeMin2"       (nf   RM2.mkRangeMin2 v)
       ]
-    , env (setupEnvRmm2Vector 1000000) $ \bv -> bgroup "RangeMinMax2"
+    , env (setupEnvRm2Vector 1000000) $ \bv -> bgroup "RangeMin2"
       [ bench "findClose"         (nf   (map (findClose bv)) [0, 1000..10000000])
       ]
     ]
@@ -111,20 +144,50 @@
       , bench "nextSibling"   (nf (map (PS.nextSibling ps)) [1,101..100000])
       , bench "(<|)"          (nf (<| ps) True)
       , bench "(|>)"          (nf (ps |>) True)
-      , bench "drop"          (nf (fmap (flip PS.drop  ps)) [1,101..100000])
+      , bench "drop"          (nf (fmap (`PS.drop` ps)) [1,101..100000])
       ]
     , env (G.sample (G.vec2 (G.bpParensSeq (R.singleton 100000)))) $ \ ~(ps1, ps2) -> bgroup "ParensSeq"
       [ bench "(<>)"          (nf (ps1 <>) ps2)
       ]
-    , env (G.sample (G.list (R.singleton 100) (G.word64 (R.constantBounded)))) $ \ws -> bgroup "ParensSeq"
+    , env (G.sample (G.list (R.singleton 100) (G.word64 R.constantBounded))) $ \ws -> bgroup "ParensSeq"
       [ bench "fromWord64s"   (nf PS.fromWord64s ws)
       ]
     ]
   ]
 
+data EnvCorpusVector = EnvCorpusVector
+  { vector :: DVS.Vector Word64
+  , rmm2   :: RM2.RangeMin2 (DVS.Vector Word64)
+  } deriving (Generic, NFData)
+
+mkEnvCorpusVector :: FilePath -> IO EnvCorpusVector
+mkEnvCorpusVector file = do
+  myVector <- IO.mmapFromForeignRegion file
+  let myRmm2 = RM2.mkRangeMin2 myVector
+  return EnvCorpusVector
+    { vector  = myVector
+    , rmm2    = myRmm2
+    }
+
+mkBenchCorpusVector :: IO [Benchmark]
+mkBenchCorpusVector = do
+  entries <- IO.safeListDirectory "data/bench"
+  let files = L.sort (("data/bench/" ++) <$> (".ib.idx" `L.isSuffixOf`) `filter` entries)
+  benchmarks <- forM files $ \file -> return
+    [ env (mkEnvCorpusVector file) $ \e -> bgroup "Loading lazy byte string into Word64s" $ mempty
+      <> [bench ("BWV64.findClose with sum " <> file) (whnf (sum . mapMaybe (BWV64.findClose (e ^. the @"vector"))) [1 .. HW.length (e ^. the @"vector") * 64])]
+      <> [bench ("CLS.findClose   with sum " <> file) (whnf (sum . mapMaybe (CLS.findClose   (e ^. the @"rmm2"  ))) [1 .. HW.length (e ^. the @"vector") * 64])]
+    ]
+  return (join benchmarks)
+
 main :: IO ()
-main = defaultMain $ mempty
-  <> benchVector
-  <> benchRmm
-  <> benchRmm2
-  <> benchParensSeq
+main = do
+  benchCorpusVectorBroadword <- mkBenchCorpusVector
+
+  defaultMain $ mempty
+    <> benchWord64
+    <> benchVector
+    <> benchRm
+    <> benchRm2
+    <> benchParensSeq
+    <> benchCorpusVectorBroadword
diff --git a/doctest/DoctestDriver.hs b/doctest/DoctestDriver.hs
new file mode 100644
--- /dev/null
+++ b/doctest/DoctestDriver.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP #-}
+
+#if MIN_VERSION_GLASGOW_HASKELL(8,4,4,0)
+{-# OPTIONS_GHC -F -pgmF doctest-discover #-}
+#else
+module Main where
+
+import qualified System.IO as IO
+
+main :: IO ()
+main = IO.putStrLn "WARNING: doctest will not run on GHC versions earlier than 8.4.4"
+#endif
diff --git a/gen/HaskellWorks/Data/BalancedParens/Gen.hs b/gen/HaskellWorks/Data/BalancedParens/Gen.hs
--- a/gen/HaskellWorks/Data/BalancedParens/Gen.hs
+++ b/gen/HaskellWorks/Data/BalancedParens/Gen.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE DeriveGeneric #-}
 
 module HaskellWorks.Data.BalancedParens.Gen
   ( BP(..)
@@ -9,31 +9,33 @@
   , bpParensSeq
   , vector
   , vec2
-  , randomRmm
-  , randomRmm2
+  , randomRm
+  , randomRm2
   ) where
 
 import Data.Coerce
-import Data.Semigroup                             ((<>))
 import Data.Word
+import GHC.Generics
 import HaskellWorks.Data.BalancedParens.ParensSeq (ParensSeq)
 import HaskellWorks.Data.Positioning
 import Hedgehog
 
-import qualified Data.Vector                                   as DV
-import qualified Data.Vector.Storable                          as DVS
-import qualified HaskellWorks.Data.BalancedParens.ParensSeq    as PS
-import qualified HaskellWorks.Data.BalancedParens.RangeMinMax  as RMM
-import qualified HaskellWorks.Data.BalancedParens.RangeMinMax2 as RMM2
-import qualified Hedgehog.Gen                                  as G
-import qualified Hedgehog.Range                                as R
+import qualified Data.Vector                                as DV
+import qualified Data.Vector.Storable                       as DVS
+import qualified HaskellWorks.Data.BalancedParens.ParensSeq as PS
+import qualified HaskellWorks.Data.BalancedParens.RangeMin  as RM
+import qualified HaskellWorks.Data.BalancedParens.RangeMin2 as RM2
+import qualified Hedgehog.Gen                               as G
+import qualified Hedgehog.Range                             as R
 
+{- HLINT ignore "Use guards" -}
+
 count :: MonadGen m => Range Count -> m Count
 count r = coerce <$> G.word64 (coerce <$> r)
 
 data LR a = L a Int | R a Int deriving (Eq, Show)
 
-newtype BP = BP [Bool] deriving Eq
+newtype BP = BP [Bool] deriving (Eq, Generic)
 
 showBps :: [Bool] -> String
 showBps = fmap fromBool
@@ -77,12 +79,12 @@
 vec2 :: MonadGen m => m a -> m (a, a)
 vec2 g = (,) <$> g <*> g
 
-randomRmm :: MonadGen m => Range Int -> m (RMM.RangeMinMax (DVS.Vector Word64))
-randomRmm r = do
+randomRm :: MonadGen m => Range Int -> m (RM.RangeMin (DVS.Vector Word64))
+randomRm r = do
   v <- storableVector (fmap (64 *) r) (G.word64 R.constantBounded)
-  return (RMM.mkRangeMinMax v)
+  return (RM.mkRangeMin v)
 
-randomRmm2 :: MonadGen m => Range Int -> m (RMM2.RangeMinMax2 (DVS.Vector Word64))
-randomRmm2 r = do
+randomRm2 :: MonadGen m => Range Int -> m (RM2.RangeMin2 (DVS.Vector Word64))
+randomRm2 r = do
   v <- storableVector (fmap (64 *) r) (G.word64 R.constantBounded)
-  return (RMM2.mkRangeMinMax2 v)
+  return (RM2.mkRangeMin2 v)
diff --git a/gen/HaskellWorks/Data/BalancedParens/Internal/IO.hs b/gen/HaskellWorks/Data/BalancedParens/Internal/IO.hs
new file mode 100644
--- /dev/null
+++ b/gen/HaskellWorks/Data/BalancedParens/Internal/IO.hs
@@ -0,0 +1,12 @@
+module HaskellWorks.Data.BalancedParens.Internal.IO
+  ( safeListDirectory
+  ) where
+
+import qualified System.Directory as IO
+
+safeListDirectory :: FilePath -> IO [FilePath]
+safeListDirectory fp = do
+  exists <- IO.doesDirectoryExist fp
+  if exists
+    then IO.listDirectory fp
+    else return []
diff --git a/hw-balancedparens.cabal b/hw-balancedparens.cabal
--- a/hw-balancedparens.cabal
+++ b/hw-balancedparens.cabal
@@ -1,131 +1,229 @@
-cabal-version:  2.2
+cabal-version: 2.2
 
-name:           hw-balancedparens
-version:        0.2.2.2
-synopsis:       Balanced parentheses
-description:    Balanced parentheses.
-category:       Data, Bit, Succinct Data Structures, Data Structures
-homepage:       http://github.com/haskell-works/hw-balancedparens#readme
-bug-reports:    https://github.com/haskell-works/hw-balancedparens/issues
-author:         John Ky
-maintainer:     newhoggy@gmail.com
-copyright:      2016-2019 John Ky
-license:        BSD-3-Clause
-license-file:   LICENSE
-tested-with:    GHC == 8.6.5, GHC == 8.4.4, GHC == 8.2.2
-build-type:     Simple
-extra-source-files:
-  README.md
+name:                   hw-balancedparens
+version:                0.4.1.3
+synopsis:               Balanced parentheses
+description:            Balanced parentheses.
+category:               Data, Bit, Succinct Data Structures, Data Structures
+homepage:               http://github.com/haskell-works/hw-balancedparens#readme
+bug-reports:            https://github.com/haskell-works/hw-balancedparens/issues
+author:                 John Ky
+maintainer:             newhoggy@gmail.com
+copyright:              2016-2022 John Ky
+license:                BSD-3-Clause
+license-file:           LICENSE
+tested-with:            GHC == 9.4.2, GHC == 9.2.4, GHC == 9.0.2, GHC == 8.10.7, GHC == 8.8.4, GHC == 8.6.5
+build-type:             Simple
+extra-source-files:     README.md
 
 source-repository head
   type:     git
   location: https://github.com/haskell-works/hw-balancedparens
 
-common base               { build-depends: base                 >= 4        && < 5      }
+common base                       { build-depends: base                       >= 4.11       && < 5      }
 
-common criterion          { build-depends: criterion            >= 1.2      && < 1.6    }
-common deepseq            { build-depends: deepseq              >= 1.4.2.0  && < 1.5    }
-common hedgehog           { build-depends: hedgehog             >= 1.0      && < 1.1    }
-common hspec              { build-depends: hspec                >= 2.2      && < 2.6    }
-common hw-hspec-hedgehog  { build-depends: hw-hspec-hedgehog    >= 0.1      && < 0.2    }
-common hw-bits            { build-depends: hw-bits              >= 0.4.0.0  && < 0.8    }
-common hw-excess          { build-depends: hw-excess            >= 0.2.2.0  && < 0.3    }
-common hw-fingertree      { build-depends: hw-fingertree        >= 0.1.1.0  && < 0.2    }
-common hw-prim            { build-depends: hw-prim              >= 0.6.2.25 && < 0.7    }
-common hw-rankselect-base { build-depends: hw-rankselect-base   >= 0.2.0.0  && < 0.4    }
-common transformers       { build-depends: transformers         >= 0.5.6.2  && < 0.6    }
-common vector             { build-depends: vector               >= 0.12     && < 0.13   }
+common bytestring                 { build-depends: bytestring                 >= 0.9        && < 0.12   }
+common criterion                  { build-depends: criterion                  >= 1.2        && < 1.7    }
+common deepseq                    { build-depends: deepseq                    >= 1.4.2.0    && < 1.5    }
+common directory                  { build-depends: directory                  >= 1.2.2      && < 1.4    }
+common doctest                    { build-depends: doctest                    >= 0.16.2     && < 0.21   }
+common doctest-discover           { build-depends: doctest-discover           >= 0.2        && < 0.3    }
+common generic-lens               { build-depends: generic-lens               >= 1.2.0.0    && < 2.3    }
+common hedgehog                   { build-depends: hedgehog                   >= 1.0        && < 1.3    }
+common hspec                      { build-depends: hspec                      >= 2.2        && < 3      }
+common hw-hspec-hedgehog          { build-depends: hw-hspec-hedgehog          >= 0.1        && < 0.2    }
+common hw-bits                    { build-depends: hw-bits                    >= 0.7.2.1    && < 0.8    }
+common hw-excess                  { build-depends: hw-excess                  >= 0.2.2.0    && < 0.3    }
+common hw-fingertree              { build-depends: hw-fingertree              >= 0.1.1.0    && < 0.2    }
+common hw-int                     { build-depends: hw-int                     >= 0.0.2      && < 0.0.3  }
+common hw-prim                    { build-depends: hw-prim                    >= 0.6.2.25   && < 0.7    }
+common hw-rankselect-base         { build-depends: hw-rankselect-base         >= 0.3.2.1    && < 0.4    }
+common lens                       { build-depends: lens                       >= 4          && < 6      }
+common mmap                       { build-depends: mmap                       >= 0.5.9      && < 0.6    }
+common optparse-applicative       { build-depends: optparse-applicative       >= 0.14       && < 0.18   }
+common transformers               { build-depends: transformers               >= 0.5.6.2    && < 0.7    }
+common vector                     { build-depends: vector                     >= 0.12       && < 0.14   }
 
+common hw-balancedparens
+  build-depends:        hw-balancedparens
+
+common hw-balancedparens-gen
+  build-depends:        hw-balancedparens-gen
+
 common config
-  default-language:   Haskell2010
-  ghc-options:        -Wall -O2 -msse4.2
+  default-language:     Haskell2010
+  ghc-options:          -Wall -O2
+  if arch(x86_64)
+    ghc-options:        -msse4.2
 
 library
-  import:   base, config
-          , deepseq
-          , hw-bits
-          , hw-excess
-          , hw-fingertree
-          , hw-prim
-          , hw-rankselect-base
-          , vector
-  exposed-modules:
-    HaskellWorks.Data.BalancedParens
-    HaskellWorks.Data.BalancedParens.BalancedParens
-    HaskellWorks.Data.BalancedParens.Broadword
-    HaskellWorks.Data.BalancedParens.CloseAt
-    HaskellWorks.Data.BalancedParens.Enclose
-    HaskellWorks.Data.BalancedParens.FindClose
-    HaskellWorks.Data.BalancedParens.FindCloseN
-    HaskellWorks.Data.BalancedParens.FindOpen
-    HaskellWorks.Data.BalancedParens.FindOpenN
-    HaskellWorks.Data.BalancedParens.Internal.List
-    HaskellWorks.Data.BalancedParens.Internal.ParensSeq
-    HaskellWorks.Data.BalancedParens.Internal.RoseTree
-    HaskellWorks.Data.BalancedParens.Internal.Word
-    HaskellWorks.Data.BalancedParens.NewCloseAt
-    HaskellWorks.Data.BalancedParens.NewOpenAt
-    HaskellWorks.Data.BalancedParens.OpenAt
-    HaskellWorks.Data.BalancedParens.ParensSeq
-    HaskellWorks.Data.BalancedParens.ParensSeq.Types
-    HaskellWorks.Data.BalancedParens.RangeMinMax
-    HaskellWorks.Data.BalancedParens.RangeMinMax2
-    HaskellWorks.Data.BalancedParens.Simple
-  other-modules:      Paths_hw_balancedparens
-  autogen-modules:    Paths_hw_balancedparens
-  hs-source-dirs:     src
+  import:               base, config
+                      , deepseq
+                      , hw-bits
+                      , hw-excess
+                      , hw-fingertree
+                      , hw-int
+                      , hw-prim
+                      , hw-rankselect-base
+                      , vector
+  exposed-modules:      HaskellWorks.Data.BalancedParens
+                        HaskellWorks.Data.BalancedParens.BalancedParens
+                        HaskellWorks.Data.BalancedParens.CloseAt
+                        HaskellWorks.Data.BalancedParens.Enclose
+                        HaskellWorks.Data.BalancedParens.FindClose
+                        HaskellWorks.Data.BalancedParens.FindCloseN
+                        HaskellWorks.Data.BalancedParens.FindOpen
+                        HaskellWorks.Data.BalancedParens.FindOpenN
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word16
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word32
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word64
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word8
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64
+                        HaskellWorks.Data.BalancedParens.Internal.List
+                        HaskellWorks.Data.BalancedParens.Internal.ParensSeq
+                        HaskellWorks.Data.BalancedParens.Internal.RoseTree
+                        HaskellWorks.Data.BalancedParens.Internal.Show
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseC.Generic
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector16
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector32
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector64
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector8
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word16
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word32
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word64
+                        HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word8
+                        HaskellWorks.Data.BalancedParens.Internal.Trace
+                        HaskellWorks.Data.BalancedParens.Internal.Vector.Storable
+                        HaskellWorks.Data.BalancedParens.Internal.Word
+                        HaskellWorks.Data.BalancedParens.Internal.Word16
+                        HaskellWorks.Data.BalancedParens.Internal.Word32
+                        HaskellWorks.Data.BalancedParens.Internal.Word64
+                        HaskellWorks.Data.BalancedParens.Internal.Word8
+                        HaskellWorks.Data.BalancedParens.NewCloseAt
+                        HaskellWorks.Data.BalancedParens.NewOpenAt
+                        HaskellWorks.Data.BalancedParens.OpenAt
+                        HaskellWorks.Data.BalancedParens.ParensSeq
+                        HaskellWorks.Data.BalancedParens.ParensSeq.Types
+                        HaskellWorks.Data.BalancedParens.RangeMin
+                        HaskellWorks.Data.BalancedParens.RangeMin2
+                        HaskellWorks.Data.BalancedParens.Simple
+  other-modules:        Paths_hw_balancedparens
+  autogen-modules:      Paths_hw_balancedparens
+  hs-source-dirs:       src
 
 library hw-balancedparens-gen
-  import:   base, config
-          , deepseq
-          , hedgehog
-          , hspec
-          , hw-prim
-          , vector
-  exposed-modules:
-    HaskellWorks.Data.BalancedParens.Gen
-    Paths_hw_balancedparens
-  build-depends:      hw-balancedparens
-  hs-source-dirs:     gen
-  autogen-modules:    Paths_hw_balancedparens
+  import:               base, config
+                      , deepseq
+                      , directory
+                      , hedgehog
+                      , hspec
+                      , hw-balancedparens
+                      , hw-prim
+                      , vector
+  exposed-modules:      HaskellWorks.Data.BalancedParens.Gen
+                        HaskellWorks.Data.BalancedParens.Internal.IO
+  hs-source-dirs:       gen
 
+executable hw-balancedparens
+  import:               base, config
+                      , bytestring
+                      , generic-lens
+                      , hw-balancedparens
+                      , hw-bits
+                      , hw-prim
+                      , lens
+                      , mmap
+                      , optparse-applicative
+                      , vector
+  main-is:              Main.hs
+  hs-source-dirs:       app
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
+  other-modules:        App.Commands
+                        App.Commands.BitsToParens
+                        App.Commands.Options.Type
+                        App.Commands.ParensToBits
+                        App.Commands.Positions
+                        App.IO
+                        Paths_hw_balancedparens
+
 test-suite hw-balancedparens-test
-  import:   base, config
-          , hedgehog
-          , hspec
-          , hw-bits
-          , hw-hspec-hedgehog
-          , hw-prim
-          , hw-rankselect-base
-          , transformers
-          , vector
-  type:               exitcode-stdio-1.0
-  main-is:            Spec.hs
-  other-modules:
-    HaskellWorks.Data.BalancedParens.Internal.BroadwordSpec
-    HaskellWorks.Data.BalancedParens.Internal.ParensSeqSpec
-    HaskellWorks.Data.BalancedParens.RangeMinMax2Spec
-    HaskellWorks.Data.BalancedParens.RangeMinMaxSpec
-    HaskellWorks.Data.BalancedParens.SimpleSpec
-    Paths_hw_balancedparens
-  build-depends:      hw-balancedparens
-                    , hw-balancedparens-gen
-  hs-source-dirs:     test
-  ghc-options:        -threaded -rtsopts -with-rtsopts=-N
-  autogen-modules:    Paths_hw_balancedparens
-  build-tool-depends: hspec-discover:hspec-discover
+  import:               base, config
+                      , directory
+                      , hedgehog
+                      , hspec
+                      , hw-balancedparens
+                      , hw-balancedparens-gen
+                      , hw-bits
+                      , hw-hspec-hedgehog
+                      , hw-int
+                      , hw-prim
+                      , hw-rankselect-base
+                      , transformers
+                      , vector
+  type:                 exitcode-stdio-1.0
+  main-is:              Spec.hs
+  other-modules:        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64Spec
+                        HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8Spec
+                        HaskellWorks.Data.BalancedParens.Internal.BroadwordSpec
+                        HaskellWorks.Data.BalancedParens.Internal.ParensSeqSpec
+                        HaskellWorks.Data.BalancedParens.FindCloseNSpec
+                        HaskellWorks.Data.BalancedParens.RangeMin2Spec
+                        HaskellWorks.Data.BalancedParens.RangeMinSpec
+                        HaskellWorks.Data.BalancedParens.SimpleSpec
+  hs-source-dirs:       test
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
+  build-tool-depends:   hspec-discover:hspec-discover
 
 benchmark bench
-  import:   base, config
-          , criterion
-          , hedgehog
-          , hw-bits
-          , hw-prim
-          , vector
-  type:               exitcode-stdio-1.0
-  main-is:            Main.hs
-  other-modules:      Paths_hw_balancedparens
-  autogen-modules:    Paths_hw_balancedparens
-  hs-source-dirs:     bench
-  build-depends:      hw-balancedparens
-                    , hw-balancedparens-gen
+  import:               base, config
+                      , criterion
+                      , deepseq
+                      , directory
+                      , generic-lens
+                      , hedgehog
+                      , hw-balancedparens
+                      , hw-balancedparens-gen
+                      , hw-bits
+                      , hw-prim
+                      , lens
+                      , vector
+  type:                 exitcode-stdio-1.0
+  main-is:              Main.hs
+  hs-source-dirs:       bench
+
+test-suite doctest
+  import:               base, config
+                      , doctest
+                      , doctest-discover
+                      , hw-balancedparens
+                      , hw-bits
+                      , hw-prim
+  default-language:     Haskell2010
+  type:                 exitcode-stdio-1.0
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
+  main-is:              DoctestDriver.hs
+  HS-Source-Dirs:       doctest
+  build-tool-depends:   doctest-discover:doctest-discover
diff --git a/src/HaskellWorks/Data/BalancedParens/BalancedParens.hs b/src/HaskellWorks/Data/BalancedParens/BalancedParens.hs
--- a/src/HaskellWorks/Data/BalancedParens/BalancedParens.hs
+++ b/src/HaskellWorks/Data/BalancedParens/BalancedParens.hs
@@ -22,20 +22,22 @@
 
 class (OpenAt v, CloseAt v, FindOpen v, FindClose v, Enclose v) => BalancedParens v where
   -- TODO Second argument should be Int
-  firstChild  :: v -> Count -> Maybe Count
-  nextSibling :: v -> Count -> Maybe Count
-  parent      :: v -> Count -> Maybe Count
+  firstChild :: v -> Count -> Maybe Count
   firstChild  v p = if openAt v p && openAt v (p + 1)   then Just (p + 1) else Nothing
+  {-# INLINE firstChild #-}
+
+  nextSibling :: v -> Count -> Maybe Count
   nextSibling v p = if closeAt v p
     then Nothing
     else openAt v `mfilter` (findClose v p >>= (\q ->
       if p /= q
         then return (q + 1)
         else Nothing))
-  parent      v p = enclose   v p >>= (\r -> if r >= 1 then return r      else Nothing)
-  {-# INLINE firstChild   #-}
-  {-# INLINE nextSibling  #-}
-  {-# INLINE parent       #-}
+  {-# INLINE nextSibling #-}
+
+  parent :: v -> Count -> Maybe Count
+  parent v p = enclose v p >>= (\r -> if r >= 1 then return r      else Nothing)
+  {-# INLINE parent #-}
 
 depth :: (BalancedParens v, Rank0 v, Rank1 v) => v -> Count -> Maybe Count
 depth v p = (\q -> rank1 v q - rank0 v q) <$> findOpen v p
diff --git a/src/HaskellWorks/Data/BalancedParens/Broadword.hs b/src/HaskellWorks/Data/BalancedParens/Broadword.hs
deleted file mode 100644
--- a/src/HaskellWorks/Data/BalancedParens/Broadword.hs
+++ /dev/null
@@ -1,200 +0,0 @@
-{-# LANGUAGE BangPatterns          #-}
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE InstanceSigs          #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-
-module HaskellWorks.Data.BalancedParens.Broadword
-  ( findCloseW64
-  , ocCalc8
-  , ocCalc64
-  , showPadded
-  , kkBitDiffPos
-  , kkBitDiff
-  , kkBitDiffSimple
-  ) where
-
-import Data.Int
-import Data.Word
-import Debug.Trace
-import HaskellWorks.Data.Bits.BitShown
-import HaskellWorks.Data.Bits.BitWise
-import HaskellWorks.Data.Bits.Broadword
-
-import qualified Data.Bits as DB
-
-traceW :: String -> Word64 -> Word64
-traceW s w = trace (s ++ ": " ++ show (BitShown w) ++ " : " ++ show w ++ ", " ++ show (fromIntegral w :: Int64)) w
-
-findCloseW64 :: Word64 -> Word64
-findCloseW64 x =                                                                         -- let !_ = traceW "x00" x   in
-  let !b00 = x - ((x .&. 0xaaaaaaaaaaaaaaaa) .>. 1)                                   in -- let !_ = traceW "b00" b00 in
-  let !b01 = (b00 .&. 0x3333333333333333) + ((b00 .>. 2) .&. 0x3333333333333333)      in -- let !_ = traceW "b01" b01 in
-  let !b02 = (b01 + (b01 .>. 4)) .&. 0x0f0f0f0f0f0f0f0f                               in -- let !_ = traceW "b02" b02 in
-  let !b03 = (b02 * 0x0101010101010101) .<. 1                                         in -- let !_ = traceW "b03" b03 in
-  let !b04 = kBitDiffUnsafe 8 (h 8 .|. 0x4038302820181008) b03                        in -- let !_ = traceW "b04" b04 in
-  let !u00 = (((((b04 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                  in -- let !_ = traceW "u00" u00 in
-  let !z00 =                         ((h 8 .>. 1) .|. (l 8 * 7)) .&. u00              in -- let !_ = traceW "z00" z00 in
-                                                                                         -- let !_ = trace "" False   in
-  let !d10 = (l 8 * 2 - (((x .>. 6) .&. (l 8 .<. 1)) + ((x .>. 5) .&. (l 8 .<. 1))))  in -- let !_ = traceW "d10" d10 in
-  let !b10 = b04 - d10                                                                in -- let !_ = traceW "b10" b10 in
-  let !u10 = (((((b10 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                  in -- let !_ = traceW "u10" u10 in
-  let !z10 = (z00 .&. comp u10) .|. (((h 8 .>. 1) .|. (l 8 * 5)) .&. u10)             in -- let !_ = traceW "z10" z10 in
-                                                                                         -- let !_ = trace "" False   in
-  let !d20 = (l 8 * 2 - (((x .>. 4) .&. (l 8 .<. 1)) + ((x .>. 3) .&. (l 8 .<. 1))))  in -- let !_ = traceW "d20" d20 in
-  let !b20 = b10 - d20                                                                in -- let !_ = traceW "b20" b20 in
-  let !u20 = (((((b20 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                  in -- let !_ = traceW "u20" u20 in
-  let !z20 = (z10 .&. comp u20) .|. (((h 8 .>. 1) .|. (l 8 * 3)) .&. u20)             in -- let !_ = traceW "z20" z20 in
-                                                                                         -- let !_ = trace "" False   in
-  let !d30 = (l 8 * 2 - (((x .>. 2) .&. (l 8 .<. 1)) + ((x .>. 1) .&. (l 8 .<. 1))))  in -- let !_ = traceW "d30" d30 in
-  let !b30 = b20 - d30                                                                in -- let !_ = traceW "b30" b30 in
-  let !u30 = (((((b30 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                  in -- let !_ = traceW "u30" u30 in
-  let !z30 = (z20 .&. comp u30) .|. (((h 8 .>. 1) .|.  l 8     ) .&. u30)             in -- let !_ = traceW "z30" z30 in
-
-  let !p00 = lsb (z30 .>. 6 .&. l 8)                                                  in -- let !_ = traceW "p00" p00 in
-  let !r00 = ((p00 + ((z30 .>. fromIntegral p00) .&. 0x3f)) .|. (p00 .>. 8)) .&. 0x7f in -- let !_ = traceW "r00" r00 in
-  r00
-{-# INLINE findCloseW64 #-}
-
--- µ0 :: Word64
--- µ0 = 0x5555555555555555
-
-µ1 :: Word64
-µ1 = 0x3333333333333333
-
-µ2 :: Word64
-µ2 = 0x0F0F0F0F0F0F0F0F
-
-µ3 :: Word64
-µ3 = 0x00FF00FF00FF00FF
-
-µ4 :: Word64
-µ4 = 0x0000FFFF0000FFFF
-
-µ5 :: Word64
-µ5 = 0x00000000FFFFFFFF
-
-ocCalc64 :: Word64 -> (Word64, Word64)
-ocCalc64 x =
-  let b0  =   x .&. 0x5555555555555555                            in let !_ = traceW "b0 " b0  in
-  let b1  =  (x .&. 0xAAAAAAAAAAAAAAAA) .>. 1                     in let !_ = traceW "b1 " b1  in
-  let ll  =  (b0 .^. b1) .&. b1                                   in let !_ = traceW "ll " ll  in
-  let o1  =  (b0 .&. b1) .<. 1 .|. ll                             in let !_ = traceW "o1 " o1  in
-  let c1  = ((b0 .|. b1) .^. 0x5555555555555555) .<. 1 .|. ll     in let !_ = traceW "c1 " c1  in
-
-  let eo1 =    o1 .&. µ1                                          in let !_ = traceW "eo1" eo1 in
-  let ec1 =  ((c1 .&. µ1) .<.  2) .>.  2                          in let !_ = traceW "ec1" ec1 in
-  let o2  = (((o1 .&. µ1) .<.  2) .>.  2) + kBitDiffPos 8 eo1 ec1 in let !_ = traceW "o2 " o2  in
-  let c2  =   (c1 .&. µ1)                 + kBitDiffPos 8 ec1 eo1 in let !_ = traceW "c2 " c2  in
-
-  let eo2 =    o2 .&. µ2                                          in let !_ = traceW "eo2" eo2 in
-  let ec2 =  ((c2 .&. µ2) .<.  4) .>.  4                          in let !_ = traceW "ec2" ec2 in
-  let o3  = (((o2 .&. µ2) .<.  4) .>.  4) + kBitDiffPos 8 eo2 ec2 in let !_ = traceW "o3 " o3  in
-  let c3  =   (c2 .&. µ2)                 + kBitDiffPos 8 ec2 eo2 in let !_ = traceW "c3 " c3  in
-
-  let eo3 =    o3 .&. µ3                                          in let !_ = traceW "eo3" eo3 in
-  let ec3 =  ((c3 .&. µ3) .<.  8) .>.  8                          in let !_ = traceW "ec3" ec3 in
-  let o4  = (((o3 .&. µ3) .<.  8) .>.  8) + kBitDiffPos 8 eo3 ec3 in let !_ = traceW "o4 " o4  in
-  let c4  =   (c3 .&. µ3)                 + kBitDiffPos 8 ec3 eo3 in let !_ = traceW "c4 " c4  in
-
-  let eo4 =    o4 .&. µ4                                          in let !_ = traceW "eo4" eo4 in
-  let ec4 =  ((c4 .&. µ4) .<. 16) .>. 16                          in let !_ = traceW "ec4" ec4 in
-  let o5  = (((o4 .&. µ4) .<. 16) .>. 16) + kBitDiffPos 8 eo4 ec4 in let !_ = traceW "o5 " o5  in
-  let c5  =   (c4 .&. µ4)                 + kBitDiffPos 8 ec4 eo4 in let !_ = traceW "c5 " c5  in
-
-  let eo5 =    o5 .&. µ5                                          in let !_ = traceW "eo5" eo5 in
-  let ec5 =  ((c5 .&. µ5) .<. 32) .>. 32                          in let !_ = traceW "ec5" ec5 in
-  let o6  = (((o5 .&. µ5) .<. 32) .>. 32) + kBitDiffPos 8 eo5 ec5 in let !_ = traceW "o6 " o6  in
-  let c6  =   (c5 .&. µ5)                 + kBitDiffPos 8 ec5 eo5 in let !_ = traceW "c6 " c6  in
-
-  (o6, c6)
-
--- µµ0 :: Word8
--- µµ0 = 0x55
-
-µµ1 :: Word8
-µµ1 = 0x33
-
-µµ2 :: Word8
-µµ2 = 0x0F
-
-hh :: Int -> Word8
-hh 2   = 0xaa
-hh 4   = 0x88
-hh 8   = 0x80
-hh 16  = 0x80
-hh 32  = 0x80
-hh 64  = 0x80
-hh k   = error ("Invalid h k where k = " ++ show k)
-{-# INLINE hh #-}
-
-kkBitDiff :: Int -> Word8 -> Word8 -> Word8
-kkBitDiff k x y = ((x .|. hh k) - (y .&. comp (hh k))) .^. ((x .^. comp y) .&. hh k)
-{-# INLINE kkBitDiff #-}
-
-kkBitDiffSimple :: Int -> Word8 -> Word8 -> Word8
-kkBitDiffSimple k x y = ((x .|. hh k) - y) .^. hh k
-{-# INLINE kkBitDiffSimple #-}
-
-kkBitDiffPos :: Int -> Word8 -> Word8 -> Word8
-kkBitDiffPos k x y = let d = kkBitDiff k x y in d .&. kkBitDiff k (d .>. fromIntegral (k - 1)) 1
-{-# INLINE kkBitDiffPos #-}
-
-showPadded :: Show a => Int -> a -> String
-showPadded n a = reverse (take n (reverse (show a) ++ [' ', ' ' ..]))
-
-traceWW :: String -> Word8 -> Word8
-traceWW s w = trace (s ++ ": " ++ show (BitShown w) ++ " : " ++ showPadded 3 w ++ ", " ++ showPadded 3 (fromIntegral w :: Int8)) w
-
-(.>+.) :: Word8 -> Int -> Word8
-(.>+.) w n = fromIntegral ((fromIntegral w :: Int8) `DB.shift` (-n))
-
--- import qualified Data.Vector.Storable as DVS
--- import HaskellWorks.Data.Bits.FromBitTextByteString
--- import Data.Word
--- import HaskellWorks.Data.BalancedParens.Broadword
-
-ocCalc8 :: Word8 -> Word8 -> Word8
-ocCalc8 p x =
-  let b0  =   x .&. 0x55                                                            in let !_ = traceWW "b0 " b0  in
-  let b1  =  (x .&. 0xAA) .>. 1                                                     in let !_ = traceWW "b1 " b1  in
-  let ll  =  (b0 .^. b1) .&. b1                                                     in let !_ = traceWW "ll " ll  in
-  let o1  =  (b0 .&. b1)           .<. 1 .|. ll                                     in let !_ = traceWW "o1 " o1  in
-  let c1  = ((b0 .|. b1) .^. 0x55) .<. 1 .|. ll                                     in let !_ = traceWW "c1 " c1  in
-
-  -- arithmetic operators come first, ordered in the standard way
-  -- followed by shifts
-  -- .&.
-  -- .^.
-  -- .|.
-  let eo1 =   o1 .&.  µµ1                                                           in let !_ = traceWW "eo1" eo1 in
-  let ec1 =  (c1 .&. (µµ1 .<.  2)) .>.  2                                           in let !_ = traceWW "ec1" ec1 in
-  let o2  = ((o1 .&. (µµ1 .<.  2)) .>.  2) + kkBitDiffPos 4 eo1 ec1                 in let !_ = traceWW "o2 " o2  in -- <- Should this be 8 or 4?
-  let !_ = traceWW "xxx" (kkBitDiffPos 4 ec1 eo1) in
-  let !_ = traceWW "yyy" (c1 .&.  µµ1) in
-  let c2  =  (c1 .&.  µµ1)                 + kkBitDiffPos 4 ec1 eo1                 in let !_ = traceWW "c2 " c2  in
-
-  let eo2 =   o2 .&.  µµ2                                                           in let !_ = traceWW "eo2" eo2 in
-  let ec2 =  (c2 .&. (µµ2 .<.  4)) .>.  4                                           in let !_ = traceWW "ec2" ec2 in
-  let o3  = ((o2 .&. (µµ2 .<.  4)) .>.  4) + kkBitDiffPos 8 eo2 ec2                 in let !_ = traceWW "o3 " o3  in
-  let c3  =  (c2 .&.  µµ2)                 + kkBitDiffPos 8 ec2 eo2                 in let !_ = traceWW "c3 " c3  in
-
-  let nnn  =       ((c2 .>. 0) .&. 15)                                              in let !_ = traceWW "nnn" nnn in
-  let qqq  =  (((c2 .>. 0) .&. 15) - p)                                             in let !_ = traceWW "qqq" qqq in
-  let bb2  = ((((c2 .>. 0) .&. 15) - p) .>+. 7)                                     in let !_ = traceWW "bb2" bb2 in
-  let mm2  = bb2 .&. 15                                                             in let !_ = traceWW "mm2" mm2 in
-  let pa2  = p   - (c2 .&. mm2)                                                     in let !_ = traceWW "pa2" pa2 in
-  let pb2  = pa2 + (o2 .&. mm2)                                                     in let !_ = traceWW "pb2" pb2 in
-  let ss2  = 4 .&. bb2                                                              in let !_ = traceWW "ss2" ss2 in
-
-  -- let nnn  =   ((c1 .>. fromIntegral ss2) .&. 3)                                    in let !_ = traceWW "nnn" nnn in
-  -- let qqq  =  (((c1 .>. fromIntegral ss2) .&. 3) - pb2)                             in let !_ = traceWW "qqq" qqq in
-  let bb1  = ((((c1 .>. fromIntegral ss2) .&. 3) - pb2) .>+. 7)                     in let !_ = traceWW "bb1" bb1 in
-  let mm1  = bb1 .&. 3                                                              in let !_ = traceWW "mm1" mm1 in
-  let pa1  = pa2 - (c1 .&. mm1)                                                     in let !_ = traceWW "pa1" pa1 in
-  let pb1  = pa1 + (o1 .&. mm1)                                                     in let !_ = traceWW "pb1" pb1 in
-  let ss1  = ss2 + (2  .&. bb1)                                                     in let !_ = traceWW "ss1" ss1 in
-
-  let rrr  = ss1 + pb1 + (((x .>. fromIntegral ss1) .&. ((pb1 .<. 1) .|. 1)) .<. 1)   in let !_ = traceWW "rrr" rrr in
-
-  rrr
diff --git a/src/HaskellWorks/Data/BalancedParens/CloseAt.hs b/src/HaskellWorks/Data/BalancedParens/CloseAt.hs
--- a/src/HaskellWorks/Data/BalancedParens/CloseAt.hs
+++ b/src/HaskellWorks/Data/BalancedParens/CloseAt.hs
@@ -4,21 +4,37 @@
   ( CloseAt(..)
   ) where
 
-import Data.Vector.Storable             as DVS
+import Data.Vector.Storable                  as DVS
 import Data.Word
 import HaskellWorks.Data.Bits.BitLength
-import HaskellWorks.Data.Bits.BitWise
 import HaskellWorks.Data.Bits.BitShown
-import HaskellWorks.Data.Bits.Broadword
-import HaskellWorks.Data.Positioning
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Type
 import HaskellWorks.Data.Naive
+import HaskellWorks.Data.Positioning
 
-closeAt' :: TestBit a => a -> Count -> Bool
-closeAt' v c = not (v .?. toPosition (c - 1))
+closeAt' :: (TestBit a, BitLength a) => a -> Count -> Bool
+closeAt' v c = c > 0 && not (v .?. toPosition (c - 1)) || c > bitLength v
 {-# INLINE closeAt' #-}
 
 class CloseAt v where
-  closeAt     :: v -> Count -> Bool
+  -- | Determine if the parenthesis at the give position (one-based) is a close.
+  --
+  -- >>> :set -XTypeApplications
+  -- >>> import HaskellWorks.Data.Bits.BitRead
+  -- >>> import Data.Maybe
+  --
+  -- >>> closeAt (fromJust $ bitRead @Word8 "10101010") 1
+  -- False
+  --
+  -- >>> closeAt (fromJust $ bitRead @Word8 "10101010") 2
+  -- True
+  --
+  -- If the parenthesis at the given position does not exist in the input, it is considered to be a close.
+  --
+  -- >>> closeAt (fromJust $ bitRead @Word8 "10101010") 9
+  -- True
+  closeAt :: v -> Count -> Bool
 
 instance (BitLength a, TestBit a) => CloseAt (BitShown a) where
   closeAt = closeAt' . bitShown
diff --git a/src/HaskellWorks/Data/BalancedParens/Enclose.hs b/src/HaskellWorks/Data/BalancedParens/Enclose.hs
--- a/src/HaskellWorks/Data/BalancedParens/Enclose.hs
+++ b/src/HaskellWorks/Data/BalancedParens/Enclose.hs
@@ -13,7 +13,7 @@
 import qualified Data.Vector.Storable as DVS
 
 class Enclose v where
-  enclose     :: v -> Count -> Maybe Count
+  enclose :: v -> Count -> Maybe Count
 
 instance (Enclose a) => Enclose (BitShown a) where
   enclose = enclose . bitShown
diff --git a/src/HaskellWorks/Data/BalancedParens/FindClose.hs b/src/HaskellWorks/Data/BalancedParens/FindClose.hs
--- a/src/HaskellWorks/Data/BalancedParens/FindClose.hs
+++ b/src/HaskellWorks/Data/BalancedParens/FindClose.hs
@@ -5,19 +5,47 @@
   ) where
 
 import Data.Word
-import HaskellWorks.Data.BalancedParens.Broadword
 import HaskellWorks.Data.BalancedParens.CloseAt
 import HaskellWorks.Data.BalancedParens.FindCloseN
 import HaskellWorks.Data.Bits.BitShown
 import HaskellWorks.Data.Bits.BitWise
-import HaskellWorks.Data.Bits.Broadword
+import HaskellWorks.Data.Bits.Broadword.Type
 import HaskellWorks.Data.Naive
 import HaskellWorks.Data.Positioning
 
-import qualified Data.Vector.Storable as DVS
+import qualified Data.Vector.Storable                                                   as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16 as BWV16
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32 as BWV32
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64 as BWV64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8  as BWV8
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64             as W64
 
 class FindClose v where
-  findClose   :: v -> Count -> Maybe Count
+  -- | Find the closing parenthesis that machines the open parenthesis at the current position.
+  --
+  -- If the parenthesis at the current position is an close parenthesis, then return the current position.
+  --
+  -- Indexes are 1-based.  1 corresponds to open and 0 corresponds to close.
+  --
+  -- If we run out of bits in the supplied bit-string, the implementation my either return Nothing, or
+  -- assume all the bits that follow are zeros.
+  --
+  -- >>> :set -XTypeApplications
+  -- >>> import Data.Maybe
+  -- >>> import HaskellWorks.Data.Bits.BitRead
+  -- >>> findClose (fromJust (bitRead @Word64 "00000000")) 1
+  -- Just 1
+  -- >>> findClose (fromJust (bitRead @Word64 "10101010")) 1
+  -- Just 2
+  -- >>> findClose (fromJust (bitRead @Word64 "10101010")) 2
+  -- Just 2
+  -- >>> findClose (fromJust (bitRead @Word64 "10101010")) 3
+  -- Just 4
+  -- >>> findClose (fromJust (bitRead @Word64 "11010010")) 1
+  -- Just 6
+  -- >>> findClose (fromJust (bitRead @Word64 "11110000")) 1
+  -- Just 8
+  findClose :: v -> Count -> Maybe Count
 
 instance (FindClose a) => FindClose (BitShown a) where
   findClose = findClose . bitShown
@@ -28,21 +56,37 @@
   {-# INLINE findClose #-}
 
 instance FindClose (DVS.Vector Word8) where
-  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  findClose = BWV8.findClose
   {-# INLINE findClose #-}
 
 instance FindClose (DVS.Vector Word16) where
-  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  findClose = BWV16.findClose
   {-# INLINE findClose #-}
 
 instance FindClose (DVS.Vector Word32) where
-  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  findClose = BWV32.findClose
   {-# INLINE findClose #-}
 
 instance FindClose (DVS.Vector Word64) where
-  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  findClose = BWV64.findClose
   {-# INLINE findClose #-}
 
+instance FindClose (Naive (DVS.Vector Word8)) where
+  findClose (Naive v) p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  {-# INLINE findClose #-}
+
+instance FindClose (Naive (DVS.Vector Word16)) where
+  findClose (Naive v) p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  {-# INLINE findClose #-}
+
+instance FindClose (Naive (DVS.Vector Word32)) where
+  findClose (Naive v) p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  {-# INLINE findClose #-}
+
+instance FindClose (Naive (DVS.Vector Word64)) where
+  findClose (Naive v) p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  {-# INLINE findClose #-}
+
 instance FindClose Word8 where
   findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
   {-# INLINE findClose #-}
@@ -65,7 +109,7 @@
 
 instance FindClose (Broadword Word64) where
   findClose (Broadword w) p = let x = w .>. (p - 1) in
-    case negate (x .&. 1) .&. findCloseW64 x of
+    case negate (x .&. 1) .&. W64.findUnmatchedClose x of
       127 -> Nothing
       r   -> let r' = fromIntegral r + p in if r' > 64 then Nothing else Just r'
   {-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/FindCloseN.hs b/src/HaskellWorks/Data/BalancedParens/FindCloseN.hs
--- a/src/HaskellWorks/Data/BalancedParens/FindCloseN.hs
+++ b/src/HaskellWorks/Data/BalancedParens/FindCloseN.hs
@@ -12,61 +12,57 @@
 import HaskellWorks.Data.Naive
 import HaskellWorks.Data.Positioning
 
-import qualified Data.Vector.Storable as DVS
+import qualified Data.Vector.Storable                                              as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic as G
 
 class FindCloseN v where
+  -- | Find the position of the corresponding close parenthesis carrying in a number of open parentheses starting from a given position.
+  --
+  -- All positions are one based.
+  --
+  -- See the reference implementation 'G.findCloseN' for details
   findCloseN :: v -> Count -> Count -> Maybe Count
 
-findClose' :: (BitLength a, CloseAt a, TestBit a) => a -> Count -> Count -> Maybe Count
-findClose' v c p = if 0 < p && p <= bitLength v
-  then if v `closeAt` p
-    then if c <= 1
-      then Just p
-      else findClose' v (c - 1) (p + 1)
-    else findClose' v (c + 1) (p + 1)
-  else Nothing
-{-# INLINE findClose' #-}
-
 instance (CloseAt a, TestBit a, BitLength a) => FindCloseN (BitShown a) where
-  findCloseN = findClose' . bitShown
+  findCloseN = G.findCloseN . bitShown
   {-# INLINE findCloseN #-}
 
 instance FindCloseN [Bool] where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN  #-}
 
 instance FindCloseN (DVS.Vector Word8) where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN  #-}
 
 instance FindCloseN (DVS.Vector Word16) where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN #-}
 
 instance FindCloseN (DVS.Vector Word32) where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN  #-}
 
 instance FindCloseN (DVS.Vector Word64) where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN #-}
 
 instance FindCloseN Word8 where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN #-}
 
 instance FindCloseN Word16 where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN #-}
 
 instance FindCloseN Word32 where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN  #-}
 
 instance FindCloseN Word64 where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN #-}
 
 instance FindCloseN (Naive Word64) where
-  findCloseN = findClose'
+  findCloseN = G.findCloseN
   {-# INLINE findCloseN #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/FindOpen.hs b/src/HaskellWorks/Data/BalancedParens/FindOpen.hs
--- a/src/HaskellWorks/Data/BalancedParens/FindOpen.hs
+++ b/src/HaskellWorks/Data/BalancedParens/FindOpen.hs
@@ -14,7 +14,7 @@
 import qualified Data.Vector.Storable as DVS
 
 class FindOpen v where
-  findOpen    :: v -> Count -> Maybe Count
+  findOpen :: v -> Count -> Maybe Count
 
 instance (FindOpen a) => FindOpen (BitShown a) where
   findOpen = findOpen . bitShown
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector16.hs
@@ -0,0 +1,54 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                               as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16 as BWV16
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: DVS.Vector Word16 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (BWV16.findUnmatchedCloseFar 0 p v + 1)
+  else Just (BWV16.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector32.hs
@@ -0,0 +1,54 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                               as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32 as BWV32
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: DVS.Vector Word32 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (BWV32.findUnmatchedCloseFar 0 p v + 1)
+  else Just (BWV32.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector64.hs
@@ -0,0 +1,54 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                               as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64 as BWV64
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: DVS.Vector Word64 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (BWV64.findUnmatchedCloseFar 0 p v + 1)
+  else Just (BWV64.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8.hs
@@ -0,0 +1,54 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                              as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8 as BWV8
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: DVS.Vector Word8 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (BWV8.findUnmatchedCloseFar 0 p v + 1)
+  else Just (BWV8.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word16.hs
@@ -0,0 +1,53 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word16
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16 as W16
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: Word16 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (W16.findUnmatchedCloseFar 0 p v + 1)
+  else Just (W16.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word32.hs
@@ -0,0 +1,53 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word32
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32 as W32
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: Word32 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (W32.findUnmatchedCloseFar 0 p v + 1)
+  else Just (W32.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word64.hs
@@ -0,0 +1,53 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word64
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64 as W64
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: Word64 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (W64.findUnmatchedCloseFar 0 p v + 1)
+  else Just (W64.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Word8.hs
@@ -0,0 +1,53 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word8
+  ( findClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Positioning
+
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8 as W8
+
+-- | Find the position of the matching close parenthesis.
+--
+-- The position argument and return value is one-based.
+--
+-- If the parenthesis at the input position is an a close, then that is considered the
+-- matching close parenthesis.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 1:
+--
+-- >>> findClose (fromJust $ bitRead "10000000") 1
+-- Just 2
+--
+-- >>> findClose (fromJust $ bitRead "11000000") 1
+-- Just 4
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 1
+-- Just 6
+--
+-- The following scans for the matching close parenthesis for the open parenthesis at position 2:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 2
+-- Just 3
+--
+-- If the input position has a close parenthesis, then that position is returned:
+--
+-- >>> findClose (fromJust $ bitRead "11010000") 3
+-- Just 3
+--
+-- The scan can continue past the end of the input word because every bit after then end of the
+-- word is considered to be zero, which is a closing parenthesis:
+--
+-- >>> findClose (fromJust $ bitRead "11111110") 1
+-- Just 14
+findClose :: Word8 -> Count -> Maybe Count
+findClose v p = if p > 0
+  then if closeAt v p
+    then Just p
+    else Just (W8.findUnmatchedCloseFar 0 p v + 1)
+  else Just (W8.findUnmatchedCloseFar 1 p v)
+{-# INLINE findClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector16.hs
@@ -0,0 +1,42 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.AtIndex
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Int.Unsigned
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                             as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16 as BWW16
+import qualified HaskellWorks.Data.Drop                                                           as HW
+import qualified HaskellWorks.Data.Length                                                         as HW
+
+findUnmatchedCloseCont :: Int64 -> Count -> DVS.Vector Word16 -> Count
+findUnmatchedCloseCont i c v = if i < HW.end v
+  then case BWW16.findUnmatchedCloseFar c 0 w of
+    q -> if q >= bitLength w
+      then findUnmatchedCloseCont (i + 1) (q - bitLength w) v
+      else b + q
+  else b + c
+  where b  = unsigned i * bitLength w -- base
+        w  = v !!! fromIntegral i
+{-# INLINE findUnmatchedCloseCont #-}
+
+findUnmatchedClose' :: Word64 -> Word64 -> DVS.Vector Word16 -> Count
+findUnmatchedClose' c p v = if DVS.length v > 0
+    then case BWW16.findUnmatchedCloseFar c p w of
+        q -> if q >= bitLength w
+          then findUnmatchedCloseCont 1 (q - bitLength w) v
+          else q
+    else p * 2 + c
+  where w  = v !!! 0
+{-# INLINE findUnmatchedClose' #-}
+
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word16 -> Count
+findUnmatchedCloseFar c p v = findUnmatchedClose' c (p - vd) (HW.drop vi v) + vd
+  where vi = p `div` elemBitLength v
+        vd = vi * elemBitLength v
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector32.hs
@@ -0,0 +1,42 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.AtIndex
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Int.Unsigned
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                             as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32 as BWW32
+import qualified HaskellWorks.Data.Drop                                                           as HW
+import qualified HaskellWorks.Data.Length                                                         as HW
+
+findUnmatchedCloseCont :: Int64 -> Count -> DVS.Vector Word32 -> Count
+findUnmatchedCloseCont i c v = if i < HW.end v
+  then case BWW32.findUnmatchedCloseFar c 0 w of
+    q -> if q >= bitLength w
+      then findUnmatchedCloseCont (i + 1) (q - bitLength w) v
+      else b + q
+  else b + c
+  where b  = unsigned i * bitLength w -- base
+        w  = v !!! fromIntegral i
+{-# INLINE findUnmatchedCloseCont #-}
+
+findUnmatchedClose' :: Word64 -> Word64 -> DVS.Vector Word32 -> Count
+findUnmatchedClose' c p v = if DVS.length v > 0
+    then case BWW32.findUnmatchedCloseFar c p w of
+        q -> if q >= bitLength w
+          then findUnmatchedCloseCont 1 (q - bitLength w) v
+          else q
+    else p * 2 + c
+  where w  = v !!! 0
+{-# INLINE findUnmatchedClose' #-}
+
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word32 -> Count
+findUnmatchedCloseFar c p v = findUnmatchedClose' c (p - vd) (HW.drop vi v) + vd
+  where vi = p `div` elemBitLength v
+        vd = vi * elemBitLength v
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector64.hs
@@ -0,0 +1,42 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.AtIndex
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Int.Unsigned
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                             as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64 as BWW64
+import qualified HaskellWorks.Data.Drop                                                           as HW
+import qualified HaskellWorks.Data.Length                                                         as HW
+
+findUnmatchedCloseCont :: Int64 -> Count -> DVS.Vector Word64 -> Count
+findUnmatchedCloseCont i c v = if i < HW.end v
+  then case BWW64.findUnmatchedCloseFar c 0 w of
+    q -> if q >= bitLength w
+      then findUnmatchedCloseCont (i + 1) (q - bitLength w) v
+      else b + q
+  else b + c
+  where b  = unsigned i * bitLength w -- base
+        w  = v !!! fromIntegral i
+{-# INLINE findUnmatchedCloseCont #-}
+
+findUnmatchedClose' :: Word64 -> Word64 -> DVS.Vector Word64 -> Count
+findUnmatchedClose' c p v = if DVS.length v > 0
+    then case BWW64.findUnmatchedCloseFar c p w of
+        q -> if q >= bitLength w
+          then findUnmatchedCloseCont 1 (q - bitLength w) v
+          else q
+    else p * 2 + c
+  where w  = v !!! 0
+{-# INLINE findUnmatchedClose' #-}
+
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word64 -> Count
+findUnmatchedCloseFar c p v = findUnmatchedClose' c (p - vd) (HW.drop vi v) + vd
+  where vi = p `div` elemBitLength v
+        vd = vi * elemBitLength v
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector8.hs
@@ -0,0 +1,42 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.AtIndex
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Int.Unsigned
+import HaskellWorks.Data.Positioning
+
+import qualified Data.Vector.Storable                                                            as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8 as BWW8
+import qualified HaskellWorks.Data.Drop                                                          as HW
+import qualified HaskellWorks.Data.Length                                                        as HW
+
+findUnmatchedCloseCont :: Int64 -> Count -> DVS.Vector Word8 -> Count
+findUnmatchedCloseCont i c v = if i < HW.end v
+  then case BWW8.findUnmatchedCloseFar c 0 w of
+    q -> if q >= bitLength w
+      then findUnmatchedCloseCont (i + 1) (q - bitLength w) v
+      else b + q
+  else b + c
+  where b  = unsigned i * bitLength w -- base
+        w  = v !!! fromIntegral i
+{-# INLINE findUnmatchedCloseCont #-}
+
+findUnmatchedClose' :: Word64 -> Word64 -> DVS.Vector Word8 -> Count
+findUnmatchedClose' c p v = if DVS.length v > 0
+    then case BWW8.findUnmatchedCloseFar c p w of
+        q -> if q >= bitLength w
+          then findUnmatchedCloseCont 1 (q - bitLength w) v
+          else q
+    else p * 2 + c
+  where w  = v !!! 0
+{-# INLINE findUnmatchedClose' #-}
+
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word8 -> Count
+findUnmatchedCloseFar c p v = findUnmatchedClose' c (p - vd) (HW.drop vi v) + vd
+  where vi = p `div` elemBitLength v
+        vd = vi * elemBitLength v
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word16.hs
@@ -0,0 +1,141 @@
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Word16
+import HaskellWorks.Data.Int.Narrow
+import HaskellWorks.Data.Int.Widen
+
+muk1 :: Word16
+muk1 = 0x3333
+{-# INLINE muk1 #-}
+
+muk2 :: Word16
+muk2 = 0x0f0f
+{-# INLINE muk2 #-}
+
+muk3 :: Word16
+muk3 = 0x00ff
+{-# INLINE muk3 #-}
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word16.findCloseFor'.
+--
+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word16 -> Word64
+findUnmatchedCloseFar c p w =
+  --  Keys:
+  --    * k1: Level of sub-words of size 2 = 1 .<. 1
+  --    * k2: Level of sub-words of size 4 = 1 .<. 2
+  --    * k3: Level of sub-words of size 8 = 1 .<. 3
+  --    * o: Open count
+  --    * c: Close count
+  --    * e: Excess
+  --    * L: Left half of sub-word
+  --    * R: Right half of sub-word
+  --    * b: deficit at position whole-word mask
+  --    * m: deficit at position sub-word mask
+  --    * pa: position accumulator
+  --    * sa: shift accumulator
+  --    * f: far sub-block close parens count
+  let x     = w .>. p                                                                           in
+  let wsz   = 16 :: Int16                                                                       in
+  let k1    = 1                                                                                 in
+  let k2    = 2                                                                                 in
+  let k3    = 3                                                                                 in
+  let k4    = 4                                                                                 in
+  let mask1 = (1 .<. (1 .<. k1)) - 1                                                            in
+  let mask2 = (1 .<. (1 .<. k2)) - 1                                                            in
+  let mask3 = (1 .<. (1 .<. k3)) - 1                                                            in
+  let mask4 = (1 .<. (1 .<. k4)) - 1                                                            in
+  let t64k1 = 1 .<. k1 :: Word64                                                                in
+  let t64k2 = 1 .<. k2 :: Word64                                                                in
+  let t64k3 = 1 .<. k3 :: Word64                                                                in
+  let t8k1  = 1 .<. k1 :: Word16                                                                in
+  let t8k2  = 1 .<. k2 :: Word16                                                                in
+  let t8k3  = 1 .<. k3 :: Word16                                                                in
+  let t8k4  = 1 .<. k4 :: Word16                                                                in
+
+  let b0    =      x .&. 0x5555                                                                 in
+  let b1    =    ( x .&. 0xaaaa) .>. 1                                                          in
+  let ll    =   (b0  .^. b1  ) .&. b1                                                           in
+  let ok1   = ( (b0  .&. b1  )             .<. 1) .|. ll                                        in
+  let ck1   = (((b0  .|. b1  ) .^. 0x5555) .<. 1) .|. ll                                        in
+
+  let eok1 =   ok1 .&.  muk1                                                                    in
+  let eck1 =  (ck1 .&. (muk1 .<. t64k1)) .>. t64k1                                              in
+  let ok2L =  (ok1 .&. (muk1 .<. t64k1)) .>. t64k1                                              in
+  let ok2R = kBitDiffPos 4 eok1 eck1                                                            in
+  let ok2  = ok2L + ok2R                                                                        in
+  let ck2  =  (ck1 .&.  muk1) + kBitDiffPos 4 eck1 eok1                                         in
+
+  let eok2 =   ok2 .&.  muk2                                                                    in
+  let eck2 =  (ck2 .&. (muk2 .<. t64k2)) .>. t64k2                                              in
+  let ok3L =  (ok2 .&. (muk2 .<. t64k2)) .>. t64k2                                              in
+  let ok3R = kBitDiffPos 8 eok2 eck2                                                            in
+  let ok3  = ok3L + ok3R                                                                        in
+  let ck3  =  (ck2 .&.  muk2) + kBitDiffPos 8 eck2 eok2                                         in
+
+  let eok3 =   ok3 .&.  muk3                                                                    in
+  let eck3 =  (ck3 .&. (muk3 .<. t64k3)) .>. t64k3                                              in
+  let ok4L =  (ok3 .&. (muk3 .<. t64k3)) .>. t64k3                                              in
+  let ok4R = kBitDiffPos 16 eok3 eck3                                                           in
+  let ok4  = ok4L + ok4R                                                                        in
+  let ck4  =  (ck3 .&.  muk3) + kBitDiffPos 16 eck3 eok3                                        in
+
+  let pak4  = c                                                                                 in
+  let sak4  = 0                                                                                 in
+
+  let hk4   = 0x0010 .&. comp (0xffff .>. fromIntegral sak4)                                    in
+  let fk4   = ((ck4 .>. fromIntegral sak4) .|. hk4) .&. mask4                                   in
+  let bk4   = ((narrow pak4 - fk4) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk4   = bk4 .&. mask4                                                                     in
+  let pbk4  = pak4 - widen ((ck4 .>. fromIntegral sak4) .&. mk4)                                in
+  let pck4  = pbk4 + widen ((ok4 .>. fromIntegral sak4) .&. mk4)                                in
+  let sbk4  = sak4 + widen (t8k4 .&. bk4)                                                       in
+
+  let pak3  = pck4                                                                              in
+  let sak3  = sbk4                                                                              in
+
+  let hk3   = 0x0808 .&. comp (0xffff .>. fromIntegral sak3)                                    in
+  let fk3   = ((ck3 .>. fromIntegral sak3) .|. hk3) .&. mask3                                   in
+  let bk3   = ((narrow pak3 - fk3) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk3   = bk3 .&. mask3                                                                     in
+  let pbk3  = pak3 - widen (((ck3 .>. fromIntegral sak3) .|. hk3) .&. mk3)                      in
+  let pck3  = pbk3 + widen ( (ok3 .>. fromIntegral sak3)          .&. mk3)                      in
+  let sbk3  = sak3 + widen (t8k3 .&. bk3)                                                       in
+
+  let pak2  = pck3                                                                              in
+  let sak2  = sbk3                                                                              in
+
+  let hk2   = 0x4444 .&. comp (0xffff .>. fromIntegral sak2)                                    in
+  let fk2   = ((ck2 .>. fromIntegral sak2) .|. hk2) .&. mask2                                   in
+  let bk2   = ((narrow pak2 - fk2) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk2   = bk2 .&. mask2                                                                     in
+  let pbk2  = pak2 - widen (((ck2 .>. fromIntegral sak2) .|. hk2) .&. mk2)                      in
+  let pck2  = pbk2 + widen ( (ok2 .>. fromIntegral sak2)          .&. mk2)                      in
+  let sbk2  = sak2 + widen (t8k2 .&. bk2)                                                       in
+
+  let pak1  = pck2                                                                              in
+  let sak1  = sbk2                                                                              in
+
+  let hk1   = 0xaaaa .&. comp (0xffff .>. fromIntegral sak1)                                    in
+  let fk1   = ((ck1 .>. fromIntegral sak1) .|. hk1) .&. mask1                                   in
+  let bk1   = ((narrow pak1 - fk1) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk1   = bk1  .&. mask1                                                                    in
+  let pbk1  = pak1 - widen (((ck1 .>. fromIntegral sak1) .|. hk1) .&. mk1)                      in
+  let pck1  = pbk1 + widen ( (ok1 .>. fromIntegral sak1)          .&. mk1)                      in
+  let sbk1  = sak1 + widen (t8k1 .&. bk1)                                                       in
+
+  let rrr   = sbk1 + pck1 + (((widen x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in
+
+  rrr + p
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word32.hs
@@ -0,0 +1,167 @@
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Word32
+import HaskellWorks.Data.Int.Narrow
+import HaskellWorks.Data.Int.Widen
+
+muk1 :: Word32
+muk1 = 0x33333333
+{-# INLINE muk1 #-}
+
+muk2 :: Word32
+muk2 = 0x0f0f0f0f
+{-# INLINE muk2 #-}
+
+muk3 :: Word32
+muk3 = 0x00ff00ff
+{-# INLINE muk3 #-}
+
+muk4 :: Word32
+muk4 = 0x0000ffff
+{-# INLINE muk4 #-}
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word32.findCloseFor'.
+--
+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word32 -> Word64
+findUnmatchedCloseFar c p w =
+  --  Keys:
+  --    * k1: Level of sub-words of size 2 = 1 .<. 1
+  --    * k2: Level of sub-words of size 4 = 1 .<. 2
+  --    * k3: Level of sub-words of size 8 = 1 .<. 3
+  --    * o: Open count
+  --    * c: Close count
+  --    * e: Excess
+  --    * L: Left half of sub-word
+  --    * R: Right half of sub-word
+  --    * b: deficit at position whole-word mask
+  --    * m: deficit at position sub-word mask
+  --    * pa: position accumulator
+  --    * sa: shift accumulator
+  --    * f: far sub-block close parens count
+  let x     = w .>. p                                                                           in
+  let wsz   = 32 :: Int32                                                                       in
+  let k1    = 1                                                                                 in
+  let k2    = 2                                                                                 in
+  let k3    = 3                                                                                 in
+  let k4    = 4                                                                                 in
+  let k5    = 5                                                                                 in
+  let mask1 = (1 .<. (1 .<. k1)) - 1                                                            in
+  let mask2 = (1 .<. (1 .<. k2)) - 1                                                            in
+  let mask3 = (1 .<. (1 .<. k3)) - 1                                                            in
+  let mask4 = (1 .<. (1 .<. k4)) - 1                                                            in
+  let mask5 = (1 .<. (1 .<. k5)) - 1                                                            in
+  let t64k1 = 1 .<. k1 :: Word64                                                                in
+  let t64k2 = 1 .<. k2 :: Word64                                                                in
+  let t64k3 = 1 .<. k3 :: Word64                                                                in
+  let t64k4 = 1 .<. k4 :: Word64                                                                in
+  let t8k1  = 1 .<. k1 :: Word32                                                                in
+  let t8k2  = 1 .<. k2 :: Word32                                                                in
+  let t8k3  = 1 .<. k3 :: Word32                                                                in
+  let t8k4  = 1 .<. k4 :: Word32                                                                in
+  let t8k5  = 1 .<. k5 :: Word32                                                                in
+
+  let b0    =      x .&. 0x55555555                                                             in
+  let b1    =    ( x .&. 0xaaaaaaaa) .>. 1                                                      in
+  let ll    =   (b0  .^. b1  ) .&. b1                                                           in
+  let ok1   = ( (b0  .&. b1  )                 .<. 1) .|. ll                                    in
+  let ck1   = (((b0  .|. b1  ) .^. 0x55555555) .<. 1) .|. ll                                    in
+
+  let eok1 =   ok1 .&.  muk1                                                                    in
+  let eck1 =  (ck1 .&. (muk1 .<. t64k1)) .>. t64k1                                              in
+  let ok2L =  (ok1 .&. (muk1 .<. t64k1)) .>. t64k1                                              in
+  let ok2R = kBitDiffPos 4 eok1 eck1                                                            in
+  let ok2  = ok2L + ok2R                                                                        in
+  let ck2  =  (ck1 .&.  muk1) + kBitDiffPos 4 eck1 eok1                                         in
+
+  let eok2 =   ok2 .&.  muk2                                                                    in
+  let eck2 =  (ck2 .&. (muk2 .<. t64k2)) .>. t64k2                                              in
+  let ok3L = ((ok2 .&. (muk2 .<. t64k2)) .>. t64k2)                                             in
+  let ok3R = kBitDiffPos 8 eok2 eck2                                                            in
+  let ok3  = ok3L + ok3R                                                                        in
+  let ck3  =  (ck2 .&.  muk2) + kBitDiffPos 8 eck2 eok2                                         in
+
+  let eok3 =   ok3 .&.  muk3                                                                    in
+  let eck3 =  (ck3 .&. (muk3 .<. t64k3)) .>. t64k3                                              in
+  let ok4L = ((ok3 .&. (muk3 .<. t64k3)) .>. t64k3)                                             in
+  let ok4R = kBitDiffPos 16 eok3 eck3                                                           in
+  let ok4  = ok4L + ok4R                                                                        in
+  let ck4  =  (ck3 .&.  muk3) + kBitDiffPos 16 eck3 eok3                                        in
+
+  let eok4 =   ok4 .&.  muk4                                                                    in
+  let eck4 =  (ck4 .&. (muk4 .<. t64k4)) .>. t64k4                                              in
+  let ok5L = ((ok4 .&. (muk4 .<. t64k4)) .>. t64k4)                                             in
+  let ok5R = kBitDiffPos 32 eok4 eck4                                                           in
+  let ok5  = ok5L + ok5R                                                                        in
+  let ck5  =  (ck4 .&.  muk4) + kBitDiffPos 32 eck4 eok4                                        in
+
+  let pak5  = c                                                                                 in
+  let sak5  = 0                                                                                 in
+
+  let hk5   = 0x00200020 .&. comp (0xffffffff .>. fromIntegral sak5)                            in
+  let fk5   = ((ck5 .>. fromIntegral sak5) .|. hk5) .&. mask5                                   in
+  let bk5   = ((narrow pak5 - fk5) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk5   = bk5 .&. mask5                                                                     in
+  let pbk5  = pak5 - widen ((ck5 .>. fromIntegral sak5) .&. mk5)                                in
+  let pck5  = pbk5 + widen ((ok5 .>. fromIntegral sak5) .&. mk5)                                in
+  let sbk5  = sak5 + widen (t8k5 .&. bk5)                                                       in
+
+  let pak4  = pck5                                                                              in
+  let sak4  = sbk5                                                                              in
+
+  let hk4   = 0x00100010 .&. comp (0xffffffff .>. fromIntegral sak4)                            in
+  let fk4   = ((ck4 .>. fromIntegral sak4) .|. hk4) .&. mask4                                   in
+  let bk4   = ((narrow pak4 - fk4) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk4   = bk4 .&. mask4                                                                     in
+  let pbk4  = pak4 - widen (((ck4 .>. fromIntegral sak4) .|. hk4) .&. mk4)                      in
+  let pck4  = pbk4 + widen ( (ok4 .>. fromIntegral sak4)          .&. mk4)                      in
+  let sbk4  = sak4 + widen (t8k4 .&. bk4)                                                       in
+
+  let pak3  = pck4                                                                              in
+  let sak3  = sbk4                                                                              in
+
+  let hk3   = 0x08080808 .&. comp (0xffffffff .>. fromIntegral sak3)                            in
+  let fk3   = ((ck3 .>. fromIntegral sak3) .|. hk3) .&. mask3                                   in
+  let bk3   = ((narrow pak3 - fk3) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk3   = bk3 .&. mask3                                                                     in
+  let pbk3  = pak3 - widen (((ck3 .>. fromIntegral sak3) .|. hk3) .&. mk3)                      in
+  let pck3  = pbk3 + widen ( (ok3 .>. fromIntegral sak3)          .&. mk3)                      in
+  let sbk3  = sak3 + widen (t8k3 .&. bk3)                                                       in
+
+  let pak2  = pck3                                                                              in
+  let sak2  = sbk3                                                                              in
+
+  let hk2   = 0x44444444 .&. comp (0xffffffff .>. fromIntegral sak2)                            in
+  let fk2   = ((ck2 .>. fromIntegral sak2) .|. hk2) .&. mask2                                   in
+  let bk2   = ((narrow pak2 - fk2) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk2   = bk2 .&. mask2                                                                     in
+  let pbk2  = pak2 - widen (((ck2 .>. fromIntegral sak2) .|. hk2) .&. mk2)                      in
+  let pck2  = pbk2 + widen ( (ok2 .>. fromIntegral sak2)          .&. mk2)                      in
+  let sbk2  = sak2 + widen (t8k2 .&. bk2)                                                       in
+
+  let pak1  = pck2                                                                              in
+  let sak1  = sbk2                                                                              in
+
+  let hk1   = 0xaaaaaaaa .&. comp (0xffffffff .>. fromIntegral sak1)                            in
+  let fk1   = ((ck1 .>. fromIntegral sak1) .|. hk1) .&. mask1                                   in
+  let bk1   = ((narrow pak1 - fk1) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk1   = bk1  .&. mask1                                                                    in
+  let pbk1  = pak1 - widen (((ck1 .>. fromIntegral sak1) .|. hk1) .&. mk1)                      in
+  let pck1  = pbk1 + widen ( (ok1 .>. fromIntegral sak1)          .&. mk1)                      in
+  let sbk1  = sak1 + widen (t8k1 .&. bk1)                                                       in
+
+  let rrr   = sbk1 + pck1 + (((widen x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in
+
+  rrr + p
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word64.hs
@@ -0,0 +1,191 @@
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Word64
+
+muk1 :: Word64
+muk1 = 0x3333333333333333
+{-# INLINE muk1 #-}
+
+muk2 :: Word64
+muk2 = 0x0f0f0f0f0f0f0f0f
+{-# INLINE muk2 #-}
+
+muk3 :: Word64
+muk3 = 0x00ff00ff00ff00ff
+{-# INLINE muk3 #-}
+
+muk4 :: Word64
+muk4 = 0x0000ffff0000ffff
+{-# INLINE muk4 #-}
+
+muk5 :: Word64
+muk5 = 0x00000000ffffffff
+{-# INLINE muk5 #-}
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word64.findCloseFor'.
+--
+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word64 -> Word64
+findUnmatchedCloseFar c p w =
+  --  Keys:
+  --    * k1: Level of sub-words of size 2 = 1 .<. 1
+  --    * k2: Level of sub-words of size 4 = 1 .<. 2
+  --    * k3: Level of sub-words of size 8 = 1 .<. 3
+  --    * o: Open count
+  --    * c: Close count
+  --    * e: Excess
+  --    * L: Left half of sub-word
+  --    * R: Right half of sub-word
+  --    * b: deficit at position whole-word mask
+  --    * m: deficit at position sub-word mask
+  --    * pa: position accumulator
+  --    * sa: shift accumulator
+  --    * f: far sub-block close parens count
+  let x     = w .>. p                                                                     in
+  let wsz   = 64 :: Int64                                                                 in
+  let k1    = 1                                                                           in
+  let k2    = 2                                                                           in
+  let k3    = 3                                                                           in
+  let k4    = 4                                                                           in
+  let k5    = 5                                                                           in
+  let k6    = 6                                                                           in
+  let mask1 = (1 .<. (1 .<. k1)) - 1                                                      in
+  let mask2 = (1 .<. (1 .<. k2)) - 1                                                      in
+  let mask3 = (1 .<. (1 .<. k3)) - 1                                                      in
+  let mask4 = (1 .<. (1 .<. k4)) - 1                                                      in
+  let mask5 = (1 .<. (1 .<. k5)) - 1                                                      in
+  let mask6 = (1 .<. (1 .<. k6)) - 1                                                      in
+  let t64k1 = 1 .<. k1 :: Word64                                                          in
+  let t64k2 = 1 .<. k2 :: Word64                                                          in
+  let t64k3 = 1 .<. k3 :: Word64                                                          in
+  let t64k4 = 1 .<. k4 :: Word64                                                          in
+  let t64k5 = 1 .<. k5 :: Word64                                                          in
+  let t8k1  = 1 .<. k1 :: Word64                                                          in
+  let t8k2  = 1 .<. k2 :: Word64                                                          in
+  let t8k3  = 1 .<. k3 :: Word64                                                          in
+  let t8k4  = 1 .<. k4 :: Word64                                                          in
+  let t8k5  = 1 .<. k5 :: Word64                                                          in
+  let t8k6  = 1 .<. k6 :: Word64                                                          in
+
+  let b0    =      x .&. 0x5555555555555555                                               in
+  let b1    =    ( x .&. 0xaaaaaaaaaaaaaaaa) .>. 1                                        in
+  let ll    =   (b0  .^. b1  ) .&. b1                                                     in
+  let ok1   = ( (b0  .&. b1  )                         .<. 1) .|. ll                      in
+  let ck1   = (((b0  .|. b1  ) .^. 0x5555555555555555) .<. 1) .|. ll                      in
+
+  let eok1 =   ok1 .&.  muk1                                                              in
+  let eck1 =  (ck1 .&. (muk1 .<. t64k1)) .>. t64k1                                        in
+  let ok2L =  (ok1 .&. (muk1 .<. t64k1)) .>. t64k1                                        in
+  let ok2R = kBitDiffPos 4 eok1 eck1                                                      in
+  let ok2  = ok2L + ok2R                                                                  in
+  let ck2  =  (ck1 .&.  muk1) + kBitDiffPos 4 eck1 eok1                                   in
+
+  let eok2 =   ok2 .&.  muk2                                                              in
+  let eck2 =  (ck2 .&. (muk2 .<. t64k2)) .>. t64k2                                        in
+  let ok3L =  (ok2 .&. (muk2 .<. t64k2)) .>. t64k2                                        in
+  let ok3R = kBitDiffPos 8 eok2 eck2                                                      in
+  let ok3  = ok3L + ok3R                                                                  in
+  let ck3  =  (ck2 .&.  muk2) + kBitDiffPos 8 eck2 eok2                                   in
+
+  let eok3 =   ok3 .&.  muk3                                                              in
+  let eck3 =  (ck3 .&. (muk3 .<. t64k3)) .>. t64k3                                        in
+  let ok4L =  (ok3 .&. (muk3 .<. t64k3)) .>. t64k3                                        in
+  let ok4R = kBitDiffPos 16 eok3 eck3                                                     in
+  let ok4  = ok4L + ok4R                                                                  in
+  let ck4  =  (ck3 .&.  muk3) + kBitDiffPos 16 eck3 eok3                                  in
+
+  let eok4 =   ok4 .&.  muk4                                                              in
+  let eck4 =  (ck4 .&. (muk4 .<. t64k4)) .>. t64k4                                        in
+  let ok5L =  (ok4 .&. (muk4 .<. t64k4)) .>. t64k4                                        in
+  let ok5R = kBitDiffPos 32 eok4 eck4                                                     in
+  let ok5  = ok5L + ok5R                                                                  in
+  let ck5  =  (ck4 .&.  muk4) + kBitDiffPos 32 eck4 eok4                                  in
+
+  let eok5 =   ok5 .&.  muk5                                                              in
+  let eck5 =  (ck5 .&. (muk5 .<. t64k5)) .>. t64k5                                        in
+  let ok6L =  (ok5 .&. (muk5 .<. t64k5)) .>. t64k5                                        in
+  let ok6R = kBitDiffPos 32 eok5 eck5                                                     in
+  let ok6  = ok6L + ok6R                                                                  in
+  let ck6  =  (ck5 .&.  muk5) + kBitDiffPos 32 eck5 eok5                                  in
+
+  let qak6  = c                                                                           in
+  let sak6  = 0                                                                           in
+
+  let hk6   = 0x0000004000000040 .&. comp (0xffffffffffffffff .>. fromIntegral sak6)      in
+  let fk6   = ((ck6 .>. fromIntegral sak6) .|. hk6) .&. mask6                             in
+  let bk6   = ((qak6 - fk6) .>. fromIntegral (wsz - 1)) - 1                               in
+  let mk6   = bk6 .&. mask6                                                               in
+  let pbk6  = qak6 - ((ck6 .>. fromIntegral sak6) .&. mk6)                                in
+  let pck6  = pbk6 + ((ok6 .>. fromIntegral sak6) .&. mk6)                                in
+  let sbk6  = sak6 + (t8k6 .&. bk6)                                                       in
+
+  let qak5  = pck6                                                                        in
+  let sak5  = sbk6                                                                        in
+
+  let hk5   = 0x0000002000000020 .&. comp (0xffffffffffffffff .>. fromIntegral sak5)      in
+  let fk5   = ((ck5 .>. fromIntegral sak5) .|. hk5) .&. mask5                             in
+  let bk5   = ((qak5 - fk5) .>. fromIntegral (wsz - 1)) - 1                               in
+  let mk5   = bk5 .&. mask5                                                               in
+  let pbk5  = qak5 - (((ck5 .>. fromIntegral sak5) .|. hk5) .&. mk5)                      in
+  let pck5  = pbk5 + ( (ok5 .>. fromIntegral sak5)          .&. mk5)                      in
+  let sbk5  = sak5 + (t8k5 .&. bk5)                                                       in
+
+  let qak4  = pck5                                                                        in
+  let sak4  = sbk5                                                                        in
+
+  let hk4   = 0x0010001000100010 .&. comp (0xffffffffffffffff .>. fromIntegral sak4)      in
+  let fk4   = ((ck4 .>. fromIntegral sak4) .|. hk4) .&. mask4                             in
+  let bk4   = ((qak4 - fk4) .>. fromIntegral (wsz - 1)) - 1                               in
+  let mk4   = bk4 .&. mask4                                                               in
+  let pbk4  = qak4 - (((ck4 .>. fromIntegral sak4) .|. hk4) .&. mk4)                      in
+  let pck4  = pbk4 + ( (ok4 .>. fromIntegral sak4)          .&. mk4)                      in
+  let sbk4  = sak4 + (t8k4 .&. bk4)                                                       in
+
+  let qak3  = pck4                                                                        in
+  let sak3  = sbk4                                                                        in
+
+  let hk3   = 0x0808080808080808 .&. comp (0xffffffffffffffff .>. fromIntegral sak3)      in
+  let fk3   = ((ck3 .>. fromIntegral sak3) .|. hk3) .&. mask3                             in
+  let bk3   = ((qak3 - fk3) .>. fromIntegral (wsz - 1)) - 1                               in
+  let mk3   = bk3 .&. mask3                                                               in
+  let pbk3  = qak3 - (((ck3 .>. fromIntegral sak3) .|. hk3) .&. mk3)                      in
+  let pck3  = pbk3 + ( (ok3 .>. fromIntegral sak3)          .&. mk3)                      in
+  let sbk3  = sak3 + (t8k3 .&. bk3)                                                       in
+
+  let qak2  = pck3                                                                        in
+  let sak2  = sbk3                                                                        in
+
+  let hk2   = 0x4444444444444444 .&. comp (0xffffffffffffffff .>. fromIntegral sak2)      in
+  let fk2   = ((ck2 .>. fromIntegral sak2) .|. hk2) .&. mask2                             in
+  let bk2   = ((qak2 - fk2) .>. fromIntegral (wsz - 1)) - 1                               in
+  let mk2   = bk2 .&. mask2                                                               in
+  let pbk2  = qak2 - (((ck2 .>. fromIntegral sak2) .|. hk2) .&. mk2)                      in
+  let pck2  = pbk2 + ( (ok2 .>. fromIntegral sak2)          .&. mk2)                      in
+  let sbk2  = sak2 + (t8k2 .&. bk2)                                                       in
+
+  let qak1  = pck2                                                                        in
+  let sak1  = sbk2                                                                        in
+
+  let hk1   = 0xaaaaaaaaaaaaaaaa .&. comp (0xffffffffffffffff .>. fromIntegral sak1)      in
+  let fk1   = ((ck1 .>. fromIntegral sak1) .|. hk1) .&. mask1                             in
+  let bk1   = ((qak1 - fk1) .>. fromIntegral (wsz - 1)) - 1                               in
+  let mk1   = bk1  .&. mask1                                                              in
+  let pbk1  = qak1 - (((ck1 .>. fromIntegral sak1) .|. hk1) .&. mk1)                      in
+  let pck1  = pbk1 + ( (ok1 .>. fromIntegral sak1)          .&. mk1)                      in
+  let sbk1  = sak1 + (t8k1 .&. bk1)                                                       in
+
+  let rrr   = sbk1 + pck1 + (((x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in
+
+  rrr + p
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word8.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Int
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Word8
+import HaskellWorks.Data.Int.Narrow
+import HaskellWorks.Data.Int.Widen
+
+muk1 :: Word8
+muk1 = 0x33
+{-# INLINE muk1 #-}
+
+muk2 :: Word8
+muk2 = 0x0f
+{-# INLINE muk2 #-}
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- This is the broadword implementation of 'HaskellWorks.Data.BalancedParens.Internal.Slow.Word8.findCloseFor'.
+--
+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word8 -> Word64
+findUnmatchedCloseFar c p w =
+  --  Keys:
+  --    * k1: Level of sub-words of size 2 = 1 .<. 1
+  --    * k2: Level of sub-words of size 4 = 1 .<. 2
+  --    * k3: Level of sub-words of size 8 = 1 .<. 3
+  --    * o: Open count
+  --    * c: Close count
+  --    * e: Excess
+  --    * L: Left half of sub-word
+  --    * R: Right half of sub-word
+  --    * b: deficit at position whole-word mask
+  --    * m: deficit at position sub-word mask
+  --    * pa: position accumulator
+  --    * sa: shift accumulator
+  --    * h: high sub-block close parens count
+  --    * f: far sub-block close parens count
+  let x     = w .>. p                                                                           in
+  let wsz   = 8 :: Int8                                                                         in
+  let k1    = 1                                                                                 in
+  let k2    = 2                                                                                 in
+  let k3    = 3                                                                                 in
+  let mask3 = (1 .<. (1 .<. k3)) - 1                                                            in
+  let mask2 = (1 .<. (1 .<. k2)) - 1                                                            in
+  let mask1 = (1 .<. (1 .<. k1)) - 1                                                            in
+  let t64k1 = 1 .<. k1 :: Word64                                                                in
+  let t64k2 = 1 .<. k2 :: Word64                                                                in
+  let t8k1  = 1 .<. k1 :: Word8                                                                 in
+  let t8k2  = 1 .<. k2 :: Word8                                                                 in
+  let t8k3  = 1 .<. k3 :: Word8                                                                 in
+
+  let b0    =      x .&. 0x55                                                                   in
+  let b1    =    ( x .&. 0xaa) .>. 1                                                            in
+  let ll    =   (b0  .^. b1  ) .&. b1                                                           in
+  let ok1   = ( (b0  .&. b1  )           .<. 1) .|. ll                                          in
+  let ck1   = (((b0  .|. b1  ) .^. 0x55) .<. 1) .|. ll                                          in
+
+  let eok1  =   ok1 .&.  muk1                                                                   in
+  let eck1  =  (ck1 .&. (muk1 .<. t64k1)) .>. t64k1                                             in
+  let ok2L  =  (ok1 .&. (muk1 .<. t64k1)) .>. t64k1                                             in
+  let ok2R  = kBitDiffPos 4 eok1 eck1                                                           in
+  let ok2   = ok2L + ok2R                                                                       in
+  let ck2   =  (ck1 .&.  muk1) + kBitDiffPos 4 eck1 eok1                                        in
+
+  let eok2  =   ok2 .&.  muk2                                                                   in
+  let eck2  =  (ck2 .&. (muk2 .<. t64k2)) .>. t64k2                                             in
+  let ok3L  =  (ok2 .&. (muk2 .<. t64k2)) .>. t64k2                                             in
+  let ok3R  = kBitDiffPos 8 eok2 eck2                                                           in
+  let ok3   = ok3L + ok3R                                                                       in
+  let ck3   =  (ck2 .&.  muk2) + kBitDiffPos 8 eck2 eok2                                        in
+
+  let pak3  = c                                                                                 in
+  let sak3  = 0                                                                                 in
+
+  let hk3   = 0x08 .&. comp (0xff .>. fromIntegral sak3)                                        in
+  let fk3   = (ck3 .>. fromIntegral sak3 .|. hk3) .&. mask3                                     in
+  let bk3   = ((narrow pak3 - fk3) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk3   = bk3 .&. mask3                                                                     in
+  let pbk3  = pak3 - widen (((ck3 .>. fromIntegral sak3) .|. hk3) .&. mk3)                      in
+  let pck3  = pbk3 + widen (((ok3 .>. fromIntegral sak3) .|. hk3) .&. mk3)                      in
+  let sbk3  = sak3 + widen (t8k3 .&. bk3)                                                       in
+
+  let pak2  = pck3                                                                              in
+  let sak2  = sbk3                                                                              in
+
+  let hk2   = 0x44 .&. comp (0xff .>. fromIntegral sak2)                                        in
+  let fk2   = ((ck2 .>. fromIntegral sak2) .|. hk2) .&. mask2                                   in
+  let bk2   = ((narrow pak2 - fk2) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk2   = bk2 .&. mask2                                                                     in
+  let pbk2  = pak2 - widen (((ck2 .>. fromIntegral sak2) .|. hk2) .&. mk2)                      in
+  let pck2  = pbk2 + widen ( (ok2 .>. fromIntegral sak2)          .&. mk2)                      in
+  let sbk2  = sak2 + widen (t8k2 .&. bk2)                                                       in
+
+  let pak1  = pck2                                                                              in
+  let sak1  = sbk2                                                                              in
+
+  let hk1   = 0xaa .&. comp (0xff .>. fromIntegral sak1)                                        in
+  let fk1   = ((ck1 .>. fromIntegral sak1) .|. hk1) .&. mask1                                   in
+  let bk1   = ((narrow pak1 - fk1) .>. fromIntegral (wsz - 1)) - 1                              in
+  let mk1   = bk1  .&. mask1                                                                    in
+  let pbk1  = pak1 - widen (((ck1 .>. fromIntegral sak1) .|. hk1) .&. mk1)                      in
+  let pck1  = pbk1 + widen ( (ok1 .>. fromIntegral sak1)          .&. mk1)                      in
+  let sbk1  = sak1 + widen (t8k1 .&. bk1)                                                       in
+
+  let rrr   = sbk1 + pck1 + (((widen x .>. fromIntegral sbk1) .&. ((pck1 .<. 1) .|. 1)) .<. 1)  in
+
+  rrr + p
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/Word64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/Word64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Broadword/Word64.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE BangPatterns        #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.Word64
+  ( findUnmatchedClose
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Bits.Broadword.Word64
+import HaskellWorks.Data.Bits.Word64
+
+-- | Find the position of the first unmatch parenthesis within a word.
+--
+-- See [Broadword Implementation of Parenthesis Queries](https://arxiv.org/pdf/1301.5468.pdf), Sebastiano Vigna, 2013
+findUnmatchedClose :: Word64 -> Word64
+findUnmatchedClose x =
+  let !b00 = x - ((x .&. 0xaaaaaaaaaaaaaaaa) .>. 1)                                               in
+  let !b01 = (b00 .&. 0x3333333333333333) + ((b00 .>. 2) .&. 0x3333333333333333)                  in
+  let !b02 = (b01 + (b01 .>. 4)) .&. 0x0f0f0f0f0f0f0f0f                                           in
+  let !b03 = (b02 * 0x0101010101010101) .<. 1                                                     in
+  let !b04 = kBitDiffUnsafe 8 (h 8 .|. 0x4038302820181008) b03                                    in
+  let !u00 = (((((b04 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in
+  let !z00 =                         ((h 8 .>. 1) .|. (l 8 * 7)) .&. u00                          in
+
+  let !d10 = (l 8 * 2 - (((x .>. 6) .&. (l 8 .<. 1)) + ((x .>. 5) .&. (l 8 .<. 1))))              in
+  let !b10 = b04 - d10                                                                            in
+  let !u10 = (((((b10 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in
+  let !z10 = (z00 .&. comp u10) .|. (((h 8 .>. 1) .|. (l 8 * 5)) .&. u10)                         in
+
+  let !d20 = (l 8 * 2 - (((x .>. 4) .&. (l 8 .<. 1)) + ((x .>. 3) .&. (l 8 .<. 1))))              in
+  let !b20 = b10 - d20                                                                            in
+  let !u20 = (((((b20 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in
+  let !z20 = (z10 .&. comp u20) .|. (((h 8 .>. 1) .|. (l 8 * 3)) .&. u20)                         in
+
+  let !d30 = (l 8 * 2 - (((x .>. 2) .&. (l 8 .<. 1)) + ((x .>. 1) .&. (l 8 .<. 1))))              in
+  let !b30 = b20 - d30                                                                            in
+  let !u30 = (((((b30 .|. h 8) - l 8) .>. 7) .&. l 8) .|. h 8) - l 8                              in
+  let !z30 = (z20 .&. comp u30) .|. (((h 8 .>. 1) .|.  l 8     ) .&. u30)                         in
+
+  let !p00 = lsb (z30 .>. 6 .&. l 8)                                                              in
+  let !r00 = ((p00 + ((z30 .>. fromIntegral (p00 .&. 0x3f)) .&. 0x3f)) .|. (p00 .>. 8)) .&. 0x7f  in
+  r00
+{-# INLINE findUnmatchedClose #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/List.hs b/src/HaskellWorks/Data/BalancedParens/Internal/List.hs
--- a/src/HaskellWorks/Data/BalancedParens/Internal/List.hs
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/List.hs
@@ -9,7 +9,7 @@
 import qualified HaskellWorks.Data.BalancedParens.Internal.Word as W
 
 chunkBy :: Int -> [a] -> [[a]]
-chunkBy n bs = case (take n bs, drop n bs) of
+chunkBy n bs = case splitAt n bs of
   (as, zs) -> if null zs then [as] else as:chunkBy n zs
 
 toBoolsDiff :: [Word64] -> [Bool] -> [Bool]
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/ParensSeq.hs b/src/HaskellWorks/Data/BalancedParens/Internal/ParensSeq.hs
--- a/src/HaskellWorks/Data/BalancedParens/Internal/ParensSeq.hs
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/ParensSeq.hs
@@ -1,10 +1,10 @@
+{-# LANGUAGE CPP                        #-}
 {-# LANGUAGE DeriveGeneric              #-}
 {-# LANGUAGE DuplicateRecordFields      #-}
 {-# LANGUAGE FlexibleInstances          #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE MultiParamTypeClasses      #-}
 {-# LANGUAGE NamedFieldPuns             #-}
-{-# LANGUAGE StandaloneDeriving         #-}
 {-# LANGUAGE TypeFamilies               #-}
 
 module HaskellWorks.Data.BalancedParens.Internal.ParensSeq
@@ -21,8 +21,6 @@
 
 import Control.DeepSeq
 import Data.Int
-import Data.Monoid                                (Monoid)
-import Data.Semigroup                             (Semigroup (..))
 import Data.Word
 import GHC.Generics
 import HaskellWorks.Data.Bits.BitWise
@@ -68,6 +66,10 @@
 
 instance Monoid Measure where
   mempty = Measure 0 0 0
+#if MIN_VERSION_GLASGOW_HASKELL(8, 4, 4, 0)
+#else
+  mappend = (<>)
+#endif
 
 instance FT.Measured Measure Elem where
   measure (Elem w size) = Measure { min, excess, size }
@@ -121,7 +123,7 @@
           else 0
 
 atSizeBelowZero :: Count -> Measure -> Bool
-atSizeBelowZero n m = n < size (m :: Measure)
+atSizeBelowZero n (Measure { size = sz }) = n < sz
 
 atMinZero :: Measure -> Bool
-atMinZero m = min (m :: Measure) <= 0
+atMinZero (Measure { min = m }) = m <= 0
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/RoseTree.hs b/src/HaskellWorks/Data/BalancedParens/Internal/RoseTree.hs
--- a/src/HaskellWorks/Data/BalancedParens/Internal/RoseTree.hs
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/RoseTree.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE DeriveGeneric #-}
+
 module HaskellWorks.Data.BalancedParens.Internal.RoseTree
   ( RoseTree(..)
   , toBools
@@ -6,9 +8,11 @@
   , depth
   ) where
 
+import GHC.Generics
+
 newtype RoseTree = RoseTree
   { children :: [RoseTree]
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Generic)
 
 toBools :: RoseTree -> [Bool]
 toBools rt = toBools' rt []
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Show.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Show.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Show.hs
@@ -0,0 +1,6 @@
+module HaskellWorks.Data.BalancedParens.Internal.Show
+  ( showPadded
+  ) where
+
+showPadded :: Show a => Int -> a -> String
+showPadded n a = reverse (take n (reverse (show a) ++ [' ', ' ' ..]))
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindCloseC/Generic.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindCloseC/Generic.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindCloseC/Generic.hs
@@ -0,0 +1,15 @@
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseC.Generic
+  ( findCloseC
+  ) where
+
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Positioning
+
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic as G
+
+-- | Find position closing parenthesis from beginning of bit string, carrying a nesting level of 'c'
+findCloseC :: (BitLength a, CloseAt a, TestBit a) => a -> Count -> Maybe Count
+findCloseC v c = G.findCloseN v c 0
+{-# INLINE findCloseC #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindCloseN/Generic.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindCloseN/Generic.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindCloseN/Generic.hs
@@ -0,0 +1,36 @@
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic
+  ( findCloseN
+  ) where
+
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Positioning
+
+-- | Find the position of the corresponding close parenthesis carrying in a number of open parentheses starting from a given position.
+--
+-- All positions are one based.
+--
+-- This is a reference implementation.
+--
+-- >>> :set -XTypeApplications
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+-- >>> import Data.Word
+-- >>> findCloseN (fromJust (bitRead @Word64 "1100000")) 0 1
+-- Just 4
+-- >>> findCloseN (fromJust (bitRead @Word64 "1100000")) 0 2
+-- Just 3
+-- >>> findCloseN (fromJust (bitRead @Word64 "1100000")) 1 1
+-- Just 5
+-- >>> findCloseN (fromJust (bitRead @Word64 "1100000")) 1 2
+-- Just 4
+findCloseN :: (BitLength a, CloseAt a, TestBit a) => a -> Count -> Count -> Maybe Count
+findCloseN v c p = if 0 < p
+  then if v `closeAt` p
+    then if c <= 1
+      then Just p
+      else findCloseN v (c - 1) (p + 1)
+    else findCloseN v (c + 1) (p + 1)
+  else Nothing
+{-# INLINE findCloseN #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector16.hs
@@ -0,0 +1,82 @@
+
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector16
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Signed
+
+import qualified Data.Vector.Storable as DVS
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111"
+-- 16
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000"
+-- 8
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word16 -> Word64
+findUnmatchedCloseFar d i v = if i < bitLength v
+  then if v .?. signed i
+    then findUnmatchedCloseFar (d + 1) (i + 1) v
+    else if d == 0
+      then i
+      else findUnmatchedCloseFar (d - 1) (i + 1) v
+  else bitLength v + d
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector32.hs
@@ -0,0 +1,82 @@
+
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector32
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Signed
+
+import qualified Data.Vector.Storable as DVS
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111"
+-- 16
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000"
+-- 8
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word32 -> Word64
+findUnmatchedCloseFar d i v = if i < bitLength v
+  then if v .?. signed i
+    then findUnmatchedCloseFar (d + 1) (i + 1) v
+    else if d == 0
+      then i
+      else findUnmatchedCloseFar (d - 1) (i + 1) v
+  else bitLength v + d
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector64.hs
@@ -0,0 +1,82 @@
+
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector64
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Signed
+
+import qualified Data.Vector.Storable as DVS
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111"
+-- 16
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000"
+-- 8
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word64 -> Word64
+findUnmatchedCloseFar d i v = if i < bitLength v
+  then if v .?. signed i
+    then findUnmatchedCloseFar (d + 1) (i + 1) v
+    else if d == 0
+      then i
+      else findUnmatchedCloseFar (d - 1) (i + 1) v
+  else bitLength v + d
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Vector8.hs
@@ -0,0 +1,82 @@
+
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector8
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Signed
+
+import qualified Data.Vector.Storable as DVS
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111"
+-- 16
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000"
+-- 8
+findUnmatchedCloseFar :: Word64 -> Word64 -> DVS.Vector Word8 -> Word64
+findUnmatchedCloseFar d i v = if i < bitLength v
+  then if v .?. signed i
+    then findUnmatchedCloseFar (d + 1) (i + 1) v
+    else if d == 0
+      then i
+      else findUnmatchedCloseFar (d - 1) (i + 1) v
+  else bitLength v + d
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word16.hs
@@ -0,0 +1,77 @@
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word16
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000 00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000 00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000 00000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111 00000000"
+-- 16
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111 11111111"
+-- 32
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000 11110000"
+-- 16
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000 11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000 11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000 11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000 11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000 11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000 11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000 11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000 11110000"
+-- 16
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word16 -> Word64
+findUnmatchedCloseFar = go
+  where go :: Word64 -> Word64 -> Word16 -> Word64
+        go d 16 _ = 16 + d
+        go d i w = case (w .>. i) .&. 1 of
+          1 -> go (d + 1) (i + 1) w
+          _ -> if d == 0
+            then i
+            else go (d - 1) (i + 1) w
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word32.hs
@@ -0,0 +1,77 @@
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word32
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000 00000000 00000000 00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000 00000000 00000000 00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000 00000000 00000000 00000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111 11111111 00000000 00000000"
+-- 32
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111 11111111 11111111 11111111"
+-- 64
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 32
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000 11110000 11110000 11110000"
+-- 32
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word32 -> Word64
+findUnmatchedCloseFar = go
+  where go :: Word64 -> Word64 -> Word32 -> Word64
+        go d 32 _ = 32 + d
+        go d i w = case (w .>. i) .&. 1 of
+          1 -> go (d + 1) (i + 1) w
+          _ -> if d == 0
+            then i
+            else go (d - 1) (i + 1) w
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word64.hs
@@ -0,0 +1,78 @@
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word64
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111 11111111 11111111 11111111 00000000 00000000 00000000 00000000"
+-- 64
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111"
+-- 128
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 64
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000 11110000 11110000 11110000 11110000 11110000 11110000 11110000"
+-- 64
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word64 -> Word64
+findUnmatchedCloseFar = go
+  where go :: Word64 -> Word64 -> Word64 -> Word64
+        go d 64 _ = 64 + d
+        go d i w = case (w .>. fromIntegral i) .&. 1 of
+          1 -> go (d + 1) (i + 1) w
+          _ -> if d == 0
+            then i
+            else go (d - 1) (i + 1) w
+{-# INLINE findUnmatchedCloseFar #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Slow/FindUnmatchedCloseFar/Word8.hs
@@ -0,0 +1,77 @@
+module HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word8
+  ( findUnmatchedCloseFar
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+
+-- | Find the position of the first unmatch parenthesis.
+--
+-- The digits 1 and 0 are treated as an open parenthesis and closing parenthesis respectively.
+--
+-- All positions are indexed from zero.  If the search runs out of bits, then continue as if there remain an infinite
+-- string of zeros.
+--
+-- >>> import HaskellWorks.Data.Bits.BitRead
+-- >>> import Data.Maybe
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "00000000"
+-- 0
+--
+-- The following scans for the first unmatched closing parenthesis after skipping one bit from the beginning of the
+-- bit string:
+--
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "00000000"
+-- 1
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string.  To find
+-- unmatched parenthesis, the scan passes over the first parent of matching parentheses:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "10000000"
+-- 2
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows, the first of which is at
+-- position 64, which also happens to be the position of the unmatched parenthesis.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+--
+-- The following scans for the first unmatched closing parenthesis from the beginning of the bit string, but runs
+-- out of bits.  The scan continues as if there an inifinite string of zero bits follows and we don't get to the
+-- unmatched parenthesis until position 128.
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11111111"
+-- 16
+--
+-- Following are some more examples:
+--
+-- >>> findUnmatchedCloseFar 0 0 $ fromJust $ bitRead "11110000"
+-- 8
+-- >>> findUnmatchedCloseFar 0 1 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 2 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 3 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 4 $ fromJust $ bitRead "11110000"
+-- 4
+-- >>> findUnmatchedCloseFar 0 5 $ fromJust $ bitRead "11110000"
+-- 5
+-- >>> findUnmatchedCloseFar 0 6 $ fromJust $ bitRead "11110000"
+-- 6
+-- >>> findUnmatchedCloseFar 0 7 $ fromJust $ bitRead "11110000"
+-- 7
+-- >>> findUnmatchedCloseFar 0 8 $ fromJust $ bitRead "11110000"
+-- 8
+findUnmatchedCloseFar :: Word64 -> Word64 -> Word8 -> Word64
+findUnmatchedCloseFar = go
+  where go :: Word64 -> Word64 -> Word8 -> Word64
+        go d 8 _ = 8 + d
+        go d i w = case (w .>. i) .&. 1 of
+          1 -> go (d + 1) (i + 1) w
+          _ -> if d == 0
+            then i
+            else go (d - 1) (i + 1) w
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Trace.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Trace.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Trace.hs
@@ -0,0 +1,8 @@
+module HaskellWorks.Data.BalancedParens.Internal.Trace
+  ( traceW
+  ) where
+
+import Debug.Trace
+
+traceW :: Show a => String -> a -> a
+traceW s a = trace (s <> " = " <> show a) a
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Vector/Storable.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Vector/Storable.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Vector/Storable.hs
@@ -0,0 +1,39 @@
+module HaskellWorks.Data.BalancedParens.Internal.Vector.Storable
+  ( lastOrZero
+  , reword
+  , dropTake
+  , dropTakeFill
+  , pageFill
+  ) where
+
+import qualified Data.Vector.Storable as DVS
+
+lastOrZero :: (DVS.Storable a, Integral a) => DVS.Vector a -> a
+lastOrZero v = if not (DVS.null v) then DVS.last v else 0
+{-# INLINE lastOrZero #-}
+
+reword :: (DVS.Storable a, Integral a, DVS.Storable b, Num b) => DVS.Vector a -> DVS.Vector b
+reword v = DVS.generate (DVS.length v) (\i -> fromIntegral (v DVS.! i))
+{-# INLINE reword #-}
+
+dropTake :: DVS.Storable a => Int -> Int -> DVS.Vector a -> DVS.Vector a
+dropTake n o = DVS.take o . DVS.drop n
+{-# INLINE dropTake #-}
+
+dropTakeFill :: DVS.Storable a => Int -> Int -> a -> DVS.Vector a -> DVS.Vector a
+dropTakeFill n o a v =  let r = DVS.take o (DVS.drop n v) in
+                        let len = DVS.length r in
+                        if len == o then r else DVS.concat [r, DVS.fromList (replicate (o - len) a)]
+{-# INLINE dropTakeFill #-}
+
+-- | Return the n-th page of size s from the input vector.  In the case where there isn't
+-- sufficient data to fill the page from the input vector, then the remainder of the page
+-- is filled with a.
+pageFill :: DVS.Storable a
+  => Int          -- ^ The n-th page to retrieve
+  -> Int          -- ^ The page size
+  -> a            -- ^ The element value to fill the page when input vector has insufficient values
+  -> DVS.Vector a -- ^ The input vector
+  -> DVS.Vector a -- ^ The page
+pageFill n s = dropTakeFill (n * s) s
+{-# INLINE pageFill #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Word16.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Word16.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Word16.hs
@@ -0,0 +1,34 @@
+module HaskellWorks.Data.BalancedParens.Internal.Word16
+  ( mu0
+  , mu1
+  , mu2
+  , mu3
+  , mu4
+  ) where
+
+import Data.Word
+
+-- | Subwords of size 2 ^ 0 alternating between all bits cleared and all bits
+mu0 :: Word16
+mu0 = 0x5555
+{-# INLINE mu0 #-}
+
+-- | Subwords of size 2 ^ 1 alternating between all bits cleared and all bits
+mu1 :: Word16
+mu1 = 0x3333
+{-# INLINE mu1 #-}
+
+-- | Subwords of size 2 ^ 2 alternating between all bits cleared and all bits
+mu2 :: Word16
+mu2 = 0x0f0f
+{-# INLINE mu2 #-}
+
+-- | Subwords of size 2 ^ 3 alternating between all bits cleared and all bits
+mu3 :: Word16
+mu3 = 0x00ff
+{-# INLINE mu3 #-}
+
+-- | Subwords of size 2 ^ 4 alternating between all bits cleared and all bits
+mu4 :: Word16
+mu4 = 0xffff
+{-# INLINE mu4 #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Word32.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Word32.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Word32.hs
@@ -0,0 +1,40 @@
+module HaskellWorks.Data.BalancedParens.Internal.Word32
+  ( mu0
+  , mu1
+  , mu2
+  , mu3
+  , mu4
+  , mu5
+  ) where
+
+import Data.Word
+
+-- | Subwords of size 2 ^ 0 alternating between all bits cleared and all bits
+mu0 :: Word32
+mu0 = 0x55555555
+{-# INLINE mu0 #-}
+
+-- | Subwords of size 2 ^ 1 alternating between all bits cleared and all bits
+mu1 :: Word32
+mu1 = 0x33333333
+{-# INLINE mu1 #-}
+
+-- | Subwords of size 2 ^ 2 alternating between all bits cleared and all bits
+mu2 :: Word32
+mu2 = 0x0f0f0f0f
+{-# INLINE mu2 #-}
+
+-- | Subwords of size 2 ^ 3 alternating between all bits cleared and all bits
+mu3 :: Word32
+mu3 = 0x00ff00ff
+{-# INLINE mu3 #-}
+
+-- | Subwords of size 2 ^ 4 alternating between all bits cleared and all bits
+mu4 :: Word32
+mu4 = 0x0000ffff
+{-# INLINE mu4 #-}
+
+-- | Subwords of size 2 ^ 5 alternating between all bits cleared and all bits
+mu5 :: Word32
+mu5 = 0xffffffff
+{-# INLINE mu5 #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Word64.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Word64.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Word64.hs
@@ -0,0 +1,46 @@
+module HaskellWorks.Data.BalancedParens.Internal.Word64
+  ( mu0
+  , mu1
+  , mu2
+  , mu3
+  , mu4
+  , mu5
+  , mu6
+  ) where
+
+import Data.Word
+
+-- | Subwords of size 2 ^ 0 alternating between all bits cleared and all bits
+mu0 :: Word64
+mu0 = 0x5555555555555555
+{-# INLINE mu0 #-}
+
+-- | Subwords of size 2 ^ 1 alternating between all bits cleared and all bits
+mu1 :: Word64
+mu1 = 0x3333333333333333
+{-# INLINE mu1 #-}
+
+-- | Subwords of size 2 ^ 2 alternating between all bits cleared and all bits
+mu2 :: Word64
+mu2 = 0x0f0f0f0f0f0f0f0f
+{-# INLINE mu2 #-}
+
+-- | Subwords of size 2 ^ 3 alternating between all bits cleared and all bits
+mu3 :: Word64
+mu3 = 0x00ff00ff00ff00ff
+{-# INLINE mu3 #-}
+
+-- | Subwords of size 2 ^ 4 alternating between all bits cleared and all bits
+mu4 :: Word64
+mu4 = 0x0000ffff0000ffff
+{-# INLINE mu4 #-}
+
+-- | Subwords of size 2 ^ 5 alternating between all bits cleared and all bits
+mu5 :: Word64
+mu5 = 0x00000000ffffffff
+{-# INLINE mu5 #-}
+
+-- | Subwords of size 2 ^ 6 alternating between all bits cleared and all bits
+mu6 :: Word64
+mu6 = 0xffffffffffffffff
+{-# INLINE mu6 #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/Internal/Word8.hs b/src/HaskellWorks/Data/BalancedParens/Internal/Word8.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/Internal/Word8.hs
@@ -0,0 +1,28 @@
+module HaskellWorks.Data.BalancedParens.Internal.Word8
+  ( mu0
+  , mu1
+  , mu2
+  , mu3
+  ) where
+
+import Data.Word
+
+-- | Subwords of size 2 ^ 0 alternating between all bits cleared and all bits
+mu0 :: Word16
+mu0 = 0x55
+{-# INLINE mu0 #-}
+
+-- | Subwords of size 2 ^ 1 alternating between all bits cleared and all bits
+mu1 :: Word16
+mu1 = 0x33
+{-# INLINE mu1 #-}
+
+-- | Subwords of size 2 ^ 2 alternating between all bits cleared and all bits
+mu2 :: Word16
+mu2 = 0x0f
+{-# INLINE mu2 #-}
+
+-- | Subwords of size 2 ^ 3 alternating between all bits cleared and all bits
+mu3 :: Word16
+mu3 = 0xff
+{-# INLINE mu3 #-}
diff --git a/src/HaskellWorks/Data/BalancedParens/NewCloseAt.hs b/src/HaskellWorks/Data/BalancedParens/NewCloseAt.hs
--- a/src/HaskellWorks/Data/BalancedParens/NewCloseAt.hs
+++ b/src/HaskellWorks/Data/BalancedParens/NewCloseAt.hs
@@ -14,7 +14,7 @@
 import qualified Data.Vector.Storable as DVS
 
 class NewCloseAt v where
-  newCloseAt     :: v -> Count -> Bool
+  newCloseAt :: v -> Count -> Bool
 
 newCloseAt' :: TestBit a => a -> Count -> Bool
 newCloseAt' v c = not (v .?. toPosition c)
diff --git a/src/HaskellWorks/Data/BalancedParens/NewOpenAt.hs b/src/HaskellWorks/Data/BalancedParens/NewOpenAt.hs
--- a/src/HaskellWorks/Data/BalancedParens/NewOpenAt.hs
+++ b/src/HaskellWorks/Data/BalancedParens/NewOpenAt.hs
@@ -13,7 +13,7 @@
 import qualified Data.Vector.Storable as DVS
 
 class NewOpenAt v where
-  newOpenAt      :: v -> Count -> Bool
+  newOpenAt :: v -> Count -> Bool
 
 newOpenAt' :: (BitLength a, TestBit a) => a -> Count -> Bool
 newOpenAt' v c = (0 <= c && c < bitLength v) && (v .?. toPosition c)
diff --git a/src/HaskellWorks/Data/BalancedParens/OpenAt.hs b/src/HaskellWorks/Data/BalancedParens/OpenAt.hs
--- a/src/HaskellWorks/Data/BalancedParens/OpenAt.hs
+++ b/src/HaskellWorks/Data/BalancedParens/OpenAt.hs
@@ -8,14 +8,14 @@
 import HaskellWorks.Data.Bits.BitLength
 import HaskellWorks.Data.Bits.BitShown
 import HaskellWorks.Data.Bits.BitWise
-import HaskellWorks.Data.Bits.Broadword
+import HaskellWorks.Data.Bits.Broadword.Type
 import HaskellWorks.Data.Naive
 import HaskellWorks.Data.Positioning
 
 import qualified Data.Vector.Storable as DVS
 
 class OpenAt v where
-  openAt      :: v -> Count -> Bool
+  openAt :: v -> Count -> Bool
 
 openAt' :: (BitLength a, TestBit a) => a -> Count -> Bool
 openAt' v c = (0 <= c && c < bitLength v) && (v .?. toPosition (c - 1))
diff --git a/src/HaskellWorks/Data/BalancedParens/ParensSeq.hs b/src/HaskellWorks/Data/BalancedParens/ParensSeq.hs
--- a/src/HaskellWorks/Data/BalancedParens/ParensSeq.hs
+++ b/src/HaskellWorks/Data/BalancedParens/ParensSeq.hs
@@ -21,7 +21,6 @@
 
 import Data.Coerce
 import Data.Foldable
-import Data.Monoid
 import Data.Word
 import HaskellWorks.Data.BalancedParens.Internal.ParensSeq (Elem (Elem), ParensSeq (ParensSeq), ParensSeqFt)
 import HaskellWorks.Data.Bits.BitWise
@@ -31,6 +30,7 @@
 
 import qualified Data.List                                           as L
 import qualified HaskellWorks.Data.BalancedParens.Internal.ParensSeq as PS
+  hiding ( Elem(size) )
 import qualified HaskellWorks.Data.BalancedParens.Internal.Word      as W
 import qualified HaskellWorks.Data.FingerTree                        as FT
 
@@ -97,7 +97,7 @@
         else (ParensSeq (lt |> PS.Elem ((w .<. u) .>. u) n'), ParensSeq (PS.Elem (w .>. n') (nw - n') <| rrt))
       FT.EmptyL          -> (ParensSeq lt, ParensSeq FT.empty)
 
-firstChild  :: ParensSeq -> Count -> Maybe Count
+firstChild :: ParensSeq -> Count -> Maybe Count
 firstChild ps n = case FT.viewl ft of
   PS.Elem w nw :< rt -> if nw >= 2
     then case w .&. 3 of
@@ -117,7 +117,7 @@
   FT.EmptyL -> Nothing
   where ParensSeq ft = drop (n - 1) ps
 
-nextSibling  :: ParensSeq -> Count -> Maybe Count
+nextSibling :: ParensSeq -> Count -> Maybe Count
 nextSibling (ParensSeq ps) n = do
   let (lt0, rt0) = PS.ftSplit (PS.atSizeBelowZero (n - 1)) ps
   _ <- case FT.viewl rt0 of
diff --git a/src/HaskellWorks/Data/BalancedParens/RangeMin.hs b/src/HaskellWorks/Data/BalancedParens/RangeMin.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/RangeMin.hs
@@ -0,0 +1,212 @@
+{-# LANGUAGE BangPatterns          #-}
+{-# LANGUAGE DeriveAnyClass        #-}
+{-# LANGUAGE DeriveGeneric         #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE InstanceSigs          #-}
+{-# LANGUAGE TypeFamilies          #-}
+
+module HaskellWorks.Data.BalancedParens.RangeMin
+  ( RangeMin(..)
+  , mkRangeMin
+  ) where
+
+import Control.DeepSeq
+import Data.Int
+import GHC.Generics
+import HaskellWorks.Data.AtIndex
+import HaskellWorks.Data.BalancedParens.BalancedParens
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.BalancedParens.Enclose
+import HaskellWorks.Data.BalancedParens.FindClose
+import HaskellWorks.Data.BalancedParens.FindCloseN
+import HaskellWorks.Data.BalancedParens.FindOpen
+import HaskellWorks.Data.BalancedParens.FindOpenN
+import HaskellWorks.Data.BalancedParens.NewCloseAt
+import HaskellWorks.Data.BalancedParens.OpenAt
+import HaskellWorks.Data.Bits.AllExcess.AllExcess1
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Excess.MinExcess
+import HaskellWorks.Data.Excess.MinExcess1
+import HaskellWorks.Data.Positioning
+import HaskellWorks.Data.RankSelect.Base.Rank0
+import HaskellWorks.Data.RankSelect.Base.Rank1
+import HaskellWorks.Data.Vector.AsVector64
+import Prelude                                         hiding (length)
+
+import qualified Data.Vector.Storable                                      as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Vector.Storable as DVS
+
+data RangeMin a = RangeMin
+  { rangeMinBP       :: !a
+  , rangeMinL0Min    :: !(DVS.Vector Int8)
+  , rangeMinL0Excess :: !(DVS.Vector Int8)
+  , rangeMinL1Min    :: !(DVS.Vector Int16)
+  , rangeMinL1Excess :: !(DVS.Vector Int16)
+  , rangeMinL2Min    :: !(DVS.Vector Int16)
+  , rangeMinL2Excess :: !(DVS.Vector Int16)
+  } deriving (Eq, Show, NFData, Generic)
+
+factorL0 :: Integral a => a
+factorL0 = 1
+{-# INLINE factorL0 #-}
+
+factorL1 :: Integral a => a
+factorL1 = 32
+{-# INLINE factorL1 #-}
+
+factorL2 :: Integral a => a
+factorL2 = 32
+{-# INLINE factorL2 #-}
+
+pageSizeL0 :: Integral a => a
+pageSizeL0 = factorL0
+{-# INLINE pageSizeL0 #-}
+
+pageSizeL1 :: Integral a => a
+pageSizeL1 = pageSizeL0 * factorL1
+{-# INLINE pageSizeL1 #-}
+
+pageSizeL2 :: Integral a => a
+pageSizeL2 = pageSizeL1 * factorL2
+{-# INLINE pageSizeL2 #-}
+
+mkRangeMin :: AsVector64 a => a -> RangeMin a
+mkRangeMin bp = RangeMin
+  { rangeMinBP       = bp
+  , rangeMinL0Min    = rmL0Min
+  , rangeMinL0Excess = DVS.reword rmL0Excess
+  , rangeMinL1Min    = rmL1Min
+  , rangeMinL1Excess = DVS.reword rmL1Excess
+  , rangeMinL2Min    = rmL2Min
+  , rangeMinL2Excess = rmL2Excess
+  }
+  where bpv           = asVector64 bp
+        lenBP         = fromIntegral (length bpv) :: Int
+        lenL0         = lenBP
+        lenL1         = (DVS.length rmL0Min `div` pageSizeL1) + 1 :: Int
+        lenL2         = (DVS.length rmL0Min `div` pageSizeL2) + 1 :: Int
+        allMinL0      = DVS.generate lenL0 (\i -> if i == lenBP then MinExcess (-64) (-64) else minExcess1 (bpv !!! fromIntegral i))
+        allMinL1      = DVS.generate lenL1 (\i -> minExcess1 (DVS.dropTake (i * pageSizeL1) pageSizeL1 bpv))
+        allMinL2      = DVS.generate lenL2 (\i -> minExcess1 (DVS.dropTake (i * pageSizeL2) pageSizeL2 bpv))
+        -- Note: (0xffffffffffffffc0 :: Int64) = -64
+        rmL0Excess    = DVS.generate lenL0 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL0 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL1Excess    = DVS.generate lenL1 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL1 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL2Excess    = DVS.generate lenL2 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL2 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL0Min       = DVS.generate lenL0 (\i -> let MinExcess minE _ = allMinL0 DVS.! i in fromIntegral minE)
+        rmL1Min       = DVS.generate lenL1 (\i -> let MinExcess minE _ = allMinL1 DVS.! i in fromIntegral minE)
+        rmL2Min       = DVS.generate lenL2 (\i -> let MinExcess minE _ = allMinL2 DVS.! i in fromIntegral minE)
+
+data FindState = FindBP
+  | FindL0 | FindFromL0
+  | FindL1 | FindFromL1
+  | FindL2 | FindFromL2
+
+rm2FindClose  :: (BitLength a, NewCloseAt a) => RangeMin a -> Int -> Count -> FindState -> Maybe Count
+rm2FindClose v s p FindBP = if v `newCloseAt` p
+  then if s <= 1
+    then Just p
+    else rm2FindClose v (s - 1) (p + 1) FindFromL0
+  else rm2FindClose v (s + 1) (p + 1) FindFromL0
+rm2FindClose v s p FindL0 =
+  let i = p `div` 64 in
+  let mins = rangeMinL0Min v in
+  let minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindBP
+    else if v `newCloseAt` p && s <= 1
+      then Just p
+      else  let excesses  = rangeMinL0Excess v in
+            let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+            rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + 64) FindFromL0
+rm2FindClose v s p FindL1 =
+  let !i = p `div` (64 * pageSizeL1) in
+  let !mins = rangeMinL1Min v in
+  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindL0
+    else if 0 <= p && p < bitLength v
+      then if v `newCloseAt` p && s <= 1
+        then Just p
+        else  let excesses  = rangeMinL1Excess v in
+              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+              rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL1)) FindFromL1
+      else Nothing
+rm2FindClose v s p FindL2 =
+  let !i = p `div` (64 * pageSizeL2) in
+  let !mins = rangeMinL2Min v in
+  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindL1
+    else if 0 <= p && p < bitLength v
+      then if v `newCloseAt` p && s <= 1
+        then Just p
+        else  let excesses  = rangeMinL2Excess v in
+              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+              rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL2)) FindFromL2
+      else Nothing
+rm2FindClose v s p FindFromL0
+  | p `mod` 64 == 0             = rm2FindClose v s p FindFromL1
+  | 0 <= p && p < bitLength v   = rm2FindClose v s p FindBP
+  | otherwise                   = Nothing
+rm2FindClose v s p FindFromL1
+  | p `mod` (64 * pageSizeL1) == 0  = if 0 <= p && p < bitLength v then rm2FindClose v s p FindFromL2 else Nothing
+  | 0 <= p && p < bitLength v       = rm2FindClose v s p FindL0
+  | otherwise                       = Nothing
+rm2FindClose v s p FindFromL2
+  | p `mod` (64 * pageSizeL2) == 0  = if 0 <= p && p < bitLength v then rm2FindClose v s p FindL2 else Nothing
+  | 0 <= p && p < bitLength v       = rm2FindClose v s p FindL1
+  | otherwise                       = Nothing
+{-# INLINE rm2FindClose #-}
+
+instance TestBit a => TestBit (RangeMin a) where
+  (.?.) = (.?.) . rangeMinBP
+  {-# INLINE (.?.) #-}
+
+instance Rank1 a => Rank1 (RangeMin a) where
+  rank1 = rank1 . rangeMinBP
+  {-# INLINE rank1 #-}
+
+instance Rank0 a => Rank0 (RangeMin a) where
+  rank0 = rank0 . rangeMinBP
+  {-# INLINE rank0 #-}
+
+instance BitLength a => BitLength (RangeMin a) where
+  bitLength = bitLength . rangeMinBP
+  {-# INLINE bitLength #-}
+
+instance OpenAt a => OpenAt (RangeMin a) where
+  openAt = openAt . rangeMinBP
+  {-# INLINE openAt #-}
+
+instance CloseAt a => CloseAt (RangeMin a) where
+  closeAt = closeAt . rangeMinBP
+  {-# INLINE closeAt #-}
+
+instance NewCloseAt a => NewCloseAt (RangeMin a) where
+  newCloseAt = newCloseAt . rangeMinBP
+  {-# INLINE newCloseAt #-}
+
+instance FindOpenN a => FindOpenN (RangeMin a) where
+  findOpenN = findOpenN . rangeMinBP
+  {-# INLINE findOpenN #-}
+
+instance (BitLength a, NewCloseAt a) => FindCloseN (RangeMin a) where
+  findCloseN v s p  = (+ 1) `fmap` rm2FindClose v (fromIntegral s) (p - 1) FindFromL0
+  {-# INLINE findCloseN  #-}
+
+instance (BitLength a, CloseAt a, NewCloseAt a, FindCloseN a) => FindClose (RangeMin a) where
+  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  {-# INLINE findClose #-}
+
+instance (OpenAt a, FindOpenN a) => FindOpen (RangeMin a) where
+  findOpen v p = if v `openAt`  p then Just p else findOpenN  v 0 (p - 1)
+  {-# INLINE findOpen #-}
+
+instance FindOpenN a => Enclose (RangeMin a) where
+  enclose v = findOpenN v 1
+  {-# INLINE enclose #-}
+
+instance (BitLength a, NewCloseAt a, CloseAt a, OpenAt a, FindOpenN a, FindCloseN a) => BalancedParens (RangeMin a)
diff --git a/src/HaskellWorks/Data/BalancedParens/RangeMin2.hs b/src/HaskellWorks/Data/BalancedParens/RangeMin2.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/BalancedParens/RangeMin2.hs
@@ -0,0 +1,281 @@
+{-# LANGUAGE BangPatterns      #-}
+{-# LANGUAGE DeriveAnyClass    #-}
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE InstanceSigs      #-}
+{-# LANGUAGE TypeFamilies      #-}
+
+module HaskellWorks.Data.BalancedParens.RangeMin2
+  ( RangeMin2(..)
+  , mkRangeMin2
+  ) where
+
+import Control.DeepSeq
+import Data.Int
+import GHC.Generics
+import HaskellWorks.Data.AtIndex
+import HaskellWorks.Data.BalancedParens.BalancedParens
+import HaskellWorks.Data.BalancedParens.CloseAt
+import HaskellWorks.Data.BalancedParens.Enclose
+import HaskellWorks.Data.BalancedParens.FindClose
+import HaskellWorks.Data.BalancedParens.FindCloseN
+import HaskellWorks.Data.BalancedParens.FindOpen
+import HaskellWorks.Data.BalancedParens.FindOpenN
+import HaskellWorks.Data.BalancedParens.NewCloseAt
+import HaskellWorks.Data.BalancedParens.OpenAt
+import HaskellWorks.Data.Bits.AllExcess.AllExcess1
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Excess.MinExcess
+import HaskellWorks.Data.Excess.MinExcess1
+import HaskellWorks.Data.Positioning
+import HaskellWorks.Data.RankSelect.Base.Rank0
+import HaskellWorks.Data.RankSelect.Base.Rank1
+import HaskellWorks.Data.Vector.AsVector64
+import Prelude                                         hiding (length)
+
+import qualified Data.Vector                                               as DV
+import qualified Data.Vector.Storable                                      as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Vector.Storable as DVS
+
+data RangeMin2 a = RangeMin2
+  { rangeMin2BP       :: !a
+  , rangeMin2L0Min    :: !(DVS.Vector Int8)
+  , rangeMin2L0Excess :: !(DVS.Vector Int8)
+  , rangeMin2L1Min    :: !(DVS.Vector Int16)
+  , rangeMin2L1Excess :: !(DVS.Vector Int16)
+  , rangeMin2L2Min    :: !(DVS.Vector Int16)
+  , rangeMin2L2Excess :: !(DVS.Vector Int16)
+  , rangeMin2L3Min    :: !(DVS.Vector Int16)
+  , rangeMin2L3Excess :: !(DVS.Vector Int16)
+  , rangeMin2L4Min    :: !(DVS.Vector Int16)
+  , rangeMin2L4Excess :: !(DVS.Vector Int16)
+  } deriving (NFData, Generic)
+
+factorL0 :: Integral a => a
+factorL0 = 1
+{-# INLINE factorL0 #-}
+
+factorL1 :: Integral a => a
+factorL1 = 32
+{-# INLINE factorL1 #-}
+
+factorL2 :: Integral a => a
+factorL2 = 32
+{-# INLINE factorL2 #-}
+
+factorL3 :: Integral a => a
+factorL3 = 32
+{-# INLINE factorL3 #-}
+
+factorL4 :: Integral a => a
+factorL4 = 32
+{-# INLINE factorL4 #-}
+
+pageSizeL0 :: Integral a => a
+pageSizeL0 = factorL0
+{-# INLINE pageSizeL0 #-}
+
+pageSizeL1 :: Integral a => a
+pageSizeL1 = pageSizeL0 * factorL1
+{-# INLINE pageSizeL1 #-}
+
+pageSizeL2 :: Integral a => a
+pageSizeL2 = pageSizeL1 * factorL2
+{-# INLINE pageSizeL2 #-}
+
+pageSizeL3 :: Integral a => a
+pageSizeL3 = pageSizeL2 * factorL3
+{-# INLINE pageSizeL3 #-}
+
+pageSizeL4 :: Integral a => a
+pageSizeL4 = pageSizeL3 * factorL4
+{-# INLINE pageSizeL4 #-}
+
+mkRangeMin2 :: AsVector64 a => a -> RangeMin2 a
+mkRangeMin2 bp = RangeMin2
+  { rangeMin2BP       = bp
+  , rangeMin2L0Min    = DVS.reword rmL0Min
+  , rangeMin2L0Excess = DVS.reword rmL0Excess
+  , rangeMin2L1Min    = rmL1Min
+  , rangeMin2L1Excess = rmL1Excess
+  , rangeMin2L2Min    = rmL2Min
+  , rangeMin2L2Excess = rmL2Excess
+  , rangeMin2L3Min    = rmL3Min
+  , rangeMin2L3Excess = rmL3Excess
+  , rangeMin2L4Min    = rmL4Min
+  , rangeMin2L4Excess = rmL4Excess
+  }
+  where bpv           = asVector64 bp
+        lenBP         = fromIntegral (length bpv) :: Int
+        lenL0         = lenBP
+        lenL1         = (DVS.length rmL0Min `div` pageSizeL1) + 1 :: Int
+        lenL2         = (DVS.length rmL0Min `div` pageSizeL2) + 1 :: Int
+        lenL3         = (DVS.length rmL0Min `div` pageSizeL3) + 1 :: Int
+        lenL4         = (DVS.length rmL0Min `div` pageSizeL4) + 1 :: Int
+        allMinL0      = DV.generate  lenL0 (\i -> if i == lenBP then MinExcess (-64) (-64) else minExcess1 (bpv !!! fromIntegral i))
+        -- Note: (0xffffffffffffffc0 :: Int64) = -64
+        rmL0Excess    = DVS.generate lenL0 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL0 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL1Excess    = DVS.generate lenL1 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL1 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL2Excess    = DVS.generate lenL2 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL2 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL3Excess    = DVS.generate lenL3 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL3 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL4Excess    = DVS.generate lenL4 (\i -> fromIntegral (allExcess1 (DVS.pageFill i pageSizeL4 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
+        rmL0Min       = DVS.generate lenL0 (\i -> let MinExcess minE _ = allMinL0 DV.! i in fromIntegral minE) :: DVS.Vector Int16
+        rmL1Min       = DVS.generate lenL1 (\i -> genMin 0 (DVS.pageFill i factorL1 0 rmL0Min) (DVS.pageFill i factorL1 0 rmL0Excess))
+        rmL2Min       = DVS.generate lenL2 (\i -> genMin 0 (DVS.pageFill i factorL2 0 rmL1Min) (DVS.pageFill i factorL2 0 rmL1Excess))
+        rmL3Min       = DVS.generate lenL3 (\i -> genMin 0 (DVS.pageFill i factorL3 0 rmL2Min) (DVS.pageFill i factorL3 0 rmL2Excess))
+        rmL4Min       = DVS.generate lenL4 (\i -> genMin 0 (DVS.pageFill i factorL4 0 rmL3Min) (DVS.pageFill i factorL4 0 rmL3Excess))
+
+genMin :: (Integral a, DVS.Storable a) => a -> DVS.Vector a -> DVS.Vector a -> a
+genMin mL mins excesses = if not (DVS.null mins) || not (DVS.null excesses)
+  then genMin (DVS.lastOrZero mins `min` (mL + DVS.lastOrZero excesses)) (DVS.init mins) (DVS.init excesses)
+  else mL
+
+data FindState = FindBP
+  | FindL0 | FindFromL0
+  | FindL1 | FindFromL1
+  | FindL2 | FindFromL2
+  | FindL3 | FindFromL3
+  | FindL4 | FindFromL4
+
+rm2FindClose  :: (BitLength a, NewCloseAt a) => RangeMin2 a -> Int -> Count -> FindState -> Maybe Count
+rm2FindClose v s p FindBP = if v `newCloseAt` p
+  then if s <= 1
+    then Just p
+    else rm2FindClose v (s - 1) (p + 1) FindFromL0
+  else rm2FindClose v (s + 1) (p + 1) FindFromL0
+rm2FindClose v s p FindL0 =
+  let i = p `div` 64 in
+  let mins = rangeMin2L0Min v in
+  let minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindBP
+    else if v `newCloseAt` p && s <= 1
+      then Just p
+      else  let excesses  = rangeMin2L0Excess v in
+            let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+            rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + 64) FindFromL0
+rm2FindClose v s p FindL1 =
+  let !i = p `div` (64 * pageSizeL1) in
+  let !mins = rangeMin2L1Min v in
+  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindL0
+    else if 0 <= p && p < bitLength v
+      then if v `newCloseAt` p && s <= 1
+        then Just p
+        else  let excesses  = rangeMin2L1Excess v in
+              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+              rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL1)) FindFromL1
+      else Nothing
+rm2FindClose v s p FindL2 =
+  let !i = p `div` (64 * pageSizeL2) in
+  let !mins = rangeMin2L2Min v in
+  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindL1
+    else if 0 <= p && p < bitLength v
+      then if v `newCloseAt` p && s <= 1
+        then Just p
+        else  let excesses  = rangeMin2L2Excess v in
+              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+              rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL2)) FindFromL2
+      else Nothing
+rm2FindClose v s p FindL3 =
+  let !i = p `div` (64 * pageSizeL3) in
+  let !mins = rangeMin2L3Min v in
+  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindL2
+    else if 0 <= p && p < bitLength v
+      then if v `newCloseAt` p && s <= 1
+        then Just p
+        else  let excesses  = rangeMin2L3Excess v in
+              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+              rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL3)) FindFromL3
+        else Nothing
+rm2FindClose v s p FindL4 =
+  let !i = p `div` (64 * pageSizeL4) in
+  let !mins = rangeMin2L4Min v in
+  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
+  if fromIntegral s + minE <= 0
+    then rm2FindClose v s p FindL3
+    else if 0 <= p && p < bitLength v
+      then if v `newCloseAt` p && s <= 1
+        then Just p
+        else  let excesses  = rangeMin2L4Excess v in
+              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
+              rm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL4)) FindFromL4
+        else Nothing
+rm2FindClose v s p FindFromL0
+  | p `mod` 64 == 0             = rm2FindClose v s p FindFromL1
+  | 0 <= p && p < bitLength v   = rm2FindClose v s p FindBP
+  | otherwise                   = Nothing
+rm2FindClose v s p FindFromL1
+  | p `mod` (64 * pageSizeL1) == 0  = if 0 <= p && p < bitLength v then rm2FindClose v s p FindFromL2 else Nothing
+  | 0 <= p && p < bitLength v       = rm2FindClose v s p FindL0
+  | otherwise                       = Nothing
+rm2FindClose v s p FindFromL2
+  | p `mod` (64 * pageSizeL2) == 0  = if 0 <= p && p < bitLength v then rm2FindClose v s p FindFromL3 else Nothing
+  | 0 <= p && p < bitLength v       = rm2FindClose v s p FindL1
+  | otherwise                       = Nothing
+rm2FindClose v s p FindFromL3
+  | p `mod` (64 * pageSizeL3) == 0  = if 0 <= p && p < bitLength v then rm2FindClose v s p FindFromL4 else Nothing
+  | 0 <= p && p < bitLength v       = rm2FindClose v s p FindL2
+  | otherwise                       = Nothing
+rm2FindClose v s p FindFromL4
+  | p `mod` (64 * pageSizeL4) == 0  = if 0 <= p && p < bitLength v then rm2FindClose v s p FindL4 else Nothing
+  | 0 <= p && p < bitLength v       = rm2FindClose v s p FindL3
+  | otherwise                       = Nothing
+{-# INLINE rm2FindClose #-}
+
+instance TestBit a => TestBit (RangeMin2 a) where
+  (.?.) = (.?.) . rangeMin2BP
+  {-# INLINE (.?.) #-}
+
+instance Rank1 a => Rank1 (RangeMin2 a) where
+  rank1 = rank1 . rangeMin2BP
+  {-# INLINE rank1 #-}
+
+instance Rank0 a => Rank0 (RangeMin2 a) where
+  rank0 = rank0 . rangeMin2BP
+  {-# INLINE rank0 #-}
+
+instance BitLength a => BitLength (RangeMin2 a) where
+  bitLength = bitLength . rangeMin2BP
+  {-# INLINE bitLength #-}
+
+instance OpenAt a => OpenAt (RangeMin2 a) where
+  openAt = openAt . rangeMin2BP
+  {-# INLINE openAt #-}
+
+instance CloseAt a => CloseAt (RangeMin2 a) where
+  closeAt = closeAt . rangeMin2BP
+  {-# INLINE closeAt #-}
+
+instance NewCloseAt a => NewCloseAt (RangeMin2 a) where
+  newCloseAt = newCloseAt . rangeMin2BP
+  {-# INLINE newCloseAt #-}
+
+instance FindOpenN a => FindOpenN (RangeMin2 a) where
+  findOpenN = findOpenN . rangeMin2BP
+  {-# INLINE findOpenN #-}
+
+instance (BitLength a, FindCloseN a, NewCloseAt a) => FindCloseN (RangeMin2 a) where
+  findCloseN v s p  = (+ 1) `fmap` rm2FindClose v (fromIntegral s) (p - 1) FindFromL0
+  {-# INLINE findCloseN  #-}
+
+instance (BitLength a, NewCloseAt a, CloseAt a, FindCloseN a) => FindClose (RangeMin2 a) where
+  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
+  {-# INLINE findClose #-}
+
+instance (OpenAt a, FindOpenN a) => FindOpen (RangeMin2 a) where
+  findOpen v p = if v `openAt`  p then Just p else findOpenN  v 0 (p - 1)
+  {-# INLINE findOpen #-}
+
+instance FindOpenN a => Enclose (RangeMin2 a) where
+  enclose v = findOpenN v 1
+  {-# INLINE enclose #-}
+
+instance (BitLength a, NewCloseAt a, CloseAt a, OpenAt a, FindOpenN a, FindCloseN a) => BalancedParens (RangeMin2 a)
diff --git a/src/HaskellWorks/Data/BalancedParens/RangeMinMax.hs b/src/HaskellWorks/Data/BalancedParens/RangeMinMax.hs
deleted file mode 100644
--- a/src/HaskellWorks/Data/BalancedParens/RangeMinMax.hs
+++ /dev/null
@@ -1,233 +0,0 @@
-{-# LANGUAGE BangPatterns          #-}
-{-# LANGUAGE DeriveAnyClass        #-}
-{-# LANGUAGE DeriveGeneric         #-}
-{-# LANGUAGE DuplicateRecordFields #-}
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE InstanceSigs          #-}
-{-# LANGUAGE TypeFamilies          #-}
-
-module HaskellWorks.Data.BalancedParens.RangeMinMax
-  ( RangeMinMax(..)
-  , mkRangeMinMax
-  ) where
-
-import Control.DeepSeq
-import Data.Int
-import GHC.Generics
-import HaskellWorks.Data.AtIndex
-import HaskellWorks.Data.BalancedParens.BalancedParens
-import HaskellWorks.Data.BalancedParens.CloseAt
-import HaskellWorks.Data.BalancedParens.Enclose
-import HaskellWorks.Data.BalancedParens.FindClose
-import HaskellWorks.Data.BalancedParens.FindCloseN
-import HaskellWorks.Data.BalancedParens.FindOpen
-import HaskellWorks.Data.BalancedParens.FindOpenN
-import HaskellWorks.Data.BalancedParens.NewCloseAt
-import HaskellWorks.Data.BalancedParens.OpenAt
-import HaskellWorks.Data.Bits.AllExcess.AllExcess1
-import HaskellWorks.Data.Bits.BitLength
-import HaskellWorks.Data.Bits.BitWise
-import HaskellWorks.Data.Excess.MinExcess
-import HaskellWorks.Data.Excess.MinExcess1
-import HaskellWorks.Data.Positioning
-import HaskellWorks.Data.RankSelect.Base.Rank0
-import HaskellWorks.Data.RankSelect.Base.Rank1
-import HaskellWorks.Data.Vector.AsVector64
-import Prelude                                         hiding (length)
-
-import qualified Data.Vector.Storable as DVS
-
-data RangeMinMax a = RangeMinMax
-  { rangeMinMaxBP       :: !a
-  , rangeMinMaxL0Min    :: !(DVS.Vector Int8)
-  , rangeMinMaxL0Excess :: !(DVS.Vector Int8)
-  , rangeMinMaxL1Min    :: !(DVS.Vector Int16)
-  , rangeMinMaxL1Excess :: !(DVS.Vector Int16)
-  , rangeMinMaxL2Min    :: !(DVS.Vector Int16)
-  , rangeMinMaxL2Excess :: !(DVS.Vector Int16)
-  } deriving (Eq, Show, NFData, Generic)
-
-factorL0 :: Integral a => a
-factorL0 = 1
-{-# INLINE factorL0 #-}
-
-factorL1 :: Integral a => a
-factorL1 = 32
-{-# INLINE factorL1 #-}
-
-factorL2 :: Integral a => a
-factorL2 = 32
-{-# INLINE factorL2 #-}
-
-pageSizeL0 :: Integral a => a
-pageSizeL0 = factorL0
-{-# INLINE pageSizeL0 #-}
-
-pageSizeL1 :: Integral a => a
-pageSizeL1 = pageSizeL0 * factorL1
-{-# INLINE pageSizeL1 #-}
-
-pageSizeL2 :: Integral a => a
-pageSizeL2 = pageSizeL1 * factorL2
-{-# INLINE pageSizeL2 #-}
-
-mkRangeMinMax :: AsVector64 a => a -> RangeMinMax a
-mkRangeMinMax bp = RangeMinMax
-  { rangeMinMaxBP       = bp
-  , rangeMinMaxL0Min    = rmmL0Min
-  , rangeMinMaxL0Excess = dvsReword rmmL0Excess
-  , rangeMinMaxL1Min    = rmmL1Min
-  , rangeMinMaxL1Excess = dvsReword rmmL1Excess
-  , rangeMinMaxL2Min    = rmmL2Min
-  , rangeMinMaxL2Excess = rmmL2Excess
-  }
-  where bpv           = asVector64 bp
-        lenBP         = fromIntegral (length bpv) :: Int
-        lenL0         = lenBP
-        lenL1         = (DVS.length rmmL0Min `div` pageSizeL1) + 1 :: Int
-        lenL2         = (DVS.length rmmL0Min `div` pageSizeL2) + 1 :: Int
-        allMinMaxL0   = dvsConstructNI lenL0 (\i -> if i == lenBP then MinExcess (-64) (-64) else minExcess1 (bpv !!! fromIntegral i))
-        allMinMaxL1   = dvsConstructNI lenL1 (\i -> minExcess1 (dropTake (i * pageSizeL1) pageSizeL1 bpv))
-        allMinMaxL2   = dvsConstructNI lenL2 (\i -> minExcess1 (dropTake (i * pageSizeL2) pageSizeL2 bpv))
-        -- Note: (0xffffffffffffffc0 :: Int64) = -64
-        rmmL0Excess   = dvsConstructNI lenL0 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL0 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL1Excess   = dvsConstructNI lenL1 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL1 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL2Excess   = dvsConstructNI lenL2 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL2 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL0Min      = dvsConstructNI lenL0 (\i -> let MinExcess minE _ = allMinMaxL0 DVS.! i in fromIntegral minE)
-        rmmL1Min      = dvsConstructNI lenL1 (\i -> let MinExcess minE _ = allMinMaxL1 DVS.! i in fromIntegral minE)
-        rmmL2Min      = dvsConstructNI lenL2 (\i -> let MinExcess minE _ = allMinMaxL2 DVS.! i in fromIntegral minE)
-
-dropTake :: DVS.Storable a => Int -> Int -> DVS.Vector a -> DVS.Vector a
-dropTake n o = DVS.take o . DVS.drop n
-{-# INLINE dropTake #-}
-
-dvsReword :: (DVS.Storable a, Integral a, DVS.Storable b, Num b) => DVS.Vector a -> DVS.Vector b
-dvsReword v = dvsConstructNI (DVS.length v) (\i -> fromIntegral (v DVS.! i))
-{-# INLINE dvsReword #-}
-
-pageFill :: DVS.Storable a => Int -> Int -> a -> DVS.Vector a -> DVS.Vector a
-pageFill n s = dropTakeFill (n * s) s
-{-# INLINE pageFill #-}
-
-dropTakeFill :: DVS.Storable a => Int -> Int -> a -> DVS.Vector a -> DVS.Vector a
-dropTakeFill n o a v =  let r = DVS.take o (DVS.drop n v) in
-                        let len = DVS.length r in
-                        if len == o then r else DVS.concat [r, DVS.fromList (replicate (o - len) a)]
-{-# INLINE dropTakeFill #-}
-
-dvsConstructNI :: DVS.Storable a => Int -> (Int -> a) -> DVS.Vector a
-dvsConstructNI n g = DVS.constructN n (g . DVS.length)
-{-# INLINE dvsConstructNI #-}
-
-data FindState = FindBP
-  | FindL0 | FindFromL0
-  | FindL1 | FindFromL1
-  | FindL2 | FindFromL2
-
-rmm2FindClose  :: (BitLength a, NewCloseAt a) => RangeMinMax a -> Int -> Count -> FindState -> Maybe Count
-rmm2FindClose v s p FindBP = if v `newCloseAt` p
-  then if s <= 1
-    then Just p
-    else rmm2FindClose v (s - 1) (p + 1) FindFromL0
-  else rmm2FindClose v (s + 1) (p + 1) FindFromL0
-rmm2FindClose v s p FindL0 =
-  let i = p `div` 64 in
-  let mins = rangeMinMaxL0Min v in
-  let minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindBP
-    else if v `newCloseAt` p && s <= 1
-      then Just p
-      else  let excesses  = rangeMinMaxL0Excess v in
-            let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-            rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + 64) FindFromL0
-rmm2FindClose v s p FindL1 =
-  let !i = p `div` (64 * pageSizeL1) in
-  let !mins = rangeMinMaxL1Min v in
-  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindL0
-    else if 0 <= p && p < bitLength v
-      then if v `newCloseAt` p && s <= 1
-        then Just p
-        else  let excesses  = rangeMinMaxL1Excess v in
-              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-              rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL1)) FindFromL1
-      else Nothing
-rmm2FindClose v s p FindL2 =
-  let !i = p `div` (64 * pageSizeL2) in
-  let !mins = rangeMinMaxL2Min v in
-  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindL1
-    else if 0 <= p && p < bitLength v
-      then if v `newCloseAt` p && s <= 1
-        then Just p
-        else  let excesses  = rangeMinMaxL2Excess v in
-              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-              rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL2)) FindFromL2
-      else Nothing
-rmm2FindClose v s p FindFromL0
-  | p `mod` 64 == 0             = rmm2FindClose v s p FindFromL1
-  | 0 <= p && p < bitLength v   = rmm2FindClose v s p FindBP
-  | otherwise                   = Nothing
-rmm2FindClose v s p FindFromL1
-  | p `mod` (64 * pageSizeL1) == 0  = if 0 <= p && p < bitLength v then rmm2FindClose v s p FindFromL2 else Nothing
-  | 0 <= p && p < bitLength v       = rmm2FindClose v s p FindL0
-  | otherwise                       = Nothing
-rmm2FindClose v s p FindFromL2
-  | p `mod` (64 * pageSizeL2) == 0  = if 0 <= p && p < bitLength v then rmm2FindClose v s p FindL2 else Nothing
-  | 0 <= p && p < bitLength v       = rmm2FindClose v s p FindL1
-  | otherwise                       = Nothing
-{-# INLINE rmm2FindClose #-}
-
-instance TestBit a => TestBit (RangeMinMax a) where
-  (.?.) = (.?.) . rangeMinMaxBP
-  {-# INLINE (.?.) #-}
-
-instance Rank1 a => Rank1 (RangeMinMax a) where
-  rank1 = rank1 . rangeMinMaxBP
-  {-# INLINE rank1 #-}
-
-instance Rank0 a => Rank0 (RangeMinMax a) where
-  rank0 = rank0 . rangeMinMaxBP
-  {-# INLINE rank0 #-}
-
-instance BitLength a => BitLength (RangeMinMax a) where
-  bitLength = bitLength . rangeMinMaxBP
-  {-# INLINE bitLength #-}
-
-instance OpenAt a => OpenAt (RangeMinMax a) where
-  openAt = openAt . rangeMinMaxBP
-  {-# INLINE openAt #-}
-
-instance CloseAt a => CloseAt (RangeMinMax a) where
-  closeAt = closeAt . rangeMinMaxBP
-  {-# INLINE closeAt #-}
-
-instance NewCloseAt a => NewCloseAt (RangeMinMax a) where
-  newCloseAt = newCloseAt . rangeMinMaxBP
-  {-# INLINE newCloseAt #-}
-
-instance FindOpenN a => FindOpenN (RangeMinMax a) where
-  findOpenN = findOpenN . rangeMinMaxBP
-  {-# INLINE findOpenN #-}
-
-instance (BitLength a, NewCloseAt a) => FindCloseN (RangeMinMax a) where
-  findCloseN v s p  = (+ 1) `fmap` rmm2FindClose v (fromIntegral s) (p - 1) FindFromL0
-  {-# INLINE findCloseN  #-}
-
-instance (BitLength a, CloseAt a, NewCloseAt a, FindCloseN a) => FindClose (RangeMinMax a) where
-  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
-  {-# INLINE findClose #-}
-
-instance (OpenAt a, FindOpenN a) => FindOpen (RangeMinMax a) where
-  findOpen v p = if v `openAt`  p then Just p else findOpenN  v 0 (p - 1)
-  {-# INLINE findOpen #-}
-
-instance FindOpenN a => Enclose (RangeMinMax a) where
-  enclose v = findOpenN v 1
-  {-# INLINE enclose #-}
-
-instance (BitLength a, NewCloseAt a, CloseAt a, OpenAt a, FindOpenN a, FindCloseN a) => BalancedParens (RangeMinMax a)
diff --git a/src/HaskellWorks/Data/BalancedParens/RangeMinMax2.hs b/src/HaskellWorks/Data/BalancedParens/RangeMinMax2.hs
deleted file mode 100644
--- a/src/HaskellWorks/Data/BalancedParens/RangeMinMax2.hs
+++ /dev/null
@@ -1,306 +0,0 @@
-{-# LANGUAGE BangPatterns      #-}
-{-# LANGUAGE DeriveAnyClass    #-}
-{-# LANGUAGE DeriveGeneric     #-}
-{-# LANGUAGE FlexibleContexts  #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE InstanceSigs      #-}
-{-# LANGUAGE TypeFamilies      #-}
-
-module HaskellWorks.Data.BalancedParens.RangeMinMax2
-  ( RangeMinMax2(..)
-  , mkRangeMinMax2
-  ) where
-
-import Control.DeepSeq
-import Data.Int
-import GHC.Generics
-import HaskellWorks.Data.AtIndex
-import HaskellWorks.Data.BalancedParens.BalancedParens
-import HaskellWorks.Data.BalancedParens.CloseAt
-import HaskellWorks.Data.BalancedParens.Enclose
-import HaskellWorks.Data.BalancedParens.FindClose
-import HaskellWorks.Data.BalancedParens.FindCloseN
-import HaskellWorks.Data.BalancedParens.FindOpen
-import HaskellWorks.Data.BalancedParens.FindOpenN
-import HaskellWorks.Data.BalancedParens.NewCloseAt
-import HaskellWorks.Data.BalancedParens.OpenAt
-import HaskellWorks.Data.Bits.AllExcess.AllExcess1
-import HaskellWorks.Data.Bits.BitLength
-import HaskellWorks.Data.Bits.BitWise
-import HaskellWorks.Data.Excess.MinExcess
-import HaskellWorks.Data.Excess.MinExcess1
-import HaskellWorks.Data.Positioning
-import HaskellWorks.Data.RankSelect.Base.Rank0
-import HaskellWorks.Data.RankSelect.Base.Rank1
-import HaskellWorks.Data.Vector.AsVector64
-import Prelude                                         hiding (length)
-
-import qualified Data.Vector          as DV
-import qualified Data.Vector.Storable as DVS
-
-data RangeMinMax2 a = RangeMinMax2
-  { rangeMinMax2BP       :: !a
-  , rangeMinMax2L0Min    :: !(DVS.Vector Int8)
-  , rangeMinMax2L0Excess :: !(DVS.Vector Int8)
-  , rangeMinMax2L1Min    :: !(DVS.Vector Int16)
-  , rangeMinMax2L1Excess :: !(DVS.Vector Int16)
-  , rangeMinMax2L2Min    :: !(DVS.Vector Int16)
-  , rangeMinMax2L2Excess :: !(DVS.Vector Int16)
-  , rangeMinMax2L3Min    :: !(DVS.Vector Int16)
-  , rangeMinMax2L3Excess :: !(DVS.Vector Int16)
-  , rangeMinMax2L4Min    :: !(DVS.Vector Int16)
-  , rangeMinMax2L4Excess :: !(DVS.Vector Int16)
-  } deriving (NFData, Generic)
-
-factorL0 :: Integral a => a
-factorL0 = 1
-{-# INLINE factorL0 #-}
-
-factorL1 :: Integral a => a
-factorL1 = 32
-{-# INLINE factorL1 #-}
-
-factorL2 :: Integral a => a
-factorL2 = 32
-{-# INLINE factorL2 #-}
-
-factorL3 :: Integral a => a
-factorL3 = 32
-{-# INLINE factorL3 #-}
-
-factorL4 :: Integral a => a
-factorL4 = 32
-{-# INLINE factorL4 #-}
-
-pageSizeL0 :: Integral a => a
-pageSizeL0 = factorL0
-{-# INLINE pageSizeL0 #-}
-
-pageSizeL1 :: Integral a => a
-pageSizeL1 = pageSizeL0 * factorL1
-{-# INLINE pageSizeL1 #-}
-
-pageSizeL2 :: Integral a => a
-pageSizeL2 = pageSizeL1 * factorL2
-{-# INLINE pageSizeL2 #-}
-
-pageSizeL3 :: Integral a => a
-pageSizeL3 = pageSizeL2 * factorL3
-{-# INLINE pageSizeL3 #-}
-
-pageSizeL4 :: Integral a => a
-pageSizeL4 = pageSizeL3 * factorL4
-{-# INLINE pageSizeL4 #-}
-
-mkRangeMinMax2 :: AsVector64 a => a -> RangeMinMax2 a
-mkRangeMinMax2 bp = RangeMinMax2
-  { rangeMinMax2BP       = bp
-  , rangeMinMax2L0Min    = dvsReword rmmL0Min
-  , rangeMinMax2L0Excess = dvsReword rmmL0Excess
-  , rangeMinMax2L1Min    = rmmL1Min
-  , rangeMinMax2L1Excess = rmmL1Excess
-  , rangeMinMax2L2Min    = rmmL2Min
-  , rangeMinMax2L2Excess = rmmL2Excess
-  , rangeMinMax2L3Min    = rmmL3Min
-  , rangeMinMax2L3Excess = rmmL3Excess
-  , rangeMinMax2L4Min    = rmmL4Min
-  , rangeMinMax2L4Excess = rmmL4Excess
-  }
-  where bpv           = asVector64 bp
-        lenBP         = fromIntegral (length bpv) :: Int
-        lenL0         = lenBP
-        lenL1         = (DVS.length rmmL0Min `div` pageSizeL1) + 1 :: Int
-        lenL2         = (DVS.length rmmL0Min `div` pageSizeL2) + 1 :: Int
-        lenL3         = (DVS.length rmmL0Min `div` pageSizeL3) + 1 :: Int
-        lenL4         = (DVS.length rmmL0Min `div` pageSizeL4) + 1 :: Int
-        allMinMaxL0   = dvConstructNI  lenL0 (\i -> if i == lenBP then MinExcess (-64) (-64) else minExcess1 (bpv !!! fromIntegral i))
-        -- Note: (0xffffffffffffffc0 :: Int64) = -64
-        rmmL0Excess   = dvsConstructNI lenL0 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL0 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL1Excess   = dvsConstructNI lenL1 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL1 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL2Excess   = dvsConstructNI lenL2 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL2 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL3Excess   = dvsConstructNI lenL3 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL3 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL4Excess   = dvsConstructNI lenL4 (\i -> fromIntegral (allExcess1 (pageFill i pageSizeL4 0xffffffffffffffc0 bpv))) :: DVS.Vector Int16
-        rmmL0Min      = dvsConstructNI lenL0 (\i -> let MinExcess minE _ = allMinMaxL0 DV.! i in fromIntegral minE) :: DVS.Vector Int16
-        rmmL1Min      = dvsConstructNI lenL1 (\i -> genMin 0 (pageFill i factorL1 0 rmmL0Min) (pageFill i factorL1 0 rmmL0Excess))
-        rmmL2Min      = dvsConstructNI lenL2 (\i -> genMin 0 (pageFill i factorL2 0 rmmL1Min) (pageFill i factorL2 0 rmmL1Excess))
-        rmmL3Min      = dvsConstructNI lenL3 (\i -> genMin 0 (pageFill i factorL3 0 rmmL2Min) (pageFill i factorL3 0 rmmL2Excess))
-        rmmL4Min      = dvsConstructNI lenL4 (\i -> genMin 0 (pageFill i factorL4 0 rmmL3Min) (pageFill i factorL4 0 rmmL3Excess))
-
-genMin :: (Integral a, DVS.Storable a) => a -> DVS.Vector a -> DVS.Vector a -> a
-genMin mL mins excesses = if not (DVS.null mins) || not (DVS.null excesses)
-  then genMin (dvsLastOrZero mins `min` (mL + dvsLastOrZero excesses)) (DVS.init mins) (DVS.init excesses)
-  else mL
-
-pageFill :: DVS.Storable a => Int -> Int -> a -> DVS.Vector a -> DVS.Vector a
-pageFill n s = dropTakeFill (n * s) s
-{-# INLINE pageFill #-}
-
-dropTakeFill :: DVS.Storable a => Int -> Int -> a -> DVS.Vector a -> DVS.Vector a
-dropTakeFill n s a v =  let r = DVS.take s (DVS.drop n v) in
-                        let rLen = DVS.length r in
-                        if rLen == s then r else DVS.concat [r, DVS.replicate (s - rLen) a]
-{-# INLINE dropTakeFill #-}
-
-dvConstructNI :: Int -> (Int -> a) -> DV.Vector a
-dvConstructNI n g = DV.constructN n (g . DV.length)
-{-# INLINE dvConstructNI #-}
-
-dvsConstructNI :: DVS.Storable a => Int -> (Int -> a) -> DVS.Vector a
-dvsConstructNI n g = DVS.constructN n (g . DVS.length)
-{-# INLINE dvsConstructNI #-}
-
-dvsReword :: (DVS.Storable a, Integral a, DVS.Storable b, Num b) => DVS.Vector a -> DVS.Vector b
-dvsReword v = dvsConstructNI (DVS.length v) (\i -> fromIntegral (v DVS.! i))
-{-# INLINE dvsReword #-}
-
-dvsLastOrZero :: (DVS.Storable a, Integral a) => DVS.Vector a -> a
-dvsLastOrZero v = if not (DVS.null v) then DVS.last v else 0
-{-# INLINE dvsLastOrZero #-}
-
-data FindState = FindBP
-  | FindL0 | FindFromL0
-  | FindL1 | FindFromL1
-  | FindL2 | FindFromL2
-  | FindL3 | FindFromL3
-  | FindL4 | FindFromL4
-
-rmm2FindClose  :: (BitLength a, NewCloseAt a) => RangeMinMax2 a -> Int -> Count -> FindState -> Maybe Count
-rmm2FindClose v s p FindBP = if v `newCloseAt` p
-  then if s <= 1
-    then Just p
-    else rmm2FindClose v (s - 1) (p + 1) FindFromL0
-  else rmm2FindClose v (s + 1) (p + 1) FindFromL0
-rmm2FindClose v s p FindL0 =
-  let i = p `div` 64 in
-  let mins = rangeMinMax2L0Min v in
-  let minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindBP
-    else if v `newCloseAt` p && s <= 1
-      then Just p
-      else  let excesses  = rangeMinMax2L0Excess v in
-            let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-            rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + 64) FindFromL0
-rmm2FindClose v s p FindL1 =
-  let !i = p `div` (64 * pageSizeL1) in
-  let !mins = rangeMinMax2L1Min v in
-  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindL0
-    else if 0 <= p && p < bitLength v
-      then if v `newCloseAt` p && s <= 1
-        then Just p
-        else  let excesses  = rangeMinMax2L1Excess v in
-              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-              rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL1)) FindFromL1
-      else Nothing
-rmm2FindClose v s p FindL2 =
-  let !i = p `div` (64 * pageSizeL2) in
-  let !mins = rangeMinMax2L2Min v in
-  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindL1
-    else if 0 <= p && p < bitLength v
-      then if v `newCloseAt` p && s <= 1
-        then Just p
-        else  let excesses  = rangeMinMax2L2Excess v in
-              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-              rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL2)) FindFromL2
-      else Nothing
-rmm2FindClose v s p FindL3 =
-  let !i = p `div` (64 * pageSizeL3) in
-  let !mins = rangeMinMax2L3Min v in
-  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindL2
-    else if 0 <= p && p < bitLength v
-      then if v `newCloseAt` p && s <= 1
-        then Just p
-        else  let excesses  = rangeMinMax2L3Excess v in
-              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-              rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL3)) FindFromL3
-        else Nothing
-rmm2FindClose v s p FindL4 =
-  let !i = p `div` (64 * pageSizeL4) in
-  let !mins = rangeMinMax2L4Min v in
-  let !minE = fromIntegral (mins !!! fromIntegral i) :: Int in
-  if fromIntegral s + minE <= 0
-    then rmm2FindClose v s p FindL3
-    else if 0 <= p && p < bitLength v
-      then if v `newCloseAt` p && s <= 1
-        then Just p
-        else  let excesses  = rangeMinMax2L4Excess v in
-              let excess    = fromIntegral (excesses !!! fromIntegral i)  :: Int in
-              rmm2FindClose v (fromIntegral (excess + fromIntegral s)) (p + (64 * pageSizeL4)) FindFromL4
-        else Nothing
-rmm2FindClose v s p FindFromL0
-  | p `mod` 64 == 0             = rmm2FindClose v s p FindFromL1
-  | 0 <= p && p < bitLength v   = rmm2FindClose v s p FindBP
-  | otherwise                   = Nothing
-rmm2FindClose v s p FindFromL1
-  | p `mod` (64 * pageSizeL1) == 0  = if 0 <= p && p < bitLength v then rmm2FindClose v s p FindFromL2 else Nothing
-  | 0 <= p && p < bitLength v       = rmm2FindClose v s p FindL0
-  | otherwise                       = Nothing
-rmm2FindClose v s p FindFromL2
-  | p `mod` (64 * pageSizeL2) == 0  = if 0 <= p && p < bitLength v then rmm2FindClose v s p FindFromL3 else Nothing
-  | 0 <= p && p < bitLength v       = rmm2FindClose v s p FindL1
-  | otherwise                       = Nothing
-rmm2FindClose v s p FindFromL3
-  | p `mod` (64 * pageSizeL3) == 0  = if 0 <= p && p < bitLength v then rmm2FindClose v s p FindFromL4 else Nothing
-  | 0 <= p && p < bitLength v       = rmm2FindClose v s p FindL2
-  | otherwise                       = Nothing
-rmm2FindClose v s p FindFromL4
-  | p `mod` (64 * pageSizeL4) == 0  = if 0 <= p && p < bitLength v then rmm2FindClose v s p FindL4 else Nothing
-  | 0 <= p && p < bitLength v       = rmm2FindClose v s p FindL3
-  | otherwise                       = Nothing
-{-# INLINE rmm2FindClose #-}
-
-instance TestBit a => TestBit (RangeMinMax2 a) where
-  (.?.) = (.?.) . rangeMinMax2BP
-  {-# INLINE (.?.) #-}
-
-instance Rank1 a => Rank1 (RangeMinMax2 a) where
-  rank1 = rank1 . rangeMinMax2BP
-  {-# INLINE rank1 #-}
-
-instance Rank0 a => Rank0 (RangeMinMax2 a) where
-  rank0 = rank0 . rangeMinMax2BP
-  {-# INLINE rank0 #-}
-
-instance BitLength a => BitLength (RangeMinMax2 a) where
-  bitLength = bitLength . rangeMinMax2BP
-  {-# INLINE bitLength #-}
-
-instance OpenAt a => OpenAt (RangeMinMax2 a) where
-  openAt = openAt . rangeMinMax2BP
-  {-# INLINE openAt #-}
-
-instance CloseAt a => CloseAt (RangeMinMax2 a) where
-  closeAt = closeAt . rangeMinMax2BP
-  {-# INLINE closeAt #-}
-
-instance NewCloseAt a => NewCloseAt (RangeMinMax2 a) where
-  newCloseAt = newCloseAt . rangeMinMax2BP
-  {-# INLINE newCloseAt #-}
-
-instance FindOpenN a => FindOpenN (RangeMinMax2 a) where
-  findOpenN = findOpenN . rangeMinMax2BP
-  {-# INLINE findOpenN #-}
-
-instance (BitLength a, FindCloseN a, NewCloseAt a) => FindCloseN (RangeMinMax2 a) where
-  findCloseN v s p  = (+ 1) `fmap` rmm2FindClose v (fromIntegral s) (p - 1) FindFromL0
-  {-# INLINE findCloseN  #-}
-
-instance (BitLength a, NewCloseAt a, CloseAt a, FindCloseN a) => FindClose (RangeMinMax2 a) where
-  findClose v p = if v `closeAt` p then Just p else findCloseN v 1 (p + 1)
-  {-# INLINE findClose #-}
-
-instance (OpenAt a, FindOpenN a) => FindOpen (RangeMinMax2 a) where
-  findOpen v p = if v `openAt`  p then Just p else findOpenN  v 0 (p - 1)
-  {-# INLINE findOpen #-}
-
-instance FindOpenN a => Enclose (RangeMinMax2 a) where
-  enclose v = findOpenN v 1
-  {-# INLINE enclose #-}
-
-instance (BitLength a, NewCloseAt a, CloseAt a, OpenAt a, FindOpenN a, FindCloseN a) => BalancedParens (RangeMinMax2 a)
diff --git a/src/HaskellWorks/Data/BalancedParens/Simple.hs b/src/HaskellWorks/Data/BalancedParens/Simple.hs
--- a/src/HaskellWorks/Data/BalancedParens/Simple.hs
+++ b/src/HaskellWorks/Data/BalancedParens/Simple.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveGeneric              #-}
 {-# LANGUAGE FlexibleInstances          #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
@@ -6,6 +7,7 @@
   ) where
 
 import Control.Monad
+import GHC.Generics
 import HaskellWorks.Data.BalancedParens.BalancedParens
 import HaskellWorks.Data.BalancedParens.CloseAt
 import HaskellWorks.Data.BalancedParens.Enclose
@@ -22,7 +24,7 @@
 import Prelude                                         as P
 
 newtype SimpleBalancedParens a = SimpleBalancedParens a
-  deriving (BalancedParens, FindOpen, FindClose, Enclose, OpenAt, CloseAt, BitLength, BitShow, Eq, Rank0, Rank1, Select0, Select1, TestBit)
+  deriving (BalancedParens, FindOpen, FindClose, Enclose, OpenAt, CloseAt, BitLength, BitShow, Eq, Rank0, Rank1, Select0, Select1, TestBit, Generic)
 
 instance Functor SimpleBalancedParens where
   fmap f (SimpleBalancedParens a) = SimpleBalancedParens (f a)
diff --git a/test/HaskellWorks/Data/BalancedParens/FindCloseNSpec.hs b/test/HaskellWorks/Data/BalancedParens/FindCloseNSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/FindCloseNSpec.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.FindCloseNSpec where
+
+import HaskellWorks.Data.BalancedParens
+import HaskellWorks.Data.Bits.Broadword.Type
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Hedgehog.Gen   as G
+import qualified Hedgehog.Range as R
+
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.FindCloseNSpec" $ do
+  it "returns same result as broadword" $ requireProperty $ do
+    w <- forAll $ G.word64 R.constantBounded
+    p <- forAll $ G.word64 (R.linear 1 64)
+    findClose w p === findClose (Broadword w) p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector16Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector16Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector16Spec.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE TypeApplications #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16Spec
+  ( spec
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Widen
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                   as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16 as V16
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic      as G
+import qualified Hedgehog.Gen                                                           as G
+import qualified Hedgehog.Range                                                         as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector16Spec" $ do
+  describe "findClose" $ do
+    it "Two element vector zero as second word" $ require $ withTests 1000 $ property $ do
+      w   <- forAll $ G.word16 R.constantBounded
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w, 0]
+      V16.findClose v p === G.findCloseN w 0 p
+    it "Two element vector up to position 16" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word16 R.constantBounded
+      w1  <- forAll $ G.word16 R.constantBounded
+      w   <- forAll $ pure $ id @Word32 $
+                (widen w1 .<. (bitLength w0 * 1)) .|.
+                (widen w0 .<. (bitLength w0 * 0))
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w0, w1]
+      V16.findClose v p === G.findCloseN w 0 p
+    it "Four element vector up to position 32" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word16 R.constantBounded
+      w1  <- forAll $ G.word16 R.constantBounded
+      w2  <- forAll $ G.word16 R.constantBounded
+      w3  <- forAll $ G.word16 R.constantBounded
+      w   <- forAll $ pure $ id @Word64 $
+                (widen w3 .<. (bitLength w0 * 3)) .|.
+                (widen w2 .<. (bitLength w0 * 2)) .|.
+                (widen w1 .<. (bitLength w0 * 1)) .|.
+                (widen w0 .<. (bitLength w0 * 0))
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w0, w1, w2, w3]
+      V16.findClose v p === G.findCloseN w 0 p
+  it "Two element vector" $ require $ withTests 1000 $ property $ do
+    w0  <- forAll $ G.word16 R.constantBounded
+    w1  <- forAll $ G.word16 R.constantBounded
+    p   <- forAll $ G.word64 (R.linear 1 (bitLength w0 * 2))
+    v   <- forAll $ pure $ DVS.fromList [w0, w1]
+    _   <- forAll $ pure $ bitShow v
+    V16.findClose v p === G.findCloseN v 0 p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector32Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector32Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector32Spec.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE TypeApplications #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32Spec
+  ( spec
+  ) where
+
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Widen
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                   as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32 as V32
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic      as G
+import qualified Hedgehog.Gen                                                           as G
+import qualified Hedgehog.Range                                                         as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector32Spec" $ do
+  describe "findClose" $ do
+    it "Two element vector zero as second word" $ require $ withTests 1000 $ property $ do
+      w   <- forAll $ G.word32 R.constantBounded
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w, 0]
+      V32.findClose v p === G.findCloseN w 0 p
+    it "Two element vector up to position 32" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word32 R.constantBounded
+      w1  <- forAll $ G.word32 R.constantBounded
+      w   <- forAll $ pure $ id @Word64 $
+                (widen w1 .<. (bitLength w0 * 1)) .|.
+                (widen w0 .<. (bitLength w0 * 0))
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w0, w1]
+      V32.findClose v p === G.findCloseN w 0 p
+  it "Two element vector" $ require $ withTests 1000 $ property $ do
+    w0  <- forAll $ G.word32 R.constantBounded
+    w1  <- forAll $ G.word32 R.constantBounded
+    p   <- forAll $ G.word64 (R.linear 1 (bitLength w0 * 2))
+    v   <- forAll $ pure $ DVS.fromList [w0, w1]
+    _   <- forAll $ pure $ bitShow v
+    V32.findClose v p === G.findCloseN v 0 p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector64Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector64Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector64Spec.hs
@@ -0,0 +1,37 @@
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64Spec
+  ( spec
+  ) where
+
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                   as DVS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64 as V64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic      as G
+import qualified Hedgehog.Gen                                                           as G
+import qualified Hedgehog.Range                                                         as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector64Spec" $ do
+  describe "findClose" $ do
+    it "Two element vector zero as second word" $ require $ withTests 1000 $ property $ do
+      w   <- forAll $ G.word64 R.constantBounded
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w, 0]
+      V64.findClose v p === G.findCloseN w 0 p
+    it "Two element vector" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word64 R.constantBounded
+      w1  <- forAll $ G.word64 R.constantBounded
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w0 * 2))
+      v   <- forAll $ pure $ DVS.fromList [w0, w1]
+      _   <- forAll $ pure $ bitShow v
+      V64.findClose v p === G.findCloseN v 0 p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8Spec.hs
@@ -0,0 +1,111 @@
+{-# LANGUAGE TypeApplications #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8Spec
+  ( spec
+  ) where
+
+import Control.Monad
+import Data.Word
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Widen
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.List                                                             as L
+import qualified Data.Vector.Storable                                                  as DVS
+import qualified HaskellWorks.Data.BalancedParens.FindClose                            as CLS
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8 as V8
+import qualified HaskellWorks.Data.BalancedParens.Internal.IO                          as IO
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic     as G
+import qualified HaskellWorks.Data.BalancedParens.RangeMin2                            as RM2
+import qualified HaskellWorks.Data.FromForeignRegion                                   as IO
+import qualified Hedgehog.Gen                                                          as G
+import qualified Hedgehog.Range                                                        as R
+import qualified System.IO.Unsafe                                                      as IO
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+testFiles :: [FilePath]
+testFiles = IO.unsafePerformIO $ do
+  files <- IO.safeListDirectory "data/test"
+  return $ L.sort (("data/test/" ++) <$> (".ib.idx" `L.isSuffixOf`) `filter` files)
+{-# NOINLINE testFiles #-}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8Spec" $ do
+  describe "findClose" $ do
+    it "Two element vector zero as second word" $ require $ withTests 1000 $ property $ do
+      w   <- forAll $ G.word8 R.constantBounded
+      p   <- forAll $ G.word64 (R.linear 1 8)
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w, 0]
+      V8.findClose v p === G.findCloseN w 0 p
+    it "Two element vector up to position 16" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word8 R.constantBounded
+      w1  <- forAll $ G.word8 R.constantBounded
+      w   <- forAll $ pure $ id @Word16 $
+                (widen w1 .<. (bitLength w0 * 1)) .|.
+                (widen w0 .<. (bitLength w0 * 0))
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w0, w1]
+      V8.findClose v p === G.findCloseN w 0 p
+    it "Four element vector up to position 32" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word8 R.constantBounded
+      w1  <- forAll $ G.word8 R.constantBounded
+      w2  <- forAll $ G.word8 R.constantBounded
+      w3  <- forAll $ G.word8 R.constantBounded
+      w   <- forAll $ pure $ id @Word32 $
+                (widen w3 .<. (bitLength w0 * 3)) .|.
+                (widen w2 .<. (bitLength w0 * 2)) .|.
+                (widen w1 .<. (bitLength w0 * 1)) .|.
+                (widen w0 .<. (bitLength w0 * 0))
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w0, w1, w2, w3]
+      V8.findClose v p === G.findCloseN w 0 p
+    it "Eight element vector up to position 64" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word8 R.constantBounded
+      w1  <- forAll $ G.word8 R.constantBounded
+      w2  <- forAll $ G.word8 R.constantBounded
+      w3  <- forAll $ G.word8 R.constantBounded
+      w4  <- forAll $ G.word8 R.constantBounded
+      w5  <- forAll $ G.word8 R.constantBounded
+      w6  <- forAll $ G.word8 R.constantBounded
+      w7  <- forAll $ G.word8 R.constantBounded
+      w   <- forAll $ pure $ id @Word64 $
+                (widen w7 .<. (bitLength w0 * 7)) .|.
+                (widen w6 .<. (bitLength w0 * 6)) .|.
+                (widen w5 .<. (bitLength w0 * 5)) .|.
+                (widen w4 .<. (bitLength w0 * 4)) .|.
+                (widen w3 .<. (bitLength w0 * 3)) .|.
+                (widen w2 .<. (bitLength w0 * 2)) .|.
+                (widen w1 .<. (bitLength w0 * 1)) .|.
+                (widen w0 .<. (bitLength w0 * 0))
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
+      _   <- forAll $ pure $ bitShow w
+      v   <- forAll $ pure $ DVS.fromList [w0, w1, w2, w3, w4, w5, w6, w7]
+      V8.findClose v p === G.findCloseN w 0 p
+    it "Two element vector" $ require $ withTests 1000 $ property $ do
+      w0  <- forAll $ G.word8 R.constantBounded
+      w1  <- forAll $ G.word8 R.constantBounded
+      p   <- forAll $ G.word64 (R.linear 1 (bitLength w0 * 2))
+      v   <- forAll $ pure $ DVS.fromList [w0, w1]
+      _   <- forAll $ pure $ bitShow v
+      V8.findClose v p === G.findCloseN v 0 p
+    describe "Corpus tests" $ do
+      forM_ testFiles $ \file -> do
+        it ("File " <> file) $ do
+          v     <- IO.mmapFromForeignRegion file
+          let rmm2 = RM2.mkRangeMin2 (v :: DVS.Vector Word64)
+          require $ withTests 100000 $ property $ do
+            _   <- forAll $ pure file
+            p   <- forAll $ G.word64 (R.linear 1 (bitLength v))
+            _   <- forAll $ pure $ bitShow v
+            mfilter (<= bitLength v) (CLS.findClose v p) === CLS.findClose rmm2 p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector16Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector16Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector16Spec.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16Spec where
+
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Widen
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                               as DVS
+import qualified HaskellWorks.Data.BalancedParens.Gen                                               as G
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16 as BWV16
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32   as BWW32
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector16      as SV16
+import qualified Hedgehog.Gen                                                                       as G
+import qualified Hedgehog.Range                                                                     as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector16Spec" $ do
+  it "findUnmatchedCloseFar against two words" $ require $ withTests 1000 $ property $ do
+    c   <- forAll $ G.word64 (R.linear 0 64)
+    p   <- forAll $ G.word64 (R.linear 0 16)
+    w0  <- forAll $ G.word16 R.constantBounded
+    w1  <- forAll $ G.word16 R.constantBounded
+    w   <- forAll $ pure $ (widen w1 .<. bitLength w0) .|. widen w0
+    v   <- forAll $ pure $ DVS.fromList [w0, w1]
+    annotateShow $ bitShow w
+    actual    <- forAll $ pure $ BWV16.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ BWW32.findUnmatchedCloseFar c p w
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure DVS.empty
+    c   <- forAll $ pure 0
+    p   <- forAll $ pure 0
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV16.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV16.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure $ DVS.fromList [0]
+    c   <- forAll $ pure 1
+    p   <- forAll $ pure 8
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV16.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV16.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ require $ withTests 10000 $ property $ do
+    v   <- forAll $ G.storableVector (R.linear 0 4) (G.word16 R.constantBounded)
+    c   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    p   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV16.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV16.findUnmatchedCloseFar  c p v
+    actual === expected
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector32Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector32Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector32Spec.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32Spec where
+
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Widen
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                               as DVS
+import qualified HaskellWorks.Data.BalancedParens.Gen                                               as G
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32 as BWV32
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64   as BWW64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector32      as SV32
+import qualified Hedgehog.Gen                                                                       as G
+import qualified Hedgehog.Range                                                                     as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector32Spec" $ do
+  it "findUnmatchedCloseFar against two words" $ require $ withTests 1000 $ property $ do
+    c   <- forAll $ G.word64 (R.linear 0 64)
+    p   <- forAll $ G.word64 (R.linear 0 16)
+    w0  <- forAll $ G.word32 R.constantBounded
+    w1  <- forAll $ G.word32 R.constantBounded
+    w   <- forAll $ pure $ (widen w1 .<. bitLength w0) .|. widen w0
+    v   <- forAll $ pure $ DVS.fromList [w0, w1]
+    annotateShow $ bitShow w
+    actual    <- forAll $ pure $ BWV32.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ BWW64.findUnmatchedCloseFar c p w
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure DVS.empty
+    c   <- forAll $ pure 0
+    p   <- forAll $ pure 0
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV32.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV32.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure $ DVS.fromList [0]
+    c   <- forAll $ pure 1
+    p   <- forAll $ pure 8
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV32.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV32.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ require $ withTests 10000 $ property $ do
+    v   <- forAll $ G.storableVector (R.linear 0 4) (G.word32 R.constantBounded)
+    c   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    p   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV32.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV32.findUnmatchedCloseFar  c p v
+    actual === expected
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector64Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector64Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector64Spec.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64Spec where
+
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                               as DVS
+import qualified HaskellWorks.Data.BalancedParens.Gen                                               as G
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64 as BWV64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector64      as SV64
+import qualified Hedgehog.Gen                                                                       as G
+import qualified Hedgehog.Range                                                                     as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector64Spec" $ do
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure DVS.empty
+    c   <- forAll $ pure 0
+    p   <- forAll $ pure 0
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV64.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV64.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure $ DVS.fromList [0]
+    c   <- forAll $ pure 1
+    p   <- forAll $ pure 8
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV64.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV64.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ require $ withTests 10000 $ property $ do
+    v   <- forAll $ G.storableVector (R.linear 0 4) (G.word64 R.constantBounded)
+    c   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    p   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV64.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV64.findUnmatchedCloseFar  c p v
+    actual === expected
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector8Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector8Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Vector8Spec.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8Spec where
+
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.BitWise
+import HaskellWorks.Data.Int.Widen
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                                                              as DVS
+import qualified HaskellWorks.Data.BalancedParens.Gen                                              as G
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8 as BWV8
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16  as BWW16
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Vector8      as SV8
+import qualified Hedgehog.Gen                                                                      as G
+import qualified Hedgehog.Range                                                                    as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Vector8Spec" $ do
+  it "findUnmatchedCloseFar against two words" $ require $ withTests 1000 $ property $ do
+    c   <- forAll $ G.word64 (R.linear 0 64)
+    p   <- forAll $ G.word64 (R.linear 0 8)
+    w0  <- forAll $ G.word8 R.constantBounded
+    w1  <- forAll $ G.word8 R.constantBounded
+    w   <- forAll $ pure $ (widen w1 .<. bitLength w0) .|. widen w0
+    v   <- forAll $ pure $ DVS.fromList [w0, w1]
+    annotateShow $ bitShow w
+    actual    <- forAll $ pure $ BWV8.findUnmatchedCloseFar  c p v
+    expected  <- forAll $ pure $ BWW16.findUnmatchedCloseFar c p w
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure DVS.empty
+    c   <- forAll $ pure 0
+    p   <- forAll $ pure 0
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV8.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV8.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ requireTest $ do
+    v   <- forAll $ pure $ DVS.fromList [0]
+    c   <- forAll $ pure 1
+    p   <- forAll $ pure 8
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV8.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV8.findUnmatchedCloseFar  c p v
+    actual === expected
+  it "findUnmatchedCloseFar against slow" $ require $ withTests 10000 $ property $ do
+    v   <- forAll $ G.storableVector (R.linear 0 4) (G.word8 R.constantBounded)
+    c   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    p   <- forAll $ G.word64 (R.linear 0 (bitLength v))
+    annotateShow $ bitShow v
+    actual    <- forAll $ pure $ BWV8.findUnmatchedCloseFar c p v
+    expected  <- forAll $ pure $ SV8.findUnmatchedCloseFar  c p v
+    actual === expected
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word16Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word16Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word16Spec.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16Spec where
+
+import Data.Maybe
+import HaskellWorks.Data.Bits.BitRead
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Numeric
+import Test.Hspec
+
+import qualified HaskellWorks.Data.BalancedParens.FindClose                                       as C
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word16             as BW16
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word16 as BW16
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word16      as SW16
+import qualified Hedgehog.Gen                                                                     as G
+import qualified Hedgehog.Range                                                                   as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word16Spec" $ do
+  it "findUnmatchedCloseFar 0 [11111111 11110100]" $ requireTest $ do
+    p <- forAll $ pure 0
+    w <- forAll $ pure $ fromJust $ bitRead "11111111 11110100"
+    annotateShow $ bitShow w
+    annotateShow $ showHex w ""
+    BW16.findUnmatchedCloseFar 0 p w === SW16.findUnmatchedCloseFar 0 p w
+  it "findUnmatchedCloseFar" $ require $ withTests 2000 $ property $ do
+    c <- forAll $ G.word64 (R.linear 0 64)
+    p <- forAll $ G.word64 (R.linear 0 16)
+    w <- forAll $ G.word16 R.constantBounded
+    annotateShow $ bitShow w
+    BW16.findUnmatchedCloseFar c p w === SW16.findUnmatchedCloseFar c p w
+  it "findClose" $ require $ withTests 1000 $ property $ do
+    p <- forAll $ G.word64 (R.linear 1 128)
+    w <- forAll $ G.word16 R.constantBounded
+    annotateShow $ bitShow w
+    BW16.findClose w p === C.findClose w p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word32Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word32Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word32Spec.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32Spec where
+
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified HaskellWorks.Data.BalancedParens.FindClose                                       as C
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word32             as BW32
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word32 as BW32
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word32      as SW32
+import qualified Hedgehog.Gen                                                                     as G
+import qualified Hedgehog.Range                                                                   as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word32Spec" $ do
+  it "findUnmatchedCloseFar" $ requireTest $ do
+    p <- forAll $ pure 0
+    w <- forAll $ pure 0xe9f6e7ff
+    annotateShow $ bitShow w
+    BW32.findUnmatchedCloseFar 0 p w === SW32.findUnmatchedCloseFar 0 p w
+  it "findUnmatchedCloseFar" $ require $ withTests 40000 $ property $ do
+    c <- forAll $ G.word64 (R.linear 0 64)
+    p <- forAll $ G.word64 (R.linear 0 32)
+    w <- forAll $ G.word32 R.constantBounded
+    annotateShow $ bitShow w
+    BW32.findUnmatchedCloseFar c p w === SW32.findUnmatchedCloseFar c p w
+  it "findClose" $ require $ withTests 1000 $ property $ do
+    p <- forAll $ G.word64 (R.linear 1 128)
+    w <- forAll $ G.word32 R.constantBounded
+    annotateShow $ bitShow w
+    BW32.findClose w p === C.findClose w p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word64Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word64Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word64Spec.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64Spec where
+
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Naive
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified HaskellWorks.Data.BalancedParens.FindClose                                       as C
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word64             as BW64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word64 as BW64
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word64      as SW64
+import qualified Hedgehog.Gen                                                                     as G
+import qualified Hedgehog.Range                                                                   as R
+
+{- HLINT ignore "Redundant do"      -}
+{- HLINT ignore "Redundant return"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word64Spec" $ do
+  it "findUnmatchedCloseFar" $ require $ withTests 100000 $ property $ do
+    c <- forAll $ G.word64 (R.linear 0 128)
+    p <- forAll $ G.word64 (R.linear 0 128)
+    w <- forAll $ G.word64 R.constantBounded
+    annotateShow $ bitShow w
+    BW64.findUnmatchedCloseFar c p w === SW64.findUnmatchedCloseFar c p w
+  it "findClose" $ require $ withTests 1000 $ property $ do
+    p <- forAll $ G.word64 (R.linear 1 128)
+    w <- forAll $ G.word64 R.constantBounded
+    annotateShow $ bitShow w
+    BW64.findClose w p === C.findClose (Naive w) p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word8Spec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word8Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindUnmatchedCloseFar/Word8Spec.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8Spec where
+
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified HaskellWorks.Data.BalancedParens.FindClose                                      as C
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Word8             as BW8
+import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindUnmatchedCloseFar.Word8 as BW8
+import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindUnmatchedCloseFar.Word8      as SW8
+import qualified Hedgehog.Gen                                                                    as G
+import qualified Hedgehog.Range                                                                  as R
+
+{- HLINT ignore "Evaluate"            -}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.Broadword.Word8Spec" $ do
+  it "findUnmatchedCloseFar" $ require $ withTests 1000 $ property $ do
+    c <- forAll $ G.word64 (R.linear 0 64)
+    p <- forAll $ G.word64 (R.linear 0 8)
+    w <- forAll $ G.word8 R.constantBounded
+    annotateShow $ bitShow w
+    BW8.findUnmatchedCloseFar c p w === SW8.findUnmatchedCloseFar c p w
+  it "findClose" $ require $ withTests 1000 $ property $ do
+    p <- forAll $ G.word64 (R.linear 1 128)
+    w <- forAll $ G.word8 R.constantBounded
+    annotateShow $ bitShow w
+    BW8.findClose w p === C.findClose w p
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/BroadwordSpec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/BroadwordSpec.hs
--- a/test/HaskellWorks/Data/BalancedParens/Internal/BroadwordSpec.hs
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/BroadwordSpec.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveGeneric              #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE OverloadedStrings          #-}
 {-# LANGUAGE ScopedTypeVariables        #-}
@@ -5,9 +6,10 @@
 module HaskellWorks.Data.BalancedParens.Internal.BroadwordSpec where
 
 import Data.Word
+import GHC.Generics
 import HaskellWorks.Data.BalancedParens.FindClose
 import HaskellWorks.Data.Bits.BitShow
-import HaskellWorks.Data.Bits.Broadword
+import HaskellWorks.Data.Bits.Broadword.Type
 import HaskellWorks.Data.Bits.FromBitTextByteString
 import HaskellWorks.Hspec.Hedgehog
 import Hedgehog
@@ -18,10 +20,11 @@
 import qualified Hedgehog.Gen                         as G
 import qualified Hedgehog.Range                       as R
 
-{-# ANN module ("HLint: Ignore Redundant do"        :: String) #-}
-{-# ANN module ("HLint: Ignore Reduce duplication"  :: String) #-}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
 
-newtype ShowVector a = ShowVector a deriving (Eq, BitShow)
+newtype ShowVector a = ShowVector a deriving (Eq, BitShow, Generic)
 
 instance BitShow a => Show (ShowVector a) where
   show = bitShow
@@ -30,108 +33,66 @@
 spec = describe "HaskellWorks.Data.BalancedParens.BroadwordSpec" $ do
   describe "For (()(()())) 1101101000" $ do
     let bs = Broadword (91 :: Word64)
-    it "Test 1a" $ findClose bs  1 `shouldBe` Just 10
-    it "Test 1b" $ findClose bs  2 `shouldBe` Just  3
-    it "Test 1b" $ findClose bs  3 `shouldBe` Just  3
-    it "Test 1b" $ findClose bs  4 `shouldBe` Just  9
-    it "Test 1b" $ findClose bs  5 `shouldBe` Just  6
-    it "Test 1b" $ findClose bs  6 `shouldBe` Just  6
-    it "Test 1b" $ findClose bs  7 `shouldBe` Just  8
-    it "Test 1b" $ findClose bs  8 `shouldBe` Just  8
-    it "Test 1b" $ findClose bs  9 `shouldBe` Just  9
-    it "Test 1b" $ findClose bs 10 `shouldBe` Just 10
-    -- it "Test 2a" $ findOpen  bs 10 `shouldBe` Just  1
-    -- it "Test 2b" $ findOpen  bs  3 `shouldBe` Just  2
-    -- it "Test 3a" $ enclose   bs  2 `shouldBe` Just  1
-    -- it "Test 3b" $ enclose   bs  7 `shouldBe` Just  4
-  -- describe "For (()(()())) 1101101000" $ do
-  --   let bs = Broadword (fromJust (bitRead "1101101000") :: [Bool])
-  --   it "Test 1a" $ findClose bs  1 `shouldBe` Just 10
-  --   it "Test 1b" $ findClose bs  2 `shouldBe` Just  3
-  --   it "Test 1b" $ findClose bs  3 `shouldBe` Just  3
-  --   it "Test 1b" $ findClose bs  4 `shouldBe` Just  9
-  --   it "Test 1b" $ findClose bs  5 `shouldBe` Just  6
-  --   it "Test 1b" $ findClose bs  6 `shouldBe` Just  6
-  --   it "Test 1b" $ findClose bs  7 `shouldBe` Just  8
-  --   it "Test 1b" $ findClose bs  8 `shouldBe` Just  8
-  --   it "Test 1b" $ findClose bs  9 `shouldBe` Just  9
-  --   it "Test 1b" $ findClose bs 10 `shouldBe` Just 10
-    -- it "Test 2a" $ findOpen  bs 10 `shouldBe` Just  1
-    -- it "Test 2b" $ findOpen  bs  3 `shouldBe` Just  2
-    -- it "Test 3a" $ enclose   bs  2 `shouldBe` Just  1
-    -- it "Test 3b" $ enclose   bs  7 `shouldBe` Just  4
-    -- it "firstChild 1"   $ firstChild  bs 1 `shouldBe` Just 2
-    -- it "firstChild 4"   $ firstChild  bs 4 `shouldBe` Just 5
-    -- it "nextSibling 2"  $ nextSibling bs 2 `shouldBe` Just 4
-    -- it "nextSibling 5"  $ nextSibling bs 5 `shouldBe` Just 7
-    -- it "parent 2" $ parent  bs  2 `shouldBe` Just 1
-    -- it "parent 5" $ parent  bs  5 `shouldBe` Just 4
-    -- it "depth  1" $ depth   bs  1 `shouldBe` Just 1
-    -- it "depth  2" $ depth   bs  2 `shouldBe` Just 2
-    -- it "depth  3" $ depth   bs  3 `shouldBe` Just 2
-    -- it "depth  4" $ depth   bs  4 `shouldBe` Just 2
-    -- it "depth  5" $ depth   bs  5 `shouldBe` Just 3
-    -- it "depth  6" $ depth   bs  6 `shouldBe` Just 3
-    -- it "depth  7" $ depth   bs  7 `shouldBe` Just 3
-    -- it "depth  8" $ depth   bs  8 `shouldBe` Just 3
-    -- it "depth  9" $ depth   bs  9 `shouldBe` Just 2
-    -- it "depth 10" $ depth   bs 10 `shouldBe` Just 1
-    -- it "subtreeSize  1" $ subtreeSize bs  1 `shouldBe` Just 5
-    -- it "subtreeSize  2" $ subtreeSize bs  2 `shouldBe` Just 1
-    -- it "subtreeSize  3" $ subtreeSize bs  3 `shouldBe` Just 0
-    -- it "subtreeSize  4" $ subtreeSize bs  4 `shouldBe` Just 3
-    -- it "subtreeSize  5" $ subtreeSize bs  5 `shouldBe` Just 1
-    -- it "subtreeSize  6" $ subtreeSize bs  6 `shouldBe` Just 0
-    -- it "subtreeSize  7" $ subtreeSize bs  7 `shouldBe` Just 1
-    -- it "subtreeSize  8" $ subtreeSize bs  8 `shouldBe` Just 0
-    -- it "subtreeSize  9" $ subtreeSize bs  9 `shouldBe` Just 0
-    -- it "subtreeSize 10" $ subtreeSize bs 10 `shouldBe` Just 0
+    it "Test 1a" $ requireTest $ findClose bs  1 === Just 10
+    it "Test 1b" $ requireTest $ findClose bs  2 === Just  3
+    it "Test 1b" $ requireTest $ findClose bs  3 === Just  3
+    it "Test 1b" $ requireTest $ findClose bs  4 === Just  9
+    it "Test 1b" $ requireTest $ findClose bs  5 === Just  6
+    it "Test 1b" $ requireTest $ findClose bs  6 === Just  6
+    it "Test 1b" $ requireTest $ findClose bs  7 === Just  8
+    it "Test 1b" $ requireTest $ findClose bs  8 === Just  8
+    it "Test 1b" $ requireTest $ findClose bs  9 === Just  9
+    it "Test 1b" $ requireTest $ findClose bs 10 === Just 10
+    -- it "Test 2a" $ requireTest $ findOpen  bs 10 === Just  1
+    -- it "Test 2b" $ requireTest $ findOpen  bs  3 === Just  2
+    -- it "Test 3a" $ requireTest $ enclose   bs  2 === Just  1
+    -- it "Test 3b" $ requireTest $ enclose   bs  7 === Just  4
   describe "For (()(()())) 11011010 00000000 :: DVS.Vector Word8" $ do
     let bs = Broadword (DVS.head (fromBitTextByteString "11011010 00000000") :: Word64)
-    it "Test 1a" $ findClose bs  1 `shouldBe` Just 10
-    it "Test 1b" $ findClose bs  2 `shouldBe` Just  3
-    it "Test 1b" $ findClose bs  3 `shouldBe` Just  3
-    it "Test 1b" $ findClose bs  4 `shouldBe` Just  9
-    it "Test 1b" $ findClose bs  5 `shouldBe` Just  6
-    it "Test 1b" $ findClose bs  6 `shouldBe` Just  6
-    it "Test 1b" $ findClose bs  7 `shouldBe` Just  8
-    it "Test 1b" $ findClose bs  8 `shouldBe` Just  8
-    it "Test 1b" $ findClose bs  9 `shouldBe` Just  9
-    it "Test 1b" $ findClose bs 10 `shouldBe` Just 10
-    -- it "Test 2a" $ findOpen  bs 10 `shouldBe` Just  1
-    -- it "Test 2b" $ findOpen  bs  3 `shouldBe` Just  2
-    -- it "Test 3a" $ enclose   bs  2 `shouldBe` Just  1
-    -- it "Test 3b" $ enclose   bs  7 `shouldBe` Just  4
-    -- it "firstChild 1"  $ firstChild  bs 1 `shouldBe` Just 2
-    -- it "firstChild 4"  $ firstChild  bs 4 `shouldBe` Just 5
-    -- it "nextSibling 2" $ nextSibling bs 2 `shouldBe` Just 4
-    -- it "nextSibling 5" $ nextSibling bs 5 `shouldBe` Just 7
-    -- it "parent 2" $ parent bs 2 `shouldBe` Just 1
-    -- it "parent 5" $ parent bs 5 `shouldBe` Just 4
-    -- it "depth  1" $ depth bs  1 `shouldBe` Just 1
-    -- it "depth  2" $ depth bs  2 `shouldBe` Just 2
-    -- it "depth  3" $ depth bs  3 `shouldBe` Just 2
-    -- it "depth  4" $ depth bs  4 `shouldBe` Just 2
-    -- it "depth  5" $ depth bs  5 `shouldBe` Just 3
-    -- it "depth  6" $ depth bs  6 `shouldBe` Just 3
-    -- it "depth  7" $ depth bs  7 `shouldBe` Just 3
-    -- it "depth  8" $ depth bs  8 `shouldBe` Just 3
-    -- it "depth  9" $ depth bs  9 `shouldBe` Just 2
-    -- it "depth 10" $ depth bs 10 `shouldBe` Just 1
-    -- it "subtreeSize  1" $ subtreeSize bs  1 `shouldBe` Just 5
-    -- it "subtreeSize  2" $ subtreeSize bs  2 `shouldBe` Just 1
-    -- it "subtreeSize  3" $ subtreeSize bs  3 `shouldBe` Just 0
-    -- it "subtreeSize  4" $ subtreeSize bs  4 `shouldBe` Just 3
-    -- it "subtreeSize  5" $ subtreeSize bs  5 `shouldBe` Just 1
-    -- it "subtreeSize  6" $ subtreeSize bs  6 `shouldBe` Just 0
-    -- it "subtreeSize  7" $ subtreeSize bs  7 `shouldBe` Just 1
-    -- it "subtreeSize  8" $ subtreeSize bs  8 `shouldBe` Just 0
-    -- it "subtreeSize  9" $ subtreeSize bs  9 `shouldBe` Just 0
-    -- it "subtreeSize 10" $ subtreeSize bs 10 `shouldBe` Just 0
+    it "Test 1a" $ requireTest $ findClose bs  1 === Just 10
+    it "Test 1b" $ requireTest $ findClose bs  2 === Just  3
+    it "Test 1b" $ requireTest $ findClose bs  3 === Just  3
+    it "Test 1b" $ requireTest $ findClose bs  4 === Just  9
+    it "Test 1b" $ requireTest $ findClose bs  5 === Just  6
+    it "Test 1b" $ requireTest $ findClose bs  6 === Just  6
+    it "Test 1b" $ requireTest $ findClose bs  7 === Just  8
+    it "Test 1b" $ requireTest $ findClose bs  8 === Just  8
+    it "Test 1b" $ requireTest $ findClose bs  9 === Just  9
+    it "Test 1b" $ requireTest $ findClose bs 10 === Just 10
+    -- it "Test 2a" $ requireTest $ findOpen  bs 10 === Just  1
+    -- it "Test 2b" $ requireTest $ findOpen  bs  3 === Just  2
+    -- it "Test 3a" $ requireTest $ enclose   bs  2 === Just  1
+    -- it "Test 3b" $ requireTest $ enclose   bs  7 === Just  4
+    -- it "firstChild 1"  $ requireTest $ firstChild  bs 1 === Just 2
+    -- it "firstChild 4"  $ requireTest $ firstChild  bs 4 === Just 5
+    -- it "nextSibling 2" $ requireTest $ nextSibling bs 2 === Just 4
+    -- it "nextSibling 5" $ requireTest $ nextSibling bs 5 === Just 7
+    -- it "parent 2" $ requireTest $ parent bs 2 === Just 1
+    -- it "parent 5" $ requireTest $ parent bs 5 === Just 4
+    -- it "depth  1" $ requireTest $ depth bs  1 === Just 1
+    -- it "depth  2" $ requireTest $ depth bs  2 === Just 2
+    -- it "depth  3" $ requireTest $ depth bs  3 === Just 2
+    -- it "depth  4" $ requireTest $ depth bs  4 === Just 2
+    -- it "depth  5" $ requireTest $ depth bs  5 === Just 3
+    -- it "depth  6" $ requireTest $ depth bs  6 === Just 3
+    -- it "depth  7" $ requireTest $ depth bs  7 === Just 3
+    -- it "depth  8" $ requireTest $ depth bs  8 === Just 3
+    -- it "depth  9" $ requireTest $ depth bs  9 === Just 2
+    -- it "depth 10" $ requireTest $ depth bs 10 === Just 1
+    -- it "subtreeSize  1" $ requireTest $ subtreeSize bs  1 === Just 5
+    -- it "subtreeSize  2" $ requireTest $ subtreeSize bs  2 === Just 1
+    -- it "subtreeSize  3" $ requireTest $ subtreeSize bs  3 === Just 0
+    -- it "subtreeSize  4" $ requireTest $ subtreeSize bs  4 === Just 3
+    -- it "subtreeSize  5" $ requireTest $ subtreeSize bs  5 === Just 1
+    -- it "subtreeSize  6" $ requireTest $ subtreeSize bs  6 === Just 0
+    -- it "subtreeSize  7" $ requireTest $ subtreeSize bs  7 === Just 1
+    -- it "subtreeSize  8" $ requireTest $ subtreeSize bs  8 === Just 0
+    -- it "subtreeSize  9" $ requireTest $ subtreeSize bs  9 === Just 0
+    -- it "subtreeSize 10" $ requireTest $ subtreeSize bs 10 === Just 0
   -- describe "Does not suffer exceptions" $ do
   --   it "when calling nextSibling from valid locations" $ do
   --     forAll (vectorSizedBetween 1 64) $ \(ShowVector v) -> do
-  --       [nextSibling v p | p <- [1..bitLength v]] `shouldBe` [nextSibling v p | p <- [1..bitLength v]]
+  --       [nextSibling v p | p <- [1..bitLength v]] === [nextSibling v p | p <- [1..bitLength v]]
   it "Broadword findClose should behave the same as Naive findClose" $ requireProperty $ do
     w <- forAll $ G.word64 R.constantBounded
     p <- forAll $ G.count (R.linear 1 64)
diff --git a/test/HaskellWorks/Data/BalancedParens/Internal/ParensSeqSpec.hs b/test/HaskellWorks/Data/BalancedParens/Internal/ParensSeqSpec.hs
--- a/test/HaskellWorks/Data/BalancedParens/Internal/ParensSeqSpec.hs
+++ b/test/HaskellWorks/Data/BalancedParens/Internal/ParensSeqSpec.hs
@@ -1,10 +1,8 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 
 module HaskellWorks.Data.BalancedParens.Internal.ParensSeqSpec where
 
-import Data.Semigroup                             ((<>))
 import HaskellWorks.Data.BalancedParens.ParensSeq ((<|), (><), (|>))
 import HaskellWorks.Data.RankSelect.Base.Select1
 import HaskellWorks.Hspec.Hedgehog
@@ -18,32 +16,33 @@
 import qualified Hedgehog.Gen                                    as G
 import qualified Hedgehog.Range                                  as R
 
-{-# ANN module ("HLint: Ignore Redundant do"        :: String) #-}
-{-# ANN module ("HLint: Ignore Reduce duplication"  :: String) #-}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
 
 spec :: Spec
 spec = describe "HaskellWorks.Data.BalancedParens.Internal.ParensSeqSpec" $ do
-  it "fromWord64s should produce Rmm of the right size" $ requireProperty $ do
+  it "fromWord64s should produce Rm of the right size" $ requireProperty $ do
     ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)
 
     PS.size (PS.fromWord64s ws) === fromIntegral (length ws * 64)
-  it "fromWord64s should produce Rmm with the right data" $ requireProperty $ do
+  it "fromWord64s should produce Rm with the right data" $ requireProperty $ do
     wns <- forAll $ G.list (R.linear 0 10) $ (,)
       <$> G.word64 R.constantBounded
       <*> G.count (R.linear 1 64)
 
     PS.size (PS.fromPartialWord64s wns) === sum (snd <$> wns)
-  it "fromWord64s should produce Rmm with the right data" $ requireProperty $ do
+  it "fromWord64s should produce Rm with the right data" $ requireProperty $ do
     ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)
 
     PS.toPartialWord64s (PS.fromWord64s ws) === zip ws (repeat 64)
-  it "fromPartialWord64s should produce Rmm with the right data" $ requireProperty $ do
+  it "fromPartialWord64s should produce Rm with the right data" $ requireProperty $ do
     wns <- forAll $ G.list (R.linear 0 10) $ (,)
       <$> G.word64 R.constantBounded
       <*> G.count (R.linear 1 64)
 
     PS.toPartialWord64s (PS.fromPartialWord64s wns) === wns
-  it "fromBools should produce Rmm with the right data" $ requireProperty $ do
+  it "fromBools should produce Rm with the right data" $ requireProperty $ do
     ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)
 
     PS.toPartialWord64s (PS.fromBools (L.toBools ws)) === zip ws (repeat 64)
@@ -89,7 +88,7 @@
     PS.firstChild ps pos === BP.firstChild bs pos
   it "firstChild should select first child" $ requireTest $ do
     let bps = "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))"
-    let bs  = fmap (\c -> if c == '(' then True else False) bps
+    let bs  = fmap (== '(') bps
     let ps = PS.fromBools bs
 
     PS.firstChild ps 64 === Just 65
@@ -98,15 +97,15 @@
     nodeCount <- forAll $ pure (fromIntegral (length bs `div` 2))
     ranked    <- forAll $ G.count (R.linear 1 nodeCount)
     pos       <- forAll $ pure $ select1 bs ranked
-    rmm       <- forAll $ pure $ PS.fromBools bs
+    rm       <- forAll $ pure $ PS.fromBools bs
 
-    PS.nextSibling rmm pos === BP.nextSibling bs pos
+    PS.nextSibling rm pos === BP.nextSibling bs pos
   it "nextSibling on ()()" $ requireTest $ do
     bs        <- forAll $ pure [True , False , True , False]
     pos       <- forAll $ pure 1
-    rmm       <- forAll $ pure $ PS.fromBools bs
+    rm       <- forAll $ pure $ PS.fromBools bs
 
-    PS.nextSibling rmm pos === BP.nextSibling bs pos
+    PS.nextSibling rm pos === BP.nextSibling bs pos
   it "(><) should append" $ requireTest $ do
     bs1       <- forAll $ G.bpBools (R.linear 1 1000)
     bs2       <- forAll $ G.bpBools (R.linear 1 1000)
@@ -115,13 +114,13 @@
 
     PS.toBools (ps1 >< ps2) === PS.toBools ps1 >< PS.toBools ps2
   it "(<|) should cons" $ requireTest $ do
-    b         <- forAll $ G.bool
+    b         <- forAll   G.bool
     bs        <- forAll $ G.bpBools (R.linear 1 1000)
     ps        <- forAll $ pure $ PS.fromBools bs
 
     PS.toBools (b <| ps) === b:PS.toBools ps
   it "(|>) should snoc" $ requireTest $ do
-    b         <- forAll $ G.bool
+    b         <- forAll   G.bool
     bs        <- forAll $ G.bpBools (R.linear 1 1000)
     ps        <- forAll $ pure $ PS.fromBools bs
 
diff --git a/test/HaskellWorks/Data/BalancedParens/RangeMin2Spec.hs b/test/HaskellWorks/Data/BalancedParens/RangeMin2Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/RangeMin2Spec.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE BangPatterns        #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.BalancedParens.RangeMin2Spec where
+
+import Control.Monad                                (mfilter)
+import Data.Word
+import HaskellWorks.Data.BalancedParens
+import HaskellWorks.Data.BalancedParens.RangeMin2
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.FromBitTextByteString
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                 as DVS
+import qualified HaskellWorks.Data.BalancedParens.Gen as G
+import qualified Hedgehog.Gen                         as G
+import qualified Hedgehog.Range                       as R
+
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+factor :: Int
+factor = 16384
+{-# INLINE factor #-}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.RangeMinSpec2" $ do
+  it "For a simple bit string can find close" $ requireTest $ do
+    let v = fromBitTextByteString "11101111 10100101 01111110 10110010 10111011 10111011 00011111 11011100" :: DVS.Vector Word64
+    let !rm = mkRangeMin2 v
+    findClose rm 61 === findClose v 61
+  it "findClose should return the same result" $ requireProperty $ do
+    v <- forAll $ G.storableVector (R.linear 1 4) (G.word64 R.constantBounded)
+    let !rm = mkRangeMin2 v
+    let len = bitLength v
+    [mfilter (<= bitLength v) (findClose rm i) | i <- [1..len]] === [mfilter (<= bitLength v) (findClose v i) | i <- [1..len]]
+  it "findClose should return the same result over all counts" $ requireProperty $ do
+    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
+    p <- forAll $ G.count (R.linear 1 (bitLength v))
+    let !rm = mkRangeMin2 v
+    mfilter (<= bitLength v) (findClose rm p) === mfilter (<= bitLength v) (findClose v p)
+  it "nextSibling should return the same result over all counts" $ requireProperty $ do
+    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
+    p <- forAll $ G.count (R.linear 1 (bitLength v))
+    let !rm = mkRangeMin2 v
+    nextSibling rm p === nextSibling v p
diff --git a/test/HaskellWorks/Data/BalancedParens/RangeMinMax2Spec.hs b/test/HaskellWorks/Data/BalancedParens/RangeMinMax2Spec.hs
deleted file mode 100644
--- a/test/HaskellWorks/Data/BalancedParens/RangeMinMax2Spec.hs
+++ /dev/null
@@ -1,135 +0,0 @@
-{-# LANGUAGE BangPatterns               #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-
-module HaskellWorks.Data.BalancedParens.RangeMinMax2Spec where
-
-import Data.Word
-import HaskellWorks.Data.BalancedParens
-import HaskellWorks.Data.BalancedParens.RangeMinMax
-import HaskellWorks.Data.Bits.BitShow
-import HaskellWorks.Data.Bits.FromBitTextByteString
-import Test.Hspec
-
-import qualified Data.Vector.Storable as DVS
-
-{-# ANN module ("HLint: Ignore Redundant do"        :: String) #-}
-{-# ANN module ("HLint: Ignore Reduce duplication"  :: String) #-}
-
-newtype ShowVector a = ShowVector a deriving (Eq, BitShow)
-
-instance BitShow a => Show (ShowVector a) where
-  show = bitShow
-
-maxVectorSize :: Int
-maxVectorSize = 16384
-{-# INLINE maxVectorSize #-}
-
-spec :: Spec
-spec = describe "HaskellWorks.Data.BalancedParens.RangeMinMaxSpec2" $ do
-  -- let maxSuccessDefault = 5
-  it "For a simple bit string can find close" $ do
-    let v = fromBitTextByteString "11101111 10100101 01111110 10110010 10111011 10111011 00011111 11011100" :: DVS.Vector Word64
-    let !rmm = mkRangeMinMax v
-    findClose rmm 61 `shouldBe` findClose v 61
-  -- it "findClose should return the same result" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 4) $ \(ShowVector v) -> do
-  --       let !rmm = mkRangeMinMax v
-  --       let len = bitLength v
-  --       [findClose rmm i | i <- [1..len]] `shouldBe `[findClose v i | i <- [1..len]]
-  -- it "findClose should return the same result over all counts" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       forAll (choose (1, bitLength v)) $ \p -> do
-  --         let !rmm = mkRangeMinMax v
-  --         findClose rmm p `shouldBe` findClose v p
-  -- it "nextSibling should return the same result" $ do
-  --   forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --     let !rmm = mkRangeMinMax v
-  --     nextSibling rmm 0 `shouldBe` nextSibling v 0
-  -- it "nextSibling should return the same result over all counts" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       forAll (choose (1, bitLength v)) $ \p -> do
-  --         let !rmm = mkRangeMinMax v
-  --         nextSibling rmm p `shouldBe` nextSibling v p
-  -- it "rangeMinMaxBP should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2BP rmm2 `shouldBe` rangeMinMaxBP rmm1
-  -- it "rangeMinMaxL0Excess should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L0Excess rmm2 `shouldBe` rangeMinMaxL0Excess rmm1
-  -- it "rangeMinMaxL0Min should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L0Min rmm2 `shouldBe` rangeMinMaxL0Min rmm1
-  -- it "rangeMinMaxL0Max should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L0Max rmm2 `shouldBe` rangeMinMaxL0Max rmm1
-  -- it "rangeMinMaxL1Min should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L1Min rmm2 `shouldBe` rangeMinMaxL1Min rmm1
-  -- it "rangeMinMaxL1Max should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L1Max rmm2 `shouldBe` rangeMinMaxL1Max rmm1
-  -- it "rangeMinMaxL1Excess should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L1Excess rmm2 `shouldBe` rangeMinMaxL1Excess rmm1
-  -- it "rangeMinMaxL2Min should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L2Min rmm2 `shouldBe` rangeMinMaxL2Min rmm1
-  -- it "rangeMinMaxL2Max should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L2Max rmm2 `shouldBe` rangeMinMaxL2Max rmm1
-  -- it "rangeMinMaxL2Excess should match" $ do
-  --   quickCheckWith stdArgs { maxSuccess = maxSuccessDefault } $ do
-  --     forAll (vectorSizedBetween 1 maxVectorSize) $ \(ShowVector v) -> do
-  --       let !rmm1 = mkRangeMinMax   v
-  --       let !rmm2 = mkRangeMinMax2  v
-  --       rangeMinMax2L2Excess rmm2 `shouldBe` rangeMinMaxL2Excess rmm1
-  -- describe "For example long bit string" $ do
-  --   let v = fromBitTextByteString " \
-  --     \ 01101101 01111100 10011111 01100101 11111100 01101111 00000000 00000000 10001010 11000000 01000010 01010010 01001101 01000101 00000000 00000000 \
-  --     \ " :: DVS.Vector Word64
-  --   let !rmm1 = mkRangeMinMax   v
-  --   let !rmm2 = mkRangeMinMax2  v
-  --   it "l0 max matches" $ do
-  --     rangeMinMax2L0Max rmm2 `shouldBe` rangeMinMaxL0Max rmm1
-  --   it "l1 max matches" $ do
-  --     rangeMinMax2L1Max rmm2 `shouldBe` rangeMinMaxL1Max rmm1
-  --   -- it "l2 max matches" $ do
-  --   --   rangeMinMax2L2Max rmm2 `shouldBe` rangeMinMaxL2Max rmm1
-  --   it "l0 min matches" $ do
-  --     rangeMinMax2L0Min rmm2 `shouldBe` rangeMinMaxL0Min rmm1
-  --   it "l1 min matches" $ do
-  --     rangeMinMax2L1Min rmm2 `shouldBe` rangeMinMaxL1Min rmm1
-  --   it "l2 min matches" $ do
-  --     rangeMinMax2L2Min rmm2 `shouldBe` rangeMinMaxL2Min rmm1
diff --git a/test/HaskellWorks/Data/BalancedParens/RangeMinMaxSpec.hs b/test/HaskellWorks/Data/BalancedParens/RangeMinMaxSpec.hs
deleted file mode 100644
--- a/test/HaskellWorks/Data/BalancedParens/RangeMinMaxSpec.hs
+++ /dev/null
@@ -1,59 +0,0 @@
-{-# LANGUAGE BangPatterns               #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-
-module HaskellWorks.Data.BalancedParens.RangeMinMaxSpec where
-
-import Data.Word
-import HaskellWorks.Data.BalancedParens
-import HaskellWorks.Data.BalancedParens.RangeMinMax
-import HaskellWorks.Data.Bits.BitLength
-import HaskellWorks.Data.Bits.BitShow
-import HaskellWorks.Data.Bits.FromBitTextByteString
-import HaskellWorks.Hspec.Hedgehog
-import Hedgehog
-import Test.Hspec
-
-import qualified Data.Vector.Storable                 as DVS
-import qualified HaskellWorks.Data.BalancedParens.Gen as G
-import qualified Hedgehog.Gen                         as G
-import qualified Hedgehog.Range                       as R
-
-{-# ANN module ("HLint: Ignore Redundant do"        :: String) #-}
-{-# ANN module ("HLint: Ignore Reduce duplication"  :: String) #-}
-
-newtype ShowVector a = ShowVector a deriving (Eq, BitShow)
-
-instance BitShow a => Show (ShowVector a) where
-  show = bitShow
-
-factor :: Int
-factor = 16384
-{-# INLINE factor #-}
-
-spec :: Spec
-spec = describe "HaskellWorks.Data.BalancedParens.RangeMinMaxSpec" $ do
-  it "For a simple bit string can find close" $ requireTest $ do
-    let v = fromBitTextByteString "11101111 10100101 01111110 10110010 10111011 10111011 00011111 11011100" :: DVS.Vector Word64
-    let !rmm = mkRangeMinMax v
-    findClose rmm 61 === findClose v 61
-  it "findClose should return the same result" $ requireProperty $ do
-    v <- forAll $ G.storableVector (R.linear 1 4) (G.word64 R.constantBounded)
-    let !rmm = mkRangeMinMax v
-    let len = bitLength v
-    [findClose rmm i | i <- [1..len]] === [findClose v i | i <- [1..len]]
-  it "findClose should return the same result over all counts" $ requireProperty $ do
-    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
-    p <- forAll $ G.count (R.linear 1 (bitLength v))
-    let !rmm = mkRangeMinMax v
-    findClose rmm p === findClose v p
-  it "nextSibling should return the same result" $ requireProperty $ do
-    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
-    let !rmm = mkRangeMinMax v
-    nextSibling rmm 0 === nextSibling v 0
-  it "nextSibling should return the same result over all counts" $ requireProperty $ do
-    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
-    p <- forAll $ G.count (R.linear 1 (bitLength v))
-    let !rmm = mkRangeMinMax v
-    nextSibling rmm p === nextSibling v p
diff --git a/test/HaskellWorks/Data/BalancedParens/RangeMinSpec.hs b/test/HaskellWorks/Data/BalancedParens/RangeMinSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/BalancedParens/RangeMinSpec.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE BangPatterns               #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+
+module HaskellWorks.Data.BalancedParens.RangeMinSpec where
+
+import Control.Monad                                (mfilter)
+import Data.Word
+import GHC.Generics
+import HaskellWorks.Data.BalancedParens
+import HaskellWorks.Data.BalancedParens.RangeMin
+import HaskellWorks.Data.Bits.BitLength
+import HaskellWorks.Data.Bits.BitShow
+import HaskellWorks.Data.Bits.FromBitTextByteString
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                 as DVS
+import qualified HaskellWorks.Data.BalancedParens.Gen as G
+import qualified Hedgehog.Gen                         as G
+import qualified Hedgehog.Range                       as R
+
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
+
+newtype ShowVector a = ShowVector a deriving (Eq, BitShow, Generic)
+
+instance BitShow a => Show (ShowVector a) where
+  show = bitShow
+
+factor :: Int
+factor = 16384
+{-# INLINE factor #-}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.BalancedParens.RangeMinSpec" $ do
+  it "For a simple bit string can find close" $ requireTest $ do
+    let v = fromBitTextByteString "11101111 10100101 01111110 10110010 10111011 10111011 00011111 11011100" :: DVS.Vector Word64
+    let !rm = mkRangeMin v
+    findClose rm 61 === findClose v 61
+  it "findClose should return the same result" $ requireProperty $ do
+    v <- forAll $ G.storableVector (R.linear 1 4) (G.word64 R.constantBounded)
+    let !rm = mkRangeMin v
+    let len = bitLength v
+    [mfilter (<= bitLength v) (findClose rm i) | i <- [1..len]] === [mfilter (<= bitLength v) (findClose v i) | i <- [1..len]]
+  it "findClose should return the same result over all counts" $ requireProperty $ do
+    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
+    p <- forAll $ G.count (R.linear 1 (bitLength v))
+    let !rm = mkRangeMin v
+    mfilter (<= bitLength v) (findClose rm p) === mfilter (<= bitLength v) (findClose v p)
+  it "nextSibling should return the same result over all counts" $ requireProperty $ do
+    v <- forAll $ G.storableVector (R.linear 1 factor) (G.word64 R.constantBounded)
+    p <- forAll $ G.count (R.linear 1 (bitLength v))
+    let !rm = mkRangeMin v
+    nextSibling rm p === nextSibling v p
diff --git a/test/HaskellWorks/Data/BalancedParens/SimpleSpec.hs b/test/HaskellWorks/Data/BalancedParens/SimpleSpec.hs
--- a/test/HaskellWorks/Data/BalancedParens/SimpleSpec.hs
+++ b/test/HaskellWorks/Data/BalancedParens/SimpleSpec.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 
 module HaskellWorks.Data.BalancedParens.SimpleSpec where
 
@@ -17,8 +16,9 @@
 import qualified Hedgehog.Gen                         as G
 import qualified Hedgehog.Range                       as R
 
-{-# ANN module ("HLint: Ignore Redundant do"        :: String) #-}
-{-# ANN module ("HLint: Ignore Reduce duplication"  :: String) #-}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Redundant return"    -}
+{- HLINT ignore "Reduce duplication"  -}
 
 spec :: Spec
 spec = describe "HaskellWorks.Data.BalancedParens.SimpleSpec" $ do
