commit :: (RaftLog l e v) => Raft l e v -> Clients -> IO ()
commit vRaft clients = do
    raft <- atomically $ readTVar (raftContext vRaft)
    let initialLog = raftLog raft
        leader = raftName raft
        endpoint = raftEndpoint raft
        cs = newCallSite endpoint leader
        term = raftCurrentTerm raft
        cfg = raftStateConfiguration $ raftState raft
    (prevTime,entries) <- gatherUnsynchronizedEntries (raftMembers raft) (clusterConfiguration cfg) initialLog
    infoM _log $ printf "%v: Broadcasting %d entries after %d" leader (length entries) (logIndex $ prevTime)
    results <- goAppendEntries cs cfg term prevTime (lastCommittedTime initialLog) entries
    let members = raftMembers raft
        newMembers = updateMembers members results
        newCommittedIndex = membersSafeAppendedIndex newMembers $ clusterConfiguration cfg
        newTerm = membersHighestTerm newMembers
    infoM _log $ printf "%v: Member appended indexes are %v" leader (show $ membersAppendedIndex newMembers $ clusterConfiguration cfg)
    atomically $ modifyTVar (raftContext vRaft) $ \oldRaft ->
        setRaftMembers newMembers oldRaft
    if newTerm > (raftCurrentTerm raft)
        then do
            atomically $ modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftTerm newTerm oldRaft
            infoM _log $ printf "Leader stepping down; new term %v discovered" (show newTerm)
            return ()
        else do
            newRaft <- atomically $ readTVar $ raftContext vRaft
            (newLog,newState) <- if (newCommittedIndex > lastCommitted initialLog) 
                then do
                    infoM _log $ printf "%v: Committing at %d" leader newCommittedIndex
                    (log,state) <- commitEntries initialLog newCommittedIndex (raftState newRaft)
                    checkpoint log state
                else return (initialLog,raftState newRaft)
            (revisedLog,revisedState) <- case raftStateConfigurationIndex newState of
                Nothing -> return (newLog,newState)
                Just cfgIndex ->
                    if lastCommitted newLog >= cfgIndex
                        then do
                            let revisedCfg = case (clusterConfiguration $ raftStateConfiguration newState) of
                                    JointConfiguration _ jointNew -> jointNew
                                    newCfg -> newCfg
                            revisedLog <- appendEntries newLog ((lastAppended newLog) + 1)
                                    [RaftLogEntry (raftStateCurrentTerm newState) (Cfg $ SetConfiguration revisedCfg)]
                            let revisedState = newState {raftStateConfigurationIndex = Nothing}
                            return (revisedLog,revisedState)
                        else return (newLog,newState)
            atomically $ modifyTVar (raftContext vRaft) $ \oldRaft ->
                setRaftLog revisedLog
                    $ setRaftState revisedState
                        $ setRaftMembers newMembers oldRaft
            notifyClients vRaft clients revisedLog revisedState
    return ()
