diff --git a/bioinformatics-toolkit.cabal b/bioinformatics-toolkit.cabal
--- a/bioinformatics-toolkit.cabal
+++ b/bioinformatics-toolkit.cabal
@@ -1,5 +1,5 @@
 name:                bioinformatics-toolkit
-version:             0.6.0
+version:             0.7.0
 synopsis:            A collection of bioinformatics tools
 description:         A collection of bioinformatics tools
 license:             MIT
@@ -21,6 +21,8 @@
   tests/data/example_intersect_peaks.bed
   tests/data/motifs.fasta
   tests/data/motifs.meme
+  tests/data/test.fastq
+
 library
   hs-source-dirs: src
   ghc-options: -Wall
@@ -114,6 +116,7 @@
   other-modules:
       Tests.Bed
     , Tests.Bam
+    , Tests.Fastq
     , Tests.Motif
     , Tests.Seq
     , Tests.Tools
diff --git a/src/Bio/Data/Bed.hs b/src/Bio/Data/Bed.hs
--- a/src/Bio/Data/Bed.hs
+++ b/src/Bio/Data/Bed.hs
@@ -36,14 +36,15 @@
     , mergeSortedBed
     , mergeSortedBedWith
     , splitOverlapped
-    , hReadBed
-    , hReadBed'
+
+    -- * IO
+    , streamBed
+    , streamBedGzip
     , readBed
-    , readBed'
-    , hWriteBed
-    , hWriteBed'
+    , sinkFileBed
+    , sinkFileBedGzip
+    , sinkHandleBed
     , writeBed
-    , writeBed'
 
     , compareBed
     ) where
@@ -59,6 +60,7 @@
 import qualified Data.IntervalMap.Strict      as IM
 import           Data.List                    (groupBy, sortBy)
 import           Data.Ord                     (comparing)
+import           Data.Conduit.Zlib           (gzip, ungzip, multiple)
 import qualified Data.Vector                  as V
 import qualified Data.Vector.Algorithms.Intro as I
 import           System.IO
