func (p *MemoryProposer) IdentityRead(ctx context.Context, key string) error {
	_, _, err := p.Propose(ctx, key, func(x []byte) []byte { return x })
	return err
}
IdentityRead is an alias for propose with an identity change function. It's a
separate method to make implementing an e.g. HTTP proposer simpler;
serializing change functions is difficult.
package protocol
import (
	"context"
	"errors"
	"math/rand"
	"sort"
	"sync"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
)
type ChangeFunc func(current []byte) (new []byte)
var (
	ErrPrepareFailed = errors.New("not enough confirmations during prepare phase; proposer ballot was fast-forwarded")
	ErrAcceptFailed = errors.New("not enough confirmations during accept phase")
	ErrDuplicate = errors.New("duplicate")
	ErrNotFound = errors.New("not found")
)
type MemoryProposer struct {
	mtx       sync.Mutex
	id        string
	age       Age
	ballot    Ballot
	preparers map[string]Preparer
	accepters map[string]Accepter
	watchers  map[string]StateWatcher
	logger    log.Logger
}
func NewMemoryProposer(id string, logger log.Logger, initial ...Acceptor) *MemoryProposer {
	p := &MemoryProposer{
		id:        id,
		age:       Age{Counter: 0, ID: id},
		ballot:    Ballot{Counter: 0, ID: id},
		preparers: map[string]Preparer{},
		accepters: map[string]Accepter{},
		watchers:  map[string]StateWatcher{},
		logger:    logger,
	}
	for _, target := range initial {
		p.preparers[target.Address()] = target
		p.accepters[target.Address()] = target
		p.watchers[target.Address()] = target
	}
	return p
}
func (p *MemoryProposer) Address() string {
	return p.id
}
func (p *MemoryProposer) Propose(ctx context.Context, key string, f ChangeFunc) (state []byte, b Ballot, err error) {
	p.mtx.Lock()
	defer p.mtx.Unlock()
	state, b, err = p.propose(ctx, key, f, regularQuorum)
	if err == ErrPrepareFailed {
		state, b, err = p.propose(ctx, key, f, regularQuorum)
	}
	return state, b, err
}
type quorumFunc func(n int) int
var (
	regularQuorum = func(n int) int { return (n / 2) + 1 }  
	fullQuorum    = func(n int) int { return n }            
)
func (p *MemoryProposer) propose(ctx context.Context, key string, f ChangeFunc, qf quorumFunc) (state []byte, b Ballot, err error) {
	b = p.ballot.inc()
	logger := level.Debug(log.With(p.logger, "method", "Propose", "key", key, "B", b))
	var currentState []byte
	{
		logger := log.With(logger, "phase", "prepare")
		type result struct {
			addr   string
			value  []byte
			ballot Ballot
			err    error
		}
		results := make(chan result, len(p.preparers))
		logger.Log("broadcast_to", len(p.preparers))
		for addr, target := range p.preparers {
			go func(addr string, target Preparer) {
				value, ballot, err := target.Prepare(ctx, key, p.age, b)
				results <- result{addr, value, ballot, err}
			}(addr, target)
		}
		var (
			quorum          = qf(len(p.preparers))
			biggestConfirm  Ballot
			biggestConflict Ballot
		)
		for i := 0; i < cap(results) && quorum > 0; i++ {
			result := <-results
			if result.err != nil {
				logger.Log("addr", result.addr, "result", "conflict", "ballot", result.ballot, "err", result.err)
				if result.ballot.greaterThan(biggestConflict) {
					biggestConflict = result.ballot
				}
			} else {
				logger.Log("addr", result.addr, "result", "confirm", "ballot", result.ballot)
				if result.ballot.greaterThan(biggestConfirm) {
					biggestConfirm, currentState = result.ballot, result.value
				}
				quorum--
			}
		}
		if len(p.preparers) > 0 && quorum > 0 {
			logger.Log("result", "failed", "fast_forward_to", biggestConflict.Counter)
			p.ballot.Counter = biggestConflict.Counter  
			return nil, b, ErrPrepareFailed
		}
		logger.Log("result", "success")
	}
	newState := f(currentState)
	{
		logger := log.With(logger, "phase", "accept")
		type result struct {
			addr string
			err  error
		}
		results := make(chan result, len(p.accepters))
		logger.Log("broadcast_to", len(p.accepters))
		for addr, target := range p.accepters {
			go func(addr string, target Accepter) {
				err := target.Accept(ctx, key, p.age, b, newState)
				results <- result{addr, err}
			}(addr, target)
		}
		quorum := qf(len(p.accepters))
		for i := 0; i < cap(results) && quorum > 0; i++ {
			result := <-results
			if result.err != nil {
				logger.Log("addr", result.addr, "result", "conflict", "err", result.err)
			} else {
				logger.Log("addr", result.addr, "result", "confirm")
				quorum--
			}
		}
		if len(p.accepters) > 0 && quorum > 0 {
			logger.Log("result", "failed", "err", "not enough confirmations")
			return nil, b, ErrAcceptFailed
		}
		logger.Log("result", "success")
	}
	return newState, b, nil
}