commit :: (RaftLog l e v) => Raft l e v -> Clients -> IO ()
commit vRaft clients = do
    raft <- atomically $ readTVar (raftContext vRaft)
    let initialLog = raftLog raft
        leader = raftName raft
        endpoint = raftEndpoint raft
        cs = newCallSite endpoint leader
        term = raftCurrentTerm raft
        cfg = raftStateConfiguration $ raftState raft
    (prevTime,entries) <- gatherUnsynchronizedEntries (raftMembers raft) (clusterConfiguration cfg) initialLog
    infoM _log $ printf "%v: Broadcasting %d entries after %d" leader (length entries) (logIndex $ prevTime)
    results <- goAppendEntries cs cfg term prevTime (lastCommittedTime initialLog) entries
    let members = raftMembers raft
        newMembers = updateMembers members results
        newCommittedIndex = membersSafeAppendedIndex newMembers $ clusterConfiguration cfg
        newTerm = membersHighestTerm newMembers
    infoM _log $ printf "%v: Member appended indexes are %v" leader (show $ membersAppendedIndex newMembers $ clusterConfiguration cfg)
    atomically $ modifyTVar (raftContext vRaft) $ \oldRaft ->
        setRaftMembers newMembers oldRaft
    if newTerm > (raftCurrentTerm raft)
        then do
            atomically $ modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftTerm newTerm oldRaft
            infoM _log $ printf "Leader stepping down; new term %v discovered" (show newTerm)
            return ()
        else do
            newRaft <- atomically $ readTVar $ raftContext vRaft
            (newLog,newState) <- if (newCommittedIndex > lastCommitted initialLog) 
                then do
                    infoM _log $ printf "%v: Committing at %d" leader newCommittedIndex
                    (log,state) <- commitEntries initialLog newCommittedIndex (raftState newRaft)
                    checkpoint log state
                else return (initialLog,raftState newRaft)
            (revisedLog,revisedState) <- case raftStateConfigurationIndex newState of
                Nothing -> return (newLog,newState)
                Just cfgIndex ->
                    if lastCommitted newLog >= cfgIndex
                        then do
                            let revisedCfg = case (clusterConfiguration $ raftStateConfiguration newState) of
                                    JointConfiguration _ jointNew -> jointNew
                                    newCfg -> newCfg
                            revisedLog <- appendEntries newLog ((lastAppended newLog) + 1)
                                    [RaftLogEntry (raftStateCurrentTerm newState) (Cfg $ SetConfiguration revisedCfg)]
                            let revisedState = newState {raftStateConfigurationIndex = Nothing}
                            return (revisedLog,revisedState)
                        else return (newLog,newState)
            atomically $ modifyTVar (raftContext vRaft) $ \oldRaft ->
                setRaftLog revisedLog
                    $ setRaftState revisedState
                        $ setRaftMembers newMembers oldRaft
            notifyClients vRaft clients revisedLog revisedState
    return ()
commit vRaft clients = do
    raft <- atomically $ readTVar (raftContext vRaft)
    let initialLog = raftLog raft
        leader = raftName raft
        endpoint = raftEndpoint raft
        cs = newCallSite endpoint leader
        term = raftCurrentTerm raft
        cfg = raftStateConfiguration $ raftState raft
    (prevTime,entries) <- gatherUnsynchronizedEntries (raftMembers raft) (clusterConfiguration cfg) initialLog
    infoM _log $ printf "%v: Broadcasting %d entries after %d" leader (length entries) (logIndex $ prevTime)
    results <- goAppendEntries cs cfg term prevTime (lastCommittedTime initialLog) entries
    let members = raftMembers raft
        newMembers = updateMembers members results
        newCommittedIndex = membersSafeAppendedIndex newMembers $ clusterConfiguration cfg
        newTerm = membersHighestTerm newMembers
    infoM _log $ printf "%v: Member appended indexes are %v" leader (show $ membersAppendedIndex newMembers $ clusterConfiguration cfg)
    atomically $ modifyTVar (raftContext vRaft) $ \oldRaft ->
        setRaftMembers newMembers oldRaft
    if newTerm > (raftCurrentTerm raft)
        then do
            atomically $ modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftTerm newTerm oldRaft
            infoM _log $ printf "Leader stepping down; new term %v discovered" (show newTerm)
            return ()
        else do
            newRaft <- atomically $ readTVar $ raftContext vRaft
            (newLog,newState) <- if (newCommittedIndex > lastCommitted initialLog) 
                then do
                    infoM _log $ printf "%v: Committing at %d" leader newCommittedIndex
                    (log,state) <- commitEntries initialLog newCommittedIndex (raftState newRaft)
                    checkpoint log state
                else return (initialLog,raftState newRaft)
            (revisedLog,revisedState) <- case raftStateConfigurationIndex newState of
                Nothing -> return (newLog,newState)
                Just cfgIndex ->
                    if lastCommitted newLog >= cfgIndex
                        then do
                            let revisedCfg = case (clusterConfiguration $ raftStateConfiguration newState) of
                                    JointConfiguration _ jointNew -> jointNew
                                    newCfg -> newCfg
                            revisedLog <- appendEntries newLog ((lastAppended newLog) + 1)
                                    [RaftLogEntry (raftStateCurrentTerm newState) (Cfg $ SetConfiguration revisedCfg)]
                            let revisedState = newState {raftStateConfigurationIndex = Nothing}
                            return (revisedLog,revisedState)
                        else return (newLog,newState)
            atomically $ modifyTVar (raftContext vRaft) $ \oldRaft ->
                setRaftLog revisedLog
                    $ setRaftState revisedState
                        $ setRaftMembers newMembers oldRaft
            notifyClients vRaft clients revisedLog revisedState
    return ()