<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	"image"
	"image/draw"
	"image/png"
)

type Size struct {
	X, Y int
}

type sprite struct {
	Name   string
	Offset image.Point
	Size   Size
	img    image.Image
	area   int
}

type ByArea []sprite

func (a ByArea) Len() int           { return len(a) }
func (a ByArea) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByArea) Less(i, j int) bool { return a[i].area < a[j].area }

type Node struct {
	child [2]*Node
	rect  image.Rectangle
	img   *sprite
}

func (n *Node) size() Size {
	return Size{n.rect.Dx(), n.rect.Dy()}
}

func (n *Node) print() {
	fmt.Println(n)
	if n.child[0] != nil {
		n.child[0].print()
	}
	if n.child[1] != nil {
		n.child[1].print()
	}
}

func (n *Node) isLeaf() bool {
	return n.child[0] == nil || n.child[1] == nil
}

func (n *Node) insert(img *sprite) *Node {
	if !n.isLeaf() {
		node := n.child[0].insert(img)

		if node != nil {
			return node
		} else {
			return n.child[1].insert(img)
		}
	}

	// there is already an image in this node
	if n.img != nil {
		return nil
	}

	// space too small
	if n.rect.Dx() < img.Size.X || n.rect.Dy() < img.Size.Y {
		return nil
	}

	// just right
	if n.rect.Dx() == img.Size.X && n.rect.Dy() == img.Size.Y {
		img.Offset = n.rect.Min
		n.img = img
		return n
	}

	// the space that is left will be large enough to split
	n.split(img)

	return n.child[0].insert(img)
}

func (n *Node) split(img *sprite) {
	dx := n.rect.Dx() - img.Size.X
	dy := n.rect.Dy() - img.Size.Y

	if dx > dy {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Min.X+img.Size.X,
			n.rect.Max.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X+img.Size.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	} else {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Min.Y+img.Size.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y+img.Size.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	}

}

func main() {
	var space int
	var dim string

	flag.IntVar(&space, "space", 1, "space added between images")
	flag.StringVar(&dim, "dimensions", "1024x1024", "atlas size")

	flag.Parse()

	args := flag.Args()

	inputDir := args[0]
	outputName := args[1]

	dimX, dimY, err := parseDimensions(dim)
	if err != nil {
		log.Fatal(err)
	}

	files, err := ioutil.ReadDir(inputDir)
	if err != nil {
		log.Fatal(err)
	}

	sprites := make([]sprite, len(files))

	totalArea := 0

	for i := range sprites {
		s, err := readSprite(inputDir, files[i].Name(), space)
		if err != nil {
			log.Fatal(err)
		}
		totalArea += s.area
		sprites[i] = s
	}

	if totalArea > dimX*dimY {
		log.Fatalf("%s atlas to small", dim)
	}

	// we want to place the largest sprite first
	sort.Sort(sort.Reverse(ByArea(sprites)))

	// the final image
	dst := image.NewRGBA(image.Rect(0, 0, dimX, dimY))

	n := Node{rect: image.Rect(0, 0, dimX, dimY)}

	for i := range sprites {
		s := &sprites[i]
		node := n.insert(s)
		if node != nil {
			draw.Draw(dst, node.rect, s.img, image.ZP, draw.Src)
		} else {
			log.Fatalf("could not place %s\n", s.Name)
		}

	}

	err = writeAtlas(outputName, dst)
	if err != nil {
		log.Fatal(err)
	}
}

func parseDimensions(dim string) (dimX, dimY int, err error) {
	dims := strings.Split(dim, "x")
	if len(dims) != 2 {
		err = fmt.Errorf("couldn't parse dimension %s\n", dims)
		return
	}

	dimX, err = strconv.Atoi(dims[0])
	if err != nil {
		return
	}

	dimY, err = strconv.Atoi(dims[1])
	if err != nil {
		return
	}

	return
}

func readSprite(dir, name string, space int) (s sprite, err error) {
	path := path.Join(dir, name)
	reader, err := os.Open(path)
	if err != nil {
		return
	}
	defer reader.Close()

	img, _, err := image.Decode(reader)
	if err != nil {
		return
	}

	s.Name = strings.TrimSuffix(name, filepath.Ext(name))
	s.img = img
	rect := img.Bounds()
	s.Size = Size{rect.Dx() + space, rect.Dy() + space}
	s.area = s.Size.X * s.Size.Y
	return
}

func writeAtlas(filename string, data *image.RGBA) (err error) {
	writer, err := os.Create(filename)
	if err != nil {
		return
	}
	defer writer.Close()

	err = png.Encode(writer, data)
	if err != nil {
		return
	}

	return
}
<commit_msg>Print atlas data as json<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	"image"
	"image/draw"
	"image/png"
)

type Size struct {
	X, Y int
}

type sprite struct {
	Name   string
	Offset image.Point
	Size   Size
	img    image.Image
	area   int
}

type ByArea []sprite

func (a ByArea) Len() int           { return len(a) }
func (a ByArea) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByArea) Less(i, j int) bool { return a[i].area < a[j].area }

type Node struct {
	child [2]*Node
	rect  image.Rectangle
	img   *sprite
}

func (n *Node) size() Size {
	return Size{n.rect.Dx(), n.rect.Dy()}
}

func (n *Node) print() {
	fmt.Println(n)
	if n.child[0] != nil {
		n.child[0].print()
	}
	if n.child[1] != nil {
		n.child[1].print()
	}
}

func (n *Node) isLeaf() bool {
	return n.child[0] == nil || n.child[1] == nil
}

func (n *Node) insert(img *sprite) *Node {
	if !n.isLeaf() {
		node := n.child[0].insert(img)

		if node != nil {
			return node
		} else {
			return n.child[1].insert(img)
		}
	}

	// there is already an image in this node
	if n.img != nil {
		return nil
	}

	// space too small
	if n.rect.Dx() < img.Size.X || n.rect.Dy() < img.Size.Y {
		return nil
	}

	// just right
	if n.rect.Dx() == img.Size.X && n.rect.Dy() == img.Size.Y {
		img.Offset = n.rect.Min
		n.img = img
		return n
	}

	// the space that is left will be large enough to split
	n.split(img)

	return n.child[0].insert(img)
}

func (n *Node) split(img *sprite) {
	dx := n.rect.Dx() - img.Size.X
	dy := n.rect.Dy() - img.Size.Y

	if dx > dy {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Min.X+img.Size.X,
			n.rect.Max.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X+img.Size.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	} else {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Min.Y+img.Size.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y+img.Size.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	}

}

func main() {
	var space int
	var dim string

	flag.IntVar(&space, "space", 1, "space added between images")
	flag.StringVar(&dim, "dimensions", "1024x1024", "atlas size")

	flag.Parse()

	args := flag.Args()

	inputDir := args[0]
	outputName := args[1]

	dimX, dimY, err := parseDimensions(dim)
	if err != nil {
		log.Fatal(err)
	}

	files, err := ioutil.ReadDir(inputDir)
	if err != nil {
		log.Fatal(err)
	}

	sprites := make([]sprite, len(files))

	totalArea := 0

	for i := range sprites {
		s, err := readSprite(inputDir, files[i].Name(), space)
		if err != nil {
			log.Fatal(err)
		}
		totalArea += s.area
		sprites[i] = s
	}

	if totalArea > dimX*dimY {
		log.Fatalf("%s atlas to small", dim)
	}

	// we want to place the largest sprite first
	sort.Sort(sort.Reverse(ByArea(sprites)))

	// the final image
	dst := image.NewRGBA(image.Rect(0, 0, dimX, dimY))

	n := Node{rect: image.Rect(0, 0, dimX, dimY)}

	var data []byte

	for i := range sprites {
		s := &sprites[i]
		node := n.insert(s)

		j, err := json.Marshal(s)
		if err != nil {
			log.Fatal(err)
		}
		data = append(data, j...)

		if node != nil {
			draw.Draw(dst, node.rect, s.img, image.ZP, draw.Src)
		} else {
			log.Fatalf("could not place %s\n", s.Name)
		}

	}

	fmt.Println(string(data))

	err = writeAtlas(outputName, dst)
	if err != nil {
		log.Fatal(err)
	}
}

func parseDimensions(dim string) (dimX, dimY int, err error) {
	dims := strings.Split(dim, "x")
	if len(dims) != 2 {
		err = fmt.Errorf("couldn't parse dimension %s\n", dims)
		return
	}

	dimX, err = strconv.Atoi(dims[0])
	if err != nil {
		return
	}

	dimY, err = strconv.Atoi(dims[1])
	if err != nil {
		return
	}

	return
}

func readSprite(dir, name string, space int) (s sprite, err error) {
	path := path.Join(dir, name)
	reader, err := os.Open(path)
	if err != nil {
		return
	}
	defer reader.Close()

	img, _, err := image.Decode(reader)
	if err != nil {
		return
	}

	s.Name = strings.TrimSuffix(name, filepath.Ext(name))
	s.img = img
	rect := img.Bounds()
	s.Size = Size{rect.Dx() + space, rect.Dy() + space}
	s.area = s.Size.X * s.Size.Y
	return
}

func writeAtlas(filename string, data *image.RGBA) (err error) {
	writer, err := os.Create(filename)
	if err != nil {
		return
	}
	defer writer.Close()

	err = png.Encode(writer, data)
	if err != nil {
		return
	}

	return
}
<|endoftext|>


<commit_before>package radius

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/binary"
	"errors"
)

// MaxPacketLength is the maximum possible wire length of a RADIUS packet.
const MaxPacketLength = 4095

// Packet is a RADIUS packet.
type Packet struct {
	Code          Code
	Identifier    byte
	Authenticator [16]byte
	Secret        []byte
	Attributes
}

// New creates a new packet with the Code, Secret fields set to the given
// values. The returned packet's Identifier and Authenticator fields are filled
// with random values.
//
// The function panics if not enough random data could be generated.
func New(code Code, secret []byte) *Packet {
	var buff [17]byte
	if _, err := rand.Read(buff[:]); err != nil {
		panic(err)
	}

	packet := &Packet{
		Code:       code,
		Identifier: buff[0],
		Secret:     secret,
		Attributes: make(Attributes),
	}
	copy(packet.Authenticator[:], buff[1:])
	return packet
}

// Parse parses an encoded RADIUS packet b. An error is returned if the packet
// is malformed.
func Parse(b, secret []byte) (*Packet, error) {
	if len(b) < 20 {
		return nil, errors.New("radius: packet not at least 20 bytes long")
	}

	length := int(binary.BigEndian.Uint16(b[2:4]))
	if length < 20 || length > MaxPacketLength || len(b) > length {
		return nil, errors.New("radius: invalid packet length")
	}

	attrs, err := ParseAttributes(b[20:])
	if err != nil {
		return nil, err
	}

	packet := &Packet{
		Code:       Code(b[0]),
		Identifier: b[1],
		Secret:     secret,
		Attributes: attrs,
	}
	copy(packet.Authenticator[:], b[4:20])
	return packet, nil
}

// Response returns a new packet that has the same identifier, secret, and
// authenticator as the current packet.
func (p *Packet) Response(code Code) *Packet {
	q := &Packet{
		Code:       code,
		Identifier: p.Identifier,
		Secret:     p.Secret,
		Attributes: make(Attributes),
	}
	copy(q.Authenticator[:], p.Authenticator[:])
	return q
}

