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

// Marshalling and unmarshalling of
// bit torrent bencode data into Go structs using reflection.
//
// Based upon the standard Go language JSON package.

package bencode

import (
	"fmt"
	"io"
	"os"
	"reflect"
	"sort"
	"strings"
)

type structBuilder struct {
	val reflect.Value

	// if map_ != nil, write val to map_[key] on each change
	map_ *reflect.MapValue
	key  reflect.Value
}

var nobuilder *structBuilder

func isfloat(v reflect.Value) bool {
	switch v.(type) {
	case *reflect.FloatValue:
		return true
	}
	return false
}

func setfloat(v reflect.Value, f float64) {
	switch v := v.(type) {
	case *reflect.FloatValue:
		v.Set(f)
	}
}

func setint(val reflect.Value, i int64) {
	switch v := val.(type) {
	case *reflect.IntValue:
		v.Set(int64(i))
	case *reflect.UintValue:
		v.Set(uint64(i))
	case *reflect.InterfaceValue:
		v.Set(reflect.NewValue(i))
	}
}

// If updating b.val is not enough to update the original,
// copy a changed b.val out to the original.
func (b *structBuilder) Flush() {
	if b == nil {
		return
	}
	if b.map_ != nil {
		b.map_.SetElem(b.key, b.val)
	}
}

func (b *structBuilder) Int64(i int64) {
	if b == nil {
		return
	}
	v := b.val
	if isfloat(v) {
		setfloat(v, float64(i))
	} else {
		setint(v, i)
	}
}

func (b *structBuilder) Uint64(i uint64) {
	if b == nil {
		return
	}
	v := b.val
	if isfloat(v) {
		setfloat(v, float64(i))
	} else {
		setint(v, int64(i))
	}
}

func (b *structBuilder) Float64(f float64) {
	if b == nil {
		return
	}
	v := b.val
	if isfloat(v) {
		setfloat(v, f)
	} else {
		setint(v, int64(f))
	}
}

func (b *structBuilder) String(s string) {
	if b == nil {
		return
	}

	switch v := b.val.(type) {
	case *reflect.StringValue:
		v.Set(s)
	case *reflect.InterfaceValue:
		v.Set(reflect.NewValue(s))
	}
}

func (b *structBuilder) Array() {
	if b == nil {
		return
	}
	if v, ok := b.val.(*reflect.SliceValue); ok {
		if v.IsNil() {
			v.Set(reflect.MakeSlice(v.Type().(*reflect.SliceType), 0, 8))
		}
	}
}

func (b *structBuilder) Elem(i int) Builder {
	if b == nil || i < 0 {
		return nobuilder
	}
	switch v := b.val.(type) {
	case *reflect.ArrayValue:
		if i < v.Len() {
			return &structBuilder{val: v.Elem(i)}
		}
	case *reflect.SliceValue:
		if i >= v.Cap() {
			n := v.Cap()
			if n < 8 {
				n = 8
			}
			for n <= i {
				n *= 2
			}
			nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n)
			reflect.ArrayCopy(nv, v)
			v.Set(nv)
		}
		if v.Len() <= i && i < v.Cap() {
			v.SetLen(i + 1)
		}
		if i < v.Len() {
			return &structBuilder{val: v.Elem(i)}
		}
	}
	return nobuilder
}

func (b *structBuilder) Map() {
	if b == nil {
		return
	}
	if v, ok := b.val.(*reflect.PtrValue); ok && v.IsNil() {
		if v.IsNil() {
			v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
			b.Flush()
		}
		b.map_ = nil
		b.val = v.Elem()
	}
	if v, ok := b.val.(*reflect.MapValue); ok && v.IsNil() {
		v.Set(reflect.MakeMap(v.Type().(*reflect.MapType)))
	}
}

func (b *structBuilder) Key(k string) Builder {
	if b == nil {
		return nobuilder
	}
	switch v := reflect.Indirect(b.val).(type) {
	case *reflect.StructValue:
		t := v.Type().(*reflect.StructType)
		// Case-insensitive field lookup.
		k = strings.ToLower(k)
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			if strings.ToLower(field.Tag) == k ||
				strings.ToLower(field.Name) == k {
				return &structBuilder{val: v.Field(i)}
			}
		}
	case *reflect.MapValue:
		t := v.Type().(*reflect.MapType)
		if t.Key() != reflect.Typeof(k) {
			break
		}
		key := reflect.NewValue(k)
		elem := v.Elem(key)
		if elem == nil {
			v.SetElem(key, reflect.MakeZero(t.Elem()))
			elem = v.Elem(key)
		}
		return &structBuilder{val: elem, map_: v, key: key}
	}
	return nobuilder
}

// Unmarshal parses the bencode syntax string s and fills in
// an arbitrary struct or slice pointed at by val.
// It uses the reflect package to assign to fields
// and arrays embedded in val.  Well-formed data that does not fit
// into the struct is discarded.
//
// For example, given these definitions:
//
//	type Email struct {
//		Where string;
//		Addr string;
//	}
//
//	type Result struct {
//		Name string;
//		Phone string;
//		Email []Email
//	}
//
//	var r = Result{ "name", "phone", nil }
//
// unmarshalling the bencode syntax string
//
//	d5:emailld5:where4:home4:addr15:gre@example.come\
//  d5:where4:work4:addr12:gre@work.comee4:name14:Gr\
//  ace R. Emlin7:address15:123 Main Streete
//
// via Unmarshal(s, &r) is equivalent to assigning
//
//	r = Result{
//		"Grace R. Emlin",	// name
//		"phone",		// no phone given
//		[]Email{
//			Email{ "home", "gre@example.com" },
//			Email{ "work", "gre@work.com" }
//		}
//	}
//
// Note that the field r.Phone has not been modified and
// that the bencode field "address" was discarded.
//
// Because Unmarshal uses the reflect package, it can only
// assign to upper case fields.  Unmarshal uses a case-insensitive
// comparison to match bencode field names to struct field names.
//
// If you provide a tag string for a struct member, the tag string
// will be used as the bencode dictionary key for that member.
//
// To unmarshal a top-level bencode array, pass in a pointer to an empty
// slice of the correct type.
//

func Unmarshal(r io.Reader, val interface{}) (err os.Error) {
	// If e represents a value, the answer won't get back to the
	// caller.  Make sure it's a pointer.
	if _, ok := reflect.Typeof(val).(*reflect.PtrType); !ok {
		err = os.ErrorString("Attempt to unmarshal into a non-pointer")
		return
	}
	err = UnmarshalValue(r, reflect.NewValue(val))
	return
}

// This API is public primarily to make testing easier, but it is available if you
// have a use for it.

func UnmarshalValue(r io.Reader, v reflect.Value) (err os.Error) {
	var b *structBuilder

	// If val is a pointer to a slice, we append to the slice.
	if ptr, ok := v.(*reflect.PtrValue); ok {
		if slice, ok := ptr.Elem().(*reflect.SliceValue); ok {
			b = &structBuilder{val: slice}
		}
	}

	if b == nil {
		b = &structBuilder{val: v}
	}

	err = Parse(r, b)
	return
}

type MarshalError struct {
	T reflect.Type
}

func (e *MarshalError) String() string {
	return "bencode cannot encode value of type " + e.T.String()
}

func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) (err os.Error) {
	_, err = fmt.Fprint(w, "l")
	if err != nil {
		return
	}
	for i := 0; i < val.Len(); i++ {
		if err := writeValue(w, val.Elem(i)); err != nil {
			return err
		}
	}

	_, err = fmt.Fprint(w, "e")
	if err != nil {
		return
	}
	return nil
}

type StringValue struct {
	key   string
	value reflect.Value
}

type StringValueArray []StringValue

// Satisfy sort.Interface

func (a StringValueArray) Len() int { return len(a) }

func (a StringValueArray) Less(i, j int) bool { return a[i].key < a[j].key }

func (a StringValueArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

func writeSVList(w io.Writer, svList StringValueArray) (err os.Error) {
	sort.Sort(svList)

	for _, sv := range (svList) {
		if isValueNil(sv.value) {
			continue // Skip null values
		}
		s := sv.key
		_, err = fmt.Fprintf(w, "%d:%s", len(s), s)
		if err != nil {
			return
		}

		if err = writeValue(w, sv.value); err != nil {
			return
		}
	}
	return
}

func writeMap(w io.Writer, val *reflect.MapValue) (err os.Error) {
	key := val.Type().(*reflect.MapType).Key()
	if _, ok := key.(*reflect.StringType); !ok {
		return &MarshalError{val.Type()}
	}
	_, err = fmt.Fprint(w, "d")
	if err != nil {
		return
	}

	keys := val.Keys()

	// Sort keys

	svList := make(StringValueArray, len(keys))
	for i, key := range (keys) {
		svList[i].key = key.(*reflect.StringValue).Get()
		svList[i].value = val.Elem(key)
	}

	err = writeSVList(w, svList)
	if err != nil {
		return
	}

	_, err = fmt.Fprint(w, "e")
	if err != nil {
		return
	}
	return
}

func writeStruct(w io.Writer, val *reflect.StructValue) (err os.Error) {
	_, err = fmt.Fprint(w, "d")
	if err != nil {
		return
	}

	typ := val.Type().(*reflect.StructType)

	numFields := val.NumField()
	svList := make(StringValueArray, numFields)

	for i := 0; i < numFields; i++ {
		field := typ.Field(i)
		key := field.Name
		if len(field.Tag) > 0 {
			key = field.Tag
		}
		svList[i].key = key
		svList[i].value = val.Field(i)
	}

	err = writeSVList(w, svList)
	if err != nil {
		return
	}

	_, err = fmt.Fprint(w, "e")
	if err != nil {
		return
	}
	return
}

func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
	if val == nil {
		err = os.NewError("Can't write null value")
		return
	}

	switch v := val.(type) {
	case *reflect.StringValue:
		s := v.Get()
		_, err = fmt.Fprintf(w, "%d:%s", len(s), s)
	case *reflect.IntValue:
		_, err = fmt.Fprintf(w, "i%de", v.Get())
	case *reflect.UintValue:
		_, err = fmt.Fprintf(w, "i%de", v.Get())
	case *reflect.ArrayValue:
		err = writeArrayOrSlice(w, v)
	case *reflect.SliceValue:
		err = writeArrayOrSlice(w, v)
	case *reflect.MapValue:
		err = writeMap(w, v)
	case *reflect.StructValue:
		err = writeStruct(w, v)
	case *reflect.InterfaceValue:
		err = writeValue(w, v.Elem())
	default:
		err = &MarshalError{val.Type()}
	}
	return
}

func isValueNil(val reflect.Value) bool {
	if val == nil {
		return true
	}
	switch v := val.(type) {
	case *reflect.InterfaceValue:
		return isValueNil(v.Elem())
	default:
		return false
	}
	return false
}

func Marshal(w io.Writer, val interface{}) os.Error {
	return writeValue(w, reflect.NewValue(val))
}
<commit_msg>gofmt<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Marshalling and unmarshalling of
// bit torrent bencode data into Go structs using reflection.
//
// Based upon the standard Go language JSON package.

package bencode

import (
	"fmt"
	"io"
	"os"
	"reflect"
	"sort"
	"strings"
)

type structBuilder struct {
	val reflect.Value

	// if map_ != nil, write val to map_[key] on each change
	map_ *reflect.MapValue
	key  reflect.Value
}

var nobuilder *structBuilder

func isfloat(v reflect.Value) bool {
	switch v.(type) {
	case *reflect.FloatValue:
		return true
	}
	return false
}

func setfloat(v reflect.Value, f float64) {
	switch v := v.(type) {
	case *reflect.FloatValue:
		v.Set(f)
	}
}

func setint(val reflect.Value, i int64) {
	switch v := val.(type) {
	case *reflect.IntValue:
		v.Set(int64(i))
	case *reflect.UintValue:
		v.Set(uint64(i))
	case *reflect.InterfaceValue:
		v.Set(reflect.NewValue(i))
	}
}

// If updating b.val is not enough to update the original,
// copy a changed b.val out to the original.
func (b *structBuilder) Flush() {
	if b == nil {
		return
	}
	if b.map_ != nil {
		b.map_.SetElem(b.key, b.val)
	}
}

func (b *structBuilder) Int64(i int64) {
	if b == nil {
		return
	}
	v := b.val
	if isfloat(v) {
		setfloat(v, float64(i))
	} else {
		setint(v, i)
	}
}

func (b *structBuilder) Uint64(i uint64) {
	if b == nil {
		return
	}
	v := b.val
	if isfloat(v) {
		setfloat(v, float64(i))
	} else {
		setint(v, int64(i))
	}
}

func (b *structBuilder) Float64(f float64) {
	if b == nil {
		return
	}
	v := b.val
	if isfloat(v) {
		setfloat(v, f)
	} else {
		setint(v, int64(f))
	}
}

func (b *structBuilder) String(s string) {
	if b == nil {
		return
	}

	switch v := b.val.(type) {
	case *reflect.StringValue:
		v.Set(s)
	case *reflect.InterfaceValue:
		v.Set(reflect.NewValue(s))
	}
}

