import Control.Parallel.Strategies import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as BS import Data.List import qualified Data.Map as Map import System.Environment import Text.Regex.Posix j = 2 main :: IO () main = getArgs >>= BS.readFile . head >>= putStrLn . output . freq . count' . BS.lines count' :: [ByteString] -> Map.Map ByteString Int count' = mapReduce j count (Map.unionWith (+)) Map.empty count :: [ByteString] -> Map.Map ByteString Int count = Map.fromListWith (+) . map (flip (,) 1) . concatMap matches matches :: ByteString -> [ByteString] matches s = [ m | [_,m] <- s =~ "GET /ongoing/When/[[:digit:]]{3}x/([[:digit:]]{4}/[[:digit:]]{2}/[[:digit:]]{2}/[^ .]+) " ] freq :: Map.Map ByteString Int -> [(ByteString,Int)] freq = sortBy (\x y -> snd y `compare` snd x) . Map.toList output :: [(ByteString,Int)] -> String output fs = unlines [show c ++ ": " ++ BS.unpack x | (x,c) <- take 10 fs] -- -- * Utilities -- mapReduce :: Int -> ([a] -> b) -> (b -> b -> b) -> b -> [a] -> b mapReduce n f g b = reduce n g b . parMapChunks n f reduce :: Int -> (a -> a -> a) -> a -> [a] -> a reduce n f b = foldl f b . parMapChunks n (foldl f b) parMapChunks :: Int -> ([a] -> b) -> [a] -> [b] parMapChunks n f xs = parMap rwhnf f $ chunks (length xs `div` n) xs chunks :: Int -> [a] -> [[a]] chunks _ [] = [] chunks n xs = case splitAt n xs of (ys,zs) -> ys:chunks n zs {- parSortBy :: Int -> (a -> a -> Ordering) -> [a] -> [a] parSortBy n o = mapReduce n (sortBy o) (merge o) [] merge :: (a -> a -> Ordering) -> [a] -> [a] -> [a] merge o [] ys = ys merge o xs [] = xs merge o (x:xs) (y:ys) = case x `o` y of GT -> y:merge o (x:xs) ys _ -> x:merge o xs (y:ys) -}