// Encode encodes the RADIUS packet to wire format. An error is returned if the
// encoded packet is too long (due to its Attributes), or if the packet has an
// unknown Code.
func (p *Packet) Encode() ([]byte, error) {
	size := 20 + p.Attributes.wireSize()
	if size > MaxPacketLength {
		return nil, errors.New("encoded packet is too long")
	}

	b := make([]byte, size)
	b[0] = byte(p.Code)
	b[1] = byte(p.Identifier)
	binary.BigEndian.PutUint16(b[2:4], uint16(size))
	p.Attributes.encodeTo(b[20:])

	switch p.Code {
	case CodeAccessRequest:
		copy(b[4:20], p.Authenticator[:])
	case CodeAccessAccept, CodeAccessReject, CodeAccountingRequest, CodeAccountingResponse, CodeAccessChallenge, CodeDisconnectRequest, CodeCoARequest:
		hash := md5.New()
		hash.Write(b[:4])
		switch p.Code {
		case CodeAccountingRequest, CodeDisconnectRequest, CodeCoARequest:
			var nul [16]byte
			hash.Write(nul[:])
		default:
			hash.Write(p.Authenticator[:])
		}
		hash.Write(b[20:])
		hash.Write(p.Secret)
		hash.Sum(b[4:4:20])
	default:
		return nil, errors.New("radius: unknown Packet Code")
	}

	return b, nil
}

// IsAuthenticResponse returns if the given RADIUS response is an authentic
// response to the given request.
func IsAuthenticResponse(response, request, secret []byte) bool {
	if len(response) < 20 || len(request) < 20 || len(secret) == 0 {
		return false
	}

	hash := md5.New()
	hash.Write(response[:4])
	hash.Write(request[4:20])
	hash.Write(response[20:])
	hash.Write(secret)
	var sum [md5.Size]byte
	return bytes.Equal(hash.Sum(sum[:0]), response[4:20])
}

// IsAuthenticRequest returns if the given RADIUS request is an authentic
// request using the given secret.
func IsAuthenticRequest(request, secret []byte) bool {
	if len(request) < 20 || len(secret) == 0 {
		return false
	}

	switch Code(request[0]) {
	case CodeAccessRequest:
		return true
	case CodeAccountingRequest, CodeDisconnectRequest, CodeCoARequest:
		hash := md5.New()
		hash.Write(request[:4])
		var nul [16]byte
		hash.Write(nul[:])
		hash.Write(request[20:])
		hash.Write(secret)
		var sum [md5.Size]byte
		return bytes.Equal(hash.Sum(sum[:0]), request[4:20])
	default:
		return false
	}
}
<commit_msg>fix missing Code handling in Packet.Encode<commit_after>package radius

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/binary"
	"errors"
)

// MaxPacketLength is the maximum possible wire length of a RADIUS packet.
const MaxPacketLength = 4095

// Packet is a RADIUS packet.
type Packet struct {
	Code          Code
	Identifier    byte
	Authenticator [16]byte
	Secret        []byte
	Attributes
}

// New creates a new packet with the Code, Secret fields set to the given
// values. The returned packet's Identifier and Authenticator fields are filled
// with random values.
//
// The function panics if not enough random data could be generated.
func New(code Code, secret []byte) *Packet {
	var buff [17]byte
	if _, err := rand.Read(buff[:]); err != nil {
		panic(err)
	}

	packet := &Packet{
		Code:       code,
		Identifier: buff[0],
		Secret:     secret,
		Attributes: make(Attributes),
	}
	copy(packet.Authenticator[:], buff[1:])
	return packet
}

// Parse parses an encoded RADIUS packet b. An error is returned if the packet
// is malformed.
func Parse(b, secret []byte) (*Packet, error) {
	if len(b) < 20 {
		return nil, errors.New("radius: packet not at least 20 bytes long")
	}

	length := int(binary.BigEndian.Uint16(b[2:4]))
	if length < 20 || length > MaxPacketLength || len(b) > length {
		return nil, errors.New("radius: invalid packet length")
	}

	attrs, err := ParseAttributes(b[20:])
	if err != nil {
		return nil, err
	}

	packet := &Packet{
		Code:       Code(b[0]),
		Identifier: b[1],
		Secret:     secret,
		Attributes: attrs,
	}
	copy(packet.Authenticator[:], b[4:20])
	return packet, nil
}

// Response returns a new packet that has the same identifier, secret, and
// authenticator as the current packet.
func (p *Packet) Response(code Code) *Packet {
	q := &Packet{
		Code:       code,
		Identifier: p.Identifier,
		Secret:     p.Secret,
		Attributes: make(Attributes),
	}
	copy(q.Authenticator[:], p.Authenticator[:])
	return q
}

// Encode encodes the RADIUS packet to wire format. An error is returned if the
// encoded packet is too long (due to its Attributes), or if the packet has an
// unknown Code.
func (p *Packet) Encode() ([]byte, error) {
	size := 20 + p.Attributes.wireSize()
	if size > MaxPacketLength {
		return nil, errors.New("encoded packet is too long")
	}

	b := make([]byte, size)
	b[0] = byte(p.Code)
	b[1] = byte(p.Identifier)
	binary.BigEndian.PutUint16(b[2:4], uint16(size))
	p.Attributes.encodeTo(b[20:])

	switch p.Code {
	case CodeAccessRequest:
		copy(b[4:20], p.Authenticator[:])
	case CodeAccessAccept, CodeAccessReject, CodeAccountingRequest, CodeAccountingResponse, CodeAccessChallenge, CodeDisconnectRequest, CodeDisconnectACK, CodeDisconnectNAK, CodeCoARequest, CodeCoAACK, CodeCoANAK:
		hash := md5.New()
		hash.Write(b[:4])
		switch p.Code {
		case CodeAccountingRequest, CodeDisconnectRequest, CodeCoARequest:
			var nul [16]byte
			hash.Write(nul[:])
		default:
			hash.Write(p.Authenticator[:])
		}
		hash.Write(b[20:])
		hash.Write(p.Secret)
		hash.Sum(b[4:4:20])
	default:
		return nil, errors.New("radius: unknown Packet Code")
	}

	return b, nil
}

// IsAuthenticResponse returns if the given RADIUS response is an authentic
// response to the given request.
func IsAuthenticResponse(response, request, secret []byte) bool {
	if len(response) < 20 || len(request) < 20 || len(secret) == 0 {
		return false
	}

	hash := md5.New()
	hash.Write(response[:4])
	hash.Write(request[4:20])
	hash.Write(response[20:])
	hash.Write(secret)
	var sum [md5.Size]byte
	return bytes.Equal(hash.Sum(sum[:0]), response[4:20])
}

// IsAuthenticRequest returns if the given RADIUS request is an authentic
// request using the given secret.
func IsAuthenticRequest(request, secret []byte) bool {
	if len(request) < 20 || len(secret) == 0 {
		return false
	}

	switch Code(request[0]) {
	case CodeAccessRequest:
		return true
	case CodeAccountingRequest, CodeDisconnectRequest, CodeCoARequest:
		hash := md5.New()
		hash.Write(request[:4])
		var nul [16]byte
		hash.Write(nul[:])
		hash.Write(request[20:])
		hash.Write(secret)
		var sum [md5.Size]byte
		return bytes.Equal(hash.Sum(sum[:0]), request[4:20])
	default:
		return false
	}
}
<|endoftext|>


<commit_before>package goenocean

import (
	"bytes"
	"encoding/binary"
	"errors"
)

// header is 4 bytes
type header struct {
	dataLength    uint16
	optDataLength uint8
	packetType    uint8
}

func (h *header) crc() byte {
	return crc(h.toBytes())
}
func (h *header) toBytes() []byte {
	var ret []byte
	ret = make([]byte, 4) //since we are appending data and optdata we only neeed to set this to fixed 6
	datalen := make([]byte, 2)
	binary.BigEndian.PutUint16(datalen, h.dataLength)
	ret[0] = datalen[0]
	ret[1] = datalen[1]
	ret[2] = h.optDataLength
	ret[3] = h.packetType
	return ret
}
func (h *header) setFromBytes(data []byte) {
	h.dataLength = binary.BigEndian.Uint16(data[0:2])
	h.optDataLength = data[2]
	h.packetType = data[3]
}

func (h *header) Equal(o *header) bool { // {{{
	return h != nil && o != nil &&
		h.dataLength == o.dataLength &&
		h.optDataLength == o.optDataLength &&
		h.packetType == o.packetType
} // }}}

type Packet interface {
	SetSyncByte(byte)
	SetHeaderFromBytes([]byte)
	ValidateCrc() error
	SetData([]byte)
	Header() *header
	SetHeaderCrc(byte)
	HeaderCrc() byte
	SetOptData([]byte)
	SetDataCrc(byte)
	SyncByte() byte
	DataCrc() byte
	Data() []byte
	OptData() []byte
	Process()
	SenderId() [4]byte
	Equal(Packet) bool
}

type packet struct {
	syncByte  uint8
	header    *header
	headerCrc uint8
	data      []byte
	optData   []byte
	dataCrc   uint8
}

// NewPacket creates a new enocean packet
func NewPacket() *packet {
	header := &header{}
	return &packet{syncByte: 0x55, header: header}
}

func crc(msg []byte) byte { // {{{

	var crcTable = []byte{
		0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
		0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
		0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
		0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
		0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
		0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
		0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
		0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
		0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
		0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
		0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
		0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
		0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
		0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
		0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
		0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
		0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
		0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
		0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
		0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
		0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
		0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
		0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
		0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
		0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
		0x76, 0x71, 0x78, 0x7f, 0x6A, 0x6d, 0x64, 0x63,
		0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
		0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
		0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
		0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83,
		0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
		0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3}

	var crc uint8
	for key := range msg {
		crc = crcTable[crc^msg[key]]
	}
	return crc
} // }}}

const (
	PacketTypeRadioErp1        = 0x01
	PacketTypeResponse         = 0x02
	PacketTypeRadioSubTel      = 0x03
	PacketTypeEvent            = 0x04
	PacketTypeCommonCommand    = 0x05
	PacketTypeSmartAckCommand  = 0x06
	PacketTypeRemoteManCommand = 0x07
	PacketTypeRadioMessage     = 0x09
	PacketTypeRadioErp2        = 0x0a
)