func (b *structBuilder) Array() {
	if b == nil {
		return
	}
	if v, ok := b.val.(*reflect.SliceValue); ok {
		if v.IsNil() {
			v.Set(reflect.MakeSlice(v.Type().(*reflect.SliceType), 0, 8))
		}
	}
}

func (b *structBuilder) Elem(i int) Builder {
	if b == nil || i < 0 {
		return nobuilder
	}
	switch v := b.val.(type) {
	case *reflect.ArrayValue:
		if i < v.Len() {
			return &structBuilder{val: v.Elem(i)}
		}
	case *reflect.SliceValue:
		if i >= v.Cap() {
			n := v.Cap()
			if n < 8 {
				n = 8
			}
			for n <= i {
				n *= 2
			}
			nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n)
			reflect.ArrayCopy(nv, v)
			v.Set(nv)
		}
		if v.Len() <= i && i < v.Cap() {
			v.SetLen(i + 1)
		}
		if i < v.Len() {
			return &structBuilder{val: v.Elem(i)}
		}
	}
	return nobuilder
}

func (b *structBuilder) Map() {
	if b == nil {
		return
	}
	if v, ok := b.val.(*reflect.PtrValue); ok && v.IsNil() {
		if v.IsNil() {
			v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
			b.Flush()
		}
		b.map_ = nil
		b.val = v.Elem()
	}
	if v, ok := b.val.(*reflect.MapValue); ok && v.IsNil() {
		v.Set(reflect.MakeMap(v.Type().(*reflect.MapType)))
	}
}

func (b *structBuilder) Key(k string) Builder {
	if b == nil {
		return nobuilder
	}
	switch v := reflect.Indirect(b.val).(type) {
	case *reflect.StructValue:
		t := v.Type().(*reflect.StructType)
		// Case-insensitive field lookup.
		k = strings.ToLower(k)
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			if strings.ToLower(field.Tag) == k ||
				strings.ToLower(field.Name) == k {
				return &structBuilder{val: v.Field(i)}
			}
		}
	case *reflect.MapValue:
		t := v.Type().(*reflect.MapType)
		if t.Key() != reflect.Typeof(k) {
			break
		}
		key := reflect.NewValue(k)
		elem := v.Elem(key)
		if elem == nil {
			v.SetElem(key, reflect.MakeZero(t.Elem()))
			elem = v.Elem(key)
		}
		return &structBuilder{val: elem, map_: v, key: key}
	}
	return nobuilder
}

// Unmarshal parses the bencode syntax string s and fills in
// an arbitrary struct or slice pointed at by val.
// It uses the reflect package to assign to fields
// and arrays embedded in val.  Well-formed data that does not fit
// into the struct is discarded.
//
// For example, given these definitions:
//
//	type Email struct {
//		Where string;
//		Addr string;
//	}
//
//	type Result struct {
//		Name string;
//		Phone string;
//		Email []Email
//	}
//
//	var r = Result{ "name", "phone", nil }
//
// unmarshalling the bencode syntax string
//
//	d5:emailld5:where4:home4:addr15:gre@example.come\
//  d5:where4:work4:addr12:gre@work.comee4:name14:Gr\
//  ace R. Emlin7:address15:123 Main Streete
//
// via Unmarshal(s, &r) is equivalent to assigning
//
//	r = Result{
//		"Grace R. Emlin",	// name
//		"phone",		// no phone given
//		[]Email{
//			Email{ "home", "gre@example.com" },
//			Email{ "work", "gre@work.com" }
//		}
//	}
//
// Note that the field r.Phone has not been modified and
// that the bencode field "address" was discarded.
//
// Because Unmarshal uses the reflect package, it can only
// assign to upper case fields.  Unmarshal uses a case-insensitive
// comparison to match bencode field names to struct field names.
//
// If you provide a tag string for a struct member, the tag string
// will be used as the bencode dictionary key for that member.
//
// To unmarshal a top-level bencode array, pass in a pointer to an empty
// slice of the correct type.
//

func Unmarshal(r io.Reader, val interface{}) (err os.Error) {
	// If e represents a value, the answer won't get back to the
	// caller.  Make sure it's a pointer.
	if _, ok := reflect.Typeof(val).(*reflect.PtrType); !ok {
		err = os.ErrorString("Attempt to unmarshal into a non-pointer")
		return
	}
	err = UnmarshalValue(r, reflect.NewValue(val))
	return
}

// This API is public primarily to make testing easier, but it is available if you
// have a use for it.

func UnmarshalValue(r io.Reader, v reflect.Value) (err os.Error) {
	var b *structBuilder

	// If val is a pointer to a slice, we append to the slice.
	if ptr, ok := v.(*reflect.PtrValue); ok {
		if slice, ok := ptr.Elem().(*reflect.SliceValue); ok {
			b = &structBuilder{val: slice}
		}
	}

	if b == nil {
		b = &structBuilder{val: v}
	}

	err = Parse(r, b)
	return
}

type MarshalError struct {
	T reflect.Type
}

func (e *MarshalError) String() string {
	return "bencode cannot encode value of type " + e.T.String()
}

func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) (err os.Error) {
	_, err = fmt.Fprint(w, "l")
	if err != nil {
		return
	}
	for i := 0; i < val.Len(); i++ {
		if err := writeValue(w, val.Elem(i)); err != nil {
			return err
		}
	}

	_, err = fmt.Fprint(w, "e")
	if err != nil {
		return
	}
	return nil
}

type StringValue struct {
	key   string
	value reflect.Value
}

type StringValueArray []StringValue

// Satisfy sort.Interface

func (a StringValueArray) Len() int { return len(a) }

func (a StringValueArray) Less(i, j int) bool { return a[i].key < a[j].key }

func (a StringValueArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

func writeSVList(w io.Writer, svList StringValueArray) (err os.Error) {
	sort.Sort(svList)

	for _, sv := range svList {
		if isValueNil(sv.value) {
			continue // Skip null values
		}
		s := sv.key
		_, err = fmt.Fprintf(w, "%d:%s", len(s), s)
		if err != nil {
			return
		}

		if err = writeValue(w, sv.value); err != nil {
			return
		}
	}
	return
}

func writeMap(w io.Writer, val *reflect.MapValue) (err os.Error) {
	key := val.Type().(*reflect.MapType).Key()
	if _, ok := key.(*reflect.StringType); !ok {
		return &MarshalError{val.Type()}
	}
	_, err = fmt.Fprint(w, "d")
	if err != nil {
		return
	}

	keys := val.Keys()

	// Sort keys

	svList := make(StringValueArray, len(keys))
	for i, key := range keys {
		svList[i].key = key.(*reflect.StringValue).Get()
		svList[i].value = val.Elem(key)
	}

	err = writeSVList(w, svList)
	if err != nil {
		return
	}

	_, err = fmt.Fprint(w, "e")
	if err != nil {
		return
	}
	return
}

func writeStruct(w io.Writer, val *reflect.StructValue) (err os.Error) {
	_, err = fmt.Fprint(w, "d")
	if err != nil {
		return
	}

	typ := val.Type().(*reflect.StructType)

	numFields := val.NumField()
	svList := make(StringValueArray, numFields)

	for i := 0; i < numFields; i++ {
		field := typ.Field(i)
		key := field.Name
		if len(field.Tag) > 0 {
			key = field.Tag
		}
		svList[i].key = key
		svList[i].value = val.Field(i)
	}

	err = writeSVList(w, svList)
	if err != nil {
		return
	}

	_, err = fmt.Fprint(w, "e")
	if err != nil {
		return
	}
	return
}

func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
	if val == nil {
		err = os.NewError("Can't write null value")
		return
	}

	switch v := val.(type) {
	case *reflect.StringValue:
		s := v.Get()
		_, err = fmt.Fprintf(w, "%d:%s", len(s), s)
	case *reflect.IntValue:
		_, err = fmt.Fprintf(w, "i%de", v.Get())
	case *reflect.UintValue:
		_, err = fmt.Fprintf(w, "i%de", v.Get())
	case *reflect.ArrayValue:
		err = writeArrayOrSlice(w, v)
	case *reflect.SliceValue:
		err = writeArrayOrSlice(w, v)
	case *reflect.MapValue:
		err = writeMap(w, v)
	case *reflect.StructValue:
		err = writeStruct(w, v)
	case *reflect.InterfaceValue:
		err = writeValue(w, v.Elem())
	default:
		err = &MarshalError{val.Type()}
	}
	return
}

func isValueNil(val reflect.Value) bool {
	if val == nil {
		return true
	}
	switch v := val.(type) {
	case *reflect.InterfaceValue:
		return isValueNil(v.Elem())
	default:
		return false
	}
	return false
}

func Marshal(w io.Writer, val interface{}) os.Error {
	return writeValue(w, reflect.NewValue(val))
}
<|endoftext|>


<commit_before>package sudoku

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
)

type Availables struct {
	Size    int
	Numbers map[int]bool
	Length  int
}

type Sudoku struct {
	Debug      bool
	Size       int
	SquareSize int
	Grid       [][]int
	Availables [][]Availables
	Groups     Groups
	BruteLimit int

	DoResolveNumbersThatAreOnlyInOnePosition    bool
	DoResolveNumbersThatCanOnlyBeInFewPositions bool
	DoResolveOnlyOne                            bool
}

type GroupType int

const (
	HorizontalGroup GroupType = iota
	VerticalGroup
	RegionGroup
)

type Groups map[GroupType][]Group

type Position struct {
	Y int
	X int
}

type Group struct {
	Size      int
	Positions []Position
}

func NewSudoku() Sudoku {
	return NewSudokuWithSize(3)
}

func (s *Sudoku) Clone(dest *Sudoku) {
	dest.Debug = s.Debug
	dest.Size = s.Size
	dest.SquareSize = s.SquareSize
	dest.BruteLimit = s.BruteLimit

	dest.DoResolveNumbersThatAreOnlyInOnePosition = s.DoResolveNumbersThatAreOnlyInOnePosition
	dest.DoResolveNumbersThatCanOnlyBeInFewPositions = s.DoResolveNumbersThatCanOnlyBeInFewPositions
	dest.DoResolveOnlyOne = s.DoResolveOnlyOne

	dest.initFields()
	dest.Groups = s.Groups

	for y := 0; y < s.Size; y++ {
		for x := 0; x < s.Size; x++ {
			if s.Grid[y][x] > 0 {
				dest.SetNumber(y, x, s.Grid[y][x])
			}
		}
	}
}

func (s *Sudoku) initFields() {
	s.Grid = make([][]int, s.Size)
	s.Availables = make([][]Availables, s.Size)
	s.Groups = make(map[GroupType][]Group, 0)
	for i := 0; i < s.Size; i++ {
		s.Grid[i] = make([]int, s.Size)
		s.Availables[i] = make([]Availables, s.Size)
		for j := 0; j < s.Size; j++ {
			s.Availables[i][j] = NewAvailables(s.Size)
		}
	}
}

func NewSudokuWithSize(sqsize int) Sudoku {
	size := sqsize * sqsize
	sudoku := Sudoku{
		Debug:      os.Getenv("DEBUG") == "1",
		SquareSize: sqsize,
		Size:       size,
		BruteLimit: 2,

		DoResolveNumbersThatAreOnlyInOnePosition:    true,
		DoResolveNumbersThatCanOnlyBeInFewPositions: true,
		DoResolveOnlyOne:                            true,
	}
	sudoku.initFields()
	sudoku.initGroups()
	return sudoku
}

func (s *Sudoku) initGroups() {
	// horizontal groups
	for y := 0; y < s.Size; y++ {
		group := Group{}
		for x := 0; x < s.Size; x++ {
			group.Positions = append(group.Positions, Position{y, x})
		}
		s.Groups[HorizontalGroup] = append(s.Groups[HorizontalGroup], group)
	}

	// vertical groups
	for x := 0; x < s.Size; x++ {
		group := Group{}
		for y := 0; y < s.Size; y++ {
			group.Positions = append(group.Positions, Position{y, x})
		}
		s.Groups[VerticalGroup] = append(s.Groups[VerticalGroup], group)
	}
	// zone groups
	for a := 0; a < s.SquareSize; a++ {
		for b := 0; b < s.SquareSize; b++ {
			group := Group{}
			for c := 0; c < s.SquareSize; c++ {
				for d := 0; d < s.SquareSize; d++ {
					y := a*s.SquareSize + c
					x := b*s.SquareSize + d
					group.Positions = append(group.Positions, Position{y, x})
				}
			}
			s.Groups[RegionGroup] = append(s.Groups[RegionGroup], group)
		}
	}
}

func NewAvailables(size int) Availables {
	availables := Availables{
		Size:    size,
		Numbers: make(map[int]bool, size),
		Length:  size,
	}
	for i := 1; i <= size; i++ {
		availables.Numbers[i] = true
	}
	return availables
}

func (a *Availables) String() string {
	output := ""
	for i := 1; i <= a.Size; i++ {
		if a.Numbers[i] {
			output += strconv.Itoa(i)
		} else {
			output += "."
		}
	}
	return output
}

func (a *Availables) SetNumber(number int) {
	for i := 1; i <= a.Size; i++ {
		a.Numbers[i] = i == number
	}
	a.Length = 1
}

