diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2013, IIJ Innovation Institute Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+  * Neither the name of the copyright holders nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Network/HPACK.hs b/Network/HPACK.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK.hs
@@ -0,0 +1,55 @@
+module Network.HPACK (
+  -- * Type
+    ByteStream
+  , HeaderSet
+  , Context
+  , newContext
+  , DecodeError(..)
+  -- * Request
+  , encodeRequestHeader
+  , decodeRequestHeader
+  -- * Response
+  , encodeResponseHeader
+  , decodeResponseHeader
+  ) where
+
+import Control.Applicative ((<$>))
+import Control.Arrow (first)
+import Network.HPACK.Context
+import Network.HPACK.HeaderBlock
+import Network.HPACK.Huffman
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Converting 'HeaderSet' for HTTP request to the low level format.
+encodeRequestHeader :: HeaderSet
+                    -> Context
+                    -> IO (ByteStream, Context)
+encodeRequestHeader hs ctx =
+    first (toByteStream huffmanEncodeInRequest) <$> toHeaderBlock hs ctx
+
+-- | Converting the low level format for HTTP request to 'HeaderSet'.
+--   'DecodeError' would be thrown.
+decodeRequestHeader :: ByteStream
+                    -> Context
+                    -> IO (HeaderSet, Context)
+decodeRequestHeader bs ctx =
+    fromHeaderBlock (fromByteStream huffmanDecodeInRequest bs) ctx
+
+----------------------------------------------------------------
+
+-- | Converting 'HeaderSet' for HTTP response to the low level format.
+encodeResponseHeader :: HeaderSet
+                     -> Context
+                     -> IO (ByteStream, Context)
+encodeResponseHeader hs ctx =
+    first (toByteStream huffmanEncodeInResponse) <$> toHeaderBlock hs ctx
+
+-- | Converting the low level format for HTTP response to 'HeaderSet'.
+--   'DecodeError' would be thrown.
+decodeResponseHeader :: ByteStream
+                    -> Context
+                    -> IO (HeaderSet, Context)
+decodeResponseHeader bs ctx =
+    fromHeaderBlock (fromByteStream huffmanDecodeInResponse bs) ctx
diff --git a/Network/HPACK/Context.hs b/Network/HPACK/Context.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Context.hs
@@ -0,0 +1,169 @@
+{-# LANGUAGE BangPatterns #-}
+
+module Network.HPACK.Context (
+  -- * Types
+    HeaderSet   -- re-exporting
+  , Context
+  , newContext
+  , DecodeError(..)
+  , printContext
+  -- * Initialization and final results
+  , clearHeaderSet
+  , getHeaderSet
+  , emitNotEmitted
+  -- * Processing
+  , clearRefSets
+  , removeRef
+  , newEntry
+  , pushRef
+  , emitOnly
+  -- * Auxiliary functions
+  , isPresentIn
+  , getEntry
+  -- * Table
+  , whichTable
+  , lookupHeader
+  ) where
+
+import Control.Applicative ((<$>))
+import Network.HPACK.Context.HeaderSet
+import Network.HPACK.Context.ReferenceSet
+import Network.HPACK.Table
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Context for encoding/decoding.
+data Context = Context {
+    headerTable     :: !HeaderTable -- ^ A cache of headers
+  , oldReferenceSet :: ReferenceSet -- ^ References for not emitted
+  , newReferenceSet :: ReferenceSet -- ^ References for already mitted
+  , headerSet       :: HeaderSet    -- ^ Emitted header set.
+                                    --   Encode: the previous ones.
+                                    --   Decode: the results.
+  }
+
+-- | Printing 'Context'
+printContext :: Context -> IO ()
+printContext (Context hdrtbl oldref newref hdrset) = do
+    putStrLn "<<<Header table>>>"
+    printHeaderTable hdrtbl
+    putStr "\n"
+    putStrLn "<<<Reference set (old)>>>"
+    print $ getIndices oldref
+    putStr "\n"
+    putStrLn "<<<Reference set (new)>>>"
+    print $ getIndices newref
+    putStr "\n"
+    putStrLn "<<<Headers>>>"
+    printHeaderSet hdrset
+
+----------------------------------------------------------------
+
+-- | Creating a new 'Context'.
+--   The first argument is the size of 'HeaderTable'.
+newContext :: Size -> IO Context
+newContext maxsiz = do
+    hdrtbl <- newHeaderTable maxsiz
+    return $ Context hdrtbl
+                     emptyReferenceSet
+                     emptyReferenceSet
+                     emptyHeaderSet
+
+----------------------------------------------------------------
+
+-- | The reference set is emptied.
+clearRefSets :: Context -> IO Context
+clearRefSets ctx = return ctx {
+    oldReferenceSet = emptyReferenceSet
+  , newReferenceSet = emptyReferenceSet
+  }
+
+-- | The entry is removed from the reference set.
+removeRef :: Context -> Index -> IO Context
+removeRef ctx idx = return ctx { oldReferenceSet = removeIndex idx oldref }
+  where
+    oldref = oldReferenceSet ctx
+
+-- | The header field is emitted.
+--   The header field is inserted at the beginning of the header table.
+--   A reference to the new entry is added to the reference set.
+newEntry :: Context -> Entry -> IO Context
+newEntry (Context hdrtbl oldref newref hdrset) e = do
+    (hdrtbl', is) <- insertEntry e hdrtbl
+    let oldref' = removeIndices is $ adjustReferenceSet oldref
+        newref' = addIndex 1 $ removeIndices is $ adjustReferenceSet newref
+        hdrset' = insertHeader (fromEntry e) hdrset
+    return $ Context hdrtbl' oldref' newref' hdrset'
+
+-- | The header field corresponding to the referenced entry is emitted.
+--   The referenced header table entry is added to the reference set.
+pushRef :: Context -> Index -> Entry -> IO Context
+pushRef (Context hdrtbl oldref newref hdrset) idx e = return ctx
+  where
+    hdrset' = insertHeader (fromEntry e) hdrset
+    newref' = addIndex idx newref
+    ctx = Context hdrtbl oldref newref' hdrset'
+
+-- | The header field is emitted.
+emitOnly :: Context -> Header -> IO Context
+emitOnly (Context hdrtbl oldref newref hdrset) h = return ctx
+  where
+    hdrset' = insertHeader h hdrset
+    ctx = Context hdrtbl oldref newref hdrset'
+
+----------------------------------------------------------------
+
+-- | Emitting non-emitted headers.
+emitNotEmitted :: Context -> IO Context
+emitNotEmitted ctx = emit ctx <$> getNotEmitted ctx
+
+-- | Emit non-emitted headers.
+emit :: Context -> HeaderSet -> Context
+emit (Context hdrtbl oldref newref hdrset) notEmitted = ctx
+  where
+    hdrset' = meregeHeaderSet hdrset notEmitted
+    oldref' = mergeReferenceSet newref oldref
+    ctx = Context hdrtbl oldref' emptyReferenceSet hdrset'
+
+getNotEmitted :: Context -> IO HeaderSet
+getNotEmitted ctx = do
+    let is = getIndices $ oldReferenceSet ctx
+        hdrtbl = headerTable ctx
+    map (fromEntry . snd) <$> mapM (which hdrtbl) is
+
+----------------------------------------------------------------
+
+-- | Is 'Index' present in the reference set?
+isPresentIn :: Index -> Context -> Bool
+isPresentIn idx ctx = idx `isMember` oldref
+  where
+    oldref = oldReferenceSet ctx
+
+----------------------------------------------------------------
+
+-- | Which table does 'Index' refer to?
+whichTable :: Index -> Context -> IO (WhichTable, Entry)
+whichTable idx ctx = which hdrtbl idx
+  where
+    hdrtbl = headerTable ctx
+
+-- | Which table contains 'Header'?
+lookupHeader :: Header -> Context -> IO HeaderCache
+lookupHeader h ctx = lookupTable h (headerTable ctx)
+
+----------------------------------------------------------------
+
+-- | Getting 'Entry' by 'Index'.
+getEntry :: Index -> Context -> IO Entry
+getEntry idx ctx = snd <$> whichTable idx ctx
+
+----------------------------------------------------------------
+
+-- | Clearing 'HeaderSet' in 'Context' for the next decode.
+clearHeaderSet :: Context -> Context
+clearHeaderSet ctx = ctx { headerSet = emptyHeaderSet }
+
+-- | Getting 'HeaderSet' as emitted headers.
+getHeaderSet :: Context -> HeaderSet
+getHeaderSet = headerSet
diff --git a/Network/HPACK/Context/HeaderSet.hs b/Network/HPACK/Context/HeaderSet.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Context/HeaderSet.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Network.HPACK.Context.HeaderSet where
+
+import qualified Data.ByteString.Char8 as BS
+import Network.HPACK.Table
+import Network.HPACK.Types
+
+-- | Header set.
+type HeaderSet = [Header]
+
+-- | Empty header set.
+emptyHeaderSet :: HeaderSet
+emptyHeaderSet = []
+
+-- | Printing 'HeaderSet'.
+printHeaderSet :: HeaderSet -> IO ()
+printHeaderSet hs = mapM_ printHeader hs
+  where
+    printHeader (k,v) = do
+        BS.putStr $ fromHeaderName k
+        putStr ": "
+        BS.putStr v
+        putStr "\n"
+
+-- | Merging the emitted header set and the non-emitted header set.
+meregeHeaderSet :: HeaderSet -> HeaderSet -> HeaderSet
+meregeHeaderSet hdrset notEmitted = reverse $ notEmitted ++ hdrset
+
+-- | Inserting 'Header' to 'HeaderSet'.
+insertHeader :: Header -> HeaderSet -> HeaderSet
+insertHeader = (:)
+
diff --git a/Network/HPACK/Context/ReferenceSet.hs b/Network/HPACK/Context/ReferenceSet.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Context/ReferenceSet.hs
@@ -0,0 +1,58 @@
+module Network.HPACK.Context.ReferenceSet (
+  -- * Type
+    ReferenceSet
+  , emptyReferenceSet
+  -- * Index and reference set
+  , getIndices
+  , isMember
+  , addIndex
+  , removeIndex
+  , removeIndices
+  -- * Managing reference set
+  , adjustReferenceSet
+  , mergeReferenceSet
+  ) where
+
+import Data.List (delete, (\\))
+import Network.HPACK.Table
+
+----------------------------------------------------------------
+
+-- | Type for the reference set.
+data ReferenceSet = ReferenceSet [Index] deriving Show
+
+-- | Empty reference set.
+emptyReferenceSet :: ReferenceSet
+emptyReferenceSet = ReferenceSet []
+
+----------------------------------------------------------------
+
+-- | Get all 'Index' from 'ReferenceSet'.
+getIndices :: ReferenceSet -> [Index]
+getIndices (ReferenceSet is) = is
+
+-- | Is 'Index' a member of 'ReferenceSet'?
+isMember :: Index -> ReferenceSet -> Bool
+isMember idx (ReferenceSet is) = idx `elem` is
+
+-- | Adding 'Index' to 'ReferenceSet'.
+addIndex :: Index -> ReferenceSet -> ReferenceSet
+addIndex idx (ReferenceSet is) = ReferenceSet $ idx : is
+
+-- | Removing 'Index' from 'ReferenceSet'.
+removeIndex :: Index -> ReferenceSet -> ReferenceSet
+removeIndex idx (ReferenceSet is) = ReferenceSet $ delete idx is
+
+-- | Removing a set of 'Index' from 'ReferenceSet'.
+removeIndices :: [Index] -> ReferenceSet -> ReferenceSet
+removeIndices idcs (ReferenceSet is) = ReferenceSet $ is \\ idcs
+
+----------------------------------------------------------------
+
+-- | Incrementing all 'Index' by one.
+adjustReferenceSet :: ReferenceSet -> ReferenceSet
+adjustReferenceSet (ReferenceSet is) = ReferenceSet $ map (+1) is
+
+-- | Merging two 'ReferenceSet'.
+mergeReferenceSet :: ReferenceSet -> ReferenceSet -> ReferenceSet
+mergeReferenceSet (ReferenceSet xs) (ReferenceSet ys) = ReferenceSet $ xs ++ ys
diff --git a/Network/HPACK/HeaderBlock.hs b/Network/HPACK/HeaderBlock.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock.hs
@@ -0,0 +1,16 @@
+module Network.HPACK.HeaderBlock (
+  -- * Types for header block
+    module Network.HPACK.HeaderBlock.HeaderField
+  -- * Header block from/to Low level
+  , toByteStream
+  , fromByteStream
+  -- * Header block from/to header set
+  , toHeaderBlock
+  , fromHeaderBlock
+  ) where
+
+import Network.HPACK.HeaderBlock.Decode
+import Network.HPACK.HeaderBlock.Encode
+import Network.HPACK.HeaderBlock.From
+import Network.HPACK.HeaderBlock.HeaderField
+import Network.HPACK.HeaderBlock.To
diff --git a/Network/HPACK/HeaderBlock/Decode.hs b/Network/HPACK/HeaderBlock/Decode.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/Decode.hs
@@ -0,0 +1,92 @@
+module Network.HPACK.HeaderBlock.Decode (
+    fromByteStream
+  ) where
+
+import Data.Bits (testBit, clearBit, (.&.))
+import qualified Data.ByteString as BS
+import Data.Word (Word8)
+import Network.HPACK.HeaderBlock.HeaderField
+import qualified Network.HPACK.HeaderBlock.Integer as I
+import qualified Network.HPACK.HeaderBlock.String as S
+import Network.HPACK.Huffman
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Converting the low level format to 'HeaderBlock'.
+fromByteStream :: HuffmanDecoding -> ByteStream -> HeaderBlock
+fromByteStream hd bs = go $ BS.unpack bs
+  where
+    go [] = []
+    go ws = hf : go ws'
+       where
+         (hf, ws') = toHeaderField hd ws
+
+toHeaderField :: HuffmanDecoding -> [Word8] -> (HeaderField, [Word8])
+toHeaderField _  []     = error "toHeaderField"
+toHeaderField hd (w:ws)
+  | w `testBit` 7 = indexed w ws
+  | w `testBit` 6 = withoutIndexing hd w ws
+  | otherwise     = incrementalIndexing hd w ws
+
+----------------------------------------------------------------
+
+indexed :: Word8 -> [Word8] -> (HeaderField, [Word8])
+indexed w ws = (Indexed idx , ws)
+  where
+    idx = fromIntegral $ clearBit w 7
+
+withoutIndexing :: HuffmanDecoding -> Word8 -> [Word8] -> (HeaderField, [Word8])
+withoutIndexing hd w ws
+  | isIndexedName w = indexedName NotAdd hd w ws
+  | otherwise       = newName NotAdd hd ws
+
+incrementalIndexing :: HuffmanDecoding -> Word8 -> [Word8] -> (HeaderField, [Word8])
+incrementalIndexing hd w ws
+  | isIndexedName w = indexedName Add hd w ws
+  | otherwise       = newName Add hd ws
+
+----------------------------------------------------------------
+
+indexedName :: Indexing -> HuffmanDecoding -> Word8 -> [Word8] -> (HeaderField, [Word8])
+indexedName indexing hd w ws = (hf, ws'')
+  where
+    p = mask6 w
+    (idx,ws') = I.parseInteger 6 p ws
+    (val,ws'') = headerStuff hd ws'
+    hf = Literal indexing (Idx idx) val
+
+newName :: Indexing -> HuffmanDecoding -> [Word8] -> (HeaderField, [Word8])
+newName indexing hd ws = (hf, ws'')
+  where
+    (key,ws')  = headerStuff hd ws
+    (val,ws'') = headerStuff hd ws'
+    name = toHeaderName key
+    hf = Literal indexing (Lit name) val
+
+----------------------------------------------------------------
+
+headerStuff :: HuffmanDecoding -> [Word8] -> (HeaderStuff, [Word8])
+headerStuff _  []     = error "headerStuff"
+headerStuff hd (w:ws) = (hs, ws'')
+  where
+    p = dropHuffman w
+    huff = isHuffman w
+    (len, ws') = I.parseInteger 7 p ws
+    (hs, ws'') = S.parseString hd huff len ws'
+
+----------------------------------------------------------------
+
+mask6 :: Word8 -> Word8
+mask6 w = w .&. 63
+
+isIndexedName :: Word8 -> Bool
+isIndexedName w = mask6 w /= 0
+
+----------------------------------------------------------------
+
+isHuffman :: Word8 -> Bool
+isHuffman w = w `testBit` 7
+
+dropHuffman :: Word8 -> Word8
+dropHuffman w = w `clearBit` 7
diff --git a/Network/HPACK/HeaderBlock/Encode.hs b/Network/HPACK/HeaderBlock/Encode.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/Encode.hs
@@ -0,0 +1,75 @@
+module Network.HPACK.HeaderBlock.Encode (
+    toByteStream
+  ) where
+
+import Blaze.ByteString.Builder (Builder)
+import qualified Blaze.ByteString.Builder as BB
+import Data.Bits (setBit)
+import Data.List (foldl')
+import Data.Monoid ((<>), mempty)
+import Data.Word (Word8)
+import Network.HPACK.HeaderBlock.HeaderField
+import qualified Network.HPACK.HeaderBlock.Integer as I
+import qualified Network.HPACK.HeaderBlock.String as S
+import Network.HPACK.Huffman
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Converting 'HeaderBlock' to the low level format.
+toByteStream :: HuffmanEncoding -> HeaderBlock -> ByteStream
+toByteStream he hbs = BB.toByteString $ foldl' (<>) mempty $ map toBB hbs
+  where
+    toBB = fromHeaderField he
+
+fromHeaderField :: HuffmanEncoding -> HeaderField -> Builder
+fromHeaderField _  (Indexed idx)                = index idx
+fromHeaderField he (Literal NotAdd (Idx idx) v) = indexedName he set01 idx v
+fromHeaderField he (Literal NotAdd (Lit key) v) = newName     he set01 key v
+fromHeaderField he (Literal Add    (Idx idx) v) = indexedName he set00 idx v
+fromHeaderField he (Literal Add    (Lit key) v) = newName     he set00 key v
+
+----------------------------------------------------------------
+
+index :: Int -> Builder
+index = BB.fromWord8 . set1 . I.encodeOne
+
+-- Using Huffman encoding
+indexedName :: HuffmanEncoding -> Setter -> Int -> HeaderValue -> Builder
+indexedName he set idx v = pre <> vlen <> val
+  where
+    (p:ps) = I.encode 6 idx
+    pre = BB.fromWord8s $ set p : ps
+    value = S.encode he v
+    valueLen = length value -- FIXME: performance
+    vlen = BB.fromWord8s $ setH $ I.encode 7 valueLen
+    val = BB.fromWord8s value
+
+-- Using Huffman encoding
+newName :: HuffmanEncoding -> Setter -> HeaderName -> HeaderValue -> Builder
+newName he set ck v = pre <> klen <> key <> vlen <> val
+  where
+    pre = BB.fromWord8 $ set 0
+    k = fromHeaderName ck
+    key0 = S.encode he k
+    keyLen = length key0 -- FIXME: performance
+    value = S.encode he v
+    valueLen = length value -- FIXME: performance
+    klen = BB.fromWord8s $ setH $ I.encode 7 keyLen
+    vlen = BB.fromWord8s $ setH $ I.encode 7 valueLen
+    key = BB.fromWord8s key0
+    val = BB.fromWord8s value
+
+----------------------------------------------------------------
+
+type Setter = Word8 -> Word8
+
+-- Assuming MSBs are 0.
+set1, set01, set00 :: Setter
+set1  x = x `setBit` 7
+set01 x = x `setBit` 6
+set00   = id
+
+setH :: [Word8] -> [Word8]
+setH []     = error "setH"
+setH (x:xs) = (x `setBit` 7) : xs
diff --git a/Network/HPACK/HeaderBlock/From.hs b/Network/HPACK/HeaderBlock/From.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/From.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE BangPatterns #-}
+
+module Network.HPACK.HeaderBlock.From (
+    fromHeaderBlock
+  , decodeStep
+  ) where
+
+import Control.Applicative ((<$>))
+import Network.HPACK.Context
+import Network.HPACK.HeaderBlock.HeaderField
+import Network.HPACK.Table
+
+----------------------------------------------------------------
+
+-- | Decoding 'HeaderBlock' to 'HeaderSet'.
+fromHeaderBlock :: HeaderBlock
+                -> Context
+                -> IO (HeaderSet, Context)
+fromHeaderBlock (r:rs) !ctx = decodeStep ctx r >>= fromHeaderBlock rs
+fromHeaderBlock []     !ctx = decodeFinal ctx
+
+----------------------------------------------------------------
+
+-- | Decoding step for one 'HeaderField'. Exporting for the
+--   test purpose.
+decodeStep :: Context -> HeaderField -> IO Context
+decodeStep !ctx (Indexed idx)
+  | idx == 0  = clearRefSets ctx
+  | isPresent = removeRef ctx idx
+  | otherwise = do
+      w <- whichTable idx ctx
+      case w of
+          (InStaticTable, e) -> newEntry ctx e
+          (InHeaderTable, e) -> pushRef ctx idx e
+  where
+    isPresent = idx `isPresentIn` ctx
+decodeStep !ctx (Literal NotAdd naming v) = do
+    k <- fromNaming naming ctx
+    emitOnly ctx (k,v)
+decodeStep !ctx (Literal Add naming v) = do
+    k <- fromNaming naming ctx
+    newEntry ctx $ toEntry (k,v)
+
+decodeFinal :: Context -> IO (HeaderSet, Context)
+decodeFinal ctx = do
+    !ctx' <- emitNotEmitted ctx
+    let !hs = getHeaderSet ctx'
+        !ctx'' = clearHeaderSet ctx'
+    return (hs, ctx'')
+
+----------------------------------------------------------------
+
+fromNaming :: Naming -> Context -> IO HeaderName
+fromNaming (Lit k)   _   = return k
+fromNaming (Idx idx) ctx = entryHeaderName <$> getEntry idx ctx
diff --git a/Network/HPACK/HeaderBlock/HeaderField.hs b/Network/HPACK/HeaderBlock/HeaderField.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/HeaderField.hs
@@ -0,0 +1,33 @@
+module Network.HPACK.HeaderBlock.HeaderField (
+  -- * Type
+    HeaderBlock
+  , emptyHeaderBlock
+  , HeaderField(..)
+  , HeaderName  -- re-exporting
+  , HeaderValue -- re-exporting
+  , Index       -- re-exporting
+  , Indexing(..)
+  , Naming(..)
+  ) where
+
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Type for header block.
+type HeaderBlock = [HeaderField]
+
+-- | Empty header block.
+emptyHeaderBlock :: HeaderBlock
+emptyHeaderBlock = []
+
+-- | Type for representation.
+data HeaderField = Indexed Index
+                 | Literal Indexing Naming HeaderValue
+                 deriving (Eq,Show)
+
+-- | Whether or not adding to a table.
+data Indexing = Add | NotAdd deriving (Eq,Show)
+
+-- | Index or literal.
+data Naming = Idx Index | Lit HeaderName deriving (Eq,Show)
diff --git a/Network/HPACK/HeaderBlock/Integer.hs b/Network/HPACK/HeaderBlock/Integer.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/Integer.hs
@@ -0,0 +1,86 @@
+module Network.HPACK.HeaderBlock.Integer (
+    encode
+  , encodeOne
+  , decode
+  , decodeOne
+  , parseInteger
+  ) where
+
+import Data.Array (Array, listArray, (!))
+import Data.Word (Word8)
+
+----------------------------------------------------------------
+
+powerArray :: Array Int Int
+powerArray = listArray (1,8) [1,3,7,15,31,63,127,255]
+
+----------------------------------------------------------------
+
+-- | Integer encoding. The first argument is N of prefix.
+--
+-- >>> encode 5 10
+-- [10]
+-- >>> encode 5 1337
+-- [31,154,10]
+-- >>> encode 8 42
+-- [42]
+encode :: Int -> Int -> [Word8]
+encode n i
+  | i < p     = fromIntegral i : []
+  | otherwise = fromIntegral p : encode' (i - p)
+  where
+    p = powerArray ! n
+
+encode' :: Int -> [Word8]
+encode' i
+  | i < 128   = fromIntegral i : []
+  | otherwise = fromIntegral (r + 128) : encode' q
+  where
+    (q,r) = i `divMod` 128
+
+----------------------------------------------------------------
+
+-- | Integer encoding.
+encodeOne :: Int -> Word8
+encodeOne = fromIntegral
+
+----------------------------------------------------------------
+
+-- | Integer decoding. The first argument is N of prefix.
+--
+-- >>> decode 5 [10]
+-- 10
+-- >>> decode 5 [31,154,10]
+-- 1337
+-- >>> decode 8 [42]
+-- 42
+decode :: Int -> [Word8] -> Int
+decode _ []     = error "decode"
+decode n ws
+  | i < p     = i
+  | otherwise = foldr1 (\x y -> x - 128 + y * 128) is + i
+  where
+    p = powerArray ! n
+    (i:is) = map fromIntegral ws
+
+-- | Integer decoding.
+decodeOne :: Word8 -> Int
+decodeOne = fromIntegral
+
+----------------------------------------------------------------
+
+parseInteger :: Int -> Word8 -> [Word8] -> (Int, [Word8])
+parseInteger n w ws
+  | i < p     = (i, ws)
+  | otherwise = (len, rest)
+  where
+    p = powerArray ! n
+    i = fromIntegral w
+    (ws', rest) = split ws
+    len = decode n (w:ws')
+
+split :: [Word8] -> ([Word8],[Word8])
+split []     = error "split"
+split (w:ws)
+  | w >= 128  = let (xs,ys) = split ws in (w:xs, ys)
+  | otherwise = ([w], ws)
diff --git a/Network/HPACK/HeaderBlock/String.hs b/Network/HPACK/HeaderBlock/String.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/String.hs
@@ -0,0 +1,19 @@
+module Network.HPACK.HeaderBlock.String where
+
+import qualified Data.ByteString as BS
+import Data.Word (Word8)
+import Network.HPACK.Huffman
+import Network.HPACK.Types
+
+encode :: HuffmanEncoding -> HeaderStuff -> [Word8]
+encode he h = he $ BS.unpack h
+
+decode :: HuffmanDecoding -> [Word8] -> HeaderStuff
+decode hd ws = BS.pack $ hd ws
+
+parseString :: HuffmanDecoding -> Bool -> Int -> [Word8] -> (HeaderStuff, [Word8])
+parseString hd isHuffman len ws = (conv es, ws')
+  where
+    (es, ws') = splitAt len ws
+    conv | isHuffman = decode hd
+         | otherwise = BS.pack
diff --git a/Network/HPACK/HeaderBlock/To.hs b/Network/HPACK/HeaderBlock/To.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/HeaderBlock/To.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE BangPatterns #-}
+
+module Network.HPACK.HeaderBlock.To (
+    toHeaderBlock
+  ) where
+
+import Control.Applicative ((<$>))
+import Network.HPACK.Context
+import Network.HPACK.HeaderBlock.HeaderField
+import Network.HPACK.Table
+
+-- | Encoding 'HeaderSet' to 'HeaderBlock'.
+toHeaderBlock :: HeaderSet
+              -> Context
+              -> IO (HeaderBlock, Context)
+toHeaderBlock hs !ctx = encodeInit ctx >>= toHeaderBlock' hs
+
+toHeaderBlock' :: HeaderSet
+               -> (DL, Context)
+               -> IO (HeaderBlock, Context)
+toHeaderBlock' (h:hs) !ctx = encodeStep ctx h >>= toHeaderBlock' hs
+toHeaderBlock' []     !ctx = encodeFinal ctx
+
+----------------------------------------------------------------
+-- A simple encoding strategy to reset the reference set first
+-- by 'Index 0' and uses indexing as much as possible.
+
+encodeStep :: (DL,Context) -> Header -> IO (DL,Context)
+encodeStep (!dl,!ctx) h@(k,v) = do
+    cache <- lookupHeader h ctx
+    let e = toEntry h
+    case cache of
+        None -> do
+            let dl' = dl << Literal Add (Lit k) v
+            ctx' <- newEntry ctx e
+            return (dl', ctx')
+        KeyOnly InStaticTable i  -> do
+            let dl' = dl << Literal Add (Idx i) v
+            ctx' <- newEntry ctx e
+            return (dl', ctx')
+        KeyOnly InHeaderTable i  -> do
+            let dl' = dl << Literal Add (Idx i) v
+            ctx' <- newEntry ctx e
+            return (dl', ctx')
+        KeyValue InStaticTable i -> do
+            let dl' = dl << Indexed i
+            ctx' <- newEntry ctx e
+            return (dl', ctx')
+        KeyValue InHeaderTable i -> do
+            let dl' = dl << Indexed i
+            ctx' <- pushRef ctx i e
+            return (dl', ctx')
+
+encodeInit :: Context -> IO (DL, Context)
+encodeInit ctx = do
+    ctx' <- clearHeaderSet <$> clearRefSets ctx
+    let initialHeaderBlock = initResult $ Indexed 0
+    return (initialHeaderBlock, ctx')
+
+encodeFinal :: (DL, Context) -> IO (HeaderBlock, Context)
+encodeFinal (dl,ctx) = do
+    !ctx' <- emitNotEmitted ctx
+    let !hb = getResult dl
+    return (hb, ctx')
+
+----------------------------------------------------------------
+
+type DL = HeaderBlock -> HeaderBlock
+
+(<<) :: DL -> HeaderField -> DL
+dl << entry = dl . (entry :)
+
+initResult :: HeaderField -> DL
+initResult hf = (hf :)
+
+getResult :: DL -> HeaderBlock
+getResult dl = dl []
diff --git a/Network/HPACK/Huffman.hs b/Network/HPACK/Huffman.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Huffman.hs
@@ -0,0 +1,14 @@
+module Network.HPACK.Huffman (
+  -- * Type
+    HuffmanEncoding
+  , HuffmanDecoding
+  -- * Encoding/decoding
+  , huffmanEncodeInRequest
+  , huffmanDecodeInRequest
+  , huffmanEncodeInResponse
+  , huffmanDecodeInResponse
+  ) where
+
+import Network.HPACK.Huffman.Request
+import Network.HPACK.Huffman.Response
+import Network.HPACK.Huffman.Code
diff --git a/Network/HPACK/Huffman/Bit.hs b/Network/HPACK/Huffman/Bit.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Huffman/Bit.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE BangPatterns #-}
+
+module Network.HPACK.Huffman.Bit (
+    B(..)
+  , Bits
+  , fromBits
+  , toBits
+  ) where
+
+import Data.List (foldl')
+import Data.Word (Word8)
+
+-- | Data type for Bit.
+data B = F -- ^ Zero
+       | T -- ^ One
+       deriving (Eq,Ord,Show)
+
+fromBit :: B -> Word8
+fromBit F = 0
+fromBit T = 1
+
+toBit :: Word8 -> B
+toBit 0 = F
+toBit 1 = T
+toBit _ = error "toBit"
+
+-- | Bit sequence.
+type Bits = [B]
+
+-- | From 'Bits' of length 8 to 'Word8'.
+--
+-- >>> fromBits [T,F,T,F,T,F,T,F]
+-- 170
+-- >>> fromBits [F,T,F,T,F,T,F,T]
+-- 85
+fromBits :: Bits -> Word8
+fromBits = foldl' (\x y -> x * 2 + y) 0 . map fromBit
+
+-- | From 'Word8' to 'Bits' of length 8.
+--
+-- >>> toBits 170
+-- [T,F,T,F,T,F,T,F]
+-- >>> toBits 85
+-- [F,T,F,T,F,T,F,T]
+toBits :: Word8 -> Bits
+toBits = toBits' [] 0
+
+toBits' :: Bits -> Int -> Word8 -> Bits
+toBits' bs !cnt 0
+  | cnt == 8      = bs
+  | otherwise     = replicate (8 - cnt) F ++ bs -- filling missing bits from MSB
+toBits' bs !cnt x = toBits' (b:bs) (cnt + 1) q
+  where
+    q = x `div` 2
+    r = x `mod` 2
+    b = toBit r
diff --git a/Network/HPACK/Huffman/Code.hs b/Network/HPACK/Huffman/Code.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Huffman/Code.hs
@@ -0,0 +1,90 @@
+module Network.HPACK.Huffman.Code (
+  -- * Huffman encoding
+    Encoder
+  , toEncoder
+  , HuffmanEncoding
+  , encode
+  -- * Huffman decoding
+  , Decoder
+  , toDecoder
+  , HuffmanDecoding
+  , decode
+  ) where
+
+import Control.Arrow (second)
+import Data.Array (Array, (!), listArray)
+import Data.List (partition)
+import Data.Word (Word8)
+import Network.HPACK.Huffman.Bit
+
+----------------------------------------------------------------
+
+-- | Huffman encoding.
+type HuffmanEncoding = [Word8] -> [Word8]
+
+-- | Huffman decoding.
+type HuffmanDecoding = [Word8] -> [Word8]
+
+----------------------------------------------------------------
+
+-- | Type for Huffman encoding.
+newtype Encoder = Encoder (Array Int Bits)
+
+idxEos :: Int
+idxEos = 256
+
+enc :: Encoder -> Int -> Bits
+enc (Encoder ary) i = ary ! i
+
+-- | Creating 'Encoder'.
+toEncoder :: [Bits] -> Encoder
+toEncoder bs = Encoder $ listArray (0,idxEos) bs
+
+-- | Huffman encoding.
+encode :: Encoder -> HuffmanEncoding
+encode encoder ws = map fromBits $ group8 bits
+  where
+    bits = concatMap (enc encoder . fromIntegral) ws
+    group8 xs
+      | null zs   = eos ys : []
+      | otherwise = ys : group8 zs
+      where
+        (ys,zs) = splitAt 8 xs
+    eos xs
+      | length xs == 8 = xs
+      | otherwise      = take 8 (xs ++ enc encoder idxEos)
+
+----------------------------------------------------------------
+
+-- | Type for Huffman decoding.
+data Decoder = Tip Int | Bin Decoder Decoder deriving Show
+
+dec :: Decoder -> Bits -> (Int,Bits)
+dec (Tip i)   xs     = (i,xs)
+dec (Bin l _) (F:xs) = dec l xs
+dec (Bin _ r) (T:xs) = dec r xs
+dec _         []     = (-1,[])
+
+-- | Creating 'Decoder'.
+toDecoder :: [Bits] -> Decoder
+toDecoder decoder = build $ zip [0..idxEos] decoder
+
+build :: [(Int,Bits)] -> Decoder
+build [(i,[])]    = Tip i
+build xs = Bin (build fs) (build ts)
+  where
+    (fs',ts') = partition ((==) F . head . snd) xs
+    fs = map (second tail) fs'
+    ts = map (second tail) ts'
+
+-- | Huffman decoding.
+decode :: Decoder -> HuffmanDecoding
+decode decoder ws = decodeBits decoder (concatMap toBits ws)
+
+decodeBits :: Decoder -> Bits -> [Word8]
+decodeBits _       [] = []
+decodeBits decoder xs
+  | i < 0             = []
+  | otherwise         = fromIntegral i : decodeBits decoder ys
+  where
+    (i,ys) = dec decoder xs
diff --git a/Network/HPACK/Huffman/Request.hs b/Network/HPACK/Huffman/Request.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Huffman/Request.hs
@@ -0,0 +1,288 @@
+module Network.HPACK.Huffman.Request (
+    huffmanEncodeInRequest
+  , huffmanDecodeInRequest
+  ) where
+
+import Network.HPACK.Huffman.Bit
+import Network.HPACK.Huffman.Code
+
+----------------------------------------------------------------
+
+encoderForRequest :: Encoder
+encoderForRequest = toEncoder huffmanRequest
+
+-- | Hoffman encoding in HTTP/2.0 request.
+huffmanEncodeInRequest :: HuffmanEncoding
+huffmanEncodeInRequest = encode encoderForRequest
+
+----------------------------------------------------------------
+
+decoderForRequest :: Decoder
+decoderForRequest = toDecoder huffmanRequest
+
+-- | Hoffman decoding in HTTP/2.0 request.
+huffmanDecodeInRequest :: HuffmanDecoding
+huffmanDecodeInRequest = decode decoderForRequest
+
+----------------------------------------------------------------
+
+huffmanRequest :: [Bits]
+huffmanRequest = [
+    [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T]
+  , [T,T,T,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,F,F,T,F,F]
+  , [T,T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,F,T,F,F,T]
+  , [T,F,F,T,F,T]
+  , [F,F,T,F,F]
+  , [F,F,F,F]
+  , [F,F,T,F,T]
+  , [F,F,T,T,F]
+  , [F,F,T,T,T]
+  , [T,F,F,T,T,F]
+  , [T,F,F,T,T,T]
+  , [T,F,T,F,F,F]
+  , [T,F,T,F,F,T]
+  , [T,F,T,F,T,F]
+  , [T,F,T,F,T,T]
+  , [T,F,T,T,F,F]
+  , [T,T,T,T,F,T,T,F,F]
+  , [T,T,T,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [T,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,F,T,T,T,T]
+  , [T,T,T,F,T,F,T,T]
+  , [T,T,T,F,T,T,F,F]
+  , [T,T,T,F,T,T,F,T]
+  , [T,T,T,F,T,T,T,F]
+  , [T,T,T,F,F,F,F]
+  , [T,T,T,T,F,T,T,T,F]
+  , [T,T,T,T,F,T,T,T,T]
+  , [T,T,T,T,T,F,F,F,F]
+  , [T,T,T,T,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,F,F,T,F]
+  , [T,T,T,F,T,T,T,T]
+  , [T,T,T,T,T,F,F,T,T]
+  , [T,T,T,T,T,F,T,F,F]
+  , [T,T,T,T,T,F,T,F,T]
+  , [T,T,T,T,T,F,T,T,F]
+  , [T,T,T,T,T,F,T,T,T]
+  , [T,T,T,T,F,F,F,F]
+  , [T,T,T,T,F,F,F,T]
+  , [T,T,T,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,F,F,T]
+  , [T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [F,T,F,F,F]
+  , [T,F,T,T,T,T]
+  , [F,T,F,F,T]
+  , [T,T,F,F,F,F]
+  , [F,F,F,T]
+  , [T,T,F,F,F,T]
+  , [T,T,F,F,T,F]
+  , [T,T,F,F,T,T]
+  , [F,T,F,T,F]
+  , [T,T,T,F,F,F,T]
+  , [T,T,T,F,F,T,F]
+  , [F,T,F,T,T]
+  , [T,T,F,T,F,F]
+  , [F,T,T,F,F]
+  , [F,T,T,F,T]
+  , [F,T,T,T,F]
+  , [T,T,T,T,F,F,T,F]
+  , [F,T,T,T,T]
+  , [T,F,F,F,F]
+  , [T,F,F,F,T]
+  , [T,T,F,T,F,T]
+  , [T,T,T,F,F,T,T]
+  , [T,T,F,T,T,F]
+  , [T,T,T,T,F,F,T,T]
+  , [T,T,T,T,F,T,F,F]
+  , [T,T,T,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F]
+  ]
diff --git a/Network/HPACK/Huffman/Response.hs b/Network/HPACK/Huffman/Response.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Huffman/Response.hs
@@ -0,0 +1,288 @@
+module Network.HPACK.Huffman.Response (
+    huffmanEncodeInResponse
+  , huffmanDecodeInResponse
+  ) where
+
+import Network.HPACK.Huffman.Bit
+import Network.HPACK.Huffman.Code
+
+----------------------------------------------------------------
+
+encoderForResponse :: Encoder
+encoderForResponse = toEncoder huffmanResponse
+
+-- | Hoffman encoding in HTTP/2.0 request.
+huffmanEncodeInResponse :: HuffmanEncoding
+huffmanEncodeInResponse = encode encoderForResponse
+
+----------------------------------------------------------------
+
+decoderForResponse :: Decoder
+decoderForResponse = toDecoder huffmanResponse
+
+-- | Hoffman decoding in HTTP/2.0 request.
+huffmanDecodeInResponse :: HuffmanDecoding
+huffmanDecodeInResponse = decode decoderForResponse
+
+----------------------------------------------------------------
+
+huffmanResponse :: [Bits]
+huffmanResponse = [
+    [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T]
+  , [F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,F,T,T,F,T]
+  , [T,T,T,T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,F,T,F]
+  , [T,F,F,F,T,F]
+  , [T,F,F,F,T,T]
+  , [T,F,F,T,F,F]
+  , [T,T,F,T,F,T,T]
+  , [F,F,F,T]
+  , [F,F,T,F]
+  , [F,F,T,T]
+  , [F,T,F,F,F]
+  , [F,T,F,F,T]
+  , [F,T,F,T,F]
+  , [T,F,F,T,F,T]
+  , [T,F,F,T,T,F]
+  , [F,T,F,T,T]
+  , [F,T,T,F,F]
+  , [F,T,T,F,T]
+  , [T,T,T,T,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,F,T,T,F,T]
+  , [T,T,T,F,T,F,T,F]
+  , [T,T,T,F,T,F,T,T]
+  , [T,T,T,F,T,T,F,F]
+  , [T,T,T,F,T,T,F,T]
+  , [T,T,T,F,T,T,T,F]
+  , [T,F,F,T,T,T]
+  , [T,T,T,T,T,F,F,F,F]
+  , [T,T,T,F,T,T,T,T]
+  , [T,T,T,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,F,F,T]
+  , [T,T,T,T,T,F,F,F,T]
+  , [T,F,T,F,F,F]
+  , [T,T,T,T,F,F,F,T]
+  , [T,T,T,T,F,F,T,F]
+  , [T,T,T,T,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,F,F,T,T]
+  , [T,F,T,F,F,T]
+  , [F,T,T,T,F]
+  , [T,T,T,T,T,F,T,F,F]
+  , [T,T,T,T,T,F,T,F,T]
+  , [T,T,T,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [F,T,T,T,T]
+  , [T,T,F,T,T,T,F]
+  , [T,F,T,F,T,F]
+  , [T,F,T,F,T,T]
+  , [T,F,F,F,F]
+  , [T,T,F,T,T,T,T]
+  , [T,T,T,F,F,F,F]
+  , [T,T,T,F,F,F,T]
+  , [T,F,T,T,F,F]
+  , [T,T,T,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,F,F,T]
+  , [T,T,T,F,F,T,F]
+  , [T,F,T,T,F,T]
+  , [T,F,T,T,T,F]
+  , [T,F,T,T,T,T]
+  , [T,T,F,F,F,F]
+  , [T,T,T,T,T,T,F,T,F]
+  , [T,T,F,F,F,T]
+  , [T,T,F,F,T,F]
+  , [T,T,F,F,T,T]
+  , [T,T,F,T,F,F]
+  , [T,T,T,F,F,T,T]
+  , [T,T,T,T,F,T,F,F]
+  , [T,T,T,F,T,F,F]
+  , [T,T,T,T,F,T,F,T]
+  , [T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,T,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,F,T,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,F,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,F,T,T]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,F]
+  , [T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,T,T,T,F,T]]
+
diff --git a/Network/HPACK/Table.hs b/Network/HPACK/Table.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Table.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE TupleSections #-}
+
+module Network.HPACK.Table (
+  -- * Header table
+    HeaderTable
+  , newHeaderTable
+  , printHeaderTable
+  -- * Insertion
+  , insertEntry
+  -- * Lookup
+  , HeaderCache(..)
+  , lookupTable
+  -- * Entry
+  , module Network.HPACK.Table.Entry
+  -- * Which tables
+  , WhichTable(..)
+  , which
+  ) where
+
+import Control.Applicative ((<$>))
+import Control.Exception (throwIO)
+import Data.Array.IO (readArray)
+import Network.HPACK.Table.Entry
+import Network.HPACK.Table.Header
+import Network.HPACK.Table.Static
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+data HeaderCache = None | KeyOnly WhichTable Index | KeyValue WhichTable Index
+
+-- | Looking up the static table and the header table.
+lookupTable :: Header -> HeaderTable -> IO HeaderCache
+lookupTable h@(k,v) hdrtbl = do
+    miv <- toIndexValue k hdrtbl
+    case miv of
+        Just (i,val)
+          | val == v  -> return $ KeyValue (whic i hdrtbl) i
+          | otherwise -> return $ KeyOnly (whic i hdrtbl) i
+        Nothing
+          | isColon h -> do
+              mi <- toStaticColonIndex h
+              case mi of
+                  Just i  -> return $ KeyValue InStaticTable (i + numOfEntries hdrtbl)
+                  Nothing -> return $ None
+          | otherwise -> return $ None
+
+whic :: Int -> HeaderTable -> WhichTable
+whic i hdrtbl
+ | i <= numOfEntries hdrtbl = InHeaderTable
+ | otherwise                = InStaticTable
+
+----------------------------------------------------------------
+
+-- | Which table does `Index` refer to?
+data WhichTable = InHeaderTable | InStaticTable deriving Eq
+
+----------------------------------------------------------------
+
+-- | Which table does 'Index' belong to?
+which :: HeaderTable -> Index -> IO (WhichTable, Entry)
+which (HeaderTable maxN off n tbl _ _) idx
+  | idx <= n                        = (InHeaderTable,) <$> readArray tbl pidx
+  | 1 <= stcidx && stcidx <= stcsiz = return (InStaticTable, toStaticEntry stcidx)
+  | otherwise                       = throwIO $ IndexOverrun idx
+  where
+    stcsiz = staticTableSize
+    stcidx = idx - n
+    pidx = (off + idx + maxN) `mod` maxN
diff --git a/Network/HPACK/Table/Entry.hs b/Network/HPACK/Table/Entry.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Table/Entry.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE BangPatterns, OverloadedStrings #-}
+
+module Network.HPACK.Table.Entry (
+  -- * Type
+    Size
+  , Entry
+  , Header      -- re-exporting
+  , HeaderName  -- re-exporting
+  , HeaderValue -- re-exporting
+  , Index       -- re-exporting
+  -- * Header and Entry
+  , toEntry
+  , fromEntry
+  -- * Getters
+  , entrySize
+  , entryHeaderName
+  , entryHeaderValue
+  -- * For initialization
+  , dummyEntry
+  , maxNumbers
+  ) where
+
+import qualified Data.ByteString as BS
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Size in bytes.
+type Size = Int
+
+-- | Type for table entry. Size includes the 32 bytes magic number.
+type Entry = (Size,Header)
+
+----------------------------------------------------------------
+
+headerSizeMagicNumber :: Size
+headerSizeMagicNumber = 32
+
+headerSize :: Header -> Size
+headerSize (k,v) = BS.length (fromHeaderName k)
+                 + BS.length v
+                 + headerSizeMagicNumber
+
+----------------------------------------------------------------
+
+-- | From 'Header' to 'Entry'.
+toEntry :: Header -> Entry
+toEntry h = (siz,h)
+  where
+    !siz = headerSize h
+
+-- | From 'Entry' to 'Header'.
+fromEntry :: Entry -> Header
+fromEntry = snd
+
+----------------------------------------------------------------
+
+-- | Getting the size of 'Entry'.
+entrySize :: Entry -> Size
+entrySize = fst
+
+-- | Getting 'HeaderName'.
+entryHeaderName :: Entry -> HeaderName
+entryHeaderName (_,(k,_)) = k
+
+-- | Getting 'HeaderValue'.
+entryHeaderValue :: Entry -> HeaderValue
+entryHeaderValue (_,(_,v)) = v
+
+----------------------------------------------------------------
+
+-- | Dummy 'Entry' to initialize a table.
+dummyEntry :: Entry
+dummyEntry = (0,("dummy","dummy"))
+
+maxNumbers :: Size -> Int
+maxNumbers siz = siz `div` headerSizeMagicNumber
diff --git a/Network/HPACK/Table/Header.hs b/Network/HPACK/Table/Header.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Table/Header.hs
@@ -0,0 +1,136 @@
+module Network.HPACK.Table.Header (
+  -- * Type
+    HeaderTable(..)
+  , newHeaderTable
+  , printHeaderTable
+  -- * Utilities
+  , insertEntry
+  , toIndexValue
+  ) where
+
+import Data.Array.IO (IOArray, newArray, readArray, writeArray)
+import qualified Data.ByteString.Char8 as BS
+import Network.HPACK.Table.Entry
+import Network.HPACK.Types
+
+----------------------------------------------------------------
+
+-- | Type for header table.
+data HeaderTable = HeaderTable {
+    maxNumOfEntries :: Int
+  , offset :: Index
+  , numOfEntries :: Int
+  , circularTable :: !(IOArray Index Entry)
+  , headerTableSize :: Size
+  , maxHeaderTableSize :: Size
+  }
+
+----------------------------------------------------------------
+
+-- | Printing 'HeaderTable'.
+printHeaderTable :: HeaderTable -> IO ()
+printHeaderTable (HeaderTable maxN off n tbl tblsiz _) = do
+    es <- mapM (readArray tbl . adj maxN) [beg .. end]
+    let ts = zip [1..] es
+    mapM_ printEntry ts
+    putStrLn $ "      Table size: " ++ show tblsiz
+  where
+    beg = off + 1
+    end = off + n
+
+printEntry :: (Index,Entry) -> IO ()
+printEntry (i,e) = do
+    putStr "[ "
+    putStr $ show i
+    putStr "] (s = "
+    putStr $ show $ entrySize e
+    putStr ") "
+    BS.putStr $ fromHeaderName $ entryHeaderName e
+    putStr ": "
+    BS.putStrLn $ entryHeaderValue e
+
+----------------------------------------------------------------
+
+-- | Creating 'HeaderTable'.
+-- The default maxHeaderTableSize is 4096 bytes,
+-- an array has 128 entries, resulting 1024 bytes in 64bit machine
+newHeaderTable :: Size -> IO HeaderTable
+newHeaderTable maxsiz = do
+    tbl <- newArray (0,end) dummyEntry
+    return HeaderTable {
+        maxNumOfEntries = maxN
+      , offset = end
+      , numOfEntries = 0
+      , circularTable = tbl
+      , headerTableSize = 0
+      , maxHeaderTableSize = maxsiz
+      }
+  where
+    maxN = maxNumbers maxsiz
+    end = maxN - 1
+
+----------------------------------------------------------------
+
+-- | Inserting 'Entry' to 'HeaderTable'.
+--   New 'HeaderTable' and a set of dropped 'Index'
+--   are returned.
+insertEntry :: Entry -> HeaderTable -> IO (HeaderTable,[Index])
+insertEntry e hdrtbl = insertOne e hdrtbl >>= adjustTableSize
+
+insertOne :: Entry -> HeaderTable -> IO HeaderTable
+insertOne e hdrtbl@(HeaderTable maxN off n tbl tsize _) = do
+    writeArray tbl i e
+    return $ hdrtbl {
+        offset = off'
+      , numOfEntries = n + 1
+      , headerTableSize = tsize'
+      }
+  where
+    i = off
+    tsize' = tsize + entrySize e
+    off' = adj maxN (off - 1)
+
+adjustTableSize :: HeaderTable -> IO (HeaderTable, [Index])
+adjustTableSize hdrtbl = adjust hdrtbl []
+
+adjust :: HeaderTable -> [Index] -> IO (HeaderTable, [Index])
+adjust hdrtbl is
+  | tsize <= maxtsize = return (hdrtbl, is)
+  | otherwise         = do
+      (hdrtbl', i) <- removeOne hdrtbl
+      adjust hdrtbl' (i:is)
+  where
+    tsize = headerTableSize hdrtbl
+    maxtsize = maxHeaderTableSize hdrtbl
+
+removeOne :: HeaderTable -> IO (HeaderTable,Index)
+removeOne hdrtbl@(HeaderTable maxN off n tbl tsize _) = do
+    let i = adj maxN (off + n)
+    e <- readArray tbl i
+    writeArray tbl i dummyEntry -- let the entry GCed
+    let tsize' = tsize - entrySize e
+    let hdrtbl' = hdrtbl {
+            numOfEntries = n - 1
+          , headerTableSize = tsize'
+          }
+    return (hdrtbl',n)
+
+----------------------------------------------------------------
+
+toIndexValue :: HeaderName -> HeaderTable -> IO (Maybe (Index, HeaderValue))
+toIndexValue k (HeaderTable maxN off n tbl _ _) = go 1
+  where
+    go i
+      | i > n     = return Nothing
+      | otherwise = do
+        let idx = adj maxN (off + i)
+        e <- readArray tbl idx
+        if entryHeaderName e == k then
+            return $ Just (i, entryHeaderValue e)
+          else
+            go (i+1)
+
+----------------------------------------------------------------
+
+adj :: Int -> Int -> Int
+adj maxN x = (x + maxN) `mod` maxN
diff --git a/Network/HPACK/Table/Static.hs b/Network/HPACK/Table/Static.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Table/Static.hs
@@ -0,0 +1,147 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Network.HPACK.Table.Static (
+    staticTableSize
+  , toStaticEntry
+  , toStaticIndex
+  , toStaticColonIndex
+  , isColon
+  ) where
+
+import Data.Array (Array, listArray, (!))
+import Data.HashTable.IO (BasicHashTable)
+import qualified Data.HashTable.IO as I
+import Network.HPACK.Table.Entry
+import Network.HPACK.Types
+import System.IO.Unsafe (unsafePerformIO)
+import qualified Data.ByteString.Char8 as H
+
+----------------------------------------------------------------
+
+-- | The size of static table.
+staticTableSize :: Size
+staticTableSize = 60
+
+-- | Get 'Entry' from the static table.
+--
+-- >>> toStaticEntry 8
+-- (42,(":status","200"))
+-- >>> toStaticEntry 49
+-- (37,("range",""))
+toStaticEntry :: Index -> Entry
+toStaticEntry idx = staticTable ! idx
+
+-- | Pre-defined static table.
+staticTable :: Array Index Entry
+staticTable = listArray (1,60) $ map toEntry staticTableList
+
+----------------------------------------------------------------
+
+-- | Get 'Index' from the static table.
+--
+-- >>> toStaticIndex ":status"
+-- Just 13
+-- >>> toStaticIndex "date"
+-- Just 32
+-- >>> toStaticIndex "user-agent"
+-- Just 57
+toStaticIndex :: HeaderName -> IO (Maybe Index)
+toStaticIndex k = I.lookup staticHashTable k
+
+staticHashTable :: BasicHashTable HeaderName Index
+staticHashTable = unsafePerformIO $ I.fromList alist
+  where
+    alist = zip (map fst staticTableList) [1 ..]
+
+----------------------------------------------------------------
+
+-- | Get 'Index' from the static table.
+--   Only colon headers.
+--
+-- >>> toStaticColonIndex (":path","/index.html")
+-- Just 5
+-- >>> toStaticColonIndex (":status","200")
+-- Just 8
+toStaticColonIndex :: Header -> IO (Maybe Index)
+toStaticColonIndex h = I.lookup staticColonHashTable h
+
+staticColonHashTable :: BasicHashTable Header Index
+staticColonHashTable = unsafePerformIO $ I.fromList alist
+  where
+    alist = zip staticColonHeaderList [1 ..]
+
+----------------------------------------------------------------
+
+staticColonHeaderList :: [Header]
+
+staticColonHeaderList = takeWhile isColon staticTableList
+
+-- | Checking if 'HeaderName' starts with colon.
+isColon :: Header -> Bool
+isColon h = H.head (fromHeaderName (fst h)) == ':'
+
+----------------------------------------------------------------
+
+staticTableList :: [Header]
+staticTableList = [
+    (":authority","")
+  , (":method","GET")
+  , (":method","POST")
+  , (":path","/")
+  , (":path","/index.html")
+  , (":scheme","http")
+  , (":scheme","https")
+  , (":status","200")
+  , (":status","500")
+  , (":status","404")
+  , (":status","403")
+  , (":status","400")
+  , (":status","401")
+  , ("accept-charset","")
+  , ("accept-encoding","")
+  , ("accept-language","")
+  , ("accept-ranges","")
+  , ("accept","")
+  , ("access-control-allow-origin","")
+  , ("age","")
+  , ("allow","")
+  , ("authorization","")
+  , ("cache-control","")
+  , ("content-disposition","")
+  , ("content-encoding","")
+  , ("content-language","")
+  , ("content-length","")
+  , ("content-location","")
+  , ("content-range","")
+  , ("content-type","")
+  , ("cookie","")
+  , ("date","")
+  , ("etag","")
+  , ("expect","")
+  , ("expires","")
+  , ("from","")
+  , ("host","")
+  , ("if-match","")
+  , ("if-modified-since","")
+  , ("if-none-match","")
+  , ("if-range","")
+  , ("if-unmodified-since","")
+  , ("last-modified","")
+  , ("link","")
+  , ("location","")
+  , ("max-forwards","")
+  , ("proxy-authenticate","")
+  , ("proxy-authorization","")
+  , ("range","")
+  , ("referer","")
+  , ("refresh","")
+  , ("retry-after","")
+  , ("server","")
+  , ("set-cookie","")
+  , ("strict-transport-security","")
+  , ("transfer-encoding","")
+  , ("user-agent","")
+  , ("vary","")
+  , ("via","")
+  , ("www-authenticate","")
+  ]
diff --git a/Network/HPACK/Types.hs b/Network/HPACK/Types.hs
new file mode 100644
--- /dev/null
+++ b/Network/HPACK/Types.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+module Network.HPACK.Types (
+  -- * Header
+    HeaderName
+  , HeaderValue
+  , HeaderStuff
+  , fromHeaderName
+  , toHeaderName
+  , Header
+  -- * Misc
+  , ByteStream
+  , Index
+  , DecodeError(..)
+  ) where
+
+import Control.Exception as E
+import Data.ByteString (ByteString)
+import Data.CaseInsensitive (foldedCase, mk)
+import Data.Typeable
+import Network.HTTP.Types (HeaderName, Header)
+
+-- | Header value.
+type HeaderValue = ByteString
+
+-- | To be a 'HeaderName' or 'HeaderValue'.
+type HeaderStuff = ByteString
+
+-- | Converting 'HeaderName' to 'HeaderStuff'.
+fromHeaderName :: HeaderName -> HeaderStuff
+fromHeaderName = foldedCase
+
+-- | Converting 'HeaderStuff' to 'HeaderName'.
+toHeaderName :: HeaderStuff -> HeaderName
+toHeaderName = mk
+
+-- | Byte stream in HTTP request/response.
+type ByteStream = ByteString
+
+-- | Index for table.
+type Index = Int
+
+-- | Errors for decoder.
+data DecodeError = IndexOverrun Index -- ^ Index is out of range
+                 deriving (Show,Typeable)
+
+instance Exception DecodeError
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/http2.cabal b/http2.cabal
new file mode 100644
--- /dev/null
+++ b/http2.cabal
@@ -0,0 +1,78 @@
+Name:                   http2
+Version:                0.0.0
+Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
+Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
+License:                BSD3
+License-File:           LICENSE
+Synopsis:               HTTP/2.0 library including HPACK
+Description:            HTTP/2.0 library including HPACK.
+                        Currently only HPACK 06 is supported.
+Category:               Network
+Cabal-Version:          >= 1.10
+Build-Type:             Simple
+
+Library
+  Default-Language:     Haskell2010
+  GHC-Options:          -Wall
+  Exposed-Modules:      Network.HPACK
+                        Network.HPACK.Context
+                        Network.HPACK.Context.HeaderSet
+                        Network.HPACK.Context.ReferenceSet
+                        Network.HPACK.Huffman
+                        Network.HPACK.Huffman.Bit
+                        Network.HPACK.Huffman.Code
+                        Network.HPACK.Huffman.Request
+                        Network.HPACK.Huffman.Response
+                        Network.HPACK.HeaderBlock
+                        Network.HPACK.HeaderBlock.Decode
+                        Network.HPACK.HeaderBlock.Encode
+                        Network.HPACK.HeaderBlock.From
+                        Network.HPACK.HeaderBlock.HeaderField
+                        Network.HPACK.HeaderBlock.Integer
+                        Network.HPACK.HeaderBlock.String
+                        Network.HPACK.HeaderBlock.To
+                        Network.HPACK.Table
+                        Network.HPACK.Table.Entry
+                        Network.HPACK.Table.Header
+                        Network.HPACK.Table.Static
+                        Network.HPACK.Types
+  Build-Depends:        base >= 4 && < 5
+                      , array
+                      , blaze-builder
+                      , bytestring
+                      , case-insensitive
+                      , hashtables
+                      , http-types
+
+Test-Suite doctest
+  Type:                 exitcode-stdio-1.0
+  Default-Language:     Haskell2010
+  HS-Source-Dirs:       test
+  Ghc-Options:          -Wall
+  Main-Is:              doctests.hs
+  Build-Depends:        base
+                      , doctest >= 0.9.3
+
+Test-Suite spec
+  Type:                 exitcode-stdio-1.0
+  Default-Language:     Haskell2010
+  HS-Source-Dirs:       test
+  Ghc-Options:          -Wall
+  Main-Is:              Spec.hs
+  Other-Modules:        BitSpec
+                        DecodeSpec
+                        HeaderBlockSpec
+                        HuffmanRequestSpec
+                        HuffmanResponseSpec
+                        IntegerSpec
+                        HeaderBlock
+                        HexString
+  Build-Depends:        base
+                      , bytestring
+                      , http2
+                      , hspec >= 1.3
+
+Source-Repository head
+  Type:                 git
+  Location:             git://github.com/kazu-yamamoto/http2
+
diff --git a/test/BitSpec.hs b/test/BitSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/BitSpec.hs
@@ -0,0 +1,12 @@
+module BitSpec where
+
+import Network.HPACK.Huffman.Bit
+import Test.Hspec
+import Test.Hspec.QuickCheck
+
+spec :: Spec
+spec = do
+    describe "toBits and fromBits" $ do
+        prop "duality" $ \n ->
+            let i = fromIntegral $ abs (n :: Int) `mod` 256
+            in  fromBits (toBits i) == i
diff --git a/test/DecodeSpec.hs b/test/DecodeSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/DecodeSpec.hs
@@ -0,0 +1,25 @@
+module DecodeSpec where
+
+import Network.HPACK.Context
+import Network.HPACK.HeaderBlock
+import Test.Hspec
+
+import HeaderBlock
+
+spec :: Spec
+spec = do
+    describe "fromHeaderBlock" $ do
+        it "decodes HeaderSet in request" $ do
+            (h1,c1) <- newContext 4096 >>= fromHeaderBlock e31
+            h1 `shouldBe` e31h
+            (h2,c2) <- fromHeaderBlock e32 c1
+            h2 `shouldBe` e32h
+            (h3,_)  <- fromHeaderBlock e33 c2
+            h3 `shouldBe` e33h
+        it "decodes HeaderSet in response" $ do
+            (h1,c1) <- newContext 256 >>= fromHeaderBlock e51
+            h1 `shouldBe` e51h
+            (h2,c2) <- fromHeaderBlock e52 c1
+            h2 `shouldBe` e52h
+            (h3,_)  <- fromHeaderBlock e53 c2
+            h3 `shouldBe` e53h
diff --git a/test/HeaderBlock.hs b/test/HeaderBlock.hs
new file mode 100644
--- /dev/null
+++ b/test/HeaderBlock.hs
@@ -0,0 +1,127 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module HeaderBlock where
+
+import qualified Data.ByteString as BS
+import Network.HPACK.Context
+import Network.HPACK.HeaderBlock
+import Network.HPACK.Types
+
+import HexString
+
+----------------------------------------------------------------
+
+e31 :: HeaderBlock
+e31 = [
+    Indexed 2
+  , Indexed 7
+  , Indexed 6
+  , Literal Add (Idx 4) "www.example.com"
+  ]
+
+e31h :: HeaderSet
+e31h = [(":method","GET")
+        ,(":scheme","http")
+        ,(":path","/")
+        ,(":authority","www.example.com")
+        ]
+
+e31b :: ByteStream
+e31b = BS.pack $ fromHexString "828786048bdb6d883e68d1cb1225ba7f"
+
+e32 :: HeaderBlock
+e32 = [
+    Literal Add (Idx 27) "no-cache"
+  ]
+
+e32h :: HeaderSet
+e32h = [("cache-control","no-cache")
+        ,(":method","GET")
+        ,(":scheme","http")
+        ,(":path","/")
+        ,(":authority","www.example.com")]
+
+e32b :: ByteStream
+e32b = BS.pack $ fromHexString "1b8663654a1398ff"
+
+e33 :: HeaderBlock
+e33 = [
+    Indexed 0
+  , Indexed 5
+  , Indexed 12
+  , Indexed 11
+  , Indexed 4
+  , Literal Add (Lit "custom-key") "custom-value"
+  ]
+
+e33h :: HeaderSet
+e33h = [(":method","GET")
+        ,(":scheme","https")
+        ,(":path","/index.html")
+        ,(":authority","www.example.com")
+        ,("custom-key","custom-value")
+        ]
+
+e33b :: ByteStream
+e33b = BS.pack $ fromHexString "80858c8b8400884eb08b749790fa7f894eb08b74979a17a8ff"
+
+----------------------------------------------------------------
+
+e51 :: HeaderBlock
+e51 = [
+    Literal Add (Idx 8) "302"
+  , Literal Add (Idx 24) "private"
+  , Literal Add (Idx 34) "Mon, 21 Oct 2013 20:13:21 GMT"
+  , Literal Add (Idx 48) "https://www.example.com"
+  ]
+
+e51h :: HeaderSet
+e51h = [(":status","302")
+        ,("cache-control","private")
+        ,("date","Mon, 21 Oct 2013 20:13:21 GMT")
+        ,("location","https://www.example.com")
+        ]
+
+e51b :: ByteStream
+e51b = BS.pack $ fromHexString "0882409f1886c31b39bf387f2292a2fba20320f2ab303124018b490d3209e8773093e39e7864dd7afd3d3d248747db87284955f6ff"
+
+e52 :: HeaderBlock
+e52 = [
+    Indexed 4
+  , Indexed 12
+  ]
+
+e52h :: HeaderSet
+e52h = [(":status","200")
+        ,("cache-control","private")
+        ,("date","Mon, 21 Oct 2013 20:13:21 GMT")
+        ,("location","https://www.example.com")
+        ]
+
+e52b :: ByteStream
+e52b = BS.pack $ fromHexString "848c"
+
+e53 :: HeaderBlock
+e53 = [
+    Indexed 3
+  , Indexed 4
+  , Indexed 4
+  , Literal Add (Idx 3) "Mon, 21 Oct 2013 20:13:22 GMT"
+  , Literal Add (Idx 29) "gzip"
+  , Indexed 4
+  , Indexed 4
+  , Indexed 3
+  , Indexed 3
+  , Literal Add (Idx 58) "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"
+  ]
+
+e53h :: HeaderSet
+e53h = [("cache-control","private")
+        ,("date","Mon, 21 Oct 2013 20:13:22 GMT")
+        ,("content-encoding","gzip")
+        ,("location","https://www.example.com")
+        ,(":status","200")
+        ,("set-cookie","foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1")]
+
+e53b :: ByteStream
+e53b = BS.pack $ fromHexString "8384840392a2fba20320f2ab303124018b490d3309e8771d84e1fbb30f848483833ab3df7dfb36d3d9e1fcfc3fafe7abfcfefcbfaf3edf2f977fd36ff7fd79f6f977fd3de16bfa46fe10d889447de1ce18e565f76c2f"
diff --git a/test/HeaderBlockSpec.hs b/test/HeaderBlockSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/HeaderBlockSpec.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module HeaderBlockSpec where
+
+import qualified Data.ByteString.Char8 as BS
+import Network.HPACK.HeaderBlock
+import Network.HPACK.Huffman
+import Network.HPACK.Types
+import Test.Hspec
+import Test.Hspec.QuickCheck
+
+import HeaderBlock
+
+spec :: Spec
+spec = do
+    describe "toByteStream" $ do
+        it "encodes HeaderBlock" $ do
+            toByteStream huffmanEncodeInRequest  e31 `shouldBe` e31b
+            toByteStream huffmanEncodeInRequest  e32 `shouldBe` e32b
+            toByteStream huffmanEncodeInRequest  e33 `shouldBe` e33b
+            toByteStream huffmanEncodeInResponse e51 `shouldBe` e51b
+            toByteStream huffmanEncodeInResponse e52 `shouldBe` e52b
+            toByteStream huffmanEncodeInResponse e53 `shouldBe` e53b
+
+    describe "fromByteStream" $ do
+        it "encodes HeaderBlock" $ do
+            fromByteStream huffmanDecodeInRequest  e31b `shouldBe` e31
+            fromByteStream huffmanDecodeInRequest  e32b `shouldBe` e32
+            fromByteStream huffmanDecodeInRequest  e33b `shouldBe` e33
+            fromByteStream huffmanDecodeInResponse e51b `shouldBe` e51
+            fromByteStream huffmanDecodeInResponse e52b `shouldBe` e52
+            fromByteStream huffmanDecodeInResponse e53b `shouldBe` e53
+    describe "toByteStream & fromByteStream" $ do
+        prop "duality for request" $ \k v -> do
+            putStrLn $ "K length" ++ show (length k)
+            putStrLn $ "V length" ++ show (length v)
+            let key = toHeaderName $ BS.pack ('k':k)
+                val = BS.pack ('v':v)
+                hb = [Literal Add (Lit key) val]
+            fromByteStream huffmanDecodeInRequest
+                (toByteStream huffmanEncodeInRequest hb) `shouldBe` hb
+        prop "duality for response" $ \v -> do
+            let val = BS.pack ('v':v)
+                hb = [Literal Add (Idx 3) val]
+            fromByteStream huffmanDecodeInResponse
+                (toByteStream huffmanEncodeInResponse hb) `shouldBe` hb
diff --git a/test/HexString.hs b/test/HexString.hs
new file mode 100644
--- /dev/null
+++ b/test/HexString.hs
@@ -0,0 +1,17 @@
+module HexString where
+
+import Numeric
+import Text.Printf
+import Data.Word (Word8)
+
+fromHexString :: String -> [Word8]
+fromHexString = map fromHex . group2
+  where
+    fromHex = fst . head . readHex
+    group2 [] = []
+    group2 xs = ys : group2 zs
+      where
+       (ys,zs) = splitAt 2 xs
+
+toHexString :: [Word8] -> String
+toHexString = concatMap (printf "%02x")
diff --git a/test/HuffmanRequestSpec.hs b/test/HuffmanRequestSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/HuffmanRequestSpec.hs
@@ -0,0 +1,39 @@
+module HuffmanRequestSpec where
+
+import Data.Char
+import Network.HPACK.Huffman.Request
+import Test.Hspec
+import Test.Hspec.QuickCheck
+
+import HexString
+
+shouldBeEncoded :: String -> String -> Expectation
+shouldBeEncoded inp out = enc inp `shouldBe` out
+  where
+    enc = toHexString . huffmanEncodeInRequest . toW
+    toW = map (fromIntegral . ord)
+
+shouldBeDecoded :: String -> String -> Expectation
+shouldBeDecoded inp out = dec inp `shouldBe` out
+  where
+    dec = toS . huffmanDecodeInRequest . fromHexString
+    toS = map (chr . fromIntegral)
+
+spec :: Spec
+spec = do
+    describe "huffmanEncodeInRequest and huffmanDecodeInRequest" $ do
+        prop "duality" $ \ns ->
+            let is = map ((`mod` 255) . abs) ns
+            in huffmanDecodeInRequest (huffmanEncodeInRequest is) == is
+    describe "huffmanEncodeInRequest" $ do
+        it "encodes in request" $ do
+            "www.example.com" `shouldBeEncoded` "db6d883e68d1cb1225ba7f"
+            "no-cache" `shouldBeEncoded` "63654a1398ff"
+            "custom-key" `shouldBeEncoded` "4eb08b749790fa7f"
+            "custom-value" `shouldBeEncoded` "4eb08b74979a17a8ff"
+    describe "huffmanDecodeInRequest" $ do
+        it "decodes in request" $ do
+            "db6d883e68d1cb1225ba7f" `shouldBeDecoded` "www.example.com"
+            "63654a1398ff" `shouldBeDecoded` "no-cache"
+            "4eb08b749790fa7f" `shouldBeDecoded` "custom-key"
+            "4eb08b74979a17a8ff" `shouldBeDecoded` "custom-value"
diff --git a/test/HuffmanResponseSpec.hs b/test/HuffmanResponseSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/HuffmanResponseSpec.hs
@@ -0,0 +1,43 @@
+module HuffmanResponseSpec where
+
+import Data.Char
+import Network.HPACK.Huffman.Response
+import Test.Hspec
+import Test.Hspec.QuickCheck
+
+import HexString
+
+shouldBeEncoded :: String -> String -> Expectation
+shouldBeEncoded inp out = enc inp `shouldBe` out
+  where
+    enc = toHexString . huffmanEncodeInResponse . toW
+    toW = map (fromIntegral . ord)
+
+shouldBeDecoded :: String -> String -> Expectation
+shouldBeDecoded inp out = dec inp `shouldBe` out
+  where
+    dec = toS . huffmanDecodeInResponse . fromHexString
+    toS = map (chr . fromIntegral)
+
+spec :: Spec
+spec = do
+    describe "huffmanEncodeInResponse and huffmanDecodeInResponse" $ do
+        prop "duality" $ \ns ->
+            let is = map ((`mod` 255) . abs) ns
+            in huffmanDecodeInResponse (huffmanEncodeInResponse is) == is
+    describe "huffmanEncodeInResponse" $ do
+        it "encodes in response" $ do
+            "private" `shouldBeEncoded` "c31b39bf387f"
+            "Mon, 21 Oct 2013 20:13:21 GMT" `shouldBeEncoded` "a2fba20320f2ab303124018b490d3209e877"
+            "https://www.example.com" `shouldBeEncoded` "e39e7864dd7afd3d3d248747db87284955f6ff"
+            "Mon, 21 Oct 2013 20:13:22 GMT" `shouldBeEncoded` "a2fba20320f2ab303124018b490d3309e877"
+            "gzip" `shouldBeEncoded` "e1fbb30f"
+            "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1" `shouldBeEncoded` "df7dfb36d3d9e1fcfc3fafe7abfcfefcbfaf3edf2f977fd36ff7fd79f6f977fd3de16bfa46fe10d889447de1ce18e565f76c2f"
+    describe "huffmanDecodeInResponse" $ do
+        it "decodes in response" $ do
+            "c31b39bf387f" `shouldBeDecoded` "private"
+            "a2fba20320f2ab303124018b490d3209e877"`shouldBeDecoded` "Mon, 21 Oct 2013 20:13:21 GMT"
+            "e39e7864dd7afd3d3d248747db87284955f6ff" `shouldBeDecoded` "https://www.example.com"
+            "a2fba20320f2ab303124018b490d3309e877" `shouldBeDecoded` "Mon, 21 Oct 2013 20:13:22 GMT"
+            "e1fbb30f" `shouldBeDecoded` "gzip"
+            "df7dfb36d3d9e1fcfc3fafe7abfcfefcbfaf3edf2f977fd36ff7fd79f6f977fd3de16bfa46fe10d889447de1ce18e565f76c2f" `shouldBeDecoded` "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"
diff --git a/test/IntegerSpec.hs b/test/IntegerSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/IntegerSpec.hs
@@ -0,0 +1,22 @@
+module IntegerSpec where
+
+import Network.HPACK.HeaderBlock.Integer
+import Test.Hspec
+import Test.Hspec.QuickCheck
+
+dual :: Int -> Int -> Bool
+dual n i = decode n (encode n x) == x
+  where
+    x = abs i
+
+spec :: Spec
+spec = do
+    describe "encode and decode" $ do
+        prop "duality" $ dual 1
+        prop "duality" $ dual 2
+        prop "duality" $ dual 3
+        prop "duality" $ dual 4
+        prop "duality" $ dual 5
+        prop "duality" $ dual 6
+        prop "duality" $ dual 7
+        prop "duality" $ dual 8
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/doctests.hs b/test/doctests.hs
new file mode 100644
--- /dev/null
+++ b/test/doctests.hs
@@ -0,0 +1,9 @@
+module Main where
+
+import Test.DocTest
+
+main :: IO ()
+main = doctest [
+    "-XOverloadedStrings"
+  , "Network/HPACK.hs"
+  ]