func (p *packet) Header() *header { // {{{
	return p.header
}                                    // }}}
func (p *packet) PacketType() byte { // {{{
	return p.header.packetType
}                                              // }}}
func (p *packet) SetPacketType(pkgtype byte) { // {{{
	p.header.packetType = pkgtype
}                                // }}}
func (p *packet) Data() []byte { // {{{
	return p.data
}                                       // }}}
func (p *packet) SetData(data []byte) { // {{{
	p.data = data
}                                   // }}}
func (p *packet) OptData() []byte { // {{{
	return p.optData
}                                          // }}}
func (p *packet) SetOptData(data []byte) { // {{{
	p.optData = data
}                                         // }}}
func (p *packet) SetSyncByte(data byte) { // {{{
	p.syncByte = data
}                                  // }}}
func (p *packet) SyncByte() byte { // {{{
	return p.syncByte
}                                                  // }}}
func (p *packet) SetHeaderFromBytes(data []byte) { // {{{
	p.header.setFromBytes(data)
}                                          // }}}
func (p *packet) SetHeaderCrc(data byte) { // {{{
	p.headerCrc = data
}                                   // }}}
func (p *packet) HeaderCrc() byte { // {{{
	return p.headerCrc
}                                        // }}}
func (p *packet) SetDataCrc(data byte) { // {{{
	p.dataCrc = data
}                                 // }}}
func (p *packet) DataCrc() byte { // {{{
	return p.dataCrc
}                            // }}}
func (p *packet) Process() { // {{{
	//noop here
}                                     // }}}
func (p *packet) SenderId() [4]byte { // {{{
	//noop here
	return [4]byte{0, 0, 0, 0}
}                                  // }}}
func (p *packet) Encode() []byte { // {{{

	p.header.dataLength = uint16(len(p.data))
	p.header.optDataLength = uint8(len(p.optData))
	p.headerCrc = p.header.crc()
	p.dataCrc = crc(append(p.data, p.optData...))

	//sync+header+headercrc+data+optdata+datacrc
	ret := []byte{p.syncByte}

	ret[0] = p.syncByte

	ret = append(ret, p.header.toBytes()...) //Header
	ret = append(ret, p.headerCrc)           //Header Crc
	ret = append(ret, p.data...)             //Data = starting on byte 6
	ret = append(ret, p.optData...)          //Optional Data starting after Data
	ret = append(ret, p.dataCrc)             // Crc for data+optdata

	return ret
} // }}}
func (p *packet) ValidateCrc() error {
	if p.header.crc() != p.headerCrc {
		return errors.New("Header validation crc failed")
	}
	if p.dataCrc != crc(append(p.data, p.optData...)) {
		return errors.New("Data+Optdata validation crc failed")
	}
	return nil
}
func (p *packet) Equal(o Packet) bool { // {{{
	return p != nil && o != nil &&
		p.Header().Equal(o.Header()) &&
		p.SyncByte() == o.SyncByte() &&
		p.HeaderCrc() == o.HeaderCrc() &&
		p.DataCrc() == o.DataCrc() &&
		bytes.Equal(p.Data(), o.Data()) &&
		bytes.Equal(p.OptData(), o.OptData())
} // }}}
<commit_msg>added packettype to packet interface<commit_after>package goenocean

import (
	"bytes"
	"encoding/binary"
	"errors"
)

// header is 4 bytes
type header struct {
	dataLength    uint16
	optDataLength uint8
	packetType    uint8
}

func (h *header) crc() byte {
	return crc(h.toBytes())
}
func (h *header) toBytes() []byte {
	var ret []byte
	ret = make([]byte, 4) //since we are appending data and optdata we only neeed to set this to fixed 6
	datalen := make([]byte, 2)
	binary.BigEndian.PutUint16(datalen, h.dataLength)
	ret[0] = datalen[0]
	ret[1] = datalen[1]
	ret[2] = h.optDataLength
	ret[3] = h.packetType
	return ret
}
func (h *header) setFromBytes(data []byte) {
	h.dataLength = binary.BigEndian.Uint16(data[0:2])
	h.optDataLength = data[2]
	h.packetType = data[3]
}

func (h *header) Equal(o *header) bool { // {{{
	return h != nil && o != nil &&
		h.dataLength == o.dataLength &&
		h.optDataLength == o.optDataLength &&
		h.packetType == o.packetType
} // }}}

type Packet interface {
	SetSyncByte(byte)
	SetHeaderFromBytes([]byte)
	ValidateCrc() error
	SetData([]byte)
	Header() *header
	SetHeaderCrc(byte)
	HeaderCrc() byte
	SetOptData([]byte)
	SetDataCrc(byte)
	SyncByte() byte
	DataCrc() byte
	Data() []byte
	OptData() []byte
	Process()
	SenderId() [4]byte
	Equal(Packet) bool
	PacketType() byte
}

type packet struct {
	syncByte  uint8
	header    *header
	headerCrc uint8
	data      []byte
	optData   []byte
	dataCrc   uint8
}

// NewPacket creates a new enocean packet
func NewPacket() *packet {
	header := &header{}
	return &packet{syncByte: 0x55, header: header}
}

func crc(msg []byte) byte { // {{{

	var crcTable = []byte{
		0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
		0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
		0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
		0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
		0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
		0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
		0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
		0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
		0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
		0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
		0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
		0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
		0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
		0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
		0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
		0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
		0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
		0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
		0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
		0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
		0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
		0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
		0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
		0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
		0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
		0x76, 0x71, 0x78, 0x7f, 0x6A, 0x6d, 0x64, 0x63,
		0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
		0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
		0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
		0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83,
		0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
		0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3}

	var crc uint8
	for key := range msg {
		crc = crcTable[crc^msg[key]]
	}
	return crc
} // }}}

const (
	PacketTypeRadioErp1        = 0x01
	PacketTypeResponse         = 0x02
	PacketTypeRadioSubTel      = 0x03
	PacketTypeEvent            = 0x04
	PacketTypeCommonCommand    = 0x05
	PacketTypeSmartAckCommand  = 0x06
	PacketTypeRemoteManCommand = 0x07
	PacketTypeRadioMessage     = 0x09
	PacketTypeRadioErp2        = 0x0a
)

func (p *packet) Header() *header { // {{{
	return p.header
}                                    // }}}
func (p *packet) PacketType() byte { // {{{
	return p.header.packetType
}                                              // }}}
func (p *packet) SetPacketType(pkgtype byte) { // {{{
	p.header.packetType = pkgtype
}                                // }}}
func (p *packet) Data() []byte { // {{{
	return p.data
}                                       // }}}
func (p *packet) SetData(data []byte) { // {{{
	p.data = data
}                                   // }}}
func (p *packet) OptData() []byte { // {{{
	return p.optData
}                                          // }}}
func (p *packet) SetOptData(data []byte) { // {{{
	p.optData = data
}                                         // }}}
func (p *packet) SetSyncByte(data byte) { // {{{
	p.syncByte = data
}                                  // }}}
func (p *packet) SyncByte() byte { // {{{
	return p.syncByte
}                                                  // }}}
func (p *packet) SetHeaderFromBytes(data []byte) { // {{{
	p.header.setFromBytes(data)
}                                          // }}}
func (p *packet) SetHeaderCrc(data byte) { // {{{
	p.headerCrc = data
}                                   // }}}
func (p *packet) HeaderCrc() byte { // {{{
	return p.headerCrc
}                                        // }}}
func (p *packet) SetDataCrc(data byte) { // {{{
	p.dataCrc = data
}                                 // }}}
func (p *packet) DataCrc() byte { // {{{
	return p.dataCrc
}                            // }}}
func (p *packet) Process() { // {{{
	//noop here
}                                     // }}}
func (p *packet) SenderId() [4]byte { // {{{
	//noop here
	return [4]byte{0, 0, 0, 0}
}                                  // }}}
func (p *packet) Encode() []byte { // {{{

	p.header.dataLength = uint16(len(p.data))
	p.header.optDataLength = uint8(len(p.optData))
	p.headerCrc = p.header.crc()
	p.dataCrc = crc(append(p.data, p.optData...))

	//sync+header+headercrc+data+optdata+datacrc
	ret := []byte{p.syncByte}

	ret[0] = p.syncByte

	ret = append(ret, p.header.toBytes()...) //Header
	ret = append(ret, p.headerCrc)           //Header Crc
	ret = append(ret, p.data...)             //Data = starting on byte 6
	ret = append(ret, p.optData...)          //Optional Data starting after Data
	ret = append(ret, p.dataCrc)             // Crc for data+optdata

	return ret
} // }}}
func (p *packet) ValidateCrc() error {
	if p.header.crc() != p.headerCrc {
		return errors.New("Header validation crc failed")
	}
	if p.dataCrc != crc(append(p.data, p.optData...)) {
		return errors.New("Data+Optdata validation crc failed")
	}
	return nil
}
func (p *packet) Equal(o Packet) bool { // {{{
	return p != nil && o != nil &&
		p.Header().Equal(o.Header()) &&
		p.SyncByte() == o.SyncByte() &&
		p.HeaderCrc() == o.HeaderCrc() &&
		p.DataCrc() == o.DataCrc() &&
		bytes.Equal(p.Data(), o.Data()) &&
		bytes.Equal(p.OptData(), o.OptData())
} // }}}
<|endoftext|>


<commit_before>package iwscanner

import (
        "os/exec"
        "strings"
        "fmt"
        "bytes"
        "strconv"
        "regexp"
)

func IsWifiOn(device string) (ret bool, err error) {
        var out bytes.Buffer
        testcmd := exec.Command("ifconfig", device)
        testcmd.Stdout = &out
        if e := testcmd.Run(); e != nil {
                err = fmt.Errorf("Error with run: %v", e)
                return
        }

        contains_up := strings.Contains(out.String(), "UP")

        if (contains_up) {
                ret = true
        } else {
                ret = false
        }
        return
}

// in can have strings "on" or "off"
func TurnWifi(device string, in string) error {
        var t string

        if in == "on" {
                t = "up"
        } else {
                t = "down"
        }

        cmd := exec.Command("ifconfig", device, t)
        if err := cmd.Run(); err != nil {
                return fmt.Errorf("Error with run: %v", err)
        } else {

                wifi_on, e := IsWifiOn(device)
                if e != nil {
                        return fmt.Errorf("Error with IsWifiOn: %v", e)
                }

                if in == "on" && wifi_on {
                        return nil
                }
                if in == "off" && !wifi_on {
                        return nil
                }
                return fmt.Errorf("Error: something is wrong. This should not happen.")

        }
}

type AP struct {
        address string
        quality int
        essid string
}

type APs []AP

func GetAPs (device string) (aps APs , err error) {
        var out bytes.Buffer
        cmd := exec.Command("iwlist", device, "scan")
        cmd.Stdout = &out

        if e := cmd.Run(); e != nil {
                err = fmt.Errorf("Error with run: %v", e)
                return
        } else {
                list := parseIwlistOutput(out.String())
                aps = list
                err = nil
                return
        }
}

func parseIwlistOutput(in string) (aps APs) {
        splits := strings.Split(in, "Cell")
        address_regex, _ := regexp.Compile("Address: ([0-9A-Z:]*)")
        quality_regex, _ := regexp.Compile("Quality=([0-9]+)")
        essid_regex, _ := regexp.Compile("ESSID:\"(.*)\"")

        first := true
        for _, split := range splits {
                if first {
                        first = false
                        continue
                }

                ap := AP{}
                address_match := address_regex.FindStringSubmatch(split)
                ap.address = address_match[1]

                quality_match := quality_regex.FindStringSubmatch(split)
                i, _ := strconv.Atoi(quality_match[1])
                ap.quality = i

                ap.essid = essid_regex.FindStringSubmatch(split)[1]

                aps = append(aps, ap)
        }
        return
}

func parseIwOutput(in string) (aps APs) {
        splits := strings.Split(in, "BSS")
        address_regex, _ := regexp.Compile(" ([0-9a-z:]*)\\(on (.*)\\)")
        quality_regex, _ := regexp.Compile("signal: -([0-9]+)\\.\\d\\d dBm")
        essid_regex, _ := regexp.Compile("SSID: (.*)")

        first := true
        for _, split := range splits {
                if first {
                        first = false
                        continue
                }

                ap := AP{}
                address_match := address_regex.FindStringSubmatch(split)
                ap.address = address_match[1]

                quality_match := quality_regex.FindStringSubmatch(split)
                i, _ := strconv.Atoi(quality_match[1])
                ap.quality = 100 - i

                ap.essid = essid_regex.FindStringSubmatch(split)[1]

                aps = append(aps, ap)
        }
        return
        return
}
<commit_msg>double return<commit_after>package iwscanner

