func sequencePart(node string) (int, error) {
	if node == "" {
		return 0, errors.New("node cannot be blank")
	}
	matches := sequenceRe.FindStringSubmatch(node)
	if len(matches) != 2 {
		return 0, fmt.Errorf("invalid node: %s", node)
	}
	res, err := strconv.Atoi(matches[1])
	if err != nil {
		return 0, fmt.Errorf("invalid sequence part: %s", matches[1])
	}
	return res, nil
}
sequencePart extracts the trailing integer part of a zk sequential node
into an int.
package elector
import (
	"fmt"
	"path"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"
	"github.com/pkg/errors"
	"github.com/samuel/go-zookeeper/zk"
)
type IElector interface {
	LeaderIdent() string
	Events() <-chan Event
	Close() error
}
var _ IElector = &Elector{}
type Elector struct {
	acl      []zk.ACL
	conn     *zk.Conn
	events   chan Event
	ident    string        
	basePath string        
	closer   func() error  
	mut         sync.Mutex  
	leaderIdent string      
	isLeader    bool        
}
var (
	sequenceRe = regexp.MustCompile(`.*-lock-(-?\d+)$`)
)
func Start(ident string, basePath string, acl []zk.ACL, connector Connector) (*Elector, error) {
	if strings.TrimSpace(ident) == "" {
		return nil, errors.New("ident must not be blank")
	}
	if acl == nil {
		acl = zk.WorldACL(zk.PermAll)
	}
	conn, zkEvents, err := connector.Connect()
	if err != nil {
		return nil, err
	}
	elector := &Elector{
		acl:      acl,
		ident:    ident,
		conn:     conn,
		basePath: basePath,
		events:   make(chan Event),
		closer:   connector.Close,
	}
	if err := elector.initialize(); err != nil {
		return nil, errors.Wrap(err, "elector initialization failed")
	}
	go elector.start(zkEvents)
	return elector, nil
}
func (e *Elector) LeaderIdent() string {
	e.mut.Lock()
	defer e.mut.Unlock()
	return e.leaderIdent
}
func (e *Elector) Events() <-chan Event {
	return e.events
}
func (e *Elector) Close() error {
	return e.closer()
}
func (e *Elector) initialize() error {
	exists, _, err := e.conn.Exists(e.basePath)
	if err != nil {
		return errors.Wrapf(err, "could not check if base path %s exists", e.basePath)
	}
	if exists {
		return nil
	}
	segments := strings.Split(e.basePath, "/")
	create := "/"
	for _, segment := range segments {
		create = path.Join(create, segment)
		exists, _, err := e.conn.Exists(create)
		if err != nil {
			return errors.Wrapf(err, "could not check path '%s'", create)
		}
		if exists {
			continue
		}
		_, err = e.conn.Create(create, []byte{}, 0, e.acl)
		if err != nil {
			return errors.Wrapf(err, "could not create path '%s'", create)
		}
	}
	return nil
}
func (e *Elector) start(zkEvents <-chan zk.Event) {
	defer close(e.events)
	err := func() error {
		lockPath, err := e.conn.CreateProtectedEphemeralSequential(
			e.basePath+"/lock-",
			[]byte(e.ident),
			e.acl)
		if err != nil {
			return errors.Wrap(err, "could not create lock node")
		}
		firstLeaderUpdate := true
		updateFunc := func(children []string) error {
			isLeader, leaderNode, err := determineLeader(lockPath, children)
			if err != nil {
				return errors.Wrap(err, "could not determine leader")
			}
			leaderIdent, err := e.getIdentFromNode(leaderNode)
			if err != nil {
				return errors.Wrap(err, "could not get ident from node")
			}
			e.updateLeaderData(leaderIdent, isLeader, firstLeaderUpdate)
			firstLeaderUpdate = false
			return nil
		}
		children, _, childEvents, err := e.conn.ChildrenW(e.basePath)
		if err != nil {
			return errors.Wrap(err, "could not get children")
		}
		if err = updateFunc(children); err != nil {
			return err
		}
		for {
			select {
			case zkEvent := <-zkEvents:
				if zkEvent.Err != nil {
					return zkEvent.Err
				}
				switch zkEvent.State {
				case zk.StateExpired, zk.StateAuthFailed, zk.StateDisconnected, zk.StateUnknown:
					return fmt.Errorf("invalid ZK state: %v", zkEvent.State)
				}
			case <-childEvents:
				children, _, childEvents, err = e.conn.ChildrenW(e.basePath)
				if err != nil {
					return errors.Wrap(err, "could not get children")
				}
				if err = updateFunc(children); err != nil {
					return err
				}
			}
		}
	}()
	e.sendErr(err)
}
func (e *Elector) updateLeaderData(leaderIdent string, leader bool, forceSend bool) {
	e.mut.Lock()
	prevLeader := e.isLeader  
	e.leaderIdent = leaderIdent
	e.isLeader = leader
	e.mut.Unlock()
	if prevLeader == leader && !forceSend {
		return
	}
	e.sendEvent(Event{Leader: leader})
}
func (e *Elector) getIdentFromNode(node string) (ident string, err error) {
	nodePath := path.Join(e.basePath, node)
	b, _, err := e.conn.Get(nodePath)
	return string(b), err
}
func (e *Elector) sendErr(err error) {
	e.sendEvent(Event{Err: err})
}
func (e *Elector) sendEvent(event Event) {
	e.events <- event
}
func sortedChildrenSequences(children []string) (sorted []int, lookup map[int]string, err error) {
	sorted = make([]int, len(children))
	lookup = make(map[int]string)
	for i, child := range children {
		seq, err := sequencePart(child)
		if err != nil {
			return nil, nil, err
		}
		sorted[i] = seq
		lookup[seq] = child
	}
	sort.Slice(sorted, func(i, j int) bool {
		return sorted[i] < sorted[j]
	})
	return sorted, lookup, nil
}
func determineLeader(node string, children []string) (isLeader bool, leaderNode string, err error) {
	err = func() error {
		if len(children) == 0 {
			return errors.New("no child nodes")
		}
		sequences, lookup, err := sortedChildrenSequences(children)
		if err != nil {
			return err
		}
		mySeq, err := sequencePart(node)
		if err != nil {
			return errors.Wrap(err, "invalid owner node")
		}
		leaderSeq := sequences[0]
		isLeader = mySeq == leaderSeq
		leaderNode = lookup[leaderSeq]
		return nil
	}()
	return isLeader, leaderNode, err
}