func (a *Availables) Availables() []int {
	availables := []int{}
	for i := 1; i <= a.Size; i++ {
		if a.Numbers[i] {
			availables = append(availables, i)
		}
	}
	return availables
}

func (a *Availables) RemoveNumber(number int) bool {
	if a.Numbers[number] {
		a.Length--
		a.Numbers[number] = false
		return true
	}
	return false
}

func (g *Groups) AllGroups() []Group {
	groups := []Group{}
	for _, typeGroups := range *g {
		groups = append(groups, typeGroups...)
	}
	return groups
}

func (g *Groups) MatchCoords(y, x int) []Group {
	groups := []Group{}
	for _, group := range g.AllGroups() {
		for _, pos := range group.Positions {
			if pos.Y == y && pos.X == x {
				groups = append(groups, group)
				break
			}
		}
	}
	return groups
}

func (s *Sudoku) SetNumber(y, x, number int) {
	s.Grid[y][x] = number
	s.Availables[y][x].SetNumber(number)
	for _, group := range s.Groups.MatchCoords(y, x) {
		for _, pos := range group.Positions {
			s.Availables[pos.Y][pos.X].RemoveNumber(number)
		}
	}
}

func (s *Sudoku) ParseString(input string) error {
	input = strings.TrimSpace(input)
	lines := strings.Split(input, "\n")
	for y, line := range lines[1 : s.Size+1] {
		for x := 0; x < s.Size; x++ {
			col := line[1+x*2 : 1+x*2+1]
			if col != " " {
				colNb, err := strconv.Atoi(col)
				if err != nil {
					return err
				}
				s.SetNumber(y, x, colNb)
			}
		}
	}
	return nil
}

func (s *Sudoku) String() string {
	lines := []string{}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*2-1)))

	for _, gridLine := range s.Grid {
		line := []string{}
		for _, col := range gridLine {
			line = append(line, strconv.Itoa(col))
		}
		lineStr := fmt.Sprintf("|%s|", strings.Join(line, " "))
		lineStr = strings.Replace(lineStr, "0", " ", -1)
		lines = append(lines, lineStr)
	}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*2-1)))
	return strings.Join(lines, "\n")
}

func (s *Sudoku) AvailablesString() string {
	lines := []string{}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*(s.Size+1)-1)))
	for _, availablesLine := range s.Availables {
		line := []string{}
		for _, availables := range availablesLine {
			line = append(line, availables.String())
		}
		lineStr := fmt.Sprintf("|%s|", strings.Join(line, " "))
		lines = append(lines, lineStr)
	}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*(s.Size+1)-1)))
	return strings.Join(lines, "\n")
}

func (s *Sudoku) Missings() int {
	missings := 0
	for _, line := range s.Grid {
		for _, col := range line {
			if col == 0 {
				missings++
			}
		}
	}
	return missings
}

func (s *Sudoku) ResolveOnlyOne() int {
	changed := 0
	for y := 0; y < s.Size; y++ {
		for x := 0; x < s.Size; x++ {
			if s.Grid[y][x] != 0 {
				continue
			}
			if s.Availables[y][x].Length == 1 {
				s.SetNumber(y, x, s.Availables[y][x].Availables()[0])
				changed++
			}
		}
	}
	return changed
}

func (s *Sudoku) RemoveNumbersThatCanOnlyBeInFewPositions() int {
	changes := 0
	for _, group := range s.Groups.AllGroups() {
		for idxA, posA := range group.Positions {
			identicalSlots := 0
			availableA := s.Availables[posA.Y][posA.X]
			for idxB, posB := range group.Positions {
				if idxA == idxB {
					continue
				}
				availableB := s.Availables[posB.Y][posB.X]
				if availableA.String() == availableB.String() {
					identicalSlots++
				}
			}
			if identicalSlots != availableA.Length-1 {
				continue
			}
			for idxB, posB := range group.Positions {
				if idxA == idxB {
					continue
				}
				availableB := s.Availables[posB.Y][posB.X]
				if availableA.String() != availableB.String() {
					for _, number := range availableA.Availables() {
						if s.Availables[posB.Y][posB.X].RemoveNumber(number) {
							changes++
						}
					}
				}
			}
		}
	}
	return changes
}

func (s *Sudoku) ResolveNumbersThatAreOnlyInOnePosition() int {
	changes := 0
	for _, group := range s.Groups.AllGroups() {
		for number := 1; number <= s.Size; number++ {
			count := 0
			for _, pos := range group.Positions {
				if s.Availables[pos.Y][pos.X].Numbers[number] {
					count++
				}
			}
			if count == 1 {
				for _, pos := range group.Positions {
					if s.Availables[pos.Y][pos.X].Numbers[number] {
						s.SetNumber(pos.Y, pos.X, number)
						changes++
					}
				}
			}
		}
	}
	return changes
}

func (s *Sudoku) ResolveRec(depth int) (*Sudoku, error) {
	changes := 0
	iteration := 0
	kind := "start"

start:
	if s.Debug {
		logrus.Infof("#######  depth=%-2d iteration=%-3d changes=%-2d missings=%d kind=%s\n%s\n%s", depth, iteration, changes, s.Missings(), kind, s.String(), s.AvailablesString())
		logrus.Infof(strings.Repeat("#", 42))
	}
	iteration++

	if s.DoResolveOnlyOne {
		kind = "resolve-only-one"
		if changes = s.ResolveOnlyOne(); changes > 0 {
			goto start
		}
	}

	if s.DoResolveNumbersThatAreOnlyInOnePosition {
		kind = "resolve-numbers-that-are-only-in-one-position"
		if changes = s.ResolveNumbersThatAreOnlyInOnePosition(); changes > 0 {
			goto start
		}
	}

	if s.DoResolveNumbersThatCanOnlyBeInFewPositions && depth == 0 {
		kind = "resolve-numbers-that-can-only-be-in-few-positions"
		if changes = s.RemoveNumbersThatCanOnlyBeInFewPositions(); changes > 0 {
			goto start
		}
	}

	// Brute force
	if s.Missings() == 0 {
		return s, nil
	}

	if depth >= s.BruteLimit {
		return s, fmt.Errorf("Too deep")
	}

	for y := 0; y < s.Size; y++ {
		for x := 0; x < s.Size; x++ {
			if s.Availables[y][x].Length > 0 {
				clone := Sudoku{}
				s.Clone(&clone)
				clone.SetNumber(y, x, s.Availables[y][x].Availables()[0])
				newSudoku, err := clone.ResolveRec(depth + 1)
				if err != nil {
					continue
				}
				if newSudoku.Missings() == 0 {
					return newSudoku, nil
				}
			}
		}
	}

	return s, nil
}

func (s *Sudoku) Resolve() error {
	newSudoku, err := s.ResolveRec(0)
	if err != nil {
		return err
	}

	if newSudoku != s {
		newSudoku.Clone(s)
	}
	return nil
}
<commit_msg>Disable slow algorightm<commit_after>package sudoku

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
)

type Availables struct {
	Size    int
	Numbers map[int]bool
	Length  int
}

type Sudoku struct {
	Debug      bool
	Size       int
	SquareSize int
	Grid       [][]int
	Availables [][]Availables
	Groups     Groups
	BruteLimit int

	DoResolveNumbersThatAreOnlyInOnePosition    bool
	DoResolveNumbersThatCanOnlyBeInFewPositions bool
	DoResolveOnlyOne                            bool
}

type GroupType int

const (
	HorizontalGroup GroupType = iota
	VerticalGroup
	RegionGroup
)

type Groups map[GroupType][]Group

type Position struct {
	Y int
	X int
}

type Group struct {
	Size      int
	Positions []Position
}

func NewSudoku() Sudoku {
	return NewSudokuWithSize(3)
}

func (s *Sudoku) Clone(dest *Sudoku) {
	dest.Debug = s.Debug
	dest.Size = s.Size
	dest.SquareSize = s.SquareSize
	dest.BruteLimit = s.BruteLimit

	dest.DoResolveNumbersThatAreOnlyInOnePosition = s.DoResolveNumbersThatAreOnlyInOnePosition
	dest.DoResolveNumbersThatCanOnlyBeInFewPositions = s.DoResolveNumbersThatCanOnlyBeInFewPositions
	dest.DoResolveOnlyOne = s.DoResolveOnlyOne

	dest.initFields()
	dest.Groups = s.Groups

	for y := 0; y < s.Size; y++ {
		for x := 0; x < s.Size; x++ {
			if s.Grid[y][x] > 0 {
				dest.SetNumber(y, x, s.Grid[y][x])
			}
		}
	}
}

func (s *Sudoku) initFields() {
	s.Grid = make([][]int, s.Size)
	s.Availables = make([][]Availables, s.Size)
	s.Groups = make(map[GroupType][]Group, 0)
	for i := 0; i < s.Size; i++ {
		s.Grid[i] = make([]int, s.Size)
		s.Availables[i] = make([]Availables, s.Size)
		for j := 0; j < s.Size; j++ {
			s.Availables[i][j] = NewAvailables(s.Size)
		}
	}
}

func NewSudokuWithSize(sqsize int) Sudoku {
	size := sqsize * sqsize
	sudoku := Sudoku{
		Debug:      os.Getenv("DEBUG") == "1",
		SquareSize: sqsize,
		Size:       size,
		BruteLimit: 2,

		DoResolveNumbersThatAreOnlyInOnePosition:    true,
		DoResolveNumbersThatCanOnlyBeInFewPositions: false,
		DoResolveOnlyOne:                            true,
	}
	sudoku.initFields()
	sudoku.initGroups()
	return sudoku
}

func (s *Sudoku) initGroups() {
	// horizontal groups
	for y := 0; y < s.Size; y++ {
		group := Group{}
		for x := 0; x < s.Size; x++ {
			group.Positions = append(group.Positions, Position{y, x})
		}
		s.Groups[HorizontalGroup] = append(s.Groups[HorizontalGroup], group)
	}

	// vertical groups
	for x := 0; x < s.Size; x++ {
		group := Group{}
		for y := 0; y < s.Size; y++ {
			group.Positions = append(group.Positions, Position{y, x})
		}
		s.Groups[VerticalGroup] = append(s.Groups[VerticalGroup], group)
	}
	// zone groups
	for a := 0; a < s.SquareSize; a++ {
		for b := 0; b < s.SquareSize; b++ {
			group := Group{}
			for c := 0; c < s.SquareSize; c++ {
				for d := 0; d < s.SquareSize; d++ {
					y := a*s.SquareSize + c
					x := b*s.SquareSize + d
					group.Positions = append(group.Positions, Position{y, x})
				}
			}
			s.Groups[RegionGroup] = append(s.Groups[RegionGroup], group)
		}
	}
}

func NewAvailables(size int) Availables {
	availables := Availables{
		Size:    size,
		Numbers: make(map[int]bool, size),
		Length:  size,
	}
	for i := 1; i <= size; i++ {
		availables.Numbers[i] = true
	}
	return availables
}

func (a *Availables) String() string {
	output := ""
	for i := 1; i <= a.Size; i++ {
		if a.Numbers[i] {
			output += strconv.Itoa(i)
		} else {
			output += "."
		}
	}
	return output
}

func (a *Availables) SetNumber(number int) {
	for i := 1; i <= a.Size; i++ {
		a.Numbers[i] = i == number
	}
	a.Length = 1
}

func (a *Availables) Availables() []int {
	availables := []int{}
	for i := 1; i <= a.Size; i++ {
		if a.Numbers[i] {
			availables = append(availables, i)
		}
	}
	return availables
}

func (a *Availables) RemoveNumber(number int) bool {
	if a.Numbers[number] {
		a.Length--
		a.Numbers[number] = false
		return true
	}
	return false
}

func (g *Groups) AllGroups() []Group {
	groups := []Group{}
	for _, typeGroups := range *g {
		groups = append(groups, typeGroups...)
	}
	return groups
}

func (g *Groups) MatchCoords(y, x int) []Group {
	groups := []Group{}
	for _, group := range g.AllGroups() {
		for _, pos := range group.Positions {
			if pos.Y == y && pos.X == x {
				groups = append(groups, group)
				break
			}
		}
	}
	return groups
}

func (s *Sudoku) SetNumber(y, x, number int) {
	s.Grid[y][x] = number
	s.Availables[y][x].SetNumber(number)
	for _, group := range s.Groups.MatchCoords(y, x) {
		for _, pos := range group.Positions {
			s.Availables[pos.Y][pos.X].RemoveNumber(number)
		}
	}
}

func (s *Sudoku) ParseString(input string) error {
	input = strings.TrimSpace(input)
	lines := strings.Split(input, "\n")
	for y, line := range lines[1 : s.Size+1] {
		for x := 0; x < s.Size; x++ {
			col := line[1+x*2 : 1+x*2+1]
			if col != " " {
				colNb, err := strconv.Atoi(col)
				if err != nil {
					return err
				}
				s.SetNumber(y, x, colNb)
			}
		}
	}
	return nil
}