@@ -252,50 +254,42 @@
     chr = head xs ^. chrom
 {-# INLINE splitOverlapped #-}
 
--- | Read records from a bed file handler in a streaming fashion.
-hReadBed :: (BEDConvert b, MonadIO m) => Handle -> ConduitT i b m ()
-hReadBed h = do eof <- liftIO $ hIsEOF h
-                unless eof $ do
-                    line <- liftIO $ B.hGetLine h
-                    yield $ fromLine line
-                    hReadBed h
-{-# INLINE hReadBed #-}
 
--- | Non-streaming version.
-hReadBed' :: (BEDConvert b, MonadIO m) => Handle -> m [b]
-hReadBed' h = runConduit $ hReadBed h .| sinkList
-{-# INLINE hReadBed' #-}
+streamBed :: (MonadResource m, BEDConvert b, MonadIO m)
+          => FilePath -> ConduitT i b m () 
+streamBed input = sourceFile input .| bsToBed
+{-# INLINE streamBed #-}
 
--- | Read records from a bed file in a streaming fashion.
-readBed :: (BEDConvert b, MonadIO m) => FilePath -> ConduitT i b m ()
-readBed fl = do handle <- liftIO $ openFile fl ReadMode
-                hReadBed handle
-                liftIO $ hClose handle
+streamBedGzip :: (BEDConvert b, MonadResource m, MonadThrow m, PrimMonad m)
+              => FilePath -> ConduitT i b m () 
+streamBedGzip input = sourceFile input .| multiple ungzip .| bsToBed
+{-# INLINE streamBedGzip #-}
+
+readBed :: BEDConvert b => FilePath -> IO [b]
+readBed fl = runResourceT $ runConduit $ streamBed fl .| sinkList
 {-# INLINE readBed #-}
 
--- | Non-streaming version.
-readBed' :: (BEDConvert b, MonadIO m) => FilePath -> m [b]
-readBed' fl = runConduit $ readBed fl .| sinkList
-{-# INLINE readBed' #-}
+sinkFileBed :: (BEDConvert b, MonadResource m) => FilePath -> ConduitT b o m ()
+sinkFileBed output = bedToBS .| sinkFile output
+{-# INLINE sinkFileBed #-}
 
-hWriteBed :: (BEDConvert b, MonadIO m) => Handle -> ConduitT b o m ()
-hWriteBed handle = do
-    x <- await
-    case x of
-        Nothing -> return ()
-        Just bed -> (liftIO . B.hPutStrLn handle . toLine) bed >> hWriteBed handle
-{-# INLINE hWriteBed #-}
+sinkFileBedGzip :: (BEDConvert b, MonadResource m, MonadThrow m, PrimMonad m)
+                => FilePath -> ConduitT b o m ()
+sinkFileBedGzip output = bedToBS .| gzip .| sinkFile output
+{-# INLINE sinkFileBedGzip #-}
 
-hWriteBed' :: (BEDConvert b, MonadIO m) => Handle -> [b] -> m ()
-hWriteBed' handle beds = runConduit $ yieldMany beds .| hWriteBed handle
-{-# INLINE hWriteBed' #-}
+sinkHandleBed :: (BEDConvert b, MonadIO m) => Handle -> ConduitT b o m ()
+sinkHandleBed hdl = bedToBS .| sinkHandle hdl
+{-# INLINE sinkHandleBed #-}
 
-writeBed :: (BEDConvert b, MonadIO m) => FilePath -> ConduitT b o m ()
-writeBed fl = do handle <- liftIO $ openFile fl WriteMode
-                 hWriteBed handle
-                 liftIO $ hClose handle
+writeBed :: BEDConvert b => FilePath -> [b] -> IO ()
+writeBed fl beds = runResourceT $ runConduit $ yieldMany beds .| sinkFileBed fl
 {-# INLINE writeBed #-}
 
-writeBed' :: (BEDConvert b, MonadIO m) => FilePath -> [b] -> m ()
-writeBed' fl beds = runConduit $ yieldMany beds .| writeBed fl
-{-# INLINE writeBed' #-}
+bedToBS :: (BEDConvert b, Monad m) => ConduitT b B.ByteString m ()
+bedToBS = mapC toLine .| unlinesAsciiC
+{-# INLINE bedToBS #-}
+
+bsToBed :: (BEDConvert b, Monad m) => ConduitT B.ByteString b m ()
+bsToBed = linesUnboundedAsciiC .| mapC fromLine
+{-# INLINE bsToBed #-}
diff --git a/src/Bio/Data/Bed/Utils.hs b/src/Bio/Data/Bed/Utils.hs
--- a/src/Bio/Data/Bed/Utils.hs
+++ b/src/Bio/Data/Bed/Utils.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE FlexibleContexts      #-}
 {-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE BangPatterns #-}
 
 module Bio.Data.Bed.Utils
@@ -34,6 +35,7 @@
 import qualified Data.Vector.Generic          as G
 import qualified Data.Vector.Generic.Mutable  as GM
 import qualified Data.Vector.Unboxed          as U
+import System.IO
 
 import           Bio.Data.Bed
 import           Bio.Data.Bed.Types
@@ -68,7 +70,9 @@
 motifScan g motifs bg p = awaitForever $ \bed -> do
     r <- liftIO $ getSeq g (bed^.chrom, bed^.chromStart, bed^.chromEnd)
     case r of
-        Left _    -> return ()
+        Left _    -> liftIO $ hPutStrLn stderr $
+            "Warning: no sequence for region: " ++ show 
+                (bed^.chrom, bed^.chromStart, bed^.chromEnd)
         Right dna -> mapM_ (getTFBS dna (bed^.chrom, bed^.chromStart)) motifs'
   where
     getTFBS dna (chr, s) (nm, (pwm, cutoff), (pwm', cutoff')) = toProducer
@@ -223,36 +227,29 @@
            -> [b]   -- ^ regions
            -> ConduitT BED o m ([v a], Int)
 countTagsBinBed k beds = do
-    initRC <- lift $ forM beds $ \bed -> do
+    vs <- lift $ fmap V.fromList $ forM beds $ \bed -> do
         let start = bed^.chromStart
-            end = bed^.chromEnd
-            num = (end - start) `div` k
+            num = ((bed^.chromEnd) - start) `div` k
             index i = (i - start) `div` k
         v <- GM.replicate num 0
         return (v, index)
-
-    sink 0 $ V.fromList initRC
+    nTags <- foldMC (f vs) 0
+    rc <- lift $ mapM (G.unsafeFreeze . fst) $ G.toList vs
+    return (rc, nTags)
   where
-    sink !nTags vs = do
-        tag <- await
-        case tag of
-            Just bed -> do
-                let p | bed^.strand == Just True = bed^.chromStart
-                      | bed^.strand == Just False = bed^.chromEnd - 1
-                      | otherwise = error "profiling: unkown strand"
-                    overlaps = concat $ IM.elems $
-                        IM.containing (M.lookupDefault IM.empty (bed^.chrom) intervalMap) p
-                lift $ forM_ overlaps $ \x -> do
-                    let (v, idxFn) = vs `G.unsafeIndex` x
-                        i = let i' = idxFn p
-                                l = GM.length v
-                            in if i' >= l then l - 1 else i'
-                    GM.unsafeRead v i >>= GM.unsafeWrite v i . (+1)
-                sink (nTags+1) vs
-
-            _ -> do rc <- lift $ mapM (G.unsafeFreeze . fst) $ G.toList vs
-                    return (rc, nTags)
-
+    f vs n bed = do
+        let pos | bed^.strand == Just True = bed^.chromStart
+                | bed^.strand == Just False = bed^.chromEnd - 1
+                | otherwise = error "unkown strand."
+            overlaps = concat $ IM.elems $ IM.containing
+                (M.lookupDefault IM.empty (bed^.chrom) intervalMap) pos
+        forM_ overlaps $ \x -> do
+            let (v, idxFn) = vs `G.unsafeIndex` x
+                i = let i' = idxFn pos
+                        l = GM.length v
+                    in if i' >= l then l - 1 else i'
+            GM.unsafeModify v (+1) i
+        return $ n + 1
     intervalMap = bedToTree (++) $ zip beds $ map return [0..]
 {-# INLINE countTagsBinBed #-}
 
@@ -298,40 +295,6 @@
 
     intervalMap = bedToTree (++) $ zip beds $ map return [0..]
 {-# INLINE countTagsBinBed' #-}
-
-
-{-
--- | calculate RPKM using BAM file (*.bam) and its index file (*.bam.bai), using
--- constant space
-rpkmBam :: BEDLike b => FilePath -> Conduit b IO Double
-rpkmBam fl = do
-    nTags <- lift $ readBam fl $$ foldMC (\acc bam -> return $
-                                  if isUnmap bam then acc else acc + 1) 0.0
-    handle <- lift $ BI.open fl
-    conduit nTags handle
-  where
-    conduit n h = do
-        x <- await
-        case x of
-            Nothing -> lift $ BI.close h
-            Just bed -> do let chr = chrom bed
-                               s = chromStart bed
-                               e = chromEnd bed
-                           rc <- lift $ viewBam h (chr, s, e) $$ readCount s e
-                           yield $ rc * 1e9 / n / fromIntegral (e-s)
-                           conduit n h
-    readCount l u = foldMC f 0.0
-      where
-        f acc bam = do let p1 = fromIntegral . fromJust . position $ bam
-                           rl = fromIntegral . fromJust . queryLength $ bam
-                           p2 = p1 + rl - 1
-                       return $ if isReverse bam
-                                   then if l <= p2 && p2 < u then acc + 1
-                                                             else acc
-                                   else if l <= p1 && p1 < u then acc + 1
-                                                             else acc
-{-# INLINE rpkmBam #-}
--}
 
 tagCountDistr :: PrimMonad m => G.Vector v Int => ConduitT BED o m (v Int)
 tagCountDistr = loop M.empty
diff --git a/src/Bio/Data/Fastq.hs b/src/Bio/Data/Fastq.hs
--- a/src/Bio/Data/Fastq.hs
+++ b/src/Bio/Data/Fastq.hs
@@ -2,6 +2,10 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Bio.Data.Fastq
     ( Fastq(..)
+    , streamFastqGzip
+    , streamFastq
+    , sinkFastqGzip
+    , sinkFastq
     , parseFastqC
     , fastqToByteString
     , qualitySummary
@@ -9,12 +13,14 @@
     ) where
 
 import           Conduit
+import Data.Conduit.Zlib (ungzip, multiple, gzip)
 import           Control.Monad         (when)
 import qualified Data.ByteString.Char8 as B
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.ByteString as BS
 import           Data.Maybe            (isJust)
-import Data.Attoparsec.ByteString
+import qualified Data.Attoparsec.ByteString as A
+import Data.Attoparsec.ByteString.Char8
 import Data.Conduit.Attoparsec
 
 -- | A FASTQ file normally uses four lines per sequence.
@@ -35,17 +41,42 @@
     , fastqSeqQual :: B.ByteString
     } deriving (Show, Eq)
 
+-- | Read gzipped fastq file.
+streamFastqGzip :: (PrimMonad m, MonadThrow m, MonadResource m) 
+                => FilePath -> ConduitT i Fastq m ()
+streamFastqGzip fl = sourceFileBS fl .| multiple ungzip .| parseFastqC
+
+streamFastq :: (MonadResource m, MonadThrow m)
+            => FilePath -> ConduitT i Fastq m ()
+streamFastq fl = sourceFileBS fl .| parseFastqC
+
+sinkFastq :: (MonadResource m, MonadThrow m)
+          => FilePath -> ConduitT Fastq o m ()
+sinkFastq fl = mapC fastqToByteString .| unlinesAsciiC .| sinkFileBS fl
+
+sinkFastqGzip :: (PrimMonad m, MonadThrow m, MonadResource m)
+              => FilePath -> ConduitT Fastq o m ()
+sinkFastqGzip fl = mapC fastqToByteString .| unlinesAsciiC .| gzip .| sinkFileBS fl
+
 parseFastqC :: MonadThrow m => ConduitT B.ByteString Fastq m ()
 parseFastqC = conduitParser fastqParser .| mapC snd
 {-# INLINE parseFastqC #-}
 
 fastqParser :: Parser Fastq
 fastqParser = do
-    ident <- word8 64 *> takeTill (==10)
-    sequence <- BS.filter (/=10) <$> takeTill (==43)
-    skip (/=10)
-    score <- BS.filter (/=10) <$> takeTill (==64)
+    _ <- skipWhile (/='@') >> char8 '@'
+    ident <- A.takeTill isEndOfLine
+    endOfLine
+    sequence <- BS.filter (not . isEndOfLine) <$> takeTill (=='+')
+    char8 '+' >> A.skipWhile (not . isEndOfLine) >> endOfLine
+    score <- BS.filter (not . isEndOfLine) <$>
+        A.scan 0 (f (B.length sequence))
+    skipWhile (/='@')
     return $ Fastq ident sequence score
+  where
+    f n i x | i >= n = Nothing
+            | isEndOfLine x = Just i
+            | otherwise = Just $ i + 1
 {-# INLINE fastqParser #-}
 
 fastqToByteString :: Fastq -> B.ByteString
diff --git a/src/Bio/RealWorld/GENCODE.hs b/src/Bio/RealWorld/GENCODE.hs
--- a/src/Bio/RealWorld/GENCODE.hs
+++ b/src/Bio/RealWorld/GENCODE.hs
@@ -1,16 +1,20 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
 
 module Bio.RealWorld.GENCODE
     ( Gene(..)
     , readGenes
+    , streamElements
     ) where
 
 import           Conduit
 import qualified Data.ByteString.Char8 as B
 import           Data.CaseInsensitive  (CI, mk)
 import qualified Data.HashMap.Strict   as M
+import Data.List.Ordered (nubSort)
 import           Data.Maybe            (fromJust)
 
+import Bio.Data.Bed.Types
 import           Bio.Utils.Misc        (readInt)
 
 -- | GTF's position is 1-based, but here we convert it to 0-based indexing.
@@ -21,35 +25,47 @@
     , geneLeft        :: !Int
     , geneRight       :: !Int
     , geneStrand      :: !Bool
-    , geneTranscripts :: [(Int, Int)]
+    , geneTranscripts :: ![(Int, Int)]
+    , geneExon        :: ![(Int, Int)]
     } deriving (Show)
 
 -- | Read gene information from Gencode GTF file
 readGenes :: FilePath -> IO [Gene]
 readGenes input = do
-    (genes, transcripts) <- runResourceT $ runConduit $ sourceFile input .|
-        linesUnboundedAsciiC .| foldlC f (M.empty, M.empty)
-    return $ M.elems $ M.foldlWithKey'
-        (\m k v -> M.adjust (\g -> g{geneTranscripts=v}) k m)
-        genes transcripts
+    (genes, transcripts, exon) <- runResourceT $ runConduit $ sourceFile input .|
+        linesUnboundedAsciiC .| foldlC f (M.empty, M.empty, M.empty)
+    return $ M.elems $ flip
+        (M.foldlWithKey' (\m k v -> M.adjust (\g -> g{geneExon=nubSort v}) k m)) exon $
+        flip (M.foldlWithKey' (\m k v -> M.adjust (\g -> g{geneTranscripts=nubSort v}) k m))
+        transcripts genes
   where
-    f (genes, transcripts) l
-        | B.head l == '#' = (genes, transcripts)
+    f (genes, transcripts, exon) l
+        | B.head l == '#' = (genes, transcripts, exon)
         | f3 == "gene" =
-            let g = Gene (mk $ getField "gene_name") i f1 (readInt f4 - 1)
-                    (readInt f5 - 1) (f7=="+") []
-                i = getField "gene_id"
-            in (M.insert i g genes, transcripts)
-        | f3 == "transcript" =
-            let t = (readInt f4 - 1, readInt f5 - 1)
-                i = getField "gene_id"
-                updateFn Nothing = Just [t]
-                updateFn (Just x) = Just $ t : x
-            in (genes, M.alter updateFn i transcripts)
-        | otherwise = (genes, transcripts)
+            let g = Gene (mk $ getField "gene_name") gid f1 leftPos rightPos
+                    (f7=="+") [] []
+            in (M.insert gid g genes, transcripts, exon)
+        | f3 == "transcript" = (genes, update transcripts, exon)
+        | f3 == "exon" = (genes, transcripts, update exon)
+        | otherwise = (genes, transcripts, exon)
       where
+        gid = getField "gene_id"
+        leftPos = readInt f4 - 1
+        rightPos = readInt f5 - 1
+        update m = let updateFn Nothing = Just [(leftPos, rightPos)]
+                       updateFn (Just x) = Just $ (leftPos, rightPos) : x
+                    in M.alter updateFn gid m
         [f1,_,f3,f4,f5,_,f7,_,f9] = B.split '\t' l
-        fields = map (B.break (==' ') . strip) $ B.split ';' f9
+        fields = map (B.break isSpace . strip) $ B.split ';' f9
         getField x = B.init $ B.drop 2 $ fromJust $ lookup x fields
     strip = fst . B.spanEnd isSpace . B.dropWhile isSpace
     isSpace = (== ' ')
+
+streamElements :: Monad m => ConduitT B.ByteString BED m ()
+streamElements = linesUnboundedAsciiC .| concatMapC f
+  where
+    f l | B.head l == '#' = Nothing
+        | otherwise = Just $ BED chr (readInt start - 1) (readInt end - 1)
+            (Just name) Nothing (Just $ strand == "+")
+      where
+        [chr,_,name,start,end,_,strand,_,_] = B.split '\t' l
diff --git a/src/Bio/Utils/BitVector.hs b/src/Bio/Utils/BitVector.hs
--- a/src/Bio/Utils/BitVector.hs
+++ b/src/Bio/Utils/BitVector.hs
@@ -1,5 +1,5 @@
 module Bio.Utils.BitVector
-    ( BitVector
+    ( BitVector(..)
     , BitMVector
     , size
     , (!)
diff --git a/tests/Tests/Bam.hs b/tests/Tests/Bam.hs
--- a/tests/Tests/Bam.hs
+++ b/tests/Tests/Bam.hs
@@ -32,7 +32,7 @@
 
 bamToBedTest :: Assertion
 bamToBedTest = do
-    bed <- readBed' "tests/data/example.bed"
+    bed <- readBed "tests/data/example.bed"
     bed' <- do
         let input = "tests/data/example.bam" 
         header <- getBamHeader input
diff --git a/tests/Tests/Bed.hs b/tests/Tests/Bed.hs
--- a/tests/Tests/Bed.hs
+++ b/tests/Tests/Bed.hs
@@ -27,9 +27,9 @@
     ]
 
 sortBedTest :: Assertion
-sortBedTest = do beds <- readBed' "tests/data/peaks.bed" :: IO [BED]
+sortBedTest = do beds <- readBed "tests/data/peaks.bed" :: IO [BED]
                  let (Sorted actual) = sortBed beds
-                 expect <- fmap V.fromList $ readBed' "tests/data/peaks.sorted.bed"
+                 expect <- fmap V.fromList $ readBed "tests/data/peaks.sorted.bed"
                  expect @=? actual
 
 splitBedTest :: Assertion
@@ -73,18 +73,18 @@
 
 intersectBedTest :: Assertion
 intersectBedTest = do
-    expect <- readBed' "tests/data/example_intersect_peaks.bed" :: IO [BED3]
-    peaks <- readBed' "tests/data/peaks.bed" :: IO [BED3]
-    result <- runConduit $ readBed "tests/data/example.bed" .| intersectBed peaks .| sinkList
+    expect <- readBed "tests/data/example_intersect_peaks.bed" :: IO [BED3]
+    peaks <- readBed "tests/data/peaks.bed" :: IO [BED3]
+    result <- runResourceT $ runConduit $ streamBed "tests/data/example.bed" .| intersectBed peaks .| sinkList
     expect @=? result
 
 baseMapTest :: Assertion
 baseMapTest = do
-    BaseMap bv <- runConduit $ readBed "tests/data/example.bed" .|
+    BaseMap bv <- runResourceT $ runConduit $ streamBed "tests/data/example.bed" .|
         baseMap [("chr1", 300000000)]
     let res = M.lookupDefault undefined "chr1" $
             fmap (map fst . filter snd . zip [0..] . toList) bv
-    expect <- runConduit $ readBed "tests/data/example.bed" .|
+    expect <- runResourceT $ runConduit $ streamBed "tests/data/example.bed" .|
         concatMapC f .| sinkList
     sort expect @=? sort res
   where
diff --git a/tests/Tests/Fastq.hs b/tests/Tests/Fastq.hs
new file mode 100644
--- /dev/null
+++ b/tests/Tests/Fastq.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Tests.Fastq (tests) where
+
+import           Bio.Data.Fastq
+import Control.Lens
+import           Conduit
+import           Test.Tasty
+import           Test.Tasty.Golden
+import           Test.Tasty.HUnit
+import qualified Data.HashMap.Strict as M
+import Data.Ord
+import Data.Maybe
+
+tests :: TestTree
+tests = testGroup "Test: Bio.Data.Fastq"
+    [ fastqIO
+    ]
+
+fastqIO :: TestTree
+fastqIO = goldenVsFile "FASTQ Read/Write Test" input output io
+  where
+    io = runResourceT $ runConduit $ streamFastq input .| sinkFastq output
+    input = "tests/data/test.fastq" 
+    output = "out.fastq"
diff --git a/tests/data/test.fastq b/tests/data/test.fastq
new file mode 100644
--- /dev/null
+++ b/tests/data/test.fastq
@@ -0,0 +1,200 @@
+@M00436:256:000000000-B3PGP:1:1101:12997:1870 2:N:0:TAAGACGA
+TTTTTCCCTCCTTTTCTCTTCTCCTCTTTTTTTTTTTTTTTTTTTTTTTTT
++
+111>1111B1111313A33A1B11B01BDAB0AA/AAAAA>E>>>E>EE<<
+@M00436:256:000000000-B3PGP:1:1101:20142:2157 2:N:0:TAAGGCGA
+CATTAGAGCCTGTTATTAATGATTGTAATGTATTTTCTGTATAATTTTACT
++
+11>>>13B1>>BBGFGBGGGGF3BBAGHFHHHHGG3FBFGHFHFGDFGFHG
+@M00436:256:000000000-B3PGP:1:1101:15166:2177 2:N:0:TAAGGCGA
+TGCCACGTGATTGCTGAGGCTGTAAGAACCACCCTGGGTCCCCGTGGCATG
++
+A11>>1>>1>FFCGGFGGGGGGHHG3BDFGH0FGCCGGGGHGHGFCCGFHH
+@M00436:256:000000000-B3PGP:1:1101:16584:2188 2:N:0:TAAGGCGA
+CTAGTAAGGCATTGTAAAAGTTACTGGATTTGGTTTAAAAAAAAAAAAAA
++
+>A11>BF11>CBAA3BGGG11BEGAE1FD1GD1000EGGGHCGGGGG?E@
+@M00436:256:000000000-B3PGP:1:1101:15256:2192 2:N:0:TAAGGCGA
+CTTTGGAACAACTATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++
+1AA?11CFBFFABG3FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+@M00436:256:000000000-B3PGP:1:1101:18301:2193 2:N:0:TAAGGCGA
+CACCTACAGAAGGAGCGCTGTGCCCCCTGGAGCTGACAAGAAAGCTGAGGC
++
+111>AFCC1DFFA1FG?FGAEGHHHGGGGABGGHHDG11000BFGHG1BFG
+@M00436:256:000000000-B3PGP:1:1101:13721:2196 2:N:0:TAAGGCGA
+TAGCCTGAGCGTTTAATTTATTCAGTACCTGTGTTTGTGTGAATGCGGTGT
++
+111>AFFBBFDAECG3FGDGGGHGGHFHBGHHHBBFFGFGFHBGHGGGEAA
+@M00436:256:000000000-B3PGP:1:1101:14584:2200 2:N:0:TAAGGCGA
+GCAAAAGGACCATTTAAAGTAAAAAAAAAAAAAAAAAAAAAAAATCTCTCC
++
+1>>1>BCAFFAAGFGG3FGG3FG3GG?ECGGGGGC?EGCEGGE@FH2B2BC
+@M00436:256:000000000-B3PGP:1:1101:11335:2200 2:N:0:TAAGGCGA
+CTGAATGCCATTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++
+1AAAA33@11113BGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+@M00436:256:000000000-B3PGP:1:1101:13303:2201 2:N:0:TAAGGCGA
+TGCTTATACAATGTGAGTGTACTGAGGTAAGGGGAATATGGGAGCAGAGAC
++
+A3>A?FFF5BCFFDGGGFGGGGHHGHGCF5GHA?EGGFGHGFFEEG3FHCG
+@M00436:256:000000000-B3PGP:1:1101:13286:2203 2:N:0:TAAGGCGA
+TTCCCGAGACCGGCAGGCCTCAGCCCAAAAGAACAAAGGGAGAAAGAACTG
++
+1>111A>111>10AE00AA101110AGHH/0/00B0B00///A011B0011
+@M00436:256:000000000-B3PGP:1:1101:11054:2203 2:N:0:TAAGGCGA
+TTCGTACTCTGAGTTGATACCACTGCTTCCGCGGACAGGCGTGTAGCACTC
++
+1111>>1?DBF1BB31FFE3BA1B1E3BF1A0AEECAF////A/BA22BGC
+@M00436:256:000000000-B3PGP:1:1101:15278:2204 2:N:0:TAAGGCGA
+ACATAGTTCAGTATGAAAATAAGAGAATAAAATCTGTTATAAGCAAGTGAT
++
+111>1@DFDBFFFGGGGF1BFGF1E11BDHFCGFDHGHHHH3GFH0GAEHH
+@M00436:256:000000000-B3PGP:1:1101:14285:2204 2:N:0:TAAGGCGA
+AATGTGCGTATTGAGCACATTAAGCACTCTAAGAGCCGAGATAGCTTCCTG
++
+11>1AFBAAA1@D3GGGGGGGGG1GFFH0E1F31E0F?0AECBADDGGHHE
+@M00436:256:000000000-B3PGP:1:1101:15307:2205 2:N:0:TAAGGCGA
+TCTATAAGAAGGAGAAAGCTCGAGTCATCACTGAGGAAGAGAAGAATTTC
++
+AA3AAFDDBDCFAGECGFFGGGGGHCFHHGHBGHHGHHHHHGHHHHHHBG
+@M00436:256:000000000-B3PGP:1:1101:17837:2208 2:N:0:TAAGGCGA
+GCAGAGGTGAATGGGATTCAGACGGTACTAAAAAAAAAAAAAAAAAAAAA
++
+111>1A?1>FFFDCFGCEGGGGGCGEHEHFFHFFAEEGCEEGGGGGGGGG
+@M00436:256:000000000-B3PGP:1:1101:14152:2208 2:N:0:TAAGGCGA
+TCTATGCTCCCTCTGTGTTAGAATTGGCTGAAGTGTTTTTGTGCAGCTGAC
++
+AA>A1BD311>1A113331BFGH3311010BFE313300000A1E1FE1F0
+@M00436:256:000000000-B3PGP:1:1101:17005:2214 2:N:0:TAAGGCGA
+GTCTTGAGAGCTTCCTTTTGCTTTCTTCTCTTGCCTCTGAGAACATCAGCC
++
+1AAA>FFCA1A1B1EA3311B313A333313311B11B1F1FGCG1FH110
+@M00436:256:000000000-B3PGP:1:1101:15244:2216 2:N:0:TAAGGCGA
+GCCAAGAATGTGTTGTCTAAAATGCCTGTTTAGTTTTCAAGGATGGAACTC
++
+1>>AAAFFD@333B11B3BGGGFAAEA11B3GEAD333FHB1F1EFHH11A
+@M00436:256:000000000-B3PGP:1:1101:12952:2217 2:N:0:TAAGGCGA
+GAACTGGAGCGTGTGGCCAAGTCTAACCGCTGATTTCCCAGCTGCTGCCT
++
+111>AD1CFBDAEA11FFFGAAGFDFGF0EECE1GFHHFGFHHHFHHGFG
+@M00436:256:000000000-B3PGP:1:1101:16915:2218 2:N:0:TAAGGCGA
+ATGCACATGTGGTGTAGGAACTTTTTTCTACCATAAGTGACACCAATAAAT
++
+3>3AAFFFFD@BAFFDFGGGGGHHHHGHGHCHGHHHBFBGGFGGGFHGHHH
+@M00436:256:000000000-B3PGP:1:1101:11613:2220 2:N:0:TAAGGCGA
+TGTGTACTCTGCGTTGATACCACTGCTTCCGCGGACAGGCGTGTAGATCTC
++
+33>AADFFFFFFCGGGGFGGFCHHH4GFHFGDGGGCFFDGGEE1BFFHFH5
+@M00436:256:000000000-B3PGP:1:1101:18615:2225 2:N:0:TAAGGCGA
+CCTATCAGGAGTTCACTGACCACCTCGTCAAGACCCACACCAGAGTCTCCG
++
+>AAAAFFFFFB4FFGGFFGGGGHG4GDHGHGBGHBGHGGGGHGFEDGHHHG
+@M00436:256:000000000-B3PGP:1:1101:11230:2227 2:N:0:TAAGGCGA
+GTACTGTCACTTAACCCCTATTAACATACGGTGTTCAAGCCTTCCAGTATC
++
+?A?AAFFFBDFBFDFFGCGGGGCFHFBDHFG4FE2DFFGHDGBGFGHBGBF
+@M00436:256:000000000-B3PGP:1:1101:14569:2228 2:N:0:TAAGGCGA
+GTGAATGGAAATGCCCCAACTAAATACTACCGTATGGCCCACCATAATTAC
++
+3>AAAFFFBFFFGFGGFEFFGBGHGFHHHHHGGGGFGHHHGGGDH3GGHGH
+@M00436:256:000000000-B3PGP:1:1101:15926:2228 2:N:0:TAAGGCGA
+AATCTAGGAAAATAAAACAAGAGAAGCTGAATTAAAAAAAAAAAAAAAAA
++
+>AAA1FF1BDFFGGGGGFGG111B101ABGHDGGHHHHGGGGGGGGGGGG
+@M00436:256:000000000-B3PGP:1:1101:15169:2228 2:N:0:TAAGGCGA
+GTATCAACGAAAAGTGAGACTCATTGCTGCCCGCCGAAATGAACGGCTGCG
++
+1>A1AFF1>1>AGB11313A11B3331311000A00/A//11B10//////
+@M00436:256:000000000-B3PGP:1:1101:15774:2230 2:N:0:TAAGGCGA
+CCCAAAGACAAGGAAAGGAAAAAATAAAAACAACAAATACCTAAAAGCTG
++
+111>AFF11>C11111111BE0F0011D110000BGC1F1111BGGD011
+@M00436:256:000000000-B3PGP:1:1101:11431:2230 2:N:0:TAAGGCGA
+GAGCTGAACCTGTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++
+111>A1DD1>>1BGGDGGGCEEEEGGGCGGGGGGCEGCEEGCGCGCCCCG
+@M00436:256:000000000-B3PGP:1:1101:19030:2230 2:N:0:TAAGGCGA
+ATCCCATTACTCTCTTTGTGGAGAAGGAACGAGATAAGGAAGTCAGTGATG
++
+1AAAAFFFFBBD3FFAFF3BEGGHHH00FG?EGGGGFFFHHG1FGHDGGHB
+@M00436:256:000000000-B3PGP:1:1101:16869:2231 2:N:0:TAAGGCGA
+CCTTCCACCTGGTCCGGAGATCCCTGGACCTTAGGAGGCACTCATTTTTCC
++
+AAAA1>@D111111A1110A01101100A001BA110A/BC0AG12AA10A
+@M00436:256:000000000-B3PGP:1:1101:12374:2231 2:N:0:TAAGGCGA
+CTTTAGATGGTGGGGACATCATCAATGCCTTGTGCTTCAGCCCCAACCGCT
++
+?AAAAFFFFBBDEEGGEGGGFGHHHG5FGGGHFEDGHHHHGHGGGEGG?EA
+@M00436:256:000000000-B3PGP:1:1101:14609:2232 2:N:0:TAAGGCGA
+TCCTCCTAAGTAACTGGGACTACATATGTGCATCACCACGTCCAGTTAATT
++
+3>>AAFFFFFFFFGGGFAAG4GG4FD5A66DGHBHH4DC22BFE3GH5EFG
+@M00436:256:000000000-B3PGP:1:1101:11898:2233 2:N:0:TAAGGCGA
+GTACTGTAGTCACTCAGTATTTGTATATGTTGCTAGAATTTAGATTGTAA
++
+1A1AAFFFFFFFGBGGGBEF3BF3FFGFFGGGHFBGGFFDGGFFFFHFGF
+@M00436:256:000000000-B3PGP:1:1101:15215:2233 2:N:0:TAAGGCGA
+GTAAAAGAGTATATGTAAACTGAATGAGAACTAAAAAATAGAAATAAAAC
++
+AA1AAFF113@33333BFF1311B3311DF11FGGHH00B11DG1FAGH1
+@M00436:256:000000000-B3PGP:1:1101:18320:2233 2:N:0:TAAGGCGA
+GCATTTAATATTGATACACTTTCACCTCTAAAATGGATTTGAAGAAATGC
++
+111>>DF3BBDFGGGGGG1FBGFFCHHHHGF3ADF1GGHFH2A1AB0BFG
+@M00436:256:000000000-B3PGP:1:1101:13822:2234 2:N:0:TAAGGCGA
+TCCACAAGTACTCTGGCAAGGAAGGAGACAAGCACACCCTGAGCAAGAAGG
++
+BA3ABFA?DFFFFDGGCGGGCGHFE4AGFHBCGFHGFE2EFFFBHHEHBEF
+@M00436:256:000000000-B3PGP:1:1101:12165:2235 2:N:0:TAAGGCGA
+ACCATGCTGTGTCTGTTATGCGGCAAAGCCGAAGATACTAACAGTATTCTC
++
+AA?A@1B11313A3133B311110AEH0000AE0E1F11F21B11D2222A
+@M00436:256:000000000-B3PGP:1:1101:19900:2236 2:N:0:TAAGGCGA
+CCATTTTAGTTCAGGAGTGTTTCCTTATTTTCTCTTTTCTGATAGAGTTT
++
+>>3>AFFFFFFFGGGGCGGABGHHHCFHHGGHHHHHHHHHHHHHGHFHHH
+@M00436:256:000000000-B3PGP:1:1101:11136:2236 2:N:0:TAAGGCGA
+GGAGAGGAGCGAGGCTGAGAGAAGAGAAGAACAATGTACTCATAAAGAAAC
++
+>111111B111110000A0B1AE0F0F101B00B112D2211112111B00
+@M00436:256:000000000-B3PGP:1:1101:15661:2236 2:N:0:TAAGGCGA
+GTGTTGCCCAGGCTGGTCTCAAACTCCTGGGCTCAAGCGATCCTCCCACCT
++
+>A>AABFFFFAAGGGFAFFFFGDEGECGF4FDFHFHHHGGEEEHGGG2FEG
+@M00436:256:000000000-B3PGP:1:1101:20014:2238 2:N:0:TAAGGCGA
+TGTGCATCACAGAGGTGTGCATCACCTTTGACCAGGCTGACCTGACCATC
++
+1111>B3311DDGCC1A1ABGFFHHB1BAGHHHHFEC0FF001FGBHFHH
+@M00436:256:000000000-B3PGP:1:1101:13789:2238 2:N:0:TAAGGCGA
+ACCCTGGACTCTGGACTTCGCAGGTTCCTGCCTGTCACGCCACCCCCTTCC
++
+>A1A11AFFFBF31FGGCGGGGGGCFFHGBGHGHHHHHGHGGGHGGEEGFH
+@M00436:256:000000000-B3PGP:1:1101:11741:2240 2:N:0:TAAGGCGA
+CTCCATCCGGCACCCTGACGTTGAGGTGGATGGGTTCTCTGAGCTTCGGTG
++
+1>1A1FDF11DDEECGGFG?FCGHC0B0AFEGCCGCAGBFGGGGGGFGGFE
+@M00436:256:000000000-B3PGP:1:1101:19980:2240 2:N:0:TAAGGCGA
+GATGTGCGCATTGACACCAGGCTCAACAAAGCTGTCTGGGCCAAAGGAAT
++
+11>1>DBA@AAAGGFFGFGFGGCGHHHHG0FGFHGGHF00/GE/GFFFFH
+@M00436:256:000000000-B3PGP:1:1101:20675:2240 2:N:0:TAAGGCGA
+GGGTCCCTCTGTACTCTGCGTTGATACCACTGCTTCCGCGGACAGGCGTGT
++
+333AAAFFFFFFGGGGGGCFFGGFGHFHHHHHHHGHHGGGGEFGGGGGEGE
+@M00436:256:000000000-B3PGP:1:1101:14624:2241 2:N:0:TAAGGCGA
+TACTTATAAGTCTATCATTTAAAGACATGTACTGAAACAAATGTATTTGTT
++
+A1>AAFFFBDDBG3EFGGGGB3FBGHHHFHHHHHFFGFB0BFGEBGGHHGH
+@M00436:256:000000000-B3PGP:1:1101:11465:2241 2:N:0:TAAGGCGA
+GCCTCACCGGTGACCAGCCTGGACTCGCATGGCAGCACCCAGGGCATGCTG
++
+333AACAFAD>DGGGGGFGGGGHHGHGGEGCHFBEGCHHGGHGG1FGFHHG
+@M00436:256:000000000-B3PGP:1:1101:20263:2242 2:N:0:TAAGGCGA
+GTGTGAATGGGTTTATACTGATTTTGATATCATGTTCTTTTCATAGTCGT
++
+111>ADDFFC?CCFGGGGGFFGFHHHGHHHCHHHHFHCHHHGHHHHHGFG
+@M00436:256:000000000-B3PGP:1:1101:16263:2243 2:N:0:TAAGGCGA
+GAACTATACTGACGAAGCCATTGAAACAGATGATCTGACCATTAAGCTGGT
++
+11>AAFFFFFDFGGGG?GGGGGGGFHHHHHGHHBGHGFBFGGFHGFHFF00
diff --git a/tests/test.hs b/tests/test.hs
--- a/tests/test.hs
+++ b/tests/test.hs
@@ -1,6 +1,7 @@
 import qualified Tests.Bed as Bed
 import qualified Tests.Bam as Bam
 import qualified Tests.Motif as Motif
+import qualified Tests.Fastq as Fastq
 import qualified Tests.Seq as Seq
 import qualified Tests.Tools as Tools
 import Test.Tasty
@@ -12,4 +13,5 @@
     , Seq.tests
     , Motif.tests
     , Tools.tests
+    , Fastq.tests
     ]
