func getRequestSessions(f *SessionFactory,
	r *http.Request) *requestSessions {
	var s *requestSessions
	rv := ns.Get(r)
	if rv != nil {
		s = rv.(*requestSessions)
	} else {
		s = &requestSessions{factory: f, request: r}
		ns.Set(r, s)
	}
	return s
}
getRequestSessions returns a sessions container for a single request.
package sessions
import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/subtle"
	"encoding/base64"
	"errors"
	"fmt"
	"gob"
	"hash"
	"http"
	"strconv"
	"time"
	"gorilla.googlecode.com/hg/gorilla/context"
)
func init() {
	gob.Register(SessionData{})
	gob.Register([]interface{}{})
	DefaultSessionFactory.SetStore("cookie", new(CookieSessionStore))
}
var (
	DefaultSessionKey = "s"
	DefaultStoreKey   = "cookie"
	DefaultFlashesKey = "_flash"
	ErrEncoding       = errors.New("The value could not be encoded.")
	ErrDecoding       = errors.New("The value could not be decoded.")
	ErrAuthentication = errors.New("The value could not be verified using HMAC.")
	ErrDecryption     = errors.New("The value could not be decrypted.")
	ErrMaxLength      = errors.New("The value exceeds the maximum allowed length.")
	ErrBadTimestamp   = errors.New("Invalid timestamp.")
	ErrNewTimestamp   = errors.New("The value has a newer timestamp than expected.")
	ErrOldTimestamp   = errors.New("The value has an expired timestamp.")
	ErrMissingHash    = errors.New("A hash is required to create and verify values using HMAC.")
	ErrMissingHashKey = errors.New("Authentication secret can't be nil.")
	ErrNoSession      = errors.New("No session found for the given key.")
	ErrNoFlashes      = errors.New("No flashes found for the given key.")
	ErrNoStore        = errors.New("No store found for the given key.")
	ErrStoreMismatch  = errors.New("A session with the given key already exists using a different store.")
	ErrBadIdLength    = errors.New("Session id length must be greater than zero.")
)
type SessionData map[string]interface{}
type SessionConfig struct {
	Path   string
	Domain string
	MaxAge   int
	Secure   bool
	HttpOnly bool
}
type SessionInfo struct {
	Data   SessionData
	Store  SessionStore
	Config SessionConfig
}
func Session(r *http.Request, vars ...string) (SessionData, error) {
	return DefaultSessionFactory.Session(r, vars...)
}
func Flashes(r *http.Request, vars ...string) ([]interface{}, error) {
	return DefaultSessionFactory.Flashes(r, vars...)
}
func AddFlash(r *http.Request, value interface{},
	vars ...string) (bool, error) {
	return DefaultSessionFactory.AddFlash(r, value, vars...)
}
func Config(r *http.Request, key ...string) (*SessionConfig, error) {
	return DefaultSessionFactory.Config(r, key...)
}
func Save(r *http.Request, w http.ResponseWriter) []error {
	return DefaultSessionFactory.Save(r, w)
}
func Store(key string) (SessionStore, error) {
	return DefaultSessionFactory.Store(key)
}
func SetStore(key string, store SessionStore) {
	DefaultSessionFactory.SetStore(key, store)
}
func SetStoreKeys(key string, pairs ...[]byte) (bool, error) {
	return DefaultSessionFactory.SetStoreKeys(key, pairs...)
}
func DefaultConfig() *SessionConfig {
	return DefaultSessionFactory.DefaultConfig()
}
func SetDefaultConfig(config *SessionConfig) {
	DefaultSessionFactory.SetDefaultConfig(config)
}
var DefaultSessionFactory = new(SessionFactory)
var DefaultSessionConfig = &SessionConfig{
	Path:     "/",
	Domain:   "",
	MaxAge:   86400 * 30,
	Secure:   false,
	HttpOnly: false,
}
type SessionFactory struct {
	stores        map[string]SessionStore
	defaultConfig *SessionConfig
}
func (f *SessionFactory) Store(key string) (SessionStore, error) {
	store, ok := f.stores[key]
	if !ok {
		return nil, ErrNoStore
	}
	return store, nil
}
func (f *SessionFactory) SetStore(key string, store SessionStore) {
	if f.stores == nil {
		f.stores = make(map[string]SessionStore)
	}
	f.stores[key] = store
}
func (f *SessionFactory) SetStoreKeys(key string,
	pairs ...[]byte) (bool, error) {
	store, err := f.Store(key)
	if err != nil {
		return false, err
	}
	var b cipher.Block
	size := len(pairs)
	encoders := make([]SessionEncoder, size/2+size%2)
	for i := 0; i < size; i += 2 {
		if pairs[i] == nil || len(pairs[i]) == 0 {
			return false, ErrMissingHashKey
		}
		if size <= i+1 || pairs[i+1] == nil {
			b = nil
		} else {
			b, err = aes.NewCipher(pairs[i+1])
			if err != nil {
				return false, err
			}
		}
		encoders[i/2] = &Encoder{
			Hash:      hmac.NewSHA256(pairs[i]),
			Block:     b,
			MaxAge:    86400 * 30,
			MaxLength: 4096,
		}
	}
	store.SetEncoders(encoders...)
	return true, nil
}
func (f *SessionFactory) Session(r *http.Request,
	vars ...string) (SessionData, error) {
	return getRequestSessions(f, r).Session(vars...)
}
func (f *SessionFactory) Flashes(r *http.Request,
	vars ...string) ([]interface{}, error) {
	key, newvars := flashKey(vars...)
	session, err := f.Session(r, newvars...)
	if err != nil {
		return nil, err
	}
	if flashes, ok := session[key]; ok {
		delete(session, key)
		return flashes.([]interface{}), nil
	}
	return nil, ErrNoFlashes
}
func (f *SessionFactory) AddFlash(r *http.Request, value interface{},
	vars ...string) (bool, error) {
	key, newvars := flashKey(vars...)
	session, err := f.Session(r, newvars...)
	if err != nil {
		return false, err
	}
	var flashes []interface{}
	if v, ok := session[key]; ok {
		flashes = v.([]interface{})
	} else {
		flashes = make([]interface{}, 0)
	}
	session[key] = append(flashes, value)
	return true, nil
}
func (f *SessionFactory) Config(r *http.Request,
	key ...string) (*SessionConfig, error) {
	return getRequestSessions(f, r).Config(key...)
}
func (f *SessionFactory) Save(r *http.Request,
	w http.ResponseWriter) []error {
	return getRequestSessions(f, r).Save(w)
}
func (f *SessionFactory) DefaultConfig() *SessionConfig {
	if f.defaultConfig == nil {
		f.defaultConfig = DefaultSessionConfig
	}
	return f.defaultConfig
}
func (f *SessionFactory) SetDefaultConfig(config *SessionConfig) {
	f.defaultConfig = config
}
func (f *SessionFactory) defaultConfigValue() SessionConfig {
	d := f.DefaultConfig()
	return SessionConfig{
		Path:     d.Path,
		Domain:   d.Domain,
		MaxAge:   d.MaxAge,
		Secure:   d.Secure,
		HttpOnly: d.HttpOnly,
	}
}
func flashKey(vars ...string) (string, []string) {
	key := DefaultFlashesKey
	if len(vars) > 0 {
		if vars[0] != "" {
			key = vars[0]
		}
		vars = vars[1:]
	}
	return key, vars
}
var ns = new(context.Namespace)