func (s *Sudoku) String() string {
	lines := []string{}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*2-1)))

	for _, gridLine := range s.Grid {
		line := []string{}
		for _, col := range gridLine {
			line = append(line, strconv.Itoa(col))
		}
		lineStr := fmt.Sprintf("|%s|", strings.Join(line, " "))
		lineStr = strings.Replace(lineStr, "0", " ", -1)
		lines = append(lines, lineStr)
	}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*2-1)))
	return strings.Join(lines, "\n")
}

func (s *Sudoku) AvailablesString() string {
	lines := []string{}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*(s.Size+1)-1)))
	for _, availablesLine := range s.Availables {
		line := []string{}
		for _, availables := range availablesLine {
			line = append(line, availables.String())
		}
		lineStr := fmt.Sprintf("|%s|", strings.Join(line, " "))
		lines = append(lines, lineStr)
	}
	lines = append(lines, fmt.Sprintf("+%s+", strings.Repeat("-", s.Size*(s.Size+1)-1)))
	return strings.Join(lines, "\n")
}

func (s *Sudoku) Missings() int {
	missings := 0
	for _, line := range s.Grid {
		for _, col := range line {
			if col == 0 {
				missings++
			}
		}
	}
	return missings
}

func (s *Sudoku) ResolveOnlyOne() int {
	changed := 0
	for y := 0; y < s.Size; y++ {
		for x := 0; x < s.Size; x++ {
			if s.Grid[y][x] != 0 {
				continue
			}
			if s.Availables[y][x].Length == 1 {
				s.SetNumber(y, x, s.Availables[y][x].Availables()[0])
				changed++
			}
		}
	}
	return changed
}

func (s *Sudoku) RemoveNumbersThatCanOnlyBeInFewPositions() int {
	changes := 0
	for _, group := range s.Groups.AllGroups() {
		for idxA, posA := range group.Positions {
			identicalSlots := 0
			availableA := s.Availables[posA.Y][posA.X]
			for idxB, posB := range group.Positions {
				if idxA == idxB {
					continue
				}
				availableB := s.Availables[posB.Y][posB.X]
				if availableA.String() == availableB.String() {
					identicalSlots++
				}
			}
			if identicalSlots != availableA.Length-1 {
				continue
			}
			for idxB, posB := range group.Positions {
				if idxA == idxB {
					continue
				}
				availableB := s.Availables[posB.Y][posB.X]
				if availableA.String() != availableB.String() {
					for _, number := range availableA.Availables() {
						if s.Availables[posB.Y][posB.X].RemoveNumber(number) {
							changes++
						}
					}
				}
			}
		}
	}
	return changes
}

func (s *Sudoku) ResolveNumbersThatAreOnlyInOnePosition() int {
	changes := 0
	for _, group := range s.Groups.AllGroups() {
		for number := 1; number <= s.Size; number++ {
			count := 0
			for _, pos := range group.Positions {
				if s.Availables[pos.Y][pos.X].Numbers[number] {
					count++
				}
			}
			if count == 1 {
				for _, pos := range group.Positions {
					if s.Availables[pos.Y][pos.X].Numbers[number] {
						s.SetNumber(pos.Y, pos.X, number)
						changes++
					}
				}
			}
		}
	}
	return changes
}

func (s *Sudoku) ResolveRec(depth int) (*Sudoku, error) {
	changes := 0
	iteration := 0
	kind := "start"

start:
	if s.Debug {
		logrus.Infof("#######  depth=%-2d iteration=%-3d changes=%-2d missings=%d kind=%s\n%s\n%s", depth, iteration, changes, s.Missings(), kind, s.String(), s.AvailablesString())
		logrus.Infof(strings.Repeat("#", 42))
	}
	iteration++

	if s.DoResolveOnlyOne {
		kind = "resolve-only-one"
		if changes = s.ResolveOnlyOne(); changes > 0 {
			goto start
		}
	}

	if s.DoResolveNumbersThatAreOnlyInOnePosition {
		kind = "resolve-numbers-that-are-only-in-one-position"
		if changes = s.ResolveNumbersThatAreOnlyInOnePosition(); changes > 0 {
			goto start
		}
	}

	if s.DoResolveNumbersThatCanOnlyBeInFewPositions && depth == 0 {
		kind = "resolve-numbers-that-can-only-be-in-few-positions"
		if changes = s.RemoveNumbersThatCanOnlyBeInFewPositions(); changes > 0 {
			goto start
		}
	}

	// Brute force
	if s.Missings() == 0 {
		return s, nil
	}

	if depth >= s.BruteLimit {
		return s, fmt.Errorf("Too deep")
	}

	for y := 0; y < s.Size; y++ {
		for x := 0; x < s.Size; x++ {
			if s.Availables[y][x].Length > 0 {
				clone := Sudoku{}
				s.Clone(&clone)
				clone.SetNumber(y, x, s.Availables[y][x].Availables()[0])
				newSudoku, err := clone.ResolveRec(depth + 1)
				if err != nil {
					continue
				}
				if newSudoku.Missings() == 0 {
					return newSudoku, nil
				}
			}
		}
	}

	return s, nil
}

