{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE CPP #-}
module Raaz.Core.Encode.Base64( Base64 ) where
import Data.Char
import Data.Bits
import Data.String
import Data.ByteString as B
import Data.ByteString.Char8 as C8
import Data.ByteString.Internal (c2w, w2c)
import Data.ByteString.Unsafe(unsafeIndex)
import Data.Monoid
import Data.Word
import Raaz.Core.Encode.Internal
newtype Base64 = Base64 {Base64 -> ByteString
unBase64 :: ByteString}
#if MIN_VERSION_base(4,11,0)
deriving (Base64 -> Base64 -> Bool
(Base64 -> Base64 -> Bool)
-> (Base64 -> Base64 -> Bool) -> Eq Base64
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Base64 -> Base64 -> Bool
$c/= :: Base64 -> Base64 -> Bool
== :: Base64 -> Base64 -> Bool
$c== :: Base64 -> Base64 -> Bool
Eq, b -> Base64 -> Base64
NonEmpty Base64 -> Base64
Base64 -> Base64 -> Base64
(Base64 -> Base64 -> Base64)
-> (NonEmpty Base64 -> Base64)
-> (forall b. Integral b => b -> Base64 -> Base64)
-> Semigroup Base64
forall b. Integral b => b -> Base64 -> Base64
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: b -> Base64 -> Base64
$cstimes :: forall b. Integral b => b -> Base64 -> Base64
sconcat :: NonEmpty Base64 -> Base64
$csconcat :: NonEmpty Base64 -> Base64
<> :: Base64 -> Base64 -> Base64
$c<> :: Base64 -> Base64 -> Base64
Semigroup, Semigroup Base64
Base64
Semigroup Base64 =>
Base64
-> (Base64 -> Base64 -> Base64)
-> ([Base64] -> Base64)
-> Monoid Base64
[Base64] -> Base64
Base64 -> Base64 -> Base64
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [Base64] -> Base64
$cmconcat :: [Base64] -> Base64
mappend :: Base64 -> Base64 -> Base64
$cmappend :: Base64 -> Base64 -> Base64
mempty :: Base64
$cmempty :: Base64
$cp1Monoid :: Semigroup Base64
Monoid)
#else
deriving (Eq, Monoid)
#endif
instance Encodable Base64 where
toByteString :: Base64 -> ByteString
toByteString = ByteString -> ByteString
toB64 (ByteString -> ByteString)
-> (Base64 -> ByteString) -> Base64 -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 -> ByteString
unBase64
fromByteString :: ByteString -> Maybe Base64
fromByteString bs :: ByteString
bs
| ByteString -> Bool
B.null ByteString
bs = Base64 -> Maybe Base64
forall a. a -> Maybe a
Just (Base64 -> Maybe Base64) -> Base64 -> Maybe Base64
forall a b. (a -> b) -> a -> b
$ ByteString -> Base64
Base64 ByteString
B.empty
| ByteString -> Int
B.length ByteString
bs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` 4 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= 0 = Maybe Base64
forall a. Maybe a
Nothing
| Bool
okeyPad = Base64 -> Maybe Base64
forall a. a -> Maybe a
Just (Base64 -> Maybe Base64) -> Base64 -> Maybe Base64
forall a b. (a -> b) -> a -> b
$ ByteString -> Base64
Base64 (ByteString -> Base64) -> ByteString -> Base64
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
unsafeFromB64 ByteString
bs
| Bool
otherwise = Maybe Base64
forall a. Maybe a
Nothing
where padPart :: ByteString
padPart = (Char -> Bool) -> ByteString -> ByteString
C8.dropWhile Char -> Bool
isB64Char ByteString
bs
okeyPad :: Bool
okeyPad = ByteString
padPart ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
C8.empty Bool -> Bool -> Bool
|| ByteString
padPart ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> ByteString
C8.singleton '=' Bool -> Bool -> Bool
|| ByteString
padPart ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== String -> ByteString
C8.pack "=="
isB64Char :: Char -> Bool
isB64Char c :: Char
c = Char -> Bool
isAlpha Char
c Bool -> Bool -> Bool
|| Char -> Bool
isDigit Char
c Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '+' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '/'
unsafeFromByteString :: ByteString -> Base64
unsafeFromByteString bs :: ByteString
bs | ByteString -> Bool
B.null ByteString
bs = ByteString -> Base64
Base64 ByteString
B.empty
| Bool
otherwise = ByteString -> Base64
Base64 (ByteString -> Base64) -> ByteString -> Base64
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
unsafeFromB64 ByteString
bs
instance Show Base64 where
show :: Base64 -> String
show = ByteString -> String
C8.unpack (ByteString -> String)
-> (Base64 -> ByteString) -> Base64 -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 -> ByteString
forall a. Encodable a => a -> ByteString
toByteString
instance IsString Base64 where
fromString :: String -> Base64
fromString = ByteString -> Base64
forall a. Encodable a => ByteString -> a
unsafeFromByteString (ByteString -> Base64)
-> (String -> ByteString) -> String -> Base64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> ByteString
C8.filter (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) (ByteString -> ByteString)
-> (String -> ByteString) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
forall a. IsString a => String -> a
fromString
instance Format Base64 where
encodeByteString :: ByteString -> Base64
encodeByteString = ByteString -> Base64
Base64
{-# INLINE encodeByteString #-}
decodeFormat :: Base64 -> ByteString
decodeFormat = Base64 -> ByteString
unBase64
{-# INLINE decodeFormat #-}
top6 :: Word8 -> Word8; bot2 :: Word8 -> Word8
top4 :: Word8 -> Word8; bot4 :: Word8 -> Word8
top2 :: Word8 -> Word8; bot6 :: Word8 -> Word8
top6 :: Word8 -> Word8
top6 w :: Word8
w = Word8
w Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftR` 2; bot2 :: Word8 -> Word8
bot2 w :: Word8
w = Word8
w Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. 0x03
top4 :: Word8 -> Word8
top4 w :: Word8
w = Word8
w Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftR` 4; bot4 :: Word8 -> Word8
bot4 w :: Word8
w = Word8
w Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. 0x0F
top2 :: Word8 -> Word8
top2 w :: Word8
w = Word8
w Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftR` 6; bot6 :: Word8 -> Word8
bot6 w :: Word8
w = Word8
w Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. 0x3F
byte0 :: Word8 -> Word8
byte1 :: Word8 -> Word8 -> Word8
byte2 :: Word8 -> Word8 -> Word8
byte3 :: Word8 -> Word8
pad :: Word8
byte0 :: Word8 -> Word8
byte0 = Word8 -> Word8
b64 (Word8 -> Word8) -> (Word8 -> Word8) -> Word8 -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Word8
top6
byte1 :: Word8 -> Word8 -> Word8
byte1 t :: Word8
t p :: Word8
p = Word8 -> Word8
b64 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftL (Word8 -> Word8
bot2 Word8
p) 4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Word8
top4 Word8
t
byte2 :: Word8 -> Word8 -> Word8
byte2 t :: Word8
t p :: Word8
p = Word8 -> Word8
b64 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
shiftL (Word8 -> Word8
bot4 Word8
p) 2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Word8
top2 Word8
t
byte3 :: Word8 -> Word8
byte3 = Word8 -> Word8
b64 (Word8 -> Word8) -> (Word8 -> Word8) -> Word8 -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Word8
bot6
pad :: Word8
pad = Char -> Word8
c2w '='
b64 :: Word8 -> Word8
b64 :: Word8 -> Word8
b64 w :: Word8
w | 0 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= 25 = Char -> Word8
c2w 'A' Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
w
| 26 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= 51 = Char -> Word8
c2w 'a' Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- 26
| 52 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= 61 = Char -> Word8
c2w '0' Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- 52
| Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 62 = Char -> Word8
c2w '+'
| Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 63 = Char -> Word8
c2w '/'
| Bool
otherwise = String -> Word8
forall a. HasCallStack => String -> a
error "oops: b64"
unB64 :: Word8 -> Word8
unB64 :: Word8 -> Word8
unB64 w :: Word8
w | Char -> Word8
c2w 'A' Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Char -> Word8
c2w 'Z' = Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Char -> Word8
c2w 'A'
| Char -> Word8
c2w 'a' Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Char -> Word8
c2w 'z' = Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Char -> Word8
c2w 'a' Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ 26
| Char -> Word8
c2w '0' Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Char -> Word8
c2w '9' = Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Char -> Word8
c2w '0' Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ 52
| Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Word8
c2w '+' = 62
| Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Word8
c2w '/' = 63
| Bool
otherwise = String -> Word8
forall a. HasCallStack => String -> a
error (String -> Word8) -> String -> Word8
forall a b. (a -> b) -> a -> b
$ "oops unB64:" String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Word8 -> Char
w2c Word8
w]
toB64 :: ByteString -> ByteString
toB64 :: ByteString -> ByteString
toB64 bs :: ByteString
bs = (ByteString, Maybe Int) -> ByteString
forall a b. (a, b) -> a
fst (Int
-> (Int -> Maybe (Word8, Int)) -> Int -> (ByteString, Maybe Int)
forall a.
Int -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN (4Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
n) Int -> Maybe (Word8, Int)
gen 0) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
padding
where gen :: Int -> Maybe (Word8, Int)
gen i :: Int
i = (Word8, Int) -> Maybe (Word8, Int)
forall a. a -> Maybe a
Just (Int -> Word8
byte Int
i, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
at :: Int -> Int -> Word8
at blk :: Int
blk i :: Int
i = ByteString -> Int -> Word8
unsafeIndex ByteString
bs (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ 3 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
blk Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i
byte :: Int -> Word8
byte i :: Int
i = case Int
r of
0 -> Word8 -> Word8
byte0 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 0
1 -> Word8 -> Word8 -> Word8
byte1 (Int -> Int -> Word8
at Int
q 1) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 0
2 -> Word8 -> Word8 -> Word8
byte2 (Int -> Int -> Word8
at Int
q 2) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 1
3 -> Word8 -> Word8
byte3 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 2
_ -> String -> Word8
forall a. HasCallStack => String -> a
error "base64 bad index"
where (q :: Int
q, r :: Int
r) = Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
quotRem Int
i 4
(n :: Int
n,p :: Int
p) = ByteString -> Int
B.length ByteString
bs Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` 3
padding :: ByteString
padding = case Int
p of
0 -> ByteString
forall a. Monoid a => a
mempty
1 -> [Word8] -> ByteString
B.pack [ Word8 -> Word8
byte0 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 0
, Word8 -> Word8 -> Word8
byte1 0 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 0
, Word8
pad, Word8
pad
]
2 -> [Word8] -> ByteString
B.pack [ Word8 -> Word8
byte0 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 0
, Word8 -> Word8 -> Word8
byte1 (Int -> Int -> Word8
at Int
n 1) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 0
, Word8 -> Word8 -> Word8
byte2 0 (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 1
, Word8
pad
]
_ -> String -> ByteString
forall a. HasCallStack => String -> a
error "base64 pad bad index"
merg0 :: Word8 -> Word8 -> Word8
merg1 :: Word8 -> Word8 -> Word8
merg2 :: Word8 -> Word8 -> Word8
merg0 :: Word8 -> Word8 -> Word8
merg0 a :: Word8
a b :: Word8
b = (Word8 -> Word8
unB64 Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftL` 2) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Word8
top4 (Word8 -> Word8
unB64 Word8
b)
merg1 :: Word8 -> Word8 -> Word8
merg1 a :: Word8
a b :: Word8
b = (Word8 -> Word8
unB64 Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftL` 4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Word8
top6 (Word8 -> Word8
unB64 Word8
b)
merg2 :: Word8 -> Word8 -> Word8
merg2 a :: Word8
a b :: Word8
b = (Word8 -> Word8
unB64 Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftL` 6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Word8
unB64 Word8
b
unsafeFromB64 :: ByteString -> ByteString
unsafeFromB64 :: ByteString -> ByteString
unsafeFromB64 bs :: ByteString
bs = (ByteString, Maybe Int) -> ByteString
forall a b. (a, b) -> a
fst (Int
-> (Int -> Maybe (Word8, Int)) -> Int -> (ByteString, Maybe Int)
forall a.
Int -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN (3Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
n) Int -> Maybe (Word8, Int)
gen 0) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
unPad
where n :: Int
n = ByteString -> Int
B.length ByteString
bs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` 4 Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1
gen :: Int -> Maybe (Word8, Int)
gen i :: Int
i = (Word8, Int) -> Maybe (Word8, Int)
forall a. a -> Maybe a
Just (Int -> Word8
byte Int
i, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
at :: Int -> Int -> Word8
at blk :: Int
blk i :: Int
i = ByteString -> Int -> Word8
unsafeIndex ByteString
bs (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ 4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
blk Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i
byte :: Int -> Word8
byte i :: Int
i = case Int
r of
0 -> Word8 -> Word8 -> Word8
merg0 (Int -> Int -> Word8
at Int
q 0) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 1
1 -> Word8 -> Word8 -> Word8
merg1 (Int -> Int -> Word8
at Int
q 1) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 2
2 -> Word8 -> Word8 -> Word8
merg2 (Int -> Int -> Word8
at Int
q 2) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
q 3
_ -> String -> Word8
forall a. HasCallStack => String -> a
error "base64 bad index"
where (q :: Int
q, r :: Int
r) = Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
quotRem Int
i 3
unPad :: ByteString
unPad
| Int -> Int -> Word8
at Int
n 2 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Word8
c2w '=' = Word8 -> ByteString
B.singleton (Word8 -> ByteString) -> Word8 -> ByteString
forall a b. (a -> b) -> a -> b
$ Word8 -> Word8 -> Word8
merg0 (Int -> Int -> Word8
at Int
n 0) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 1
| Int -> Int -> Word8
at Int
n 3 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Word8
c2w '=' = [Word8] -> ByteString
B.pack [ Word8 -> Word8 -> Word8
merg0 (Int -> Int -> Word8
at Int
n 0) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 1
, Word8 -> Word8 -> Word8
merg1 (Int -> Int -> Word8
at Int
n 1) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 2
]
| Bool
otherwise = [Word8] -> ByteString
B.pack [ Word8 -> Word8 -> Word8
merg0 (Int -> Int -> Word8
at Int
n 0) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 1
, Word8 -> Word8 -> Word8
merg1 (Int -> Int -> Word8
at Int
n 1) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 2
, Word8 -> Word8 -> Word8
merg2 (Int -> Int -> Word8
at Int
n 2) (Word8 -> Word8) -> Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Word8
at Int
n 3
]