    {-# LANGUAGE TypeFamilies #-}
    -- | Module: Poll
    -- | Support for voting
    -- |
    -- | License: lGPL
    -- |
    -- | added by Kenneth Hoste (boegel), 22/11/2005
    -- |  inspiration: Where plugin (thanks shapr,dons)
    module Lambdabot.Plugin.Social.Poll (pollPlugin) where

    import Lambdabot.Plugin
    import qualified Data.ByteString.Char8 as P
    import Data.List
    import qualified Data.Map as M

    newPoll :: Poll
    newPoll :: Poll
    newPoll = (Bool
    True,[])

    appendPoll :: Choice -> Poll -> (Maybe Poll)
    appendPoll :: PollName -> Poll -> Maybe Poll
    appendPoll PollName
    choice (Bool
    o,[(PollName, Count)]
    ls) = Poll -> Maybe Poll
    forall a. a -> Maybe a
    Just (Bool
    o,(PollName
    choice,Count
    0)(PollName, Count) -> [(PollName, Count)] -> [(PollName, Count)]
    forall a. a -> [a] -> [a]
    :[(PollName, Count)]
    ls)

    voteOnPoll :: Poll -> Choice -> (Poll,String)
    voteOnPoll :: Poll -> PollName -> (Poll, String)
    voteOnPoll (Bool
    o,[(PollName, Count)]
    poll) PollName
    choice =
        if ((PollName, Count) -> Bool) -> [(PollName, Count)] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (\(PollName
    x,Count
    _) -> PollName
    x PollName -> PollName -> Bool
    forall a. Eq a => a -> a -> Bool
    == PollName
    choice) [(PollName, Count)]
    poll
            then ((Bool
    o,((PollName, Count) -> (PollName, Count))
    -> [(PollName, Count)] -> [(PollName, Count)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\(PollName
    c,Count
    n) ->
                        if PollName
    c PollName -> PollName -> Bool
    forall a. Eq a => a -> a -> Bool
    == PollName
    choice then (PollName
    c,Count
    nCount -> Count -> Count
    forall a. Num a => a -> a -> a
    +Count
    1)
                                       else (PollName
    c,Count
    n)) [(PollName, Count)]
    poll)
                                            ,String
    "voted on " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprChoice PollName
    choice)
            else ((Bool
    o,[(PollName, Count)]
    poll),PollName -> String
    pprChoice PollName
    choice String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " is not currently a candidate in this poll")

    ------------------------------------------------------------------------

    type Count             = Int
    type Choice            = P.ByteString
    type PollName          = P.ByteString
    type Poll              = (Bool, [(Choice, Count)])
    type VoteState         = M.Map PollName Poll
    type VoteWriter        = VoteState -> Cmd Vote ()
    type Vote              = ModuleT VoteState LB

    ------------------------------------------------------------------------
    -- Define a serialiser

    voteSerial :: Serial VoteState
    voteSerial :: Serial VoteState
    voteSerial = (VoteState -> Maybe PollName)
    -> (PollName -> Maybe VoteState) -> Serial VoteState
    forall s.
    (s -> Maybe PollName) -> (PollName -> Maybe s) -> Serial s
    Serial (PollName -> Maybe PollName
    forall a. a -> Maybe a
    Just (PollName -> Maybe PollName)
    -> (VoteState -> PollName) -> VoteState -> Maybe PollName
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VoteState -> PollName
    forall t. Packable t => t -> PollName
    showPacked) (VoteState -> Maybe VoteState
    forall a. a -> Maybe a
    Just (VoteState -> Maybe VoteState)
    -> (PollName -> VoteState) -> PollName -> Maybe VoteState
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PollName -> VoteState
    forall t. Packable t => PollName -> t
    readPacked)

    ------------------------------------------------------------------------

    pollPlugin :: Module (M.Map PollName Poll)
    pollPlugin :: Module VoteState
    pollPlugin = Module VoteState
    forall st. Module st
    newModule
        { moduleCmds = return
            [ (command "poll-list")
                { help = say "poll-list                   Shows all current polls"
                , process = \String
    _ -> do
                    String
    result <- (LBState (Cmd Vote)
     -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote String)
    -> Cmd Vote String
    forall a.
    (LBState (Cmd Vote)
     -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote a)
    -> Cmd Vote a
    forall (m :: * -> *) a.
    MonadLBState m =>
    (LBState m -> (LBState m -> m ()) -> m a) -> m a
    withMS ((LBState (Cmd Vote)
      -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote String)
     -> Cmd Vote String)
    -> (LBState (Cmd Vote)
        -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote String)
    -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ \LBState (Cmd Vote)
    factFM LBState (Cmd Vote) -> Cmd Vote ()
    writer -> VoteState -> VoteWriter -> String -> [PollName] -> Cmd Vote String
    processCommand VoteState
    LBState (Cmd Vote)
    factFM VoteWriter
    LBState (Cmd Vote) -> Cmd Vote ()
    writer String
    "poll-list" []
                    String -> Cmd Vote ()
    forall (m :: * -> *). Monad m => String -> Cmd m ()
    say String
    result
                }
            , (command "poll-show")
                { help = say "poll-show <poll>            Shows all choices for some poll"
                , process = process_ "poll-show"
                }
            , (command "poll-add")
                { help = say "poll-add <name>             Adds a new poll, with no candidates"
                , process = process_ "poll-add"
                }
            , (command "choice-add")
                { help = say "choice-add <poll> <choice>  Adds a new choice to the given poll"
                , process = process_ "choice-add"
                }
            , (command "vote")
                -- todo, should @vote foo automagically add foo as a possibility?
                { help = say "vote <poll> <choice>        Vote for <choice> in <poll>"
                , process = process_ "vote"
                }
            , (command "poll-result")
                { help = say "poll-result <poll>          Show result for given poll"
                , process = process_ "poll-result"
                }
            , (command "poll-close")
                { help = say "poll-close <poll>           Closes a poll"
                , process = process_ "poll-close"
                }
            , (command "poll-remove")
                { help = say "poll-remove <poll>          Removes a poll"
                , process = process_ "poll-remove"
                }
            , (command "poll-reset")
                { help = say "poll-reset <poll>           Resets votes and reopens a poll"
                , process = process_ "poll-reset"
                }
            ]

        , moduleDefState  = return M.empty
        , moduleSerialize = Just voteSerial
        }

    process_ :: [Char] -> [Char] -> Cmd Vote ()
    process_ :: String -> String -> Cmd Vote ()
    process_ String
    cmd [] = String -> Cmd Vote ()
    forall (m :: * -> *). Monad m => String -> Cmd m ()
    say (String
    "Missing argument. Check @help " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    cmd String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " for info.")
    process_ String
    cmd String
    dat
        | (Char -> Bool) -> String -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (\Char
    c -> Char
    c Char -> Char -> Bool
    forall a. Ord a => a -> a -> Bool
    < Char
    ' ' Bool -> Bool -> Bool
    || Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '"') String
    dat
        = String -> Cmd Vote ()
    forall (m :: * -> *). Monad m => String -> Cmd m ()
    say String
    "Please do not use control characters or double quotes in polls."
    process_ String
    cmd String
    dat = do
        String
    result <- (LBState (Cmd Vote)
     -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote String)
    -> Cmd Vote String
    forall a.
    (LBState (Cmd Vote)
     -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote a)
    -> Cmd Vote a
    forall (m :: * -> *) a.
    MonadLBState m =>
    (LBState m -> (LBState m -> m ()) -> m a) -> m a
    withMS ((LBState (Cmd Vote)
      -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote String)
     -> Cmd Vote String)
    -> (LBState (Cmd Vote)
        -> (LBState (Cmd Vote) -> Cmd Vote ()) -> Cmd Vote String)
    -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ \LBState (Cmd Vote)
    fm LBState (Cmd Vote) -> Cmd Vote ()
    writer ->
            VoteState -> VoteWriter -> String -> [PollName] -> Cmd Vote String
    processCommand VoteState
    LBState (Cmd Vote)
    fm VoteWriter
    LBState (Cmd Vote) -> Cmd Vote ()
    writer String
    cmd ((String -> PollName) -> [String] -> [PollName]
    forall a b. (a -> b) -> [a] -> [b]
    map String -> PollName
    P.pack (String -> [String]
    words String
    dat))
        String -> Cmd Vote ()
    forall (m :: * -> *). Monad m => String -> Cmd m ()
    say String
    result

    ------------------------------------------------------------------------

    processCommand :: VoteState -> VoteWriter -> String -> [P.ByteString] -> Cmd Vote String
    processCommand :: VoteState -> VoteWriter -> String -> [PollName] -> Cmd Vote String
    processCommand VoteState
    fm VoteWriter
    writer String
    cmd [PollName]
    dat = case String
    cmd of

        -- show all current polls
        String
    "poll-list"  -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ VoteState -> String
    listPolls VoteState
    fm

        -- show candidates
        String
    "poll-show"    -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ case [PollName]
    dat of
                            [PollName
    poll] -> VoteState -> PollName -> String
    showPoll VoteState
    fm PollName
    poll
                            [PollName]
    _ -> String
    "usage: @poll-show <poll>"

        -- declare a new poll
        String
    "poll-add"     -> case [PollName]
    dat of
                            [PollName
    poll] -> VoteState -> VoteWriter -> PollName -> Cmd Vote String
    addPoll VoteState
    fm VoteWriter
    writer PollName
    poll
                            [PollName]
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "usage: @poll-add <poll>   with \"ThisTopic\" style names"

        String
    "choice-add"   -> case [PollName]
    dat of
                            [PollName
    poll,PollName
    choice] -> VoteState -> VoteWriter -> PollName -> PollName -> Cmd Vote String
    addChoice VoteState
    fm VoteWriter
    writer PollName
    poll PollName
    choice
                            [PollName]
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "usage: @choice-add <poll> <choice>"

        String
    "vote"          -> case [PollName]
    dat of
                            [PollName
    poll,PollName
    choice] -> VoteState -> VoteWriter -> PollName -> PollName -> Cmd Vote String
    vote VoteState
    fm VoteWriter
    writer PollName
    poll PollName
    choice
                            [PollName]
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "usage: @vote <poll> <choice>"

        String
    "poll-result"   -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ case [PollName]
    dat of
                            [PollName
    poll] -> VoteState -> PollName -> String
    showResult VoteState
    fm PollName
    poll
                            [PollName]
    _ -> String
    "usage: @poll-result <poll>"

        String
    "poll-close"    -> case [PollName]
    dat of
                            [PollName
    poll] -> VoteState -> VoteWriter -> PollName -> Cmd Vote String
    closePoll VoteState
    fm VoteWriter
    writer PollName
    poll
                            [PollName]
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "usage: @poll-close <poll>"

        String
    "poll-remove"   -> case [PollName]
    dat of
                            [PollName
    poll] -> VoteState -> VoteWriter -> PollName -> Cmd Vote String
    removePoll VoteState
    fm VoteWriter
    writer PollName
    poll
                            [PollName]
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "usage: @poll-remove <poll>"

        String
    "poll-reset"    -> case [PollName]
    dat of
                            [PollName
    poll] -> VoteState -> VoteWriter -> PollName -> Cmd Vote String
    resetPoll VoteState
    fm VoteWriter
    writer PollName
    poll
                            [PollName]
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "usage: @poll-reset <poll>"
        String
    _ -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "Unknown command."

    ------------------------------------------------------------------------

    listPolls :: VoteState -> String
    listPolls :: VoteState -> String
    listPolls VoteState
    fm = (PollName -> String) -> [PollName] -> String
    forall a. (a -> String) -> [a] -> String
    pprList PollName -> String
    pprPoll ([PollName] -> String) -> [PollName] -> String
    forall a b. (a -> b) -> a -> b
    $ ((PollName, Poll) -> PollName) -> [(PollName, Poll)] -> [PollName]
    forall a b. (a -> b) -> [a] -> [b]
    map (PollName, Poll) -> PollName
    forall a b. (a, b) -> a
    fst (VoteState -> [(PollName, Poll)]
    forall k a. Map k a -> [(k, a)]
    M.toList VoteState
    fm)

    showPoll :: VoteState -> PollName -> String
    showPoll :: VoteState -> PollName -> String
    showPoll VoteState
    fm PollName
    poll =
        case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
            Maybe Poll
    Nothing -> String
    "No such poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " Use @poll-list to see the available polls."
            Just Poll
    p  -> (PollName -> String) -> [PollName] -> String
    forall a. (a -> String) -> [a] -> String
    pprList PollName -> String
    pprChoice ([PollName] -> String) -> [PollName] -> String
    forall a b. (a -> b) -> a -> b
    $ ((PollName, Count) -> PollName)
    -> [(PollName, Count)] -> [PollName]
    forall a b. (a -> b) -> [a] -> [b]
    map (PollName, Count) -> PollName
    forall a b. (a, b) -> a
    fst (Poll -> [(PollName, Count)]
    forall a b. (a, b) -> b
    snd Poll
    p)

    addPoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    addPoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    addPoll VoteState
    fm VoteWriter
    writer PollName
    poll =
        case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
            Maybe Poll
    Nothing -> do VoteWriter
    writer VoteWriter -> VoteWriter
    forall a b. (a -> b) -> a -> b
    $ PollName -> Poll -> VoteState -> VoteState
    forall k a. Ord k => k -> a -> Map k a -> Map k a
    M.insert PollName
    poll Poll
    newPoll VoteState
    fm
                          String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "Added new poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll
            Just Poll
    _  -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "Poll " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
                                String
    " already exists, choose another name for your poll"

    addChoice :: VoteState -> VoteWriter -> PollName -> Choice -> Cmd Vote String
    addChoice :: VoteState -> VoteWriter -> PollName -> PollName -> Cmd Vote String
    addChoice VoteState
    fm VoteWriter
    writer PollName
    poll PollName
    choice = case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
        Maybe Poll
    Nothing -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "No such poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll
        Just Poll
    _  -> do VoteWriter
    writer VoteWriter -> VoteWriter
    forall a b. (a -> b) -> a -> b
    $ (Poll -> Maybe Poll) -> PollName -> VoteState -> VoteState
    forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
    M.update (PollName -> Poll -> Maybe Poll
    appendPoll PollName
    choice) PollName
    poll VoteState
    fm
                      String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "New candidate " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprChoice PollName
    choice String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
                               String
    ", added to poll " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "."

    vote :: VoteState -> VoteWriter -> PollName -> Choice -> Cmd Vote String
    vote :: VoteState -> VoteWriter -> PollName -> PollName -> Cmd Vote String
    vote VoteState
    fm VoteWriter
    writer PollName
    poll PollName
    choice = case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
        Maybe Poll
    Nothing          -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "No such poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll
        Just (Bool
    False,[(PollName, Count)]
    _)   -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "The "String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " poll is closed, sorry !"
        Just p :: Poll
    p@(Bool
    True,[(PollName, Count)]
    _)  -> do let (Poll
    np,String
    msg) = Poll -> PollName -> (Poll, String)
    voteOnPoll Poll
    p PollName
    choice
                               VoteWriter
    writer VoteWriter -> VoteWriter
    forall a b. (a -> b) -> a -> b
    $ (Poll -> Maybe Poll) -> PollName -> VoteState -> VoteState
    forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
    M.update (Maybe Poll -> Poll -> Maybe Poll
    forall a b. a -> b -> a
    const (Poll -> Maybe Poll
    forall a. a -> Maybe a
    Just Poll
    np)) PollName
    poll VoteState
    fm
                               String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    msg

    showResult :: VoteState -> PollName -> String
    showResult :: VoteState -> PollName -> String
    showResult VoteState
    fm PollName
    poll = case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
        Maybe Poll
    Nothing     -> String
    "No such poll: "  String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll
        Just (Bool
    o,[(PollName, Count)]
    p)  -> String
    "Poll results for " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " (" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Bool -> String
    status Bool
    o String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "): "
                       String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ ([String] -> String
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    intersperse String
    ", " ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ ((PollName, Count) -> String) -> [(PollName, Count)] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (PollName, Count) -> String
    forall {a}. Show a => (PollName, a) -> String
    ppr [(PollName, Count)]
    p)
            where
                status :: Bool -> String
    status Bool
    s | Bool
    s         = String
    "Open"
                         | Bool
    otherwise = String
    "Closed"
                ppr :: (PollName, a) -> String
    ppr (PollName
    x,a
    y) = PollName -> String
    pprChoice PollName
    x String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "=" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ a -> String
    forall a. Show a => a -> String
    show a
    y

    removePoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    removePoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    removePoll VoteState
    fm VoteWriter
    writer PollName
    poll = case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
        Just (Bool
    True,[(PollName, Count)]
    _)  -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    "Poll should be closed before you can remove it."
        Just (Bool
    False,[(PollName, Count)]
    _) -> do VoteWriter
    writer VoteWriter -> VoteWriter
    forall a b. (a -> b) -> a -> b
    $ PollName -> VoteState -> VoteState
    forall k a. Ord k => k -> Map k a -> Map k a
    M.delete PollName
    poll VoteState
    fm
                             String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "poll " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " removed."
        Maybe Poll
    Nothing        -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "No such poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll

    closePoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    closePoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    closePoll VoteState
    fm VoteWriter
    writer PollName
    poll = case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
        Maybe Poll
    Nothing     -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "No such poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll
        Just (Bool
    _,[(PollName, Count)]
    p)  -> do VoteWriter
    writer VoteWriter -> VoteWriter
    forall a b. (a -> b) -> a -> b
    $ (Poll -> Maybe Poll) -> PollName -> VoteState -> VoteState
    forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
    M.update (Maybe Poll -> Poll -> Maybe Poll
    forall a b. a -> b -> a
    const (Poll -> Maybe Poll
    forall a. a -> Maybe a
    Just (Bool
    False,[(PollName, Count)]
    p))) PollName
    poll VoteState
    fm
                          String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "Poll " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " closed."

    resetPoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    resetPoll :: VoteState -> VoteWriter -> PollName -> Cmd Vote String
    resetPoll VoteState
    fm VoteWriter
    writer PollName
    poll = case PollName -> VoteState -> Maybe Poll
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PollName
    poll VoteState
    fm of
        Just (Bool
    _, [(PollName, Count)]
    vs)   -> do let np :: Poll
    np = (Bool
    True, ((PollName, Count) -> (PollName, Count))
    -> [(PollName, Count)] -> [(PollName, Count)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\(PollName
    c, Count
    _) -> (PollName
    c, Count
    0)) [(PollName, Count)]
    vs)
                             VoteWriter
    writer VoteWriter -> VoteWriter
    forall a b. (a -> b) -> a -> b
    $ (Poll -> Maybe Poll) -> PollName -> VoteState -> VoteState
    forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
    M.update (Maybe Poll -> Poll -> Maybe Poll
    forall a b. a -> b -> a
    const (Poll -> Maybe Poll
    forall a. a -> Maybe a
    Just Poll
    np)) PollName
    poll VoteState
    fm
                             String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "Poll " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " reset."
        Maybe Poll
    Nothing        -> String -> Cmd Vote String
    forall a. a -> Cmd Vote a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Cmd Vote String) -> String -> Cmd Vote String
    forall a b. (a -> b) -> a -> b
    $ String
    "No such poll: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    pprPoll PollName
    poll

    ------------------------------------------------------------------------

    -- we render strings verbatim but surround them with quotes,
    -- relying on previous sanitization to disallow control characters
    pprBS :: P.ByteString -> String
    pprBS :: PollName -> String
    pprBS PollName
    p = String
    "\"" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ PollName -> String
    P.unpack PollName
    p String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\""

    pprPoll :: PollName -> String
    pprPoll :: PollName -> String
    pprPoll = PollName -> String
    pprBS

    pprChoice :: Choice -> String
    pprChoice :: PollName -> String
    pprChoice = PollName -> String
    pprBS

    pprList :: (a -> String) -> [a] -> String
    pprList :: forall a. (a -> String) -> [a] -> String
    pprList a -> String
    f [a]
    as = String
    "[" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [String] -> String
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat (String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    intersperse String
    "," ((a -> String) -> [a] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map a -> String
    f [a]
    as)) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "]"