func (s *Sudoku) Resolve() error {
	newSudoku, err := s.ResolveRec(0)
	if err != nil {
		return err
	}

	if newSudoku != s {
		newSudoku.Clone(s)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"html/template"
	"net/http"
	"regexp"
	"strings"
)

type paste struct {
	Paste  []set
	Title  string
	Author string
	Notes  string
}

type set struct {
	Pokemon uint
	Form    uint
	Item    uint
	Text    template.HTML
}

var (
	reHead = regexp.MustCompile(`^(?:(.* \()([A-Z][a-z0-9:']+\.?(?:[- ][A-Za-z][a-z0-9:']*\.?)*)(\))|([A-Z][a-z0-9:']+\.?(?:[- ][A-Za-z][a-z0-9:']*\.?)*))(?:( \()([MF])(\)))?(?:( @ )([A-Z][a-z0-9:']+(?:[- ][A-Z][a-z0-9:']*)*))?( *)$`)
	reMove = regexp.MustCompile(`^(-)( ([A-Z][a-z\']*(?:[- ][A-Za-z][a-z\']*)*)(?: \[([A-Z][a-z]+)\])?(?: / [A-Z][a-z\']*(?:[- ][A-Za-z][a-z\']*)*)* *)$`)
	reStat = regexp.MustCompile(`^(\d+ HP)?( / )?(\d+ Atk)?( / )?(\d+ Def)?( / )?(\d+ SpA)?( / )?(\d+ SpD)?( / )?(\d+ Spe)?( *)$`)

	tmpl = template.Must(template.ParseFiles("paste.tmpl"))
)

func renderPaste(w http.ResponseWriter, text, title, author, notes []byte) {
	sets := bytes.Split(text, []byte("\r\n\r\n"))
	fpaste := paste{
		Paste:  make([]set, 0, len(sets)),
		Title:  string(title),
		Author: string(author),
		Notes:  string(notes),
	}

	for _, bset := range sets {
		if len(bset) == 0 {
			continue
		}

		var fset set
		var b strings.Builder

		lines := bytes.Split(bset, []byte("\r\n"))

		m := reHead.FindSubmatch(lines[0])
		if m == nil {
			template.HTMLEscape(&b, bset)
			fset.Text = template.HTML(b.String())
			fpaste.Paste = append(fpaste.Paste, fset)
			continue
		}

		if len(m[2]) != 0 {
			if p, ok := pokemonData[string(m[2])]; ok {
				fset.Pokemon = p["id"].(uint)
				fset.Form = p["form"].(uint)
				template.HTMLEscape(&b, m[1])
				b.WriteString(`<span class="type-`)
				b.WriteString(p["type"].(string))
				b.WriteString(`">`)
				template.HTMLEscape(&b, m[2])
				b.WriteString(`</span>`)
				template.HTMLEscape(&b, m[3])
			} else {
				template.HTMLEscape(&b, m[1])
				template.HTMLEscape(&b, m[2])
				template.HTMLEscape(&b, m[3])
			}
		} else if len(m[4]) != 0 {
			if p, ok := pokemonData[string(m[4])]; ok {
				fset.Pokemon = p["id"].(uint)
				fset.Form = p["form"].(uint)
				b.WriteString(`<span class="type-`)
				b.WriteString(p["type"].(string))
				b.WriteString(`">`)
				template.HTMLEscape(&b, m[4])
				b.WriteString(`</span>`)
			} else {
				template.HTMLEscape(&b, m[4])
			}
		}

		if len(m[6]) != 0 {
			template.HTMLEscape(&b, m[5])
			if m[6][0] == 'M' {
				b.WriteString(`<span class="gender-m">`)
			} else if m[6][0] == 'F' {
				b.WriteString(`<span class="gender-f">`)
			} else {
				b.WriteString(`<span>`)
			}
			template.HTMLEscape(&b, m[6])
			b.WriteString(`</span>`)
			template.HTMLEscape(&b, m[7])
		}

		if len(m[9]) != 0 {
			if i, ok := itemData[string(m[9])]; ok {
				fset.Item = i["id"].(uint)
				template.HTMLEscape(&b, m[8])
				if t, ok := i["type"]; ok {
					b.WriteString(`<span class="type-`)
					b.WriteString(t.(string))
					b.WriteString(`">`)
					template.HTMLEscape(&b, m[9])
					b.WriteString(`</span>`)
				} else {
					template.HTMLEscape(&b, m[9])
				}
			} else {
				template.HTMLEscape(&b, m[8])
				template.HTMLEscape(&b, m[9])
			}
		}

		b.Write(m[10])
		b.WriteByte('\n')

		for _, line := range lines[1:] {
			if m := reMove.FindSubmatch(line); m != nil {
				if mv, ok := moveData[string(m[3])]; ok {
					b.WriteString(`<span class="type-`)
					if len(m[4]) > 0 {
						template.HTMLEscape(&b, bytes.ToLower(m[4]))
					} else {
						b.WriteString(mv["type"].(string))
					}
					b.WriteString(`">`)
					template.HTMLEscape(&b, m[1])
					b.WriteString(`</span>`)
				} else {
					template.HTMLEscape(&b, m[1])
				}
				template.HTMLEscape(&b, m[2])
			} else if m := bytes.SplitAfterN(line, []byte(": "), 2); len(m) == 2 {
				b.WriteString(`<span class="attr">`)
				template.HTMLEscape(&b, m[0])
				b.WriteString(`</span>`)
				if len(m[0]) == 5 && m[0][1] == 'V' && m[0][2] == 's' {
					attr := m[1]
					if m := reStat.FindSubmatch(attr); m != nil {
						for i, stat := range [...]string{"hp", "atk", "def", "spa", "spd", "spe"} {
							if len(m[i*2+1]) > 0 {
								b.WriteString(`<span class="stat-`)
								b.WriteString(stat)
								b.WriteString(`">`)
								template.HTMLEscape(&b, m[i*2+1])
								b.WriteString(`</span>`)
							}
							template.HTMLEscape(&b, m[i*2+2])
						}
					} else {
						template.HTMLEscape(&b, attr)
					}
				} else {
					template.HTMLEscape(&b, m[1])
				}
			} else {
				template.HTMLEscape(&b, line)
			}
			b.WriteByte('\n')
		}

		fset.Text = template.HTML(b.String())

		fpaste.Paste = append(fpaste.Paste, fset)
	}

	err := tmpl.Execute(w, fpaste)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>Allow "X Tier" as a valid item format<commit_after>package main

import (
	"bytes"
	"html/template"
	"net/http"
	"regexp"
	"strings"
)

type paste struct {
	Paste  []set
	Title  string
	Author string
	Notes  string
}

type set struct {
	Pokemon uint
	Form    uint
	Item    uint
	Text    template.HTML
}

var (
	reHead = regexp.MustCompile(`^(?:(.* \()([A-Z][a-z0-9:']+\.?(?:[- ][A-Za-z][a-z0-9:']*\.?)*)(\))|([A-Z][a-z0-9:']+\.?(?:[- ][A-Za-z][a-z0-9:']*\.?)*))(?:( \()([MF])(\)))?(?:( @ )([A-Z][a-z0-9:']*(?:[- ][A-Z][a-z0-9:']*)*))?( *)$`)
	reMove = regexp.MustCompile(`^(-)( ([A-Z][a-z\']*(?:[- ][A-Za-z][a-z\']*)*)(?: \[([A-Z][a-z]+)\])?(?: / [A-Z][a-z\']*(?:[- ][A-Za-z][a-z\']*)*)* *)$`)
	reStat = regexp.MustCompile(`^(\d+ HP)?( / )?(\d+ Atk)?( / )?(\d+ Def)?( / )?(\d+ SpA)?( / )?(\d+ SpD)?( / )?(\d+ Spe)?( *)$`)

	tmpl = template.Must(template.ParseFiles("paste.tmpl"))
)

func renderPaste(w http.ResponseWriter, text, title, author, notes []byte) {
	sets := bytes.Split(text, []byte("\r\n\r\n"))
	fpaste := paste{
		Paste:  make([]set, 0, len(sets)),
		Title:  string(title),
		Author: string(author),
		Notes:  string(notes),
	}

	for _, bset := range sets {
		if len(bset) == 0 {
			continue
		}

		var fset set
		var b strings.Builder

		lines := bytes.Split(bset, []byte("\r\n"))

		m := reHead.FindSubmatch(lines[0])
		if m == nil {
			template.HTMLEscape(&b, bset)
			fset.Text = template.HTML(b.String())
			fpaste.Paste = append(fpaste.Paste, fset)
			continue
		}

		if len(m[2]) != 0 {
			if p, ok := pokemonData[string(m[2])]; ok {
				fset.Pokemon = p["id"].(uint)
				fset.Form = p["form"].(uint)
				template.HTMLEscape(&b, m[1])
				b.WriteString(`<span class="type-`)
				b.WriteString(p["type"].(string))
				b.WriteString(`">`)
				template.HTMLEscape(&b, m[2])
				b.WriteString(`</span>`)
				template.HTMLEscape(&b, m[3])
			} else {
				template.HTMLEscape(&b, m[1])
				template.HTMLEscape(&b, m[2])
				template.HTMLEscape(&b, m[3])
			}
		} else if len(m[4]) != 0 {
			if p, ok := pokemonData[string(m[4])]; ok {
				fset.Pokemon = p["id"].(uint)
				fset.Form = p["form"].(uint)
				b.WriteString(`<span class="type-`)
				b.WriteString(p["type"].(string))
				b.WriteString(`">`)
				template.HTMLEscape(&b, m[4])
				b.WriteString(`</span>`)
			} else {
				template.HTMLEscape(&b, m[4])
			}
		}

		if len(m[6]) != 0 {
			template.HTMLEscape(&b, m[5])
			if m[6][0] == 'M' {
				b.WriteString(`<span class="gender-m">`)
			} else if m[6][0] == 'F' {
				b.WriteString(`<span class="gender-f">`)
			} else {
				b.WriteString(`<span>`)
			}
			template.HTMLEscape(&b, m[6])
			b.WriteString(`</span>`)
			template.HTMLEscape(&b, m[7])
		}

		if len(m[9]) != 0 {
			if i, ok := itemData[string(m[9])]; ok {
				fset.Item = i["id"].(uint)
				template.HTMLEscape(&b, m[8])
				if t, ok := i["type"]; ok {
					b.WriteString(`<span class="type-`)
					b.WriteString(t.(string))
					b.WriteString(`">`)
					template.HTMLEscape(&b, m[9])
					b.WriteString(`</span>`)
				} else {
					template.HTMLEscape(&b, m[9])
				}
			} else {
				template.HTMLEscape(&b, m[8])
				template.HTMLEscape(&b, m[9])
			}
		}

		b.Write(m[10])
		b.WriteByte('\n')

		for _, line := range lines[1:] {
			if m := reMove.FindSubmatch(line); m != nil {
				if mv, ok := moveData[string(m[3])]; ok {
					b.WriteString(`<span class="type-`)
					if len(m[4]) > 0 {
						template.HTMLEscape(&b, bytes.ToLower(m[4]))
					} else {
						b.WriteString(mv["type"].(string))
					}
					b.WriteString(`">`)
					template.HTMLEscape(&b, m[1])
					b.WriteString(`</span>`)
				} else {
					template.HTMLEscape(&b, m[1])
				}
				template.HTMLEscape(&b, m[2])
			} else if m := bytes.SplitAfterN(line, []byte(": "), 2); len(m) == 2 {
				b.WriteString(`<span class="attr">`)
				template.HTMLEscape(&b, m[0])
				b.WriteString(`</span>`)
				if len(m[0]) == 5 && m[0][1] == 'V' && m[0][2] == 's' {
					attr := m[1]
					if m := reStat.FindSubmatch(attr); m != nil {
						for i, stat := range [...]string{"hp", "atk", "def", "spa", "spd", "spe"} {
							if len(m[i*2+1]) > 0 {
								b.WriteString(`<span class="stat-`)
								b.WriteString(stat)
								b.WriteString(`">`)
								template.HTMLEscape(&b, m[i*2+1])
								b.WriteString(`</span>`)
							}
							template.HTMLEscape(&b, m[i*2+2])
						}
					} else {
						template.HTMLEscape(&b, attr)
					}
				} else {
					template.HTMLEscape(&b, m[1])
				}
			} else {
				template.HTMLEscape(&b, line)
			}
			b.WriteByte('\n')
		}

		fset.Text = template.HTML(b.String())

		fpaste.Paste = append(fpaste.Paste, fset)
	}

	err := tmpl.Execute(w, fpaste)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/mesosphere/dcos-commons/cli"
	"gopkg.in/alecthomas/kingpin.v2"
	"log"
	"os"
	"strings"
)

func main() {
	modName, err := cli.GetModuleName()
	if err != nil {
		log.Fatalf(err.Error())
	}

	app, err := cli.NewApp(
		"0.1.0",
		"Mesosphere",
		fmt.Sprintf("Deploy and manage %s clusters", strings.Title(modName)))
	if err != nil {
		log.Fatalf(err.Error())
	}

	// Omit standard "connection" section. Cassandra isn't on the standard paths yet, and omit
	// standard "config" and "state" sections since Cassandra isn't installing
	// ConfigResource/StateResource yet.
	// Once these are fixed, this block can all be replaced with a call to "HandleCommonArgs"
	cli.HandleCommonFlags(app, modName, fmt.Sprintf("%s DC/OS CLI Module", strings.Title(modName)))
	//cli.HandleConfigSection(app)
	//cli.HandleConnectionSection(app)
	cli.HandlePlanSection(app)
	//cli.HandleStateSection(app)

	handleSeedsCommand(app)
	handleCustomConnectionCommand(app, modName)

	handleNodeSection(app, modName)
	handleBackupRestoreSections(app, modName)
	handleCleanupRepairSections(app)

	// Omit modname:
	kingpin.MustParse(app.Parse(os.Args[2:]))
}

func handleSeedsCommand(app *kingpin.Application) {
	app.Command("seeds", "Retrieve seed node information").Action(
		func(c *kingpin.ParseContext) error {
			cli.PrintJSON(cli.HTTPGet("v1/seeds"))
			return nil
		})
}

type ConnectionHandler struct {
	showAddress bool
	showDns bool
}
func (cmd *ConnectionHandler) runBase(c *kingpin.ParseContext) error {
	if cmd.showAddress {
		cli.PrintJSON(cli.HTTPGet("v1/nodes/connect/address"))
	} else if cmd.showDns {
		cli.PrintJSON(cli.HTTPGet("v1/nodes/connect/dns"))
	} else {
		cli.PrintJSON(cli.HTTPGet("v1/nodes/connect"))
	}
	return nil
}
func handleCustomConnectionCommand(app *kingpin.Application, modName string) {
	cmd := &ConnectionHandler{}

	// Have three explicit commands, to ensure that each possibility shows up in --help:
	connection := app.Command("connection", fmt.Sprintf("Provides %s connection information", modName)).Action(cmd.runBase)
	connection.Flag("address", fmt.Sprintf("Provide addresses of the %s nodes", modName)).BoolVar(&cmd.showAddress)
	connection.Flag("dns", fmt.Sprintf("Provide dns names of the %s nodes", modName)).BoolVar(&cmd.showDns)
}

type NodeHandler struct {
	nodeId int
}
func (cmd *NodeHandler) runDescribe(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet(fmt.Sprintf("v1/nodes/node-%d/info", cmd.nodeId)))
	return nil
}
func (cmd *NodeHandler) runList(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet("v1/nodes/list"))
	return nil
}
func (cmd *NodeHandler) runReplace(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet(fmt.Sprintf("v1/nodes/replace?node=node-%d", cmd.nodeId)))
	return nil
}
func (cmd *NodeHandler) runRestart(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet(fmt.Sprintf("v1/nodes/restart?node=node-%d", cmd.nodeId)))
	return nil
}
func (cmd *NodeHandler) runStatus(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet(fmt.Sprintf("v1/nodes/node-%d/status", cmd.nodeId)))
	return nil
}
func handleNodeSection(app *kingpin.Application, modName string) {
	cmd := &NodeHandler{}
	connection := app.Command("node", fmt.Sprintf("Manage %s nodes", modName))

	describe := connection.Command("describe", "Describes a single node").Action(cmd.runDescribe)
	describe.Arg("node_id", "The node id to describe").IntVar(&cmd.nodeId)

	connection.Command("list", "Lists all nodes").Action(cmd.runList)

	replace := connection.Command("replace", "Replaces a single node job, moving it to a different agent").Action(cmd.runReplace)
	replace.Arg("node_id", "The node id to replace").IntVar(&cmd.nodeId)

	restart := connection.Command("restart", "Restarts a single node job, keeping it on the same agent").Action(cmd.runRestart)
	restart.Arg("node_id", "The node id to restart").IntVar(&cmd.nodeId)

	status := connection.Command("status", "Gets the status of a single node").Action(cmd.runStatus)
	status.Arg("node_id", "The node id to check").IntVar(&cmd.nodeId)
}

// Reuse same struct for both 'backup start' and 'restore start' (same args)
type BackupRestoreHandler struct {
	backupName string
	externalLocation string
	s3AccessKey string
	s3SecretKey string
	azureAccount string
	azureKey string
}
func (cmd *BackupRestoreHandler) getArgs() map[string]interface{} {
	return map[string]interface{} {
		"backup_name": cmd.backupName,
		"external_location": cmd.externalLocation,
		"s3_access_key": cmd.s3AccessKey,
		"s3_secret_key": cmd.s3SecretKey,
		"azure_account": cmd.azureAccount,
		"key": cmd.azureKey,
	}
}
func (cmd *BackupRestoreHandler) runBackup(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/backup/start", string(payload)))
	return nil
}
func (cmd *BackupRestoreHandler) runRestore(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/restore/start", string(payload)))
	return nil
}
func handleBackupRestoreSections(app *kingpin.Application, modName string) {
	cmd := &BackupRestoreHandler{}
	planCmd := &cli.PlanHandler{}

	backup := app.Command("backup", fmt.Sprintf("Backup %s cluster data", modName))
	backupStart := backup.Command(
		"start",
		"Perform cluster backup via snapshot mechanism").Action(cmd.runBackup)
	backupStart.Flag("backup_name", "Name of the snapshot").StringVar(&cmd.backupName)
	backupStart.Flag("external_location", "External location where the snapshot should be stored").StringVar(&cmd.externalLocation)
	backupStart.Flag("s3_access_key", "S3 access key").StringVar(&cmd.s3AccessKey)
	backupStart.Flag("s3_secret_key", "S3 secret key").StringVar(&cmd.s3SecretKey)
	backupStart.Flag("azure_account", "Azure storage account").StringVar(&cmd.azureAccount)
	backupStart.Flag("azure_key", "Azure secret key").StringVar(&cmd.azureKey)
	// same as 'plan show':
	backup.Command(
		"status",
		"Displays the status of the backup").Action(planCmd.RunShow)

	restore := app.Command("restore", fmt.Sprintf("Restore %s cluster from backup", modName))
	restoreStart := restore.Command(
		"start",
		"Restores cluster to a previous snapshot").Action(cmd.runRestore)
	restoreStart.Flag("backup_name", "Name of the snapshot to restore").StringVar(&cmd.backupName)
	restoreStart.Flag("external_location", "External location where the snapshot is stored").StringVar(&cmd.externalLocation)
	restoreStart.Flag("s3_access_key", "S3 access key").StringVar(&cmd.s3AccessKey)
	restoreStart.Flag("s3_secret_key", "S3 secret key").StringVar(&cmd.s3SecretKey)
	restoreStart.Flag("azure_account", "Azure storage account").StringVar(&cmd.azureAccount)
	restoreStart.Flag("azure_key", "Azure secret key").StringVar(&cmd.azureKey)
	// same as 'plan show':
	restore.Command(
		"status",
		"Displays the status of the restore").Action(planCmd.RunShow)
}

// Reuse same struct for both 'cleanup start' and 'repair start' (same args)
type CleanupRepairHandler struct {
	nodes string
	keySpaces string
	columnFamilies string
}
func (cmd *CleanupRepairHandler) getArgs() map[string]interface{} {
	nodesList := []string{}
	for _, node := range strings.Split(cmd.nodes, ",") {
		nodesList = append(nodesList, fmt.Sprintf("node-%s", strings.TrimSpace(node)))
	}

	dict := map[string]interface{} {"nodes": nodesList}

	if len(cmd.keySpaces) != 0 {
		dict["key_spaces"] = cmd.keySpaces
	}
	if len(cmd.keySpaces) != 0 {
		dict["column_families"] = cmd.columnFamilies
	}
	return dict
}
func (cmd *CleanupRepairHandler) runCleanup(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/cleanup/start", string(payload)))
	return nil
}
func (cmd *CleanupRepairHandler) runRepair(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/repair/start", string(payload)))
	return nil
}
func handleCleanupRepairSections(app *kingpin.Application) {
	cmd := &CleanupRepairHandler{}

	cleanup := app.Command("cleanup", "Clean up old token mappings")
	cleanupStart := cleanup.Command(
		"start",
		"Perform cluster cleanup of deleted or moved keys").Action(cmd.runCleanup)
	cleanupStart.Flag("nodes", "A list of the nodes to cleanup or * for all.").Default("*").StringVar(&cmd.nodes)
	cleanupStart.Flag("key_spaces", "The key spaces to cleanup or empty for all.").StringVar(&cmd.keySpaces)
	cleanupStart.Flag("column_families", "The column families to cleanup.").StringVar(&cmd.columnFamilies)

	repair := app.Command("repair", "Perform primary range repair")
	repairStart := repair.Command(
		"start",
		"Perform primary range anti-entropy repair").Action(cmd.runRepair)
	repairStart.Flag("nodes", "A list of the nodes to repair or * for all.").Default("*").StringVar(&cmd.nodes)
	repairStart.Flag("key_spaces", "The key spaces to repair or empty for all.").StringVar(&cmd.keySpaces)
	repairStart.Flag("column_families", "The column families to repair.").StringVar(&cmd.columnFamilies)
}
<commit_msg>Fix query params for replace/restart<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/mesosphere/dcos-commons/cli"
	"gopkg.in/alecthomas/kingpin.v2"
	"log"
	"net/url"
	"os"
	"strings"
)

