content: import           Control.Concurrent (setNumCapabilities)
  import           Crypto.Hash        (hashWith, SHA256 (..), Digest)
  import           Control.Monad      (replicateM, join, (>=>))
  import           Control.Monad.Par  (runPar, get, spawnP)
  import           Data.ByteString    (pack)
  import           Data.List.Split    (chunksOf)
  import           GHC.Conc           (getNumProcessors)
  import           Text.Printf        (printf)
  
  hashedValues :: [Digest SHA256]
  hashedValues = read <$>
    [ "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"
    , "74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f"
    , "1115dd800feaacefdf481f1f9070374a2a81e27880f187396db67958b207cbad" ]
  
  bruteForce :: Int -> [(String, String)]
  bruteForce n = runPar $ join <$>
    (mapM (spawnP . foldr findMatch []) >=> mapM get) chunks
    where
      chunks = chunksOf (26^5 `div` n) $ replicateM 5 [97..122]
      findMatch s accum
        | hashed `elem` hashedValues = (show hashed, show bStr) : accum
        | otherwise = accum
        where
          bStr = pack s
          hashed = hashWith SHA256 bStr
  
  main :: IO ()
  main = do
    cpus <- getNumProcessors
    setNumCapabilities cpus
    printf "Using %d cores\n" cpus
    mapM_ (uncurry (printf "%s -> %s\n")) (bruteForce cpus)
  