import (
        "os/exec"
        "strings"
        "fmt"
        "bytes"
        "strconv"
        "regexp"
)

func IsWifiOn(device string) (ret bool, err error) {
        var out bytes.Buffer
        testcmd := exec.Command("ifconfig", device)
        testcmd.Stdout = &out
        if e := testcmd.Run(); e != nil {
                err = fmt.Errorf("Error with run: %v", e)
                return
        }

        contains_up := strings.Contains(out.String(), "UP")

        if (contains_up) {
                ret = true
        } else {
                ret = false
        }
        return
}

// in can have strings "on" or "off"
func TurnWifi(device string, in string) error {
        var t string

        if in == "on" {
                t = "up"
        } else {
                t = "down"
        }

        cmd := exec.Command("ifconfig", device, t)
        if err := cmd.Run(); err != nil {
                return fmt.Errorf("Error with run: %v", err)
        } else {

                wifi_on, e := IsWifiOn(device)
                if e != nil {
                        return fmt.Errorf("Error with IsWifiOn: %v", e)
                }

                if in == "on" && wifi_on {
                        return nil
                }
                if in == "off" && !wifi_on {
                        return nil
                }
                return fmt.Errorf("Error: something is wrong. This should not happen.")

        }
}

type AP struct {
        address string
        quality int
        essid string
}

type APs []AP

func GetAPs (device string) (aps APs , err error) {
        var out bytes.Buffer
        cmd := exec.Command("iwlist", device, "scan")
        cmd.Stdout = &out

        if e := cmd.Run(); e != nil {
                err = fmt.Errorf("Error with run: %v", e)
                return
        } else {
                list := parseIwlistOutput(out.String())
                aps = list
                err = nil
                return
        }
}

func parseIwlistOutput(in string) (aps APs) {
        splits := strings.Split(in, "Cell")
        address_regex, _ := regexp.Compile("Address: ([0-9A-Z:]*)")
        quality_regex, _ := regexp.Compile("Quality=([0-9]+)")
        essid_regex, _ := regexp.Compile("ESSID:\"(.*)\"")

        first := true
        for _, split := range splits {
                if first {
                        first = false
                        continue
                }

                ap := AP{}
                address_match := address_regex.FindStringSubmatch(split)
                ap.address = address_match[1]

                quality_match := quality_regex.FindStringSubmatch(split)
                i, _ := strconv.Atoi(quality_match[1])
                ap.quality = i

                ap.essid = essid_regex.FindStringSubmatch(split)[1]

                aps = append(aps, ap)
        }
        return
}

func parseIwOutput(in string) (aps APs) {
        splits := strings.Split(in, "BSS")
        address_regex, _ := regexp.Compile(" ([0-9a-z:]*)\\(on (.*)\\)")
        quality_regex, _ := regexp.Compile("signal: -([0-9]+)\\.\\d\\d dBm")
        essid_regex, _ := regexp.Compile("SSID: (.*)")

        first := true
        for _, split := range splits {
                if first {
                        first = false
                        continue
                }

                ap := AP{}
                address_match := address_regex.FindStringSubmatch(split)
                ap.address = address_match[1]

                quality_match := quality_regex.FindStringSubmatch(split)
                i, _ := strconv.Atoi(quality_match[1])
                ap.quality = 100 - i

                ap.essid = essid_regex.FindStringSubmatch(split)[1]

                aps = append(aps, ap)
        }
        return
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/danmane/abalone/go/api"
	"github.com/gorilla/mux"
)

func ListGamesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		games, err := ds.Games.List()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if games == nil {
			games = make([]api.Game, 0)
		}
		if err := json.NewEncoder(w).Encode(&games); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

func ListDetailsGamesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		games, err := ds.Games.ListDetailed()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if games == nil {
			games = make([]*api.GameWithDetails, 0)
		}
		if err := json.NewEncoder(w).Encode(&games); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

type GameStatesAPIResponse struct {
	White         *string
	Black         *string
	Outcome       string
	VictoryReason string
	States        []string `sql:"-"`
}

func ListGameStatesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		gidStr := mux.Vars(r)["game_id"]
		if gidStr == "" {
			// if wasn't in mux path, try URL query param
			gidStr = r.URL.Query().Get("game_id")
		}
		if gidStr == "" {
			http.Error(w, "game_id is required", http.StatusBadRequest)
			return
		}
		gameID, err := strconv.ParseInt(gidStr, 10, 64)
		if err != nil {
			http.Error(w, fmt.Sprintf("error parsing game_id: %s", err.Error()), http.StatusBadRequest)
			return
		}
		var game GameStatesAPIResponse
		var records []api.Record
		if err := ds.DB.Where(api.Record{GameID: gameID}).Order("turn_num asc").Find(&records).Pluck("state", &game.States).Error; err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		if err := ds.DB.Raw(` SELECT
			ROW_TO_JSON(whiteplayer) AS White,
			ROW_TO_JSON(blackplayer) AS Black,
    		g.status AS Outcome,
    		g.reason AS VictoryReason
    		FROM games g
			LEFT JOIN players whiteplayer ON whiteplayer.id = g.white_player_id
			LEFT JOIN players blackplayer ON blackplayer.id = g.black_player_id
			WHERE (g.id = ?`, gameID).Scan(&game).Error; err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		if err := json.NewEncoder(w).Encode(game); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}
<commit_msg>Revert "rename struct to GameStatesAPIResponse"<commit_after>package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/danmane/abalone/go/api"
	"github.com/gorilla/mux"
)

func ListGamesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		games, err := ds.Games.List()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if games == nil {
			games = make([]api.Game, 0)
		}
		if err := json.NewEncoder(w).Encode(&games); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

func ListDetailsGamesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		games, err := ds.Games.ListDetailed()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if games == nil {
			games = make([]*api.GameWithDetails, 0)
		}
		if err := json.NewEncoder(w).Encode(&games); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

type GameResultDets struct {

	White         *string
	Black         *string
	Outcome       string
	VictoryReason string
	States        []string `sql:"-"`
}

func ListGameStatesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		gidStr := mux.Vars(r)["game_id"]
		if gidStr == "" {
			// if wasn't in mux path, try URL query param
			gidStr = r.URL.Query().Get("game_id")
		}
		if gidStr == "" {
			http.Error(w, "game_id is required", http.StatusBadRequest)
			return
		}
		gameID, err := strconv.ParseInt(gidStr, 10, 64)
		if err != nil {
			http.Error(w, fmt.Sprintf("error parsing game_id: %s", err.Error()), http.StatusBadRequest)
			return
		}
		var game GameResultDets
		var records []api.Record
		if err := ds.DB.Where(api.Record{GameID: gameID}).Order("turn_num asc").Find(&records).Pluck("state",&game.States).Error; err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		if err := ds.DB.Raw(` SELECT
			ROW_TO_JSON(whiteplayer) AS White,
			ROW_TO_JSON(blackplayer) AS Black,
    		g.status AS Outcome,
    		g.reason AS VictoryReason
    		FROM games g
			LEFT JOIN players whiteplayer ON whiteplayer.id = g.white_player_id
			LEFT JOIN players blackplayer ON blackplayer.id = g.black_player_id
			WHERE (g.id = ?`, gameID).Scan(&game).Error; err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		if err := json.NewEncoder(w).Encode(game); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

<|endoftext|>


<commit_before>/**
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * This file is licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License. A copy of
 * the License is located at
 *
 * http://aws.amazon.com/apache2.0/
 *
 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
*/

// snippet-sourcedescription:[s3.go demonstrates how to list, create, and delete a bucket in Amazon S3.]
// snippet-service:[s3]
// snippet-keyword:[Go]
// snippet-keyword:[Amazon S3]
// snippet-keyword:[Code Sample]
// snippet-keyword:[ListBuckets]
// snippet-keyword:[CreateBucket]
// snippet-keyword:[DeleteBucket]
// snippet-sourcetype:[full-example]
// snippet-sourcedate:[2017-07-11]
// snippet-sourceauthor:[AWS]
// snippet-start:[s3.go.bucket_operations.list_create_delete]
package main

import (
  "fmt"
  "os"
  "github.com/aws/aws-sdk-go/aws"
  "github.com/aws/aws-sdk-go/aws/session"
  "github.com/aws/aws-sdk-go/service/s3"
)

func main() {

  if len(os.Args) < 3 {
    fmt.Printf("Usage: go run s3.go <the bucket name> <the AWS Region to use>\n" +
      "Example: go run s3.go my-test-bucket us-east-2\n")
    os.Exit(1)
  }

  sess := session.Must(session.NewSessionWithOptions(session.Options{
    SharedConfigState: session.SharedConfigEnable,
  }))
  svc := s3.New(sess, &aws.Config{
    Region: aws.String(os.Args[2]),
  })

  listMyBuckets(svc)
  createMyBucket(svc, os.Args[1], os.Args[2])
  listMyBuckets(svc)
  deleteMyBucket(svc, os.Args[1])
  listMyBuckets(svc)
}

// List all of your available buckets in this AWS Region.
func listMyBuckets(svc *s3.S3) {
  result, err := svc.ListBuckets(nil)

  if err != nil {
    exitErrorf("Unable to list buckets, %v", err)
  }

  fmt.Println("My buckets now are:\n")

  for _, b := range result.Buckets {
    fmt.Printf(aws.StringValue(b.Name) + "\n")
  }

  fmt.Printf("\n")
}

// Create a bucket in this AWS Region.
func createMyBucket(svc *s3.S3, bucketName string, region string) {
  fmt.Printf("\nCreating a new bucket named '" + bucketName + "'...\n\n")

  _, err := svc.CreateBucket(&s3.CreateBucketInput{
   Bucket: aws.String(bucketName),
   CreateBucketConfiguration: &s3.CreateBucketConfiguration{
     LocationConstraint: aws.String(region),
   },
 })

  if err != nil {
    exitErrorf("Unable to create bucket, %v", err)
  }
}

// Delete the bucket you just created.
func deleteMyBucket(svc *s3.S3, bucketName string) {
  fmt.Printf("\nDeleting the bucket named '" + bucketName + "'...\n\n")

  _, err := svc.DeleteBucket(&s3.DeleteBucketInput{
    Bucket: aws.String(bucketName),
  })

  if err != nil {
    exitErrorf("Unable to delete bucket, %v", err)
  }
}

// If there's an error, display it.
func exitErrorf(msg string, args ...interface{}) {
  fmt.Fprintf(os.Stderr, msg+"\n", args...)
  os.Exit(1)
}
// snippet-end:[s3.go.bucket_operations.list_create_delete]<commit_msg>Update s3.go<commit_after>/**
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * This file is licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License. A copy of
 * the License is located at
 *
 * http://aws.amazon.com/apache2.0/
 *
 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
*/
// snippet-sourcedescription:[s3.go demonstrates how to list, create, and delete a bucket in Amazon S3.]
// snippet-service:[s3]
// snippet-keyword:[Go]
// snippet-keyword:[Amazon S3]
// snippet-keyword:[Code Sample]
// snippet-keyword:[ListBuckets]
// snippet-keyword:[CreateBucket]
// snippet-keyword:[DeleteBucket]
// snippet-sourcetype:[full-example]
// snippet-sourcedate:[2017-07-11]
// snippet-sourceauthor:[AWS]
// snippet-start:[s3.go.bucket_operations.list_create_delete]
package main