func main() {
	modName, err := cli.GetModuleName()
	if err != nil {
		log.Fatalf(err.Error())
	}

	app, err := cli.NewApp(
		"0.1.0",
		"Mesosphere",
		fmt.Sprintf("Deploy and manage %s clusters", strings.Title(modName)))
	if err != nil {
		log.Fatalf(err.Error())
	}

	// Omit standard "connection" section. Cassandra isn't on the standard paths yet, and omit
	// standard "config" and "state" sections since Cassandra isn't installing
	// ConfigResource/StateResource yet.
	// Once these are fixed, this block can all be replaced with a call to "HandleCommonArgs"
	cli.HandleCommonFlags(app, modName, fmt.Sprintf("%s DC/OS CLI Module", strings.Title(modName)))
	//cli.HandleConfigSection(app)
	//cli.HandleConnectionSection(app)
	cli.HandlePlanSection(app)
	//cli.HandleStateSection(app)

	handleSeedsCommand(app)
	handleCustomConnectionCommand(app, modName)

	handleNodeSection(app, modName)
	handleBackupRestoreSections(app, modName)
	handleCleanupRepairSections(app)

	// Omit modname:
	kingpin.MustParse(app.Parse(os.Args[2:]))
}

func handleSeedsCommand(app *kingpin.Application) {
	app.Command("seeds", "Retrieve seed node information").Action(
		func(c *kingpin.ParseContext) error {
			cli.PrintJSON(cli.HTTPGet("v1/seeds"))
			return nil
		})
}

type ConnectionHandler struct {
	showAddress bool
	showDns bool
}
func (cmd *ConnectionHandler) runBase(c *kingpin.ParseContext) error {
	if cmd.showAddress {
		cli.PrintJSON(cli.HTTPGet("v1/nodes/connect/address"))
	} else if cmd.showDns {
		cli.PrintJSON(cli.HTTPGet("v1/nodes/connect/dns"))
	} else {
		cli.PrintJSON(cli.HTTPGet("v1/nodes/connect"))
	}
	return nil
}
func handleCustomConnectionCommand(app *kingpin.Application, modName string) {
	cmd := &ConnectionHandler{}

	// Have three explicit commands, to ensure that each possibility shows up in --help:
	connection := app.Command("connection", fmt.Sprintf("Provides %s connection information", modName)).Action(cmd.runBase)
	connection.Flag("address", fmt.Sprintf("Provide addresses of the %s nodes", modName)).BoolVar(&cmd.showAddress)
	connection.Flag("dns", fmt.Sprintf("Provide dns names of the %s nodes", modName)).BoolVar(&cmd.showDns)
}

type NodeHandler struct {
	nodeId int
}
func (cmd *NodeHandler) runDescribe(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet(fmt.Sprintf("v1/nodes/node-%d/info", cmd.nodeId)))
	return nil
}
func (cmd *NodeHandler) runList(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet("v1/nodes/list"))
	return nil
}
func (cmd *NodeHandler) runReplace(c *kingpin.ParseContext) error {
	query := url.Values{}
	query.Set("node", fmt.Sprintf("node-%d", cmd.nodeId))
	cli.PrintJSON(cli.HTTPGetQuery("v1/nodes/replace", query.Encode()))
	return nil
}
func (cmd *NodeHandler) runRestart(c *kingpin.ParseContext) error {
	query := url.Values{}
	query.Set("node", fmt.Sprintf("node-%d", cmd.nodeId))
	cli.PrintJSON(cli.HTTPGetQuery("v1/nodes/restart", query.Encode()))
	return nil
}
func (cmd *NodeHandler) runStatus(c *kingpin.ParseContext) error {
	cli.PrintJSON(cli.HTTPGet(fmt.Sprintf("v1/nodes/node-%d/status", cmd.nodeId)))
	return nil
}
func handleNodeSection(app *kingpin.Application, modName string) {
	cmd := &NodeHandler{}
	connection := app.Command("node", fmt.Sprintf("Manage %s nodes", modName))

	describe := connection.Command("describe", "Describes a single node").Action(cmd.runDescribe)
	describe.Arg("node_id", "The node id to describe").IntVar(&cmd.nodeId)

	connection.Command("list", "Lists all nodes").Action(cmd.runList)

	replace := connection.Command("replace", "Replaces a single node job, moving it to a different agent").Action(cmd.runReplace)
	replace.Arg("node_id", "The node id to replace").IntVar(&cmd.nodeId)

	restart := connection.Command("restart", "Restarts a single node job, keeping it on the same agent").Action(cmd.runRestart)
	restart.Arg("node_id", "The node id to restart").IntVar(&cmd.nodeId)

	status := connection.Command("status", "Gets the status of a single node").Action(cmd.runStatus)
	status.Arg("node_id", "The node id to check").IntVar(&cmd.nodeId)
}

// Reuse same struct for both 'backup start' and 'restore start' (same args)
type BackupRestoreHandler struct {
	backupName string
	externalLocation string
	s3AccessKey string
	s3SecretKey string
	azureAccount string
	azureKey string
}
func (cmd *BackupRestoreHandler) getArgs() map[string]interface{} {
	return map[string]interface{} {
		"backup_name": cmd.backupName,
		"external_location": cmd.externalLocation,
		"s3_access_key": cmd.s3AccessKey,
		"s3_secret_key": cmd.s3SecretKey,
		"azure_account": cmd.azureAccount,
		"key": cmd.azureKey,
	}
}
func (cmd *BackupRestoreHandler) runBackup(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/backup/start", string(payload)))
	return nil
}
func (cmd *BackupRestoreHandler) runRestore(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/restore/start", string(payload)))
	return nil
}
func handleBackupRestoreSections(app *kingpin.Application, modName string) {
	cmd := &BackupRestoreHandler{}
	planCmd := &cli.PlanHandler{}

	backup := app.Command("backup", fmt.Sprintf("Backup %s cluster data", modName))
	backupStart := backup.Command(
		"start",
		"Perform cluster backup via snapshot mechanism").Action(cmd.runBackup)
	backupStart.Flag("backup_name", "Name of the snapshot").StringVar(&cmd.backupName)
	backupStart.Flag("external_location", "External location where the snapshot should be stored").StringVar(&cmd.externalLocation)
	backupStart.Flag("s3_access_key", "S3 access key").StringVar(&cmd.s3AccessKey)
	backupStart.Flag("s3_secret_key", "S3 secret key").StringVar(&cmd.s3SecretKey)
	backupStart.Flag("azure_account", "Azure storage account").StringVar(&cmd.azureAccount)
	backupStart.Flag("azure_key", "Azure secret key").StringVar(&cmd.azureKey)
	// same as 'plan show':
	backup.Command(
		"status",
		"Displays the status of the backup").Action(planCmd.RunShow)

	restore := app.Command("restore", fmt.Sprintf("Restore %s cluster from backup", modName))
	restoreStart := restore.Command(
		"start",
		"Restores cluster to a previous snapshot").Action(cmd.runRestore)
	restoreStart.Flag("backup_name", "Name of the snapshot to restore").StringVar(&cmd.backupName)
	restoreStart.Flag("external_location", "External location where the snapshot is stored").StringVar(&cmd.externalLocation)
	restoreStart.Flag("s3_access_key", "S3 access key").StringVar(&cmd.s3AccessKey)
	restoreStart.Flag("s3_secret_key", "S3 secret key").StringVar(&cmd.s3SecretKey)
	restoreStart.Flag("azure_account", "Azure storage account").StringVar(&cmd.azureAccount)
	restoreStart.Flag("azure_key", "Azure secret key").StringVar(&cmd.azureKey)
	// same as 'plan show':
	restore.Command(
		"status",
		"Displays the status of the restore").Action(planCmd.RunShow)
}

// Reuse same struct for both 'cleanup start' and 'repair start' (same args)
type CleanupRepairHandler struct {
	nodes string
	keySpaces string
	columnFamilies string
}
func (cmd *CleanupRepairHandler) getArgs() map[string]interface{} {
	nodesList := []string{}
	for _, node := range strings.Split(cmd.nodes, ",") {
		nodesList = append(nodesList, fmt.Sprintf("node-%s", strings.TrimSpace(node)))
	}

	dict := map[string]interface{} {"nodes": nodesList}

	if len(cmd.keySpaces) != 0 {
		dict["key_spaces"] = cmd.keySpaces
	}
	if len(cmd.keySpaces) != 0 {
		dict["column_families"] = cmd.columnFamilies
	}
	return dict
}
func (cmd *CleanupRepairHandler) runCleanup(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/cleanup/start", string(payload)))
	return nil
}
func (cmd *CleanupRepairHandler) runRepair(c *kingpin.ParseContext) error {
	payload, err := json.Marshal(cmd.getArgs())
	if err != nil {
		return err
	}
	cli.PrintJSON(cli.HTTPPutJSON("v1/repair/start", string(payload)))
	return nil
}
func handleCleanupRepairSections(app *kingpin.Application) {
	cmd := &CleanupRepairHandler{}

	cleanup := app.Command("cleanup", "Clean up old token mappings")
	cleanupStart := cleanup.Command(
		"start",
		"Perform cluster cleanup of deleted or moved keys").Action(cmd.runCleanup)
	cleanupStart.Flag("nodes", "A list of the nodes to cleanup or * for all.").Default("*").StringVar(&cmd.nodes)
	cleanupStart.Flag("key_spaces", "The key spaces to cleanup or empty for all.").StringVar(&cmd.keySpaces)
	cleanupStart.Flag("column_families", "The column families to cleanup.").StringVar(&cmd.columnFamilies)

	repair := app.Command("repair", "Perform primary range repair")
	repairStart := repair.Command(
		"start",
		"Perform primary range anti-entropy repair").Action(cmd.runRepair)
	repairStart.Flag("nodes", "A list of the nodes to repair or * for all.").Default("*").StringVar(&cmd.nodes)
	repairStart.Flag("key_spaces", "The key spaces to repair or empty for all.").StringVar(&cmd.keySpaces)
	repairStart.Flag("column_families", "The column families to repair.").StringVar(&cmd.columnFamilies)
}
<|endoftext|>


<commit_before>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"testing"
)

func TestCommnad(t *testing.T) {
	Describe(t, "Command Tests", func() {
		Context("コマンドだけ指定する", func() {
			It("インスタンスが作成できること", func() {
				cmd := "cmd"
				sut := NewCommand(cmd)
				Expect(sut).To(Exist)
			})
			It("コマンドだけ変数が書き換えられていること", func() {
				cmd := "cmd"
				sut := NewCommand(cmd)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, "")
				Expect(sut.param).To(Equal, 0)
			})
		})
		Context("サブコマンドを作成する", func() {
			It("インスタンスが作成できること", func() {
				cmd, subcmd := "cmd", "subcmd"
				Expect(NewSubCommand(cmd, subcmd)).To(Exist)
			})
			It("コマンドとサブコマンドが指定した値で書き換えられていること", func() {
				cmd, subcmd := "cmd", "subcmd"
				sut := NewSubCommand(cmd, subcmd)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, subcmd)
				Expect(sut.param).To(Equal, 0)
			})
		})
		Context("Create Instance", func() {
			It("is exists", func() {
				cmd := "cmd"
				param := 1
				sut := NewCommandWithParam(cmd, param)
				Expect(sut).To(Exist)
			})
		})
		Context("Create Instance", func() {
			It("Initialize Instance", func() {
				cmd := "cmd"
				param := 1
				sut := NewCommandWithParam(cmd, param)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, "")
				Expect(sut.param).To(Equal, 1)
			})
		})
	})
}
<commit_msg>パラメータ付きコマンド作成関数のテストケースを変更<commit_after>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"testing"
)

