func (st *stateTracker) GetChannel(c string) *Channel {
	st.mu.Lock()
	defer st.mu.Unlock()
	if ch, ok := st.chans[c]; ok {
		return ch.Channel()
	}
	return nil
}
Returns a Channel for the channel c, if we're tracking it.
package state
import (
	"github.com/fluffle/goirc/logging"
	"sync"
)
type Tracker interface {
	NewNick(nick string) *Nick
	GetNick(nick string) *Nick
	ReNick(old, neu string) *Nick
	DelNick(nick string) *Nick
	NickInfo(nick, ident, host, name string) *Nick
	NickModes(nick, modestr string) *Nick
	NewChannel(channel string) *Channel
	GetChannel(channel string) *Channel
	DelChannel(channel string) *Channel
	Topic(channel, topic string) *Channel
	ChannelModes(channel, modestr string, modeargs ...string) *Channel
	Me() *Nick
	IsOn(channel, nick string) (*ChanPrivs, bool)
	Associate(channel, nick string) *ChanPrivs
	Dissociate(channel, nick string)
	Wipe()
	String() string
}
type stateTracker struct {
	chans map[string]*channel
	nicks map[string]*nick
	me *nick
	mu sync.Mutex
}
var _ Tracker = (*stateTracker)(nil)
func NewTracker(mynick string) *stateTracker {
	st := &stateTracker{
		chans: make(map[string]*channel),
		nicks: make(map[string]*nick),
	}
	st.me = newNick(mynick)
	st.nicks[mynick] = st.me
	return st
}
func (st *stateTracker) Wipe() {
	st.mu.Lock()
	defer st.mu.Unlock()
	for _, ch := range st.chans {
		st.delChannel(ch)
	}
}
func (st *stateTracker) NewNick(n string) *Nick {
	if n == "" {
		logging.Warn("Tracker.NewNick(): Not tracking empty nick.")
		return nil
	}
	st.mu.Lock()
	defer st.mu.Unlock()
	if _, ok := st.nicks[n]; ok {
		logging.Warn("Tracker.NewNick(): %s already tracked.", n)
		return nil
	}
	st.nicks[n] = newNick(n)
	return st.nicks[n].Nick()
}
func (st *stateTracker) GetNick(n string) *Nick {
	st.mu.Lock()
	defer st.mu.Unlock()
	if nk, ok := st.nicks[n]; ok {
		return nk.Nick()
	}
	return nil
}
func (st *stateTracker) ReNick(old, neu string) *Nick {
	st.mu.Lock()
	defer st.mu.Unlock()
	nk, ok := st.nicks[old]
	if !ok {
		logging.Warn("Tracker.ReNick(): %s not tracked.", old)
		return nil
	}
	if _, ok := st.nicks[neu]; ok {
		logging.Warn("Tracker.ReNick(): %s already exists.", neu)
		return nil
	}
	nk.nick = neu
	delete(st.nicks, old)
	st.nicks[neu] = nk
	for ch, _ := range nk.chans {
		delete(ch.lookup, old)
		ch.lookup[neu] = nk
	}
	return nk.Nick()
}
func (st *stateTracker) DelNick(n string) *Nick {
	st.mu.Lock()
	defer st.mu.Unlock()
	if nk, ok := st.nicks[n]; ok {
		if nk == st.me {
			logging.Warn("Tracker.DelNick(): won't delete myself.")
			return nil
		}
		st.delNick(nk)
		return nk.Nick()
	}
	logging.Warn("Tracker.DelNick(): %s not tracked.", n)
	return nil
}
func (st *stateTracker) delNick(nk *nick) {
	if nk == st.me {
		logging.Error("Tracker.DelNick(): TRYING TO DELETE ME :-(")
		return
	}
	delete(st.nicks, nk.nick)
	for ch, _ := range nk.chans {
		nk.delChannel(ch)
		ch.delNick(nk)
		if len(ch.nicks) == 0 {
			logging.Error("Tracker.delNick(): deleting nick %s emptied "+
				"channel %s, this shouldn't happen!", nk.nick, ch.name)
		}
	}
}
func (st *stateTracker) NickInfo(n, ident, host, name string) *Nick {
	st.mu.Lock()
	defer st.mu.Unlock()
	nk, ok := st.nicks[n]
	if !ok {
		return nil
	}
	nk.ident = ident
	nk.host = host
	nk.name = name
	return nk.Nick()
}
func (st *stateTracker) NickModes(n, modes string) *Nick {
	st.mu.Lock()
	defer st.mu.Unlock()
	nk, ok := st.nicks[n]
	if !ok {
		return nil
	}
	nk.parseModes(modes)
	return nk.Nick()
}
func (st *stateTracker) NewChannel(c string) *Channel {
	if c == "" {
		logging.Warn("Tracker.NewChannel(): Not tracking empty channel.")
		return nil
	}
	st.mu.Lock()
	defer st.mu.Unlock()
	if _, ok := st.chans[c]; ok {
		logging.Warn("Tracker.NewChannel(): %s already tracked.", c)
		return nil
	}
	st.chans[c] = newChannel(c)
	return st.chans[c].Channel()
}