import (
  "fmt"
  "os"
  "github.com/aws/aws-sdk-go/aws"
  "github.com/aws/aws-sdk-go/aws/session"
  "github.com/aws/aws-sdk-go/service/s3"
)

func main() {

  if len(os.Args) < 3 {
    fmt.Printf("Usage: go run s3.go <the bucket name> <the AWS Region to use>\n" +
      "Example: go run s3.go my-test-bucket us-east-2\n")
    os.Exit(1)
  }

  sess := session.Must(session.NewSessionWithOptions(session.Options{
    SharedConfigState: session.SharedConfigEnable,
  }))
  svc := s3.New(sess, &aws.Config{
    Region: aws.String(os.Args[2]),
  })

  listMyBuckets(svc)
  createMyBucket(svc, os.Args[1], os.Args[2])
  listMyBuckets(svc)
  deleteMyBucket(svc, os.Args[1])
  listMyBuckets(svc)
}

// List all of your available buckets in this AWS Region.
func listMyBuckets(svc *s3.S3) {
  result, err := svc.ListBuckets(nil)

  if err != nil {
    exitErrorf("Unable to list buckets, %v", err)
  }

  fmt.Println("My buckets now are:\n")

  for _, b := range result.Buckets {
    fmt.Printf(aws.StringValue(b.Name) + "\n")
  }

  fmt.Printf("\n")
}

// Create a bucket in this AWS Region.
func createMyBucket(svc *s3.S3, bucketName string, region string) {
  fmt.Printf("\nCreating a new bucket named '" + bucketName + "'...\n\n")

  _, err := svc.CreateBucket(&s3.CreateBucketInput{
   Bucket: aws.String(bucketName),
   CreateBucketConfiguration: &s3.CreateBucketConfiguration{
     LocationConstraint: aws.String(region),
   },
 })

  if err != nil {
    exitErrorf("Unable to create bucket, %v", err)
  }

  // Wait until bucket is created before finishing
  fmt.Printf("Waiting for bucket %q to be created...\n", bucketName)

  err = svc.WaitUntilBucketExists(&s3.HeadBucketInput{
    Bucket: aws.String(bucketName),
  })
}

// Delete the bucket you just created.
func deleteMyBucket(svc *s3.S3, bucketName string) {
  fmt.Printf("\nDeleting the bucket named '" + bucketName + "'...\n\n")

  _, err := svc.DeleteBucket(&s3.DeleteBucketInput{
    Bucket: aws.String(bucketName),
  })

  if err != nil {
    exitErrorf("Unable to delete bucket, %v", err)
  }

  // Wait until bucket is deleted before finishing
  fmt.Printf("Waiting for bucket %q to be deleted...\n", bucketName)

  err = svc.WaitUntilBucketNotExists(&s3.HeadBucketInput{
    Bucket: aws.String(bucketName),
  })
}

// If there's an error, display it.
func exitErrorf(msg string, args ...interface{}) {
  fmt.Fprintf(os.Stderr, msg+"\n", args...)
  os.Exit(1)
}
// snippet-end:[s3.go.bucket_operations.list_create_delete]
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sqltypes

import (
	"testing"

	querypb "vitess.io/vitess/go/vt/proto/query"
)

func TestTypeValues(t *testing.T) {
	testcases := []struct {
		defined  querypb.Type
		expected int
	}{{
		defined:  Null,
		expected: 0,
	}, {
		defined:  Int8,
		expected: 1 | flagIsIntegral,
	}, {
		defined:  Uint8,
		expected: 2 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int16,
		expected: 3 | flagIsIntegral,
	}, {
		defined:  Uint16,
		expected: 4 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int24,
		expected: 5 | flagIsIntegral,
	}, {
		defined:  Uint24,
		expected: 6 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int32,
		expected: 7 | flagIsIntegral,
	}, {
		defined:  Uint32,
		expected: 8 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int64,
		expected: 9 | flagIsIntegral,
	}, {
		defined:  Uint64,
		expected: 10 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Float32,
		expected: 11 | flagIsFloat,
	}, {
		defined:  Float64,
		expected: 12 | flagIsFloat,
	}, {
		defined:  Timestamp,
		expected: 13 | flagIsQuoted,
	}, {
		defined:  Date,
		expected: 14 | flagIsQuoted,
	}, {
		defined:  Time,
		expected: 15 | flagIsQuoted,
	}, {
		defined:  Datetime,
		expected: 16 | flagIsQuoted,
	}, {
		defined:  Year,
		expected: 17 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Decimal,
		expected: 18,
	}, {
		defined:  Text,
		expected: 19 | flagIsQuoted | flagIsText,
	}, {
		defined:  Blob,
		expected: 20 | flagIsQuoted | flagIsBinary,
	}, {
		defined:  VarChar,
		expected: 21 | flagIsQuoted | flagIsText,
	}, {
		defined:  VarBinary,
		expected: 22 | flagIsQuoted | flagIsBinary,
	}, {
		defined:  Char,
		expected: 23 | flagIsQuoted | flagIsText,
	}, {
		defined:  Binary,
		expected: 24 | flagIsQuoted | flagIsBinary,
	}, {
		defined:  Bit,
		expected: 25 | flagIsQuoted,
	}, {
		defined:  Enum,
		expected: 26 | flagIsQuoted,
	}, {
		defined:  Set,
		expected: 27 | flagIsQuoted,
	}, {
		defined:  Geometry,
		expected: 29 | flagIsQuoted,
	}, {
		defined:  TypeJSON,
		expected: 30 | flagIsQuoted,
	}, {
		defined:  Expression,
		expected: 31,
	}}
	for _, tcase := range testcases {
		if int(tcase.defined) != tcase.expected {
			t.Errorf("Type %s: %d, want: %d", tcase.defined, int(tcase.defined), tcase.expected)
		}
	}
}