func TestCommnad(t *testing.T) {
	Describe(t, "Command Tests", func() {
		Context("コマンドだけ指定する", func() {
			It("インスタンスが作成できること", func() {
				cmd := "cmd"
				sut := NewCommand(cmd)
				Expect(sut).To(Exist)
			})
			It("コマンドだけ変数が書き換えられていること", func() {
				cmd := "cmd"
				sut := NewCommand(cmd)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, "")
				Expect(sut.param).To(Equal, 0)
			})
		})
		Context("サブコマンドを作成する", func() {
			It("インスタンスが作成できること", func() {
				cmd, subcmd := "cmd", "subcmd"
				Expect(NewSubCommand(cmd, subcmd)).To(Exist)
			})
			It("コマンドとサブコマンドが指定した値で書き換えられていること", func() {
				cmd, subcmd := "cmd", "subcmd"
				sut := NewSubCommand(cmd, subcmd)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, subcmd)
				Expect(sut.param).To(Equal, 0)
			})
		})
		Context("パラメータ付きのコマンドを作成する", func() {
			It("インスタンスが作成できること", func() {
				cmd := "cmd"
				param := 1
				sut := NewCommandWithParam(cmd, param)
				Expect(sut).To(Exist)
			})
			It("コマンドとパラメータが指定した値で書き換えられていること", func() {
				cmd := "cmd"
				param := 1
				sut := NewCommandWithParam(cmd, param)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, "")
				Expect(sut.param).To(Equal, 1)
			})
		})
	})
}
<|endoftext|>


<commit_before>package cl11

import (
	"strings"

	clw "github.com/rdwilliamson/clw11"
)

// Not thread safe.
type CommandQueue struct {
	id         clw.CommandQueue
	Context    *Context
	Device     *Device
	Properties CommandQueueProperties

	// Scratch space to avoid allocating memory when converting a wait list.
	eventsScratch []clw.Event
}

type CommandQueueProperties int

// Bitfield.
const (
	QueueOutOfOrderExecution = CommandQueueProperties(clw.QueueOutOfOrderExecModeEnable)
	QueueProfilingEnable     = CommandQueueProperties(clw.QueueProfilingEnable)
)

func (cqp CommandQueueProperties) String() string {
	var propertiesStrings []string
	if cqp&QueueOutOfOrderExecution != 0 {
		propertiesStrings = append(propertiesStrings, "out of order execution")
	}
	if cqp&QueueProfilingEnable != 0 {
		propertiesStrings = append(propertiesStrings, "profiling")
	}
	return "{" + strings.Join(propertiesStrings, ", ") + "}"
}

func (c *Context) CreateCommandQueue(d *Device, cqp CommandQueueProperties) (*CommandQueue, error) {

	commandQueue, err := clw.CreateCommandQueue(c.id, d.id, clw.CommandQueueProperties(cqp))
	if err != nil {
		return nil, err
	}

	return &CommandQueue{id: commandQueue, Context: c, Device: d, Properties: cqp}, nil
}

func (cq *CommandQueue) Flush() error {
	return clw.Flush(cq.id)
}

func (cq *CommandQueue) Finish() error {
	return clw.Finish(cq.id)
}

func (cq *CommandQueue) Retain() error {
	return clw.RetainCommandQueue(cq.id)
}

func (cq *CommandQueue) Release() error {
	return clw.ReleaseCommandQueue(cq.id)
}

func (cq *CommandQueue) EnqueueMarker(e *Event) error {

	if e != nil {
		e.Context = cq.Context
		e.CommandType = CommandMarker
		e.CommandQueue = cq
	}

	return clw.EnqueueMarker(cq.id, &e.id)
}

func (cq *CommandQueue) EnqueueWaitForEvents(waitList []*Event) error {
	return clw.EnqueueWaitForEvents(cq.id, cq.toEvents(waitList))
}

func (cq *CommandQueue) EnqueueBarrier() error {
	return clw.EnqueueBarrier(cq.id)
}

func (cq *CommandQueue) toEvents(in []*Event) []clw.Event {

	if in == nil {
		return nil
	}

	if len(cq.eventsScratch) < len(in) {
		cq.eventsScratch = make([]clw.Event, len(in))
	}

	for i := range in {
		cq.eventsScratch[i] = in[i].id
	}

	return cq.eventsScratch[:len(in)]
}
<commit_msg>Started adding command queue documentation.<commit_after>package cl11

import (
	"strings"

	clw "github.com/rdwilliamson/clw11"
)

// The OpenCL functions that are submitted to a command-queue are enqueued in
// the order the calls are made but can be configured to execute in-order or
// out-of-order. In addition, a wait for events or a barrier command can be
// enqueued to the command-queue. The wait for events command ensures that
// previously enqueued commands identified by the list of events to wait for
// have finished before the next batch of commands is executed. The barrier
// command ensures that all previously enqueued commands in a command-queue have
// finished execution before the next batch of commands is executed.
type CommandQueue struct {
	id clw.CommandQueue

	// The context the command queue was created on.
	Context *Context

	// The device the command queue was created for.
	Device *Device

	// Bit-field list of properties for the command queue.
	Properties CommandQueueProperties

	// Scratch space to avoid allocating memory when converting a wait list.
	eventsScratch []clw.Event
}

type CommandQueueProperties int

// Bitfield.
const (
	QueueOutOfOrderExecution = CommandQueueProperties(clw.QueueOutOfOrderExecModeEnable)
	QueueProfilingEnable     = CommandQueueProperties(clw.QueueProfilingEnable)
)

func (cqp CommandQueueProperties) String() string {
	var propertiesStrings []string
	if cqp&QueueOutOfOrderExecution != 0 {
		propertiesStrings = append(propertiesStrings, "out of order execution")
	}
	if cqp&QueueProfilingEnable != 0 {
		propertiesStrings = append(propertiesStrings, "profiling")
	}
	return "{" + strings.Join(propertiesStrings, ", ") + "}"
}

func (c *Context) CreateCommandQueue(d *Device, cqp CommandQueueProperties) (*CommandQueue, error) {

	commandQueue, err := clw.CreateCommandQueue(c.id, d.id, clw.CommandQueueProperties(cqp))
	if err != nil {
		return nil, err
	}

	return &CommandQueue{id: commandQueue, Context: c, Device: d, Properties: cqp}, nil
}

func (cq *CommandQueue) Flush() error {
	return clw.Flush(cq.id)
}

func (cq *CommandQueue) Finish() error {
	return clw.Finish(cq.id)
}

func (cq *CommandQueue) Retain() error {
	return clw.RetainCommandQueue(cq.id)
}

func (cq *CommandQueue) Release() error {
	return clw.ReleaseCommandQueue(cq.id)
}

func (cq *CommandQueue) EnqueueMarker(e *Event) error {

	if e != nil {
		e.Context = cq.Context
		e.CommandType = CommandMarker
		e.CommandQueue = cq
	}

	return clw.EnqueueMarker(cq.id, &e.id)
}

func (cq *CommandQueue) EnqueueWaitForEvents(waitList []*Event) error {
	return clw.EnqueueWaitForEvents(cq.id, cq.toEvents(waitList))
}

func (cq *CommandQueue) EnqueueBarrier() error {
	return clw.EnqueueBarrier(cq.id)
}

func (cq *CommandQueue) toEvents(in []*Event) []clw.Event {

	if in == nil {
		return nil
	}

	if len(cq.eventsScratch) < len(in) {
		cq.eventsScratch = make([]clw.Event, len(in))
	}

	for i := range in {
		cq.eventsScratch[i] = in[i].id
	}

	return cq.eventsScratch[:len(in)]
}
<|endoftext|>


<commit_before>package commands

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"path"
	"strings"

	cli "github.com/urfave/cli"

	"github.com/ipfs/iptb/testbed"
	"github.com/ipfs/iptb/testbed/interfaces"
)

var RunCmd = cli.Command{
	Category:  "CORE",
	Name:      "run",
	Usage:     "run command on specified nodes (or all)",
	ArgsUsage: "[nodes] -- <command...>",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:   "terminator",
			Hidden: true,
		},
		cli.BoolFlag{
			Name:   "stdin",
			Hidden: true,
		},
	},
	Before: func(c *cli.Context) error {
		if c.NArg() == 0 {
			return c.Set("stdin", "true")
		}
		if present := isTerminatorPresent(c); present {
			return c.Set("terminator", "true")
		}
		return nil
	},
	Action: func(c *cli.Context) error {
		flagRoot := c.GlobalString("IPTB_ROOT")
		flagTestbed := c.GlobalString("testbed")

		tb := testbed.NewTestbed(path.Join(flagRoot, "testbeds", flagTestbed))
		nodes, err := tb.Nodes()
		if err != nil {
			return err
		}

		var args [][]string
		var terminatorPresent bool
		if c.IsSet("stdin") {
			terminatorPresent = false
			scanner := bufio.NewScanner(os.Stdin)
			for scanner.Scan() {
				tokens := strings.Fields(scanner.Text())
				args = append(args, tokens)
			}
		} else {
			terminatorPresent = c.IsSet("terminator")
			cArgsStr := make([]string, c.NArg())
			for i, arg := range c.Args() {
				cArgsStr[i] = arg
			}
			args = append(args, cArgsStr)
		}

		ranges := make([][]int, len(args))
		runCmds := make([]outputFunc, len(args))
		for i, cmd := range args {
			nodeRange, tokens := parseCommand(cmd, terminatorPresent)
			if nodeRange == "" {
				nodeRange = fmt.Sprintf("[0-%d]", len(nodes)-1)
			}
			list, err := parseRange(nodeRange)
			if err != nil {
				return fmt.Errorf("could not parse node range %s", nodeRange)
			}
			ranges[i] = list

			runCmd := func(node testbedi.Core) (testbedi.Output, error) {
				return node.RunCmd(context.Background(), nil, tokens...)
			}
			runCmds[i] = runCmd
		}

		results, err := mapListWithOutput(ranges, nodes, runCmds)
		return buildReport(results)
	},
}
<commit_msg>Abstract out `bufio.Reader` from the rest of the logic.<commit_after>package commands

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"path"
	"strings"

	cli "github.com/urfave/cli"

	"github.com/ipfs/iptb/testbed"
	"github.com/ipfs/iptb/testbed/interfaces"
)

var RunCmd = cli.Command{
	Category:  "CORE",
	Name:      "run",
	Usage:     "run command on specified nodes (or all)",
	ArgsUsage: "[nodes] -- <command...>",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:   "terminator",
			Hidden: true,
		},
		cli.BoolFlag{
			Name:   "stdin",
			Hidden: true,
		},
	},
	Before: func(c *cli.Context) error {
		if c.NArg() == 0 {
			return c.Set("stdin", "true")
		}
		if present := isTerminatorPresent(c); present {
			return c.Set("terminator", "true")
		}
		return nil
	},
	Action: func(c *cli.Context) error {
		flagRoot := c.GlobalString("IPTB_ROOT")
		flagTestbed := c.GlobalString("testbed")

		tb := testbed.NewTestbed(path.Join(flagRoot, "testbeds", flagTestbed))
		nodes, err := tb.Nodes()
		if err != nil {
			return err
		}

		var reader io.Reader
		if c.IsSet("stdin") {
			reader = bufio.NewReader(os.Stdin)
		} else {
			var builder strings.Builder
			if c.IsSet("terminator") {
				builder.WriteString("-- ")
			}
			for i, arg := range c.Args() {
				builder.WriteString(arg)
				if i != c.NArg()-1 {
					builder.WriteString(" ")
				}
			}
			reader = strings.NewReader(builder.String())
		}

		var args [][]string
		scanner := bufio.NewScanner(reader)
		for scanner.Scan() {
			tokens := strings.Fields(scanner.Text())
			args = append(args, tokens)
		}

		ranges := make([][]int, len(args))
		runCmds := make([]outputFunc, len(args))
		for i, cmd := range args {
			nodeRange, tokens := parseCommand(cmd, false)
			if nodeRange == "" {
				nodeRange = fmt.Sprintf("[0-%d]", len(nodes)-1)
			}
			list, err := parseRange(nodeRange)
			if err != nil {
				return fmt.Errorf("could not parse node range %s", nodeRange)
			}
			ranges[i] = list

			runCmd := func(node testbedi.Core) (testbedi.Output, error) {
				return node.RunCmd(context.Background(), nil, tokens...)
			}
			runCmds[i] = runCmd
		}

		results, err := mapListWithOutput(ranges, nodes, runCmds)
		return buildReport(results)
	},
}
<|endoftext|>


<commit_before>package livesplit

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/glacials/tugnut/run"
)

// parser implements parser.Parser
type parser struct {
	f io.Reader
	r RunTag
}

func NewParser(r io.Reader) *parser {
	p := parser{
		f: r,
	}

	return &p
}

func (p *parser) Parse() error {
	b := make([]byte, 1024*1024)
	bytesRead, err := p.f.Read(b)
	if err != nil {
		panic("Can't read")
	}

	log.Printf("LiveSplit parser read %d bytes", bytesRead)

	err = xml.Unmarshal(b[:bytesRead], &p.r)
	if err != nil {
		return errors.New(fmt.Sprintf("can't parse LiveSplit file: %s", err))
	}
	return nil
}

func (p *parser) Game() string {
	return p.r.Game
}

func (p *parser) Category() string {
	return p.r.Category
}

func (p *parser) Attempts() uint {
	return p.r.Attempts
}

