func (s *StoredUser) RemoveMask(mask string) (deleted bool) {
	mask = strings.ToLower(mask)
	length := len(s.Masks)
	for i := 0; i < length; i++ {
		if mask == s.Masks[i] {
			s.Masks[i], s.Masks[length-1] = s.Masks[length-1], s.Masks[i]
			s.Masks = s.Masks[:length-1]
			deleted = true
			break
		}
	}
	return
}
RemoveMask deletes a mask from this users list of wildcard masks. Returns true
if the mask was found and deleted.
package data
import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"
	"math/rand"
	"sort"
	"strings"
	"time"
	"github.com/aarondl/ultimateq/api"
	"github.com/aarondl/ultimateq/irc"
	"golang.org/x/crypto/bcrypt"
)
func init() {
	rand.Seed(time.Now().UnixNano())
}
var (
	errMissingUnameOrPwd = errors.New("data: Missing username or password")
	errDuplicateMask = errors.New("data: Duplicate mask in user creation")
)
const (
	nNewPasswordLen          = 10
	newPasswordStart         = 48
	newPasswordEnd           = 122
	digitSpecialCharsStart   = 58
	digitSpecialCharsEnd     = 64
	lettersSpecialCharsStart = 91
	lettersSpecialCharsEnd   = 96
)
type StoredUser struct {
	Username   string            `json:"username"`
	Password   []byte            `json:"password"`
	Masks      []string          `json:"masks"`
	Access     map[string]Access `json:"access"`
	JSONStorer `json:"data"`
}
var StoredUserPwdCost = bcrypt.DefaultCost
func NewStoredUser(un, pw string, masks ...string) (*StoredUser, error) {
	if len(un) == 0 || len(pw) == 0 {
		return nil, errMissingUnameOrPwd
	}
	s := &StoredUser{
		Username:   strings.ToLower(un),
		JSONStorer: make(JSONStorer),
		Access:     make(map[string]Access),
	}
	err := s.SetPassword(pw)
	if err != nil {
		return nil, err
	}
	for _, mask := range masks {
		if !s.AddMask(mask) {
			return nil, errDuplicateMask
		}
	}
	return s, nil
}
func (s *StoredUser) Clone() *StoredUser {
	newStoredUser := &StoredUser{
		Username:   s.Username,
		Password:   make([]byte, len(s.Password)),
		Masks:      make([]string, len(s.Masks)),
		JSONStorer: s.JSONStorer.Clone(),
		Access:     make(map[string]Access, len(s.Access)),
	}
	copy(newStoredUser.Password, s.Password)
	copy(newStoredUser.Masks, s.Masks)
	for k, v := range s.Access {
		newStoredUser.Access[k] = v
	}
	return newStoredUser
}
func createStoredUser(masks ...string) *StoredUser {
	s := &StoredUser{
		JSONStorer: make(JSONStorer),
		Access:     make(map[string]Access),
	}
	for _, mask := range masks {
		if !s.AddMask(mask) {
			return nil
		}
	}
	return s
}
func (s *StoredUser) SetPassword(password string) (err error) {
	var pwd []byte
	pwd, err = bcrypt.GenerateFromPassword([]byte(password), StoredUserPwdCost)
	if err != nil {
		return
	}
	s.Password = pwd
	return
}
func (s *StoredUser) ResetPassword() (newpasswd string, err error) {
	b := make([]byte, nNewPasswordLen)
	for i := 0; i < nNewPasswordLen; i++ {
		r := newPasswordStart + rand.Intn(newPasswordEnd-newPasswordStart)
		if r >= digitSpecialCharsStart && r <= digitSpecialCharsEnd {
			r -= digitSpecialCharsEnd - digitSpecialCharsStart + 1
		} else if r >= lettersSpecialCharsStart && r <= lettersSpecialCharsEnd {
			r -= lettersSpecialCharsEnd - lettersSpecialCharsStart + 1
		}
		b[i] = byte(r)
	}
	newpasswd = string(b)
	err = s.SetPassword(newpasswd)
	return
}
func (s *StoredUser) VerifyPassword(password string) bool {
	return nil == bcrypt.CompareHashAndPassword(s.Password, []byte(password))
}
func (s *StoredUser) serialize() ([]byte, error) {
	buffer := &bytes.Buffer{}
	encoder := gob.NewEncoder(buffer)
	err := encoder.Encode(s)
	if err != nil {
		return nil, err
	}
	return buffer.Bytes(), nil
}
func deserializeUser(serialized []byte) (*StoredUser, error) {
	buffer := &bytes.Buffer{}
	decoder := gob.NewDecoder(buffer)
	if _, err := buffer.Write(serialized); err != nil {
		return nil, err
	}
	dec := &StoredUser{}
	err := decoder.Decode(dec)
	return dec, err
}
func (s *StoredUser) AddMask(mask string) bool {
	mask = strings.ToLower(mask)
	for i := 0; i < len(s.Masks); i++ {
		if mask == s.Masks[i] {
			return false
		}
	}
	s.Masks = append(s.Masks, mask)
	return true
}