// TestCategory verifies that the type categorizations
// are non-overlapping and complete.
func TestCategory(t *testing.T) {
	alltypes := []querypb.Type{
		Null,
		Int8,
		Uint8,
		Int16,
		Uint16,
		Int24,
		Uint24,
		Int32,
		Uint32,
		Int64,
		Uint64,
		Float32,
		Float64,
		Timestamp,
		Date,
		Time,
		Datetime,
		Year,
		Decimal,
		Text,
		Blob,
		VarChar,
		VarBinary,
		Char,
		Binary,
		Bit,
		Enum,
		Set,
		Geometry,
		TypeJSON,
		Expression,
	}
	for _, typ := range alltypes {
		matched := false
		if IsSigned(typ) {
			if !IsIntegral(typ) {
				t.Errorf("Signed type %v is not an integral", typ)
			}
			matched = true
		}
		if IsUnsigned(typ) {
			if !IsIntegral(typ) {
				t.Errorf("Unsigned type %v is not an integral", typ)
			}
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if IsFloat(typ) {
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if IsQuoted(typ) {
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if typ == Null || typ == Decimal || typ == Expression || typ == Bit {
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if !matched {
			t.Errorf("%v matched no category", typ)
		}
	}
}

func TestIsFunctions(t *testing.T) {
	if IsIntegral(Null) {
		t.Error("Null: IsIntegral, must be false")
	}
	if !IsIntegral(Int64) {
		t.Error("Int64: !IsIntegral, must be true")
	}
	if IsSigned(Uint64) {
		t.Error("Uint64: IsSigned, must be false")
	}
	if !IsSigned(Int64) {
		t.Error("Int64: !IsSigned, must be true")
	}
	if IsUnsigned(Int64) {
		t.Error("Int64: IsUnsigned, must be false")
	}
	if !IsUnsigned(Uint64) {
		t.Error("Uint64: !IsUnsigned, must be true")
	}
	if IsFloat(Int64) {
		t.Error("Int64: IsFloat, must be false")
	}
	if !IsFloat(Float64) {
		t.Error("Uint64: !IsFloat, must be true")
	}
	if IsQuoted(Int64) {
		t.Error("Int64: IsQuoted, must be false")
	}
	if !IsQuoted(Binary) {
		t.Error("Binary: !IsQuoted, must be true")
	}
	if IsText(Int64) {
		t.Error("Int64: IsText, must be false")
	}
	if !IsText(Char) {
		t.Error("Char: !IsText, must be true")
	}
	if IsBinary(Int64) {
		t.Error("Int64: IsBinary, must be false")
	}
	if !IsBinary(Binary) {
		t.Error("Char: !IsBinary, must be true")
	}
	if !isNumber(Int64) {
		t.Error("Int64: !isNumber, must be true")
	}
}

func TestTypeToMySQL(t *testing.T) {
	v, f := TypeToMySQL(Bit)
	if v != 16 {
		t.Errorf("Bit: %d, want 16", v)
	}
	if f != mysqlUnsigned {
		t.Errorf("Bit flag: %x, want %x", f, mysqlUnsigned)
	}
	v, f = TypeToMySQL(Date)
	if v != 10 {
		t.Errorf("Bit: %d, want 10", v)
	}
	if f != mysqlBinary {
		t.Errorf("Bit flag: %x, want %x", f, mysqlBinary)
	}
}

func TestMySQLToType(t *testing.T) {
	testcases := []struct {
		intype  int64
		inflags int64
		outtype querypb.Type
	}{{
		intype:  1,
		outtype: Int8,
	}, {
		intype:  1,
		inflags: mysqlUnsigned,
		outtype: Uint8,
	}, {
		intype:  2,
		outtype: Int16,
	}, {
		intype:  2,
		inflags: mysqlUnsigned,
		outtype: Uint16,
	}, {
		intype:  3,
		outtype: Int32,
	}, {
		intype:  3,
		inflags: mysqlUnsigned,
		outtype: Uint32,
	}, {
		intype:  4,
		outtype: Float32,
	}, {
		intype:  5,
		outtype: Float64,
	}, {
		intype:  6,
		outtype: Null,
	}, {
		intype:  7,
		outtype: Timestamp,
	}, {
		intype:  8,
		outtype: Int64,
	}, {
		intype:  8,
		inflags: mysqlUnsigned,
		outtype: Uint64,
	}, {
		intype:  9,
		outtype: Int24,
	}, {
		intype:  9,
		inflags: mysqlUnsigned,
		outtype: Uint24,
	}, {
		intype:  10,
		outtype: Date,
	}, {
		intype:  11,
		outtype: Time,
	}, {
		intype:  12,
		outtype: Datetime,
	}, {
		intype:  13,
		outtype: Year,
	}, {
		intype:  16,
		outtype: Bit,
	}, {
		intype:  245,
		outtype: TypeJSON,
	}, {
		intype:  246,
		outtype: Decimal,
	}, {
		intype:  249,
		outtype: Text,
	}, {
		intype:  250,
		outtype: Text,
	}, {
		intype:  251,
		outtype: Text,
	}, {
		intype:  252,
		outtype: Text,
	}, {
		intype:  252,
		inflags: mysqlBinary,
		outtype: Blob,
	}, {
		intype:  253,
		outtype: VarChar,
	}, {
		intype:  253,
		inflags: mysqlBinary,
		outtype: VarBinary,
	}, {
		intype:  254,
		outtype: Char,
	}, {
		intype:  254,
		inflags: mysqlBinary,
		outtype: Binary,
	}, {
		intype:  254,
		inflags: mysqlEnum,
		outtype: Enum,
	}, {
		intype:  254,
		inflags: mysqlSet,
		outtype: Set,
	}, {
		intype:  255,
		outtype: Geometry,
	}, {
		// Binary flag must be ignored.
		intype:  8,
		inflags: mysqlUnsigned | mysqlBinary,
		outtype: Uint64,
	}, {
		// Unsigned flag must be ignored
		intype:  252,
		inflags: mysqlUnsigned | mysqlBinary,
		outtype: Blob,
	}}
	for _, tcase := range testcases {
		got, err := MySQLToType(tcase.intype, tcase.inflags)
		if err != nil {
			t.Error(err)
		}
		if got != tcase.outtype {
			t.Errorf("MySQLToType(%d, %x): %v, want %v", tcase.intype, tcase.inflags, got, tcase.outtype)
		}
	}
}

func TestTypeError(t *testing.T) {
	_, err := MySQLToType(15, 0)
	want := "unsupported type: 15"
	if err == nil || err.Error() != want {
		t.Errorf("MySQLToType: %v, want %s", err, want)
	}
}
<commit_msg>Fix TestTypeError<commit_after>/*
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sqltypes

import (
	"testing"

	querypb "vitess.io/vitess/go/vt/proto/query"
)

func TestTypeValues(t *testing.T) {
	testcases := []struct {
		defined  querypb.Type
		expected int
	}{{
		defined:  Null,
		expected: 0,
	}, {
		defined:  Int8,
		expected: 1 | flagIsIntegral,
	}, {
		defined:  Uint8,
		expected: 2 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int16,
		expected: 3 | flagIsIntegral,
	}, {
		defined:  Uint16,
		expected: 4 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int24,
		expected: 5 | flagIsIntegral,
	}, {
		defined:  Uint24,
		expected: 6 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int32,
		expected: 7 | flagIsIntegral,
	}, {
		defined:  Uint32,
		expected: 8 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Int64,
		expected: 9 | flagIsIntegral,
	}, {
		defined:  Uint64,
		expected: 10 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Float32,
		expected: 11 | flagIsFloat,
	}, {
		defined:  Float64,
		expected: 12 | flagIsFloat,
	}, {
		defined:  Timestamp,
		expected: 13 | flagIsQuoted,
	}, {
		defined:  Date,
		expected: 14 | flagIsQuoted,
	}, {
		defined:  Time,
		expected: 15 | flagIsQuoted,
	}, {
		defined:  Datetime,
		expected: 16 | flagIsQuoted,
	}, {
		defined:  Year,
		expected: 17 | flagIsIntegral | flagIsUnsigned,
	}, {
		defined:  Decimal,
		expected: 18,
	}, {
		defined:  Text,
		expected: 19 | flagIsQuoted | flagIsText,
	}, {
		defined:  Blob,
		expected: 20 | flagIsQuoted | flagIsBinary,
	}, {
		defined:  VarChar,
		expected: 21 | flagIsQuoted | flagIsText,
	}, {
		defined:  VarBinary,
		expected: 22 | flagIsQuoted | flagIsBinary,
	}, {
		defined:  Char,
		expected: 23 | flagIsQuoted | flagIsText,
	}, {
		defined:  Binary,
		expected: 24 | flagIsQuoted | flagIsBinary,
	}, {
		defined:  Bit,
		expected: 25 | flagIsQuoted,
	}, {
		defined:  Enum,
		expected: 26 | flagIsQuoted,
	}, {
		defined:  Set,
		expected: 27 | flagIsQuoted,
	}, {
		defined:  Geometry,
		expected: 29 | flagIsQuoted,
	}, {
		defined:  TypeJSON,
		expected: 30 | flagIsQuoted,
	}, {
		defined:  Expression,
		expected: 31,
	}}
	for _, tcase := range testcases {
		if int(tcase.defined) != tcase.expected {
			t.Errorf("Type %s: %d, want: %d", tcase.defined, int(tcase.defined), tcase.expected)
		}
	}
}

// TestCategory verifies that the type categorizations
// are non-overlapping and complete.
func TestCategory(t *testing.T) {
	alltypes := []querypb.Type{
		Null,
		Int8,
		Uint8,
		Int16,
		Uint16,
		Int24,
		Uint24,
		Int32,
		Uint32,
		Int64,
		Uint64,
		Float32,
		Float64,
		Timestamp,
		Date,
		Time,
		Datetime,
		Year,
		Decimal,
		Text,
		Blob,
		VarChar,
		VarBinary,
		Char,
		Binary,
		Bit,
		Enum,
		Set,
		Geometry,
		TypeJSON,
		Expression,
	}
	for _, typ := range alltypes {
		matched := false
		if IsSigned(typ) {
			if !IsIntegral(typ) {
				t.Errorf("Signed type %v is not an integral", typ)
			}
			matched = true
		}
		if IsUnsigned(typ) {
			if !IsIntegral(typ) {
				t.Errorf("Unsigned type %v is not an integral", typ)
			}
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if IsFloat(typ) {
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if IsQuoted(typ) {
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if typ == Null || typ == Decimal || typ == Expression || typ == Bit {
			if matched {
				t.Errorf("%v matched more than one category", typ)
			}
			matched = true
		}
		if !matched {
			t.Errorf("%v matched no category", typ)
		}
	}
}

func TestIsFunctions(t *testing.T) {
	if IsIntegral(Null) {
		t.Error("Null: IsIntegral, must be false")
	}
	if !IsIntegral(Int64) {
		t.Error("Int64: !IsIntegral, must be true")
	}
	if IsSigned(Uint64) {
		t.Error("Uint64: IsSigned, must be false")
	}
	if !IsSigned(Int64) {
		t.Error("Int64: !IsSigned, must be true")
	}
	if IsUnsigned(Int64) {
		t.Error("Int64: IsUnsigned, must be false")
	}
	if !IsUnsigned(Uint64) {
		t.Error("Uint64: !IsUnsigned, must be true")
	}
	if IsFloat(Int64) {
		t.Error("Int64: IsFloat, must be false")
	}
	if !IsFloat(Float64) {
		t.Error("Uint64: !IsFloat, must be true")
	}
	if IsQuoted(Int64) {
		t.Error("Int64: IsQuoted, must be false")
	}
	if !IsQuoted(Binary) {
		t.Error("Binary: !IsQuoted, must be true")
	}
	if IsText(Int64) {
		t.Error("Int64: IsText, must be false")
	}
	if !IsText(Char) {
		t.Error("Char: !IsText, must be true")
	}
	if IsBinary(Int64) {
		t.Error("Int64: IsBinary, must be false")
	}
	if !IsBinary(Binary) {
		t.Error("Char: !IsBinary, must be true")
	}
	if !isNumber(Int64) {
		t.Error("Int64: !isNumber, must be true")
	}
}

func TestTypeToMySQL(t *testing.T) {
	v, f := TypeToMySQL(Bit)
	if v != 16 {
		t.Errorf("Bit: %d, want 16", v)
	}
	if f != mysqlUnsigned {
		t.Errorf("Bit flag: %x, want %x", f, mysqlUnsigned)
	}
	v, f = TypeToMySQL(Date)
	if v != 10 {
		t.Errorf("Bit: %d, want 10", v)
	}
	if f != mysqlBinary {
		t.Errorf("Bit flag: %x, want %x", f, mysqlBinary)
	}
}

func TestMySQLToType(t *testing.T) {
	testcases := []struct {
		intype  int64
		inflags int64
		outtype querypb.Type
	}{{
		intype:  1,
		outtype: Int8,
	}, {
		intype:  1,
		inflags: mysqlUnsigned,
		outtype: Uint8,
	}, {
		intype:  2,
		outtype: Int16,
	}, {
		intype:  2,
		inflags: mysqlUnsigned,
		outtype: Uint16,
	}, {
		intype:  3,
		outtype: Int32,
	}, {
		intype:  3,
		inflags: mysqlUnsigned,
		outtype: Uint32,
	}, {
		intype:  4,
		outtype: Float32,
	}, {
		intype:  5,
		outtype: Float64,
	}, {
		intype:  6,
		outtype: Null,
	}, {
		intype:  7,
		outtype: Timestamp,
	}, {
		intype:  8,
		outtype: Int64,
	}, {
		intype:  8,
		inflags: mysqlUnsigned,
		outtype: Uint64,
	}, {
		intype:  9,
		outtype: Int24,
	}, {
		intype:  9,
		inflags: mysqlUnsigned,
		outtype: Uint24,
	}, {
		intype:  10,
		outtype: Date,
	}, {
		intype:  11,
		outtype: Time,
	}, {
		intype:  12,
		outtype: Datetime,
	}, {
		intype:  13,
		outtype: Year,
	}, {
		intype:  16,
		outtype: Bit,
	}, {
		intype:  245,
		outtype: TypeJSON,
	}, {
		intype:  246,
		outtype: Decimal,
	}, {
		intype:  249,
		outtype: Text,
	}, {
		intype:  250,
		outtype: Text,
	}, {
		intype:  251,
		outtype: Text,
	}, {
		intype:  252,
		outtype: Text,
	}, {
		intype:  252,
		inflags: mysqlBinary,
		outtype: Blob,
	}, {
		intype:  253,
		outtype: VarChar,
	}, {
		intype:  253,
		inflags: mysqlBinary,
		outtype: VarBinary,
	}, {
		intype:  254,
		outtype: Char,
	}, {
		intype:  254,
		inflags: mysqlBinary,
		outtype: Binary,
	}, {
		intype:  254,
		inflags: mysqlEnum,
		outtype: Enum,
	}, {
		intype:  254,
		inflags: mysqlSet,
		outtype: Set,
	}, {
		intype:  255,
		outtype: Geometry,
	}, {
		// Binary flag must be ignored.
		intype:  8,
		inflags: mysqlUnsigned | mysqlBinary,
		outtype: Uint64,
	}, {
		// Unsigned flag must be ignored
		intype:  252,
		inflags: mysqlUnsigned | mysqlBinary,
		outtype: Blob,
	}}
	for _, tcase := range testcases {
		got, err := MySQLToType(tcase.intype, tcase.inflags)
		if err != nil {
			t.Error(err)
		}
		if got != tcase.outtype {
			t.Errorf("MySQLToType(%d, %x): %v, want %v", tcase.intype, tcase.inflags, got, tcase.outtype)
		}
	}
}

func TestTypeError(t *testing.T) {
	_, err := MySQLToType(17, 0)
	want := "unsupported type: 17"
	if err == nil || err.Error() != want {
		t.Errorf("MySQLToType: %v, want %s", err, want)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package servenv contains functionality that is common for all
// Vitess server programs.  It defines and initializes command line
// flags that control the runtime environment.
//
// After a server program has called flag.Parse, it needs to call
// env.Init to make env use the command line variables to initialize
// the environment. It also needs to call env.Close before exiting.
//
// Note: If you need to plug in any custom initialization/cleanup for
// a vitess distribution, register them using onInit and onClose. A
// clean way of achieving that is adding to this package a file with
// an init() function that registers the hooks.

package servenv

import (
	"crypto/md5"
	"encoding/hex"
	"expvar"
	"flag"
	"io"
	"os"
	"runtime"
	"sync"
	"syscall"
	"time"

	log "github.com/golang/glog"
	_ "github.com/youtube/vitess/go/vt/logutil"
)

var (
	memProfileRate = flag.Int("mem-profile-rate", 512*1024, "profile every n bytes allocated")
	mu             sync.Mutex
	onCloseHooks   []func()
	onInitHooks    []func()
	inited         bool
)

func Init() {
	mu.Lock()
	defer mu.Unlock()
	if inited {
		log.Fatal("servenv.Init called second time")
	}
	inited = true

	// Once you run as root, you pretty much destroy the chances of a
	// non-privileged user starting the program correctly.
	if uid := os.Getuid(); uid == 0 {
		log.Fatalf("servenv.Init: running this as root makes no sense")
	}

	runtime.MemProfileRate = *memProfileRate
	gomaxprocs := os.Getenv("GOMAXPROCS")
	if gomaxprocs == "" {
		gomaxprocs = "1"
	}
	// Could report this in an expvar instead.
	log.Infof("GOMAXPROCS = %v", gomaxprocs)

	// We used to set this limit directly, but you pretty much have to
	// use a root account to allow increasing a limit reliably. Dropping
	// privileges is also tricky. The best strategy is to make a shell
	// script set up the limits as root and switch users before starting
	// the server.
	fdLimit := &syscall.Rlimit{}
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, fdLimit); err != nil {
		log.Errorf("max-open-fds failed: %v", err)
	} else {
		// Could report this in an expvar instead.
		log.Infof("max-open-fds: %v", fdLimit.Cur)
	}

	if err := exportBinaryVersion(); err != nil {
		log.Fatalf("servenv.Init: exportBinaryVersion: %v", err)
	}

	for _, f := range onInitHooks {
		f()
	}
}

func exportBinaryVersion() error {
	hasher := md5.New()
	exeFile, err := os.Open("/proc/self/exe")
	if err != nil {
		return err
	}
	if _, err = io.Copy(hasher, exeFile); err != nil {
		return err
	}
	md5sum := hex.EncodeToString(hasher.Sum(nil))
	fileInfo, err := exeFile.Stat()
	if err != nil {
		return err
	}
	mtime := fileInfo.ModTime().Format(time.RFC3339)
	version := mtime + " " + md5sum
	expvar.NewString("binary-version").Set(version)
	// rexport this value for varz scraper
	expvar.NewString("Version").Set(version)
	return nil
}

// Close runs any registered exit hooks and exits the program.
func Close() {
	mu.Lock()
	defer mu.Unlock()

	for _, f := range onCloseHooks {
		f()
	}
	log.Fatal("done")
}

// onInit registers f to be run at the beginning of the app
// lifecycle. It should be called in an init() function.
func onInit(f func()) {
	mu.Lock()
	defer mu.Unlock()
	onInitHooks = append(onInitHooks, f)
}

// onClose registers f to be run at the end of the app lifecycle. It
// should be called in an init() function.
func onClose(f func()) {
	mu.Lock()
	defer mu.Unlock()
	onCloseHooks = append(onCloseHooks, f)
}
<commit_msg>Don't exit servers with a log.Fatal.<commit_after>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package servenv contains functionality that is common for all
// Vitess server programs.  It defines and initializes command line
// flags that control the runtime environment.
//
// After a server program has called flag.Parse, it needs to call
// env.Init to make env use the command line variables to initialize
// the environment. It also needs to call env.Close before exiting.
//
// Note: If you need to plug in any custom initialization/cleanup for
// a vitess distribution, register them using onInit and onClose. A
// clean way of achieving that is adding to this package a file with
// an init() function that registers the hooks.

package servenv

import (
	"crypto/md5"
	"encoding/hex"
	"expvar"
	"flag"
	"io"
	"os"
	"runtime"
	"sync"
	"syscall"
	"time"

	log "github.com/golang/glog"
	_ "github.com/youtube/vitess/go/vt/logutil"
)

var (
	memProfileRate = flag.Int("mem-profile-rate", 512*1024, "profile every n bytes allocated")
	mu             sync.Mutex
	onCloseHooks   []func()
	onInitHooks    []func()
	inited         bool
)

func Init() {
	mu.Lock()
	defer mu.Unlock()
	if inited {
		log.Fatal("servenv.Init called second time")
	}
	inited = true

	// Once you run as root, you pretty much destroy the chances of a
	// non-privileged user starting the program correctly.
	if uid := os.Getuid(); uid == 0 {
		log.Fatalf("servenv.Init: running this as root makes no sense")
	}

	runtime.MemProfileRate = *memProfileRate
	gomaxprocs := os.Getenv("GOMAXPROCS")
	if gomaxprocs == "" {
		gomaxprocs = "1"
	}
	// Could report this in an expvar instead.
	log.Infof("GOMAXPROCS = %v", gomaxprocs)

	// We used to set this limit directly, but you pretty much have to
	// use a root account to allow increasing a limit reliably. Dropping
	// privileges is also tricky. The best strategy is to make a shell
	// script set up the limits as root and switch users before starting
	// the server.
	fdLimit := &syscall.Rlimit{}
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, fdLimit); err != nil {
		log.Errorf("max-open-fds failed: %v", err)
	} else {
		// Could report this in an expvar instead.
		log.Infof("max-open-fds: %v", fdLimit.Cur)
	}

	if err := exportBinaryVersion(); err != nil {
		log.Fatalf("servenv.Init: exportBinaryVersion: %v", err)
	}

	for _, f := range onInitHooks {
		f()
	}
}

func exportBinaryVersion() error {
	hasher := md5.New()
	exeFile, err := os.Open("/proc/self/exe")
	if err != nil {
		return err
	}
	if _, err = io.Copy(hasher, exeFile); err != nil {
		return err
	}
	md5sum := hex.EncodeToString(hasher.Sum(nil))
	fileInfo, err := exeFile.Stat()
	if err != nil {
		return err
	}
	mtime := fileInfo.ModTime().Format(time.RFC3339)
	version := mtime + " " + md5sum
	expvar.NewString("binary-version").Set(version)
	// rexport this value for varz scraper
	expvar.NewString("Version").Set(version)
	return nil
}

// Close runs any registered exit hooks and exits the program.
func Close() {
	mu.Lock()
	defer mu.Unlock()

	for _, f := range onCloseHooks {
		f()
	}
}

// onInit registers f to be run at the beginning of the app
// lifecycle. It should be called in an init() function.
func onInit(f func()) {
	mu.Lock()
	defer mu.Unlock()
	onInitHooks = append(onInitHooks, f)
}

// onClose registers f to be run at the end of the app lifecycle. It
// should be called in an init() function.
func onClose(f func()) {
	mu.Lock()
	defer mu.Unlock()
	onCloseHooks = append(onCloseHooks, f)
}
<|endoftext|>


<commit_before>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sessions

import (
	"bytes"
	"encoding/gob"
	"net/http"
	"time"

	"appengine"
	"appengine/datastore"
	"appengine/memcache"

	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
)

// DatastoreStore -------------------------------------------------------------

// Session is used to load and save session data in the datastore.
type Session struct {
	Date  time.Time
	Value []byte
}

// NewDatastoreStore returns a new DatastoreStore.
//
// The kind argument is the kind name used to store the session data.
// If empty it will use "Session".
//
// See NewCookieStore() for a description of the other parameters.
func NewDatastoreStore(kind string, keyPairs ...[]byte) *DatastoreStore {
	if kind == "" {
		kind = "Session"
	}
	return &DatastoreStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
		kind: kind,
	}
}

// DatastoreStore stores sessions in the App Engine datastore.
type DatastoreStore struct {
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
	kind    string
}

// Get returns a session for the given name after adding it to the registry.
//
// See CookieStore.Get().
func (s *DatastoreStore) Get(r *http.Request, name string) (*sessions.Session,
	error) {
	return sessions.GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See CookieStore.New().
func (s *DatastoreStore) New(r *http.Request, name string) (*sessions.Session,
	error) {
	session := sessions.NewSession(s, name)
	session.Options = &(*s.Options)
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err = s.load(r, session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *DatastoreStore) Save(r *http.Request, w http.ResponseWriter,
	session *sessions.Session) error {
	if session.ID == "" {
		session.ID = string(securecookie.GenerateRandomKey(32))
	}
	if err := s.save(r, session); err != nil {
		return err
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, sessions.NewCookie(session.Name(), encoded,
		session.Options))
	return nil
}

// save writes encoded session.Values to datastore.
func (s *DatastoreStore) save(r *http.Request,
	session *sessions.Session) error {
	if len(session.Values) == 0 {
		// Don't need to write anything.
		return nil
	}
	serialized, err := serialize(session.Values)
	if err != nil {
		return err
	}
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, s.kind, session.ID, 0, nil)
	k, err = datastore.Put(c, k, &Session{
		Date:  time.Now(),
		Value: serialized,
	})
	if err != nil {
		return err
	}
	return nil
}

// load gets a value from datastore and decodes its content into
// session.Values.
func (s *DatastoreStore) load(r *http.Request,
	session *sessions.Session) error {
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, s.kind, session.ID, 0, nil)
	entity := Session{}
	if err := datastore.Get(c, k, &entity); err != nil {
		return err
	}
	if err := deserialize(entity.Value, &session.Values); err != nil {
		return err
	}
	return nil
}

// MemcacheStore --------------------------------------------------------------

// NewMemcacheStore returns a new MemcacheStore.
//
// The keyPrefix argument is the prefix used for memcache keys. If empty it
// will use "gorilla.appengine.sessions.".
//
// See NewCookieStore() for a description of the other parameters.
func NewMemcacheStore(keyPrefix string, keyPairs ...[]byte) *MemcacheStore {
	if keyPrefix == "" {
		keyPrefix = "gorilla.appengine.sessions."
	}
	return &MemcacheStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
		prefix: keyPrefix,
	}
}

// MemcacheStore stores sessions in the App Engine memcache.
type MemcacheStore struct {
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
	prefix  string
}

// Get returns a session for the given name after adding it to the registry.
//
// See CookieStore.Get().
func (s *MemcacheStore) Get(r *http.Request, name string) (*sessions.Session,
	error) {
	return sessions.GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See CookieStore.New().
func (s *MemcacheStore) New(r *http.Request, name string) (*sessions.Session,
	error) {
	session := sessions.NewSession(s, name)
	session.Options = &(*s.Options)
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err = s.load(r, session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *MemcacheStore) Save(r *http.Request, w http.ResponseWriter,
	session *sessions.Session) error {
	if session.ID == "" {
		session.ID = s.prefix + string(securecookie.GenerateRandomKey(32))
	}
	if err := s.save(r, session); err != nil {
		return err
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, sessions.NewCookie(session.Name(), encoded,
		session.Options))
	return nil
}

// save writes encoded session.Values to memcache.
func (s *MemcacheStore) save(r *http.Request,
	session *sessions.Session) error {
	if len(session.Values) == 0 {
		// Don't need to write anything.
		return nil
	}
	serialized, err := serialize(session.Values)
	if err != nil {
		return err
	}
	err = memcache.Set(appengine.NewContext(r), &memcache.Item{
		Key:   session.ID,
		Value: serialized,
	})
	if err != nil {
		return err
	}
	return nil
}

// load gets a value from memcache and decodes its content into session.Values.
func (s *MemcacheStore) load(r *http.Request,
	session *sessions.Session) error {
	item, err := memcache.Get(appengine.NewContext(r), session.ID)
	if err != nil {
		return err
	}
	if err := deserialize(item.Value, &session.Values); err != nil {
		return err
	}
	return nil
}

// Serialization --------------------------------------------------------------

// serialize encodes a value using gob.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	if err := enc.Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using gob.
func deserialize(src []byte, dst interface{}) error {
	dec := gob.NewDecoder(bytes.NewBuffer(src))
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}
<commit_msg>Rename package from sessions to gaesessions.<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gaesessions

import (
	"bytes"
	"encoding/gob"
	"net/http"
	"time"

	"appengine"
	"appengine/datastore"
	"appengine/memcache"

	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
)

// DatastoreStore -------------------------------------------------------------

// Session is used to load and save session data in the datastore.
type Session struct {
	Date  time.Time
	Value []byte
}

// NewDatastoreStore returns a new DatastoreStore.
//
// The kind argument is the kind name used to store the session data.
// If empty it will use "Session".
//
// See NewCookieStore() for a description of the other parameters.
func NewDatastoreStore(kind string, keyPairs ...[]byte) *DatastoreStore {
	if kind == "" {
		kind = "Session"
	}
	return &DatastoreStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
		kind: kind,
	}
}

// DatastoreStore stores sessions in the App Engine datastore.
type DatastoreStore struct {
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
	kind    string
}

// Get returns a session for the given name after adding it to the registry.
//
// See CookieStore.Get().
func (s *DatastoreStore) Get(r *http.Request, name string) (*sessions.Session,
	error) {
	return sessions.GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See CookieStore.New().
func (s *DatastoreStore) New(r *http.Request, name string) (*sessions.Session,
	error) {
	session := sessions.NewSession(s, name)
	session.Options = &(*s.Options)
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err = s.load(r, session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *DatastoreStore) Save(r *http.Request, w http.ResponseWriter,
	session *sessions.Session) error {
	if session.ID == "" {
		session.ID = string(securecookie.GenerateRandomKey(32))
	}
	if err := s.save(r, session); err != nil {
		return err
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, sessions.NewCookie(session.Name(), encoded,
		session.Options))
	return nil
}

// save writes encoded session.Values to datastore.
func (s *DatastoreStore) save(r *http.Request,
	session *sessions.Session) error {
	if len(session.Values) == 0 {
		// Don't need to write anything.
		return nil
	}
	serialized, err := serialize(session.Values)
	if err != nil {
		return err
	}
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, s.kind, session.ID, 0, nil)
	k, err = datastore.Put(c, k, &Session{
		Date:  time.Now(),
		Value: serialized,
	})
	if err != nil {
		return err
	}
	return nil
}

// load gets a value from datastore and decodes its content into
// session.Values.
func (s *DatastoreStore) load(r *http.Request,
	session *sessions.Session) error {
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, s.kind, session.ID, 0, nil)
	entity := Session{}
	if err := datastore.Get(c, k, &entity); err != nil {
		return err
	}
	if err := deserialize(entity.Value, &session.Values); err != nil {
		return err
	}
	return nil
}

// MemcacheStore --------------------------------------------------------------

// NewMemcacheStore returns a new MemcacheStore.
//
// The keyPrefix argument is the prefix used for memcache keys. If empty it
// will use "gorilla.appengine.sessions.".
//
// See NewCookieStore() for a description of the other parameters.
func NewMemcacheStore(keyPrefix string, keyPairs ...[]byte) *MemcacheStore {
	if keyPrefix == "" {
		keyPrefix = "gorilla.appengine.sessions."
	}
	return &MemcacheStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
		prefix: keyPrefix,
	}
}

// MemcacheStore stores sessions in the App Engine memcache.
type MemcacheStore struct {
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
	prefix  string
}

// Get returns a session for the given name after adding it to the registry.
//
// See CookieStore.Get().
func (s *MemcacheStore) Get(r *http.Request, name string) (*sessions.Session,
	error) {
	return sessions.GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See CookieStore.New().
func (s *MemcacheStore) New(r *http.Request, name string) (*sessions.Session,
	error) {
	session := sessions.NewSession(s, name)
	session.Options = &(*s.Options)
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err = s.load(r, session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *MemcacheStore) Save(r *http.Request, w http.ResponseWriter,
	session *sessions.Session) error {
	if session.ID == "" {
		session.ID = s.prefix + string(securecookie.GenerateRandomKey(32))
	}
	if err := s.save(r, session); err != nil {
		return err
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, sessions.NewCookie(session.Name(), encoded,
		session.Options))
	return nil
}

// save writes encoded session.Values to memcache.
func (s *MemcacheStore) save(r *http.Request,
	session *sessions.Session) error {
	if len(session.Values) == 0 {
		// Don't need to write anything.
		return nil
	}
	serialized, err := serialize(session.Values)
	if err != nil {
		return err
	}
	err = memcache.Set(appengine.NewContext(r), &memcache.Item{
		Key:   session.ID,
		Value: serialized,
	})
	if err != nil {
		return err
	}
	return nil
}

// load gets a value from memcache and decodes its content into session.Values.
func (s *MemcacheStore) load(r *http.Request,
	session *sessions.Session) error {
	item, err := memcache.Get(appengine.NewContext(r), session.ID)
	if err != nil {
		return err
	}
	if err := deserialize(item.Value, &session.Values); err != nil {
		return err
	}
	return nil
}

// Serialization --------------------------------------------------------------

// serialize encodes a value using gob.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	if err := enc.Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using gob.
func deserialize(src []byte, dst interface{}) error {
	dec := gob.NewDecoder(bytes.NewBuffer(src))
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Workiva, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Package set is a simple unordered set implemented with a map.  This set
is threadsafe which decreases performance.

TODO: Actually write custom hashmap using the hash/fnv hasher.

TODO: Our Set implementation Could be further optimized by getting the uintptr
of the generic interface{} used and using that as the key; Golang maps handle
uintptr much better than the generic interace{} key.
*/

package set

import "sync"

var pool = sync.Pool{}

// Set is an implementation of ISet using the builtin map type. Set is threadsafe.
type Set struct {
	items     map[interface{}]struct{}
	lock      sync.RWMutex
	flattened []interface{}
}

// Add will add the provided items to the set.
func (set *Set) Add(items ...interface{}) {
	set.lock.Lock()
	defer set.lock.Unlock()

	set.flattened = nil
	for _, item := range items {
		set.items[item] = struct{}{}
	}
}

// Remove will remove the given items from the set.
func (set *Set) Remove(items ...interface{}) {
	set.lock.Lock()
	defer set.lock.Unlock()

	set.flattened = nil
	for _, item := range items {
		delete(set.items, item)
	}
}

// Exists returns a bool indicating if the given item exists in the set.
func (set *Set) Exists(item interface{}) bool {
	set.lock.RLock()

	_, ok := set.items[item]

	set.lock.RUnlock()

	return ok
}

// Flatten will return a list of the items in the set.
func (set *Set) Flatten() []interface{} {
	set.lock.Lock()
	defer set.lock.Unlock()

	if set.flattened != nil {
		return set.flattened
	}

	set.flattened = make([]interface{}, 0, len(set.items))
	for item := range set.items {
		set.flattened = append(set.flattened, item)
	}
	return set.flattened
}

// Len returns the number of items in the set.
func (set *Set) Len() int64 {
	set.lock.RLock()

	size := int64(len(set.items))

	set.lock.RUnlock()

	return size
}

// Clear will remove all items from the set.
func (set *Set) Clear() {
	set.lock.Lock()

	set.items = map[interface{}]struct{}{}

	set.lock.Unlock()
}

// All returns a bool indicating if all of the supplied items exist in the set.
func (set *Set) All(items ...interface{}) bool {
	set.lock.RLock()
	defer set.lock.RUnlock()

	for _, item := range items {
		if _, ok := set.items[item]; !ok {
			return false
		}
	}

	return true
}

// Dispose will add this set back into the pool.
func (set *Set) Dispose() {
	set.lock.Lock()
	defer set.lock.Unlock()

	for k := range set.items {
		delete(set.items, k)
	}

	//this is so we don't hang onto any references
	for i := 0; i < len(set.flattened); i++ {
		set.flattened[i] = nil
	}

	set.flattened = set.flattened[:0]
	pool.Put(set)
}

// New is the constructor for sets.  It will pull from a reuseable memory pool if it can.
// Takes a list of items to initialize the set with.
func New(items ...interface{}) *Set {
	set := pool.Get().(*Set)
	for _, item := range items {
		set.items[item] = struct{}{}
	}

	if len(items) > 0 {
		set.flattened = nil
	}

	return set
}

func init() {
	pool.New = func() interface{} {
		return &Set{
			items: make(map[interface{}]struct{}, 10),
		}
	}
}
<commit_msg>Remove obsolete whitespace from documentation<commit_after>/*
Copyright 2014 Workiva, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
Package set is a simple unordered set implemented with a map.  This set
is threadsafe which decreases performance.

TODO: Actually write custom hashmap using the hash/fnv hasher.

TODO: Our Set implementation Could be further optimized by getting the uintptr
of the generic interface{} used and using that as the key; Golang maps handle
uintptr much better than the generic interace{} key.
*/

package set

import "sync"

var pool = sync.Pool{}

// Set is an implementation of ISet using the builtin map type. Set is threadsafe.
type Set struct {
	items     map[interface{}]struct{}
	lock      sync.RWMutex
	flattened []interface{}
}

// Add will add the provided items to the set.
func (set *Set) Add(items ...interface{}) {
	set.lock.Lock()
	defer set.lock.Unlock()

	set.flattened = nil
	for _, item := range items {
		set.items[item] = struct{}{}
	}
}

// Remove will remove the given items from the set.
func (set *Set) Remove(items ...interface{}) {
	set.lock.Lock()
	defer set.lock.Unlock()

	set.flattened = nil
	for _, item := range items {
		delete(set.items, item)
	}
}

// Exists returns a bool indicating if the given item exists in the set.
func (set *Set) Exists(item interface{}) bool {
	set.lock.RLock()

	_, ok := set.items[item]

	set.lock.RUnlock()

	return ok
}

// Flatten will return a list of the items in the set.
func (set *Set) Flatten() []interface{} {
	set.lock.Lock()
	defer set.lock.Unlock()

	if set.flattened != nil {
		return set.flattened
	}

	set.flattened = make([]interface{}, 0, len(set.items))
	for item := range set.items {
		set.flattened = append(set.flattened, item)
	}
	return set.flattened
}

// Len returns the number of items in the set.
func (set *Set) Len() int64 {
	set.lock.RLock()

	size := int64(len(set.items))

	set.lock.RUnlock()

	return size
}

// Clear will remove all items from the set.
func (set *Set) Clear() {
	set.lock.Lock()

	set.items = map[interface{}]struct{}{}

	set.lock.Unlock()
}

// All returns a bool indicating if all of the supplied items exist in the set.
func (set *Set) All(items ...interface{}) bool {
	set.lock.RLock()
	defer set.lock.RUnlock()

	for _, item := range items {
		if _, ok := set.items[item]; !ok {
			return false
		}
	}

	return true
}

// Dispose will add this set back into the pool.
func (set *Set) Dispose() {
	set.lock.Lock()
	defer set.lock.Unlock()

	for k := range set.items {
		delete(set.items, k)
	}

	//this is so we don't hang onto any references
	for i := 0; i < len(set.flattened); i++ {
		set.flattened[i] = nil
	}

	set.flattened = set.flattened[:0]
	pool.Put(set)
}

// New is the constructor for sets. It will pull from a reuseable memory pool if it can.
// Takes a list of items to initialize the set with.
func New(items ...interface{}) *Set {
	set := pool.Get().(*Set)
	for _, item := range items {
		set.items[item] = struct{}{}
	}

	if len(items) > 0 {
		set.flattened = nil
	}

	return set
}

func init() {
	pool.New = func() interface{} {
		return &Set{
			items: make(map[interface{}]struct{}, 10),
		}
	}
}
<|endoftext|>