func (p *parser) Segments() ([]run.Segment, error) {
	segments := make([]run.Segment, len(p.r.Segments.Segments))

	for i, s := range p.r.Segments.Segments {

		// The current segment's start time is equal to the previous segment's end time
		var startTime run.Duration
		if i == 0 {
			startTime = run.Duration{
				RealTime: time.Duration(0),
				GameTime: time.Duration(0),
			}
		} else {
			startTime = segments[i-1].EndTime
		}

		realEndTime, err := parseTime(
			s.SplitTimes.SplitTimes[0].RealTime,
		)
		if err != nil {
			return []run.Segment{}, fmt.Errorf("can't parse segment real time: %s", err)
		}
		gameEndTime, err := parseTime(
			s.SplitTimes.SplitTimes[0].GameTime,
		)
		if err != nil {
			return []run.Segment{}, fmt.Errorf("can't parse segment game time: %s", err)
		}

		segments[i] = run.Segment{
			Name:      s.Name,
			StartTime: startTime,
			EndTime: run.Duration{
				RealTime: realEndTime,
				GameTime: gameEndTime,
			},
		}
	}
	return segments, nil
}
<commit_msg>Include segment durations<commit_after>package livesplit

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/glacials/tugnut/run"
)

// parser implements parser.Parser
type parser struct {
	f io.Reader
	r RunTag
}

func NewParser(r io.Reader) *parser {
	p := parser{
		f: r,
	}

	return &p
}

func (p *parser) Parse() error {
	b := make([]byte, 1024*1024)
	bytesRead, err := p.f.Read(b)
	if err != nil {
		panic("Can't read")
	}

	log.Printf("LiveSplit parser read %d bytes", bytesRead)

	err = xml.Unmarshal(b[:bytesRead], &p.r)
	if err != nil {
		return errors.New(fmt.Sprintf("can't parse LiveSplit file: %s", err))
	}
	return nil
}

func (p *parser) Game() string {
	return p.r.Game
}

func (p *parser) Category() string {
	return p.r.Category
}

func (p *parser) Attempts() uint {
	return p.r.Attempts
}

func (p *parser) Segments() ([]run.Segment, error) {
	segments := make([]run.Segment, len(p.r.Segments.Segments))

	for i, s := range p.r.Segments.Segments {

		// The current segment's start time is equal to the previous segment's end time
		var startTime run.Duration
		if i == 0 {
			startTime = run.Duration{
				RealTime: time.Duration(0),
				GameTime: time.Duration(0),
			}
		} else {
			startTime = segments[i-1].EndTime
		}

		realEndTime, err := parseTime(
			s.SplitTimes.SplitTimes[0].RealTime,
		)
		if err != nil {
			return []run.Segment{}, fmt.Errorf("can't parse segment real time: %s", err)
		}
		gameEndTime, err := parseTime(
			s.SplitTimes.SplitTimes[0].GameTime,
		)
		if err != nil {
			return []run.Segment{}, fmt.Errorf("can't parse segment game time: %s", err)
		}

		endTime := run.Duration{
			RealTime: realEndTime,
			GameTime: gameEndTime,
		}

		segments[i] = run.Segment{
			Name:      s.Name,
			StartTime: startTime,
			EndTime:   endTime,
		}
		segments[i].Duration = run.Duration{
			RealTime: endTime.RealTime - startTime.RealTime,
			GameTime: endTime.GameTime - startTime.GameTime,
		}
	}
	return segments, nil
}
<|endoftext|>


<commit_before>package authenticator

import (
	"net/http"
	"testing"
)

func TestAlwaysAuthenticated(t *testing.T) {

	var request, _ = http.NewRequest("GET", "", nil)
	var sut = NewAlwaysAuthenticated()

	if sut.UserID(request) != "" {
		t.Fatalf("UserID is not '', but '%v'", sut.UserID(request))
	}
	if !sut.IsAuthenticated(request) {
		t.Fatalf("UserID '' not returned as authenticated")
	}

}

func TestNeverAuthenticated(t *testing.T) {

	var request, _ = http.NewRequest("GET", "", nil)
	var sut = NewNeverAuthenticated()

	if sut.UserID(request) != "" {
		t.Fatalf("UserID is not '', but '%v'", sut.UserID(request))
	}
	if sut.IsAuthenticated(request) {
		t.Fatalf("UserID '' returned as authenticated")
	}

}
<commit_msg>wip #21: improve tests<commit_after>package authenticator

import (
	"net/http"
	"testing"
)

func TestAlwaysAuthenticated(t *testing.T) {

	var request, _ = http.NewRequest("GET", "", nil)
	var sut = NewAlwaysAuthenticated()
	sut.SetUserID(nil, request, "x") // should be ignored

	if sut.UserID(request) != "" {
		t.Fatalf("UserID is not '', but '%v'", sut.UserID(request))
	}
	if !sut.IsAuthenticated(request) {
		t.Fatalf("UserID '' not returned as authenticated")
	}

}

func TestNeverAuthenticated(t *testing.T) {

	var request, _ = http.NewRequest("GET", "", nil)
	var sut = NewNeverAuthenticated()
	sut.SetUserID(nil, request, "x") // should be ignored

	if sut.UserID(request) != "" {
		t.Fatalf("UserID is not '', but '%v'", sut.UserID(request))
	}
	if sut.IsAuthenticated(request) {
		t.Fatalf("UserID '' returned as authenticated")
	}

}
<|endoftext|>


<commit_before>package siesta

import "time"

type RecordAccumulatorConfig struct {
	batchSize         int
	totalMemorySize   int
	compressionType   string
	linger            time.Duration
	retryBackoff      time.Duration
	blockOnBufferFull bool
	metrics           map[string]Metric
	time              time.Time
	metricTags        map[string]string
	networkClient     *NetworkClient
}

type RecordAccumulator struct {
	config        *RecordAccumulatorConfig
	networkClient *NetworkClient
	batchSize     int
	batches       map[string]map[int32][]*ProducerRecord

	addChan      chan *ProducerRecord
	flushed      map[string]map[int32]chan bool
	closing      chan bool
	closed       chan bool
	metadataChan chan *RecordMetadata
	records      map[string]map[int32]chan *ProducerRecord
}

func NewRecordAccumulator(config *RecordAccumulatorConfig, metadataChan chan *RecordMetadata) *RecordAccumulator {
	accumulator := &RecordAccumulator{}
	accumulator.config = config
	accumulator.batchSize = config.batchSize
	accumulator.addChan = make(chan *ProducerRecord, 100) //TODO config
	accumulator.batches = make(map[string]map[int32][]*ProducerRecord)
	accumulator.networkClient = config.networkClient
	accumulator.closing = make(chan bool)
	accumulator.closed = make(chan bool)
	accumulator.metadataChan = metadataChan
	accumulator.records = make(map[string]map[int32]chan *ProducerRecord)

	go accumulator.sender()

	return accumulator
}

func (ra *RecordAccumulator) sender() {
	for {
		select {
		case <-ra.closing:
			ra.cleanup()
			return
		default:
			{
				select {
				case <-ra.closing:
					ra.cleanup()
					return
				case record := <-ra.addChan:
					ra.addRecord(record)
				}
			}
		}
	}
}

func (ra *RecordAccumulator) cleanup() {
	ra.flushAll()
	close(ra.addChan)
	ra.networkClient.close()
	ra.closed <- true
}

func (ra *RecordAccumulator) addRecord(record *ProducerRecord) {
	if ra.batches[record.Topic] == nil {
		ra.batches[record.Topic] = make(map[int32][]*ProducerRecord)
	}
	if ra.batches[record.Topic][record.partition] == nil {
		ra.createBatch(record.Topic, record.partition)
	}
	ra.records[record.Topic][record.partition] <- record
}

func (ra *RecordAccumulator) createBatch(topic string, partition int32) {
	ra.batches[topic][partition] = make([]*ProducerRecord, 0, ra.batchSize)
	ra.records[topic] = make(map[int32]chan *ProducerRecord)
	ra.records[topic][partition] = make(chan *ProducerRecord, ra.batchSize)
	go ra.watcher(topic, partition)
}

func (ra *RecordAccumulator) watcher(topic string, partition int32) {
	timeout := time.After(ra.config.linger)
	for {
		if len(ra.batches[topic][partition]) >= ra.batchSize {
			ra.flush(topic, partition, ra.batches[topic][partition])
			go ra.watcher(topic, partition)
			return
		}
		select {
		case record := <-ra.records[topic][partition]:
			if len(ra.batches[record.Topic][record.partition]) == 0 {
				ra.batches[topic][partition] = make([]*ProducerRecord, 0, ra.batchSize)
			}
			ra.batches[record.Topic][record.partition] = append(ra.batches[record.Topic][record.partition], record)
		case <-timeout:
			ra.flush(topic, partition, ra.batches[topic][partition])
			go ra.watcher(topic, partition)
			return
		}
	}
}

func (ra *RecordAccumulator) flush(topic string, partition int32, batch []*ProducerRecord) {
	if len(batch) > 0 {
		ra.networkClient.send(topic, partition, batch)
		ra.batches[topic][partition] = make([]*ProducerRecord, 0, ra.batchSize)
	}
}

func (ra *RecordAccumulator) flushAll() {
	for topic, partitionBatches := range ra.batches {
		for partition, _ := range partitionBatches {
			ra.flush(topic, partition, ra.batches[topic][partition])
		}
	}
}

func (ra *RecordAccumulator) close() chan bool {
	ra.closing <- true
	return ra.closed
}
<commit_msg>Cleanup.<commit_after>package siesta

import "time"

type RecordAccumulatorConfig struct {
	batchSize         int
	totalMemorySize   int
	compressionType   string
	linger            time.Duration
	retryBackoff      time.Duration
	blockOnBufferFull bool
	metrics           map[string]Metric
	time              time.Time
	metricTags        map[string]string
	networkClient     *NetworkClient
}

type RecordAccumulator struct {
	config        *RecordAccumulatorConfig
	networkClient *NetworkClient
	batchSize     int
	batches       map[string]map[int32][]*ProducerRecord

	addChan      chan *ProducerRecord
	flushed      map[string]map[int32]chan bool
	closing      chan bool
	closed       chan bool
	metadataChan chan *RecordMetadata
	records      map[string]map[int32]chan *ProducerRecord
}

func NewRecordAccumulator(config *RecordAccumulatorConfig, metadataChan chan *RecordMetadata) *RecordAccumulator {
	accumulator := &RecordAccumulator{}
	accumulator.config = config
	accumulator.batchSize = config.batchSize
	accumulator.addChan = make(chan *ProducerRecord, 100) //TODO config
	accumulator.batches = make(map[string]map[int32][]*ProducerRecord)
	accumulator.networkClient = config.networkClient
	accumulator.closing = make(chan bool)
	accumulator.closed = make(chan bool)
	accumulator.metadataChan = metadataChan
	accumulator.records = make(map[string]map[int32]chan *ProducerRecord)

	go accumulator.sender()

	return accumulator
}

func (ra *RecordAccumulator) sender() {
	for {
		select {
		case <-ra.closing:
			ra.cleanup()
			return
		default:
			{
				select {
				case <-ra.closing:
					ra.cleanup()
					return
				case record := <-ra.addChan:
					ra.addRecord(record)
				}
			}
		}
	}
}

func (ra *RecordAccumulator) cleanup() {
	ra.flushAll()
	close(ra.addChan)
	ra.networkClient.close()
	ra.closed <- true
}

func (ra *RecordAccumulator) addRecord(record *ProducerRecord) {
	if ra.batches[record.Topic] == nil {
		ra.batches[record.Topic] = make(map[int32][]*ProducerRecord)
	}
	if ra.batches[record.Topic][record.partition] == nil {
		ra.createBatch(record.Topic, record.partition)
	}
	ra.records[record.Topic][record.partition] <- record
}

func (ra *RecordAccumulator) createBatch(topic string, partition int32) {
	ra.batches[topic][partition] = make([]*ProducerRecord, 0, ra.batchSize)
	ra.records[topic] = make(map[int32]chan *ProducerRecord)
	ra.records[topic][partition] = make(chan *ProducerRecord, ra.batchSize)
	go ra.watcher(topic, partition)
}

func (ra *RecordAccumulator) watcher(topic string, partition int32) {
	timeout := time.After(ra.config.linger)
	for {
		if len(ra.batches[topic][partition]) >= ra.batchSize {
			ra.flush(topic, partition, ra.batches[topic][partition])
			go ra.watcher(topic, partition)
			return
		}
		select {
		case record := <-ra.records[topic][partition]:
			ra.batches[record.Topic][record.partition] = append(ra.batches[record.Topic][record.partition], record)
		case <-timeout:
			ra.flush(topic, partition, ra.batches[topic][partition])
			go ra.watcher(topic, partition)
			return
		}
	}
}

func (ra *RecordAccumulator) flush(topic string, partition int32, batch []*ProducerRecord) {
	if len(batch) > 0 {
		ra.networkClient.send(topic, partition, batch)
		ra.batches[topic][partition] = make([]*ProducerRecord, 0, ra.batchSize)
	}
}

func (ra *RecordAccumulator) flushAll() {
	for topic, partitionBatches := range ra.batches {
		for partition, _ := range partitionBatches {
			ra.flush(topic, partition, ra.batches[topic][partition])
		}
	}
}

func (ra *RecordAccumulator) close() chan bool {
	ra.closing <- true
	return ra.closed
}
<|endoftext|>