func (u *User) writeMsg(m Message) error {
	r := u.render(m)
	_, err := u.screen.Write([]byte(r))
	if err != nil {
		logger.Printf("Write failed to %s, closing: %s", u.ID(), err)
		u.Close()
	}
	return err
}
writeMsg renders the message and attempts to write it, will Close the user
if it fails.
package message
import (
	"errors"
	"fmt"
	"io"
	"math/rand"
	"regexp"
	"sync"
	"time"
	"github.com/shazow/ssh-chat/set"
)
const messageBuffer = 5
const messageTimeout = 5 * time.Second
const reHighlight = `\b(%s)\b`
const timestampTimeout = 30 * time.Minute
var ErrUserClosed = errors.New("user closed")
type User struct {
	Identifier
	OnChange func()
	Ignored  set.Interface
	Focused  set.Interface
	colorIdx int
	joined   time.Time
	msg      chan Message
	done     chan struct{}
	screen    io.WriteCloser
	closeOnce sync.Once
	mu         sync.Mutex
	config     UserConfig
	replyTo    *User      
	lastMsg    time.Time  
	awayReason string     
	awaySince  time.Time  
}
func NewUser(identity Identifier) *User {
	u := User{
		Identifier: identity,
		config:     DefaultUserConfig,
		joined:     time.Now(),
		msg:        make(chan Message, messageBuffer),
		done:       make(chan struct{}),
		Ignored:    set.New(),
		Focused:    set.New(),
	}
	u.setColorIdx(rand.Int())
	return &u
}
func NewUserScreen(identity Identifier, screen io.WriteCloser) *User {
	u := NewUser(identity)
	u.screen = screen
	return u
}
func (u *User) Joined() time.Time {
	return u.joined
}
func (u *User) LastMsg() time.Time {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.lastMsg
}
func (u *User) SetAway(msg string) {
	u.mu.Lock()
	defer u.mu.Unlock()
	u.awayReason = msg
	if msg == "" {
		u.awaySince = time.Time{}
	} else {
		u.awaySince = time.Now()
	}
}
func (u *User) GetAway() (bool, time.Time, string) {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.awayReason != "", u.awaySince, u.awayReason
}
func (u *User) Config() UserConfig {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.config
}
func (u *User) SetConfig(cfg UserConfig) {
	u.mu.Lock()
	u.config = cfg
	u.mu.Unlock()
	if u.OnChange != nil {
		u.OnChange()
	}
}
func (u *User) SetID(id string) {
	u.Identifier.SetID(id)
	u.setColorIdx(rand.Int())
	if u.OnChange != nil {
		u.OnChange()
	}
}
func (u *User) ReplyTo() *User {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.replyTo
}
func (u *User) SetReplyTo(user *User) {
	u.mu.Lock()
	defer u.mu.Unlock()
	u.replyTo = user
}
func (u *User) setColorIdx(idx int) {
	u.colorIdx = idx
}
func (u *User) Close() {
	u.closeOnce.Do(func() {
		if u.screen != nil {
			if err := u.screen.Close(); err != nil {
				logger.Printf("Failed to close user %q screen: %s", u.ID(), err)
			}
		}
		close(u.done)
	})
}
func (u *User) Consume() {
	for {
		select {
		case <-u.done:
			return
		case m, ok := <-u.msg:
			if !ok {
				return
			}
			u.HandleMsg(m)
		}
	}
}
func (u *User) ConsumeOne() Message {
	return <-u.msg
}
func (u *User) HasMessages() bool {
	select {
	case msg := <-u.msg:
		u.msg <- msg
		return true
	default:
		return false
	}
}
func (u *User) SetHighlight(s string) error {
	re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
	if err != nil {
		return err
	}
	u.mu.Lock()
	u.config.Highlight = re
	u.mu.Unlock()
	return nil
}
func (u *User) render(m Message) string {
	cfg := u.Config()
	var out string
	switch m := m.(type) {
	case PublicMsg:
		if u == m.From() {
			u.mu.Lock()
			u.lastMsg = m.Timestamp()
			u.mu.Unlock()
			if !cfg.Echo {
				return ""
			}
			out += m.RenderSelf(cfg)
		} else if u.Focused.Len() > 0 && !u.Focused.In(m.From().ID()) {
			return ""
		} else {
			out += m.RenderFor(cfg)
		}
	case *PrivateMsg:
		out += m.Render(cfg.Theme)
		if cfg.Bell {
			out += Bel
		}
	case *CommandMsg:
		out += m.RenderSelf(cfg)
	default:
		out += m.Render(cfg.Theme)
	}
	if cfg.Timeformat != nil {
		ts := m.Timestamp()
		if cfg.Timezone != nil {
			ts = ts.In(cfg.Timezone)
		} else {
			ts = ts.UTC()
		}
		return cfg.Theme.Timestamp(ts.Format(*cfg.Timeformat)) + "  " + out + Newline
	}
	return out + Newline
}