import qualified Data.Map.Strict as Map (Map, lookup, fromList)
import Data.Maybe (fromJust, listToMaybe, mapMaybe)
import Numeric (readInt, showIntAtBase)
import Data.Char (chr, digitToInt)
import Data.List.Split (chunksOf)

byteToASCII :: String -> String
byteToASCII = map chr . decoder


decoder :: String -> [Int]
decoder =
  map readBin .
  takeWhile (\x -> length x == 8) .
  chunksOf 8 . concatMap toBin . mapMaybe (`Map.lookup` table) . filter (/= '=')


toBin :: Int -> String
toBin n = leftPad $ showIntAtBase 2 ("01" !!) n ""


leftPad :: String -> String
leftPad a = replicate (6 - length a) '0' ++ a


readBin :: String -> Int
readBin = fromJust . fmap fst . listToMaybe . readInt 2 (`elem` "01") digitToInt


table :: Map.Map Char Int
table =
  Map.fromList $
  zip "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" [0 ..]

main :: IO ()
main =
  putStrLn $
  byteToASCII
    "VG8gZXJyIGlzIGh1bWFuLCBidXQgdG8gcmVhbGx5IGZvdWwgdGhpbmdzIHVwIHlvdSBuZWVkIGEgY29tcHV0ZXIuCi0tIFBhdWwgUi4gRWhybGljaA=="