<commit_before>package copystructure

import (
	"reflect"

	"github.com/mitchellh/reflectwalk"
)

// Copy returns a deep copy of v.
func Copy(v interface{}) (interface{}, error) {
	w := new(walker)
	err := reflectwalk.Walk(v, w)
	if err != nil {
		return nil, err
	}

	return w.Result, nil
}

// CopierFunc is a function that knows how to deep copy a specific type.
// Register these globally with the Copiers variable.
type CopierFunc func(interface{}) (interface{}, error)

// Copiers is a map of types that behave specially when they are copied.
// If a type is found in this map while deep copying, this function
// will be called to copy it instead of attempting to copy all fields.
//
// The key should be the type, obtained using: reflect.TypeOf(value with type).
//
// It is unsafe to write to this map after Copies have started. If you
// are writing to this map while also copying, wrap all modifications to
// this map as well as to Copy in a mutex.
var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc)

type walker struct {
	Result interface{}

	depth       int
	ignoreDepth int
	vals        []reflect.Value
	cs          []reflect.Value
	ps          []bool
}

func (w *walker) Enter(l reflectwalk.Location) error {
	w.depth++
	return nil
}

func (w *walker) Exit(l reflectwalk.Location) error {
	w.depth--
	if w.ignoreDepth > w.depth {
		w.ignoreDepth = 0
	}

	if w.ignoring() {
		return nil
	}

	switch l {
	case reflectwalk.Map:
		fallthrough
	case reflectwalk.Slice:
		// Pop map off our container
		w.cs = w.cs[:len(w.cs)-1]
	case reflectwalk.MapValue:
		// Pop off the key and value
		mv := w.valPop()
		mk := w.valPop()
		m := w.cs[len(w.cs)-1]
		m.SetMapIndex(mk, mv)
	case reflectwalk.SliceElem:
		// Pop off the value and the index and set it on the slice
		v := w.valPop()
		i := w.valPop().Interface().(int)
		s := w.cs[len(w.cs)-1]
		s.Index(i).Set(v)
	case reflectwalk.Struct:
		w.replacePointerMaybe()

		// Remove the struct from the container stack
		w.cs = w.cs[:len(w.cs)-1]
	case reflectwalk.StructField:
		// Pop off the value and the field
		v := w.valPop()
		f := w.valPop().Interface().(reflect.StructField)
		s := w.cs[len(w.cs)-1]
		sf := reflect.Indirect(s).FieldByName(f.Name)
		sf.Set(v)
	case reflectwalk.WalkLoc:
		// Clear out the slices for GC
		w.cs = nil
		w.vals = nil
	}

	return nil
}

func (w *walker) Map(m reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	t := m.Type()
	newMap := reflect.MakeMap(reflect.MapOf(t.Key(), t.Elem()))
	w.cs = append(w.cs, newMap)
	w.valPush(newMap)
	return nil
}

func (w *walker) MapElem(m, k, v reflect.Value) error {
	return nil
}

func (w *walker) PointerEnter(v bool) error {
	if w.ignoring() {
		return nil
	}

	w.ps = append(w.ps, v)
	return nil
}

func (w *walker) PointerExit(bool) error {
	if w.ignoring() {
		return nil
	}

	w.ps = w.ps[:len(w.ps)-1]
	return nil
}

func (w *walker) Primitive(v reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	newV := reflect.New(v.Type())
	reflect.Indirect(newV).Set(v)
	w.valPush(newV)
	w.replacePointerMaybe()
	return nil
}

func (w *walker) Slice(s reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	newS := reflect.MakeSlice(s.Type(), s.Len(), s.Cap())
	w.cs = append(w.cs, newS)
	w.valPush(newS)
	return nil
}

func (w *walker) SliceElem(i int, elem reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	// We don't write the slice here because elem might still be
	// arbitrarily complex. Just record the index and continue on.
	w.valPush(reflect.ValueOf(i))

	return nil
}

func (w *walker) Struct(s reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	var v reflect.Value
	if c, ok := Copiers[s.Type()]; ok {
		// We have a Copier for this struct, so we use that copier to
		// get the copy, and we ignore anything deeper than this.
		w.ignoreDepth = w.depth

		dup, err := c(s.Interface())
		if err != nil {
			return err
		}

		v = reflect.ValueOf(dup)
	} else {
		// No copier, we copy ourselves and allow reflectwalk to guide
		// us deeper into the structure for copying.
		v = reflect.New(s.Type())
	}

	// Push the value onto the value stack for setting the struct field,
	// and add the struct itself to the containers stack in case we walk
	// deeper so that its own fields can be modified.
	w.valPush(v)
	w.cs = append(w.cs, v)

	return nil
}

func (w *walker) StructField(f reflect.StructField, v reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	// Push the field onto the stack, we'll handle it when we exit
	// the struct field in Exit...
	w.valPush(reflect.ValueOf(f))
	return nil
}

func (w *walker) ignoring() bool {
	return w.ignoreDepth > 0 && w.depth >= w.ignoreDepth
}

func (w *walker) pointerPeek() bool {
	return w.ps[len(w.ps)-1]
}

func (w *walker) valPop() reflect.Value {
	result := w.vals[len(w.vals)-1]
	w.vals = w.vals[:len(w.vals)-1]

	// If we're out of values, that means we popped everything off. In
	// this case, we reset the result so the next pushed value becomes
	// the result.
	if len(w.vals) == 0 {
		w.Result = nil
	}

	return result
}

func (w *walker) valPush(v reflect.Value) {
	w.vals = append(w.vals, v)

	// If we haven't set the result yet, then this is the result since
	// it is the first (outermost) value we're seeing.
	if w.Result == nil {
		w.Result = v.Interface()
	}
}

func (w *walker) replacePointerMaybe() {
	// Determine the last pointer value. If it is NOT a pointer, then
	// we need to push that onto the stack.
	if !w.pointerPeek() {
		w.valPush(reflect.Indirect(w.valPop()))
	}
}
<commit_msg>don't make new slice/map if it is nil to begin with<commit_after>package copystructure

import (
	"reflect"

	"github.com/mitchellh/reflectwalk"
)

// Copy returns a deep copy of v.
func Copy(v interface{}) (interface{}, error) {
	w := new(walker)
	err := reflectwalk.Walk(v, w)
	if err != nil {
		return nil, err
	}

	return w.Result, nil
}

// CopierFunc is a function that knows how to deep copy a specific type.
// Register these globally with the Copiers variable.
type CopierFunc func(interface{}) (interface{}, error)

// Copiers is a map of types that behave specially when they are copied.
// If a type is found in this map while deep copying, this function
// will be called to copy it instead of attempting to copy all fields.
//
// The key should be the type, obtained using: reflect.TypeOf(value with type).
//
// It is unsafe to write to this map after Copies have started. If you
// are writing to this map while also copying, wrap all modifications to
// this map as well as to Copy in a mutex.
var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc)

type walker struct {
	Result interface{}

	depth       int
	ignoreDepth int
	vals        []reflect.Value
	cs          []reflect.Value
	ps          []bool
}

func (w *walker) Enter(l reflectwalk.Location) error {
	w.depth++
	return nil
}

func (w *walker) Exit(l reflectwalk.Location) error {
	w.depth--
	if w.ignoreDepth > w.depth {
		w.ignoreDepth = 0
	}

	if w.ignoring() {
		return nil
	}

	switch l {
	case reflectwalk.Map:
		fallthrough
	case reflectwalk.Slice:
		// Pop map off our container
		w.cs = w.cs[:len(w.cs)-1]
	case reflectwalk.MapValue:
		// Pop off the key and value
		mv := w.valPop()
		mk := w.valPop()
		m := w.cs[len(w.cs)-1]
		m.SetMapIndex(mk, mv)
	case reflectwalk.SliceElem:
		// Pop off the value and the index and set it on the slice
		v := w.valPop()
		i := w.valPop().Interface().(int)
		s := w.cs[len(w.cs)-1]
		s.Index(i).Set(v)
	case reflectwalk.Struct:
		w.replacePointerMaybe()

		// Remove the struct from the container stack
		w.cs = w.cs[:len(w.cs)-1]
	case reflectwalk.StructField:
		// Pop off the value and the field
		v := w.valPop()
		f := w.valPop().Interface().(reflect.StructField)
		s := w.cs[len(w.cs)-1]
		sf := reflect.Indirect(s).FieldByName(f.Name)
		sf.Set(v)
	case reflectwalk.WalkLoc:
		// Clear out the slices for GC
		w.cs = nil
		w.vals = nil
	}

	return nil
}

func (w *walker) Map(m reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	// Get the type for the map
	t := m.Type()
	mapType := reflect.MapOf(t.Key(), t.Elem())

	// Create the map. If the map itself is nil, then just make a nil map
	var newMap reflect.Value
	if m.IsNil() {
		newMap = reflect.Indirect(reflect.New(mapType))
	} else {
		newMap = reflect.MakeMap(reflect.MapOf(t.Key(), t.Elem()))
	}

	w.cs = append(w.cs, newMap)
	w.valPush(newMap)
	return nil
}

func (w *walker) MapElem(m, k, v reflect.Value) error {
	return nil
}

func (w *walker) PointerEnter(v bool) error {
	if w.ignoring() {
		return nil
	}

	w.ps = append(w.ps, v)
	return nil
}

func (w *walker) PointerExit(bool) error {
	if w.ignoring() {
		return nil
	}

	w.ps = w.ps[:len(w.ps)-1]
	return nil
}

func (w *walker) Primitive(v reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	newV := reflect.New(v.Type())
	reflect.Indirect(newV).Set(v)
	w.valPush(newV)
	w.replacePointerMaybe()
	return nil
}

func (w *walker) Slice(s reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	var newS reflect.Value
	if s.IsNil() {
		newS = reflect.Indirect(reflect.New(s.Type()))
	} else {
		newS = reflect.MakeSlice(s.Type(), s.Len(), s.Cap())
	}

	w.cs = append(w.cs, newS)
	w.valPush(newS)
	return nil
}

func (w *walker) SliceElem(i int, elem reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	// We don't write the slice here because elem might still be
	// arbitrarily complex. Just record the index and continue on.
	w.valPush(reflect.ValueOf(i))

	return nil
}

func (w *walker) Struct(s reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	var v reflect.Value
	if c, ok := Copiers[s.Type()]; ok {
		// We have a Copier for this struct, so we use that copier to
		// get the copy, and we ignore anything deeper than this.
		w.ignoreDepth = w.depth

		dup, err := c(s.Interface())
		if err != nil {
			return err
		}

		v = reflect.ValueOf(dup)
	} else {
		// No copier, we copy ourselves and allow reflectwalk to guide
		// us deeper into the structure for copying.
		v = reflect.New(s.Type())
	}

	// Push the value onto the value stack for setting the struct field,
	// and add the struct itself to the containers stack in case we walk
	// deeper so that its own fields can be modified.
	w.valPush(v)
	w.cs = append(w.cs, v)

	return nil
}

func (w *walker) StructField(f reflect.StructField, v reflect.Value) error {
	if w.ignoring() {
		return nil
	}

	// Push the field onto the stack, we'll handle it when we exit
	// the struct field in Exit...
	w.valPush(reflect.ValueOf(f))
	return nil
}

func (w *walker) ignoring() bool {
	return w.ignoreDepth > 0 && w.depth >= w.ignoreDepth
}

func (w *walker) pointerPeek() bool {
	return w.ps[len(w.ps)-1]
}

func (w *walker) valPop() reflect.Value {
	result := w.vals[len(w.vals)-1]
	w.vals = w.vals[:len(w.vals)-1]

	// If we're out of values, that means we popped everything off. In
	// this case, we reset the result so the next pushed value becomes
	// the result.
	if len(w.vals) == 0 {
		w.Result = nil
	}

	return result
}

func (w *walker) valPush(v reflect.Value) {
	w.vals = append(w.vals, v)

	// If we haven't set the result yet, then this is the result since
	// it is the first (outermost) value we're seeing.
	if w.Result == nil {
		w.Result = v.Interface()
	}
}

func (w *walker) replacePointerMaybe() {
	// Determine the last pointer value. If it is NOT a pointer, then
	// we need to push that onto the stack.
	if !w.pointerPeek() {
		w.valPush(reflect.Indirect(w.valPop()))
	}
}
<|endoftext|>


<commit_before>package compiler

type DefaultBase byte

func (d DefaultBase) Push(c *Compiler, name string) {
	switch d {
		case INT:
			c.Push(name)
		case LIST:
			c.PushList(name)
		case PIPE:
			c.PushPipe(name)
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Pull(c *Compiler, name string) {
	switch d {
		case INT:
			c.Pull(name)
		case LIST:
			c.PullList(name)
		case PIPE:
			c.PullPipe(name)
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Free(c *Compiler) {
	switch d {
		case INT:
			c.Free()
		case LIST:
			c.FreeList()
		case PIPE:
			c.FreePipe()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Drop(c *Compiler) {
	switch d {
		case INT:
			c.Drop()
		case LIST:
			c.DropList()
		case PIPE:
			c.DropPipe()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Attach(c *Compiler) {
	switch d {
		case INT:
			c.Set()
		case LIST:
			c.Int(0)
			c.HeapList()
			c.Set()
		case PIPE:
			c.Int(0)
			c.HeapPipe()
			c.Set()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Detach(c *Compiler) {
	switch d {
		case INT:
			c.Get()
		case LIST:
			c.Get()
			c.HeapList()
		case PIPE:
			c.Get()
			c.HeapPipe()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

const (
	NULL DefaultBase = iota
	INT
	LIST
	PIPE
)

type Data interface {
	Equals(Data) bool
	Name(Language) string
}

type Type struct {
	Data

	Name Translatable
	Base Base

	Immutable bool
	Fake bool
	Constant bool

	Cast func(c *Compiler, a Type, b Type) bool
	Shunt func(c *Compiler, symbol string, a Type, b Type) *Type

	Casts []func(c *Compiler, t Type) bool

	Shunts map[string]func(*Compiler, Type) Type

	Collect func(*Compiler)

	EmbeddedStatement func(*Compiler, Type)
}

func (t Type) String() string {
	if data := t.Data; data != nil && data.Name(0) != "" {
		return t.Name[0]+"."+data.Name(0)
	}
	return t.Name[0]
}

func (t Type) Equals(b Type) bool {
	if t.Name[English] == b.Name[English] {
		return true
	}
	return false
}

func (t Type) With(d Data) Type {
	t.Data = d
	return t
}

func (c *Compiler) GetType(name string) *Type {
	for i, t := range c.Types {
		if t.Name[c.Language] == name {
			return &c.Types[i]
		}
	}
	return nil
}

func (c *Compiler) Cast(a, b Type) bool {
	if a.Equals(b) {
		return true
	}

	if a.Cast != nil &&  a.Cast(c, a, b) {
		return true
	}

	for _, t := range a.Casts {
		if t(c, b) {
			return true
		}
	}
	c.RaiseError(Translatable{
		English: "Cannot cast "+a.String()+" to "+b.String(),
	})
	return false
}
<commit_msg>Better type equalty.<commit_after>package compiler

type DefaultBase byte

func (d DefaultBase) Push(c *Compiler, name string) {
	switch d {
		case INT:
			c.Push(name)
		case LIST:
			c.PushList(name)
		case PIPE:
			c.PushPipe(name)
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Pull(c *Compiler, name string) {
	switch d {
		case INT:
			c.Pull(name)
		case LIST:
			c.PullList(name)
		case PIPE:
			c.PullPipe(name)
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Free(c *Compiler) {
	switch d {
		case INT:
			c.Free()
		case LIST:
			c.FreeList()
		case PIPE:
			c.FreePipe()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Drop(c *Compiler) {
	switch d {
		case INT:
			c.Drop()
		case LIST:
			c.DropList()
		case PIPE:
			c.DropPipe()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Attach(c *Compiler) {
	switch d {
		case INT:
			c.Set()
		case LIST:
			c.Int(0)
			c.HeapList()
			c.Set()
		case PIPE:
			c.Int(0)
			c.HeapPipe()
			c.Set()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

func (d DefaultBase) Detach(c *Compiler) {
	switch d {
		case INT:
			c.Get()
		case LIST:
			c.Get()
			c.HeapList()
		case PIPE:
			c.Get()
			c.HeapPipe()
		case NULL:
		default:
			panic("Invalid default base!")
	}
}

const (
	NULL DefaultBase = iota
	INT
	LIST
	PIPE
)

type Data interface {
	Equals(Data) bool
	Name(Language) string
}

type Type struct {
	Data

	Name Translatable
	Base Base

	Immutable bool
	Fake bool
	Constant bool

	Cast func(c *Compiler, a Type, b Type) bool
	Shunt func(c *Compiler, symbol string, a Type, b Type) *Type

	Casts []func(c *Compiler, t Type) bool

	Shunts map[string]func(*Compiler, Type) Type

	Collect func(*Compiler)

	EmbeddedStatement func(*Compiler, Type)
}

func (t Type) String() string {
	if data := t.Data; data != nil && data.Name(0) != "" {
		return t.Name[0]+"."+data.Name(0)
	}
	return t.Name[0]
}

func (t Type) Equals(b Type) bool {
	if t.Name[English] == b.Name[English] {

		if t.Data != nil && b.Data != nil {
			if !t.Data.Equals(b.Data) {
				return false
			}
		}

		return true
	}
	return false
}

func (t Type) With(d Data) Type {
	t.Data = d
	return t
}

func (c *Compiler) GetType(name string) *Type {
	for i, t := range c.Types {
		if t.Name[c.Language] == name {
			return &c.Types[i]
		}
	}
	return nil
}

func (c *Compiler) Cast(a, b Type) bool {
	if a.Equals(b) {
		return true
	}

	if a.Cast != nil &&  a.Cast(c, a, b) {
		return true
	}

	for _, t := range a.Casts {
		if t(c, b) {
			return true
		}
	}
	c.RaiseError(Translatable{
		English: "Cannot cast "+a.String()+" to "+b.String(),
	})
	return false
}
<|endoftext|>


<commit_before>package joule

import (
	"errors"
	"testing"

	"gobot.io/x/gobot"
	"gobot.io/x/gobot/drivers/gpio"
	"gobot.io/x/gobot/drivers/i2c"
	"gobot.io/x/gobot/gobottest"
	"gobot.io/x/gobot/sysfs"
)

// make sure that this Adaptor fullfills all the required interfaces
var _ gobot.Adaptor = (*Adaptor)(nil)
var _ gpio.DigitalReader = (*Adaptor)(nil)
var _ gpio.DigitalWriter = (*Adaptor)(nil)
var _ gpio.PwmWriter = (*Adaptor)(nil)
var _ i2c.Connector = (*Adaptor)(nil)

func initTestAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
	a := NewAdaptor()
	fs := sysfs.NewMockFilesystem([]string{
		"/sys/class/pwm/pwmchip0/export",
		"/sys/class/pwm/pwmchip0/unexport",
		"/sys/class/pwm/pwmchip0/pwm0/duty_cycle",
		"/sys/class/pwm/pwmchip0/pwm0/period",
		"/sys/class/pwm/pwmchip0/pwm0/enable",
		"/sys/class/gpio/export",
		"/sys/class/gpio/unexport",
		"/sys/class/gpio/gpio13/value",
		"/sys/class/gpio/gpio13/direction",
		"/sys/class/gpio/gpio40/value",
		"/sys/class/gpio/gpio40/direction",
		"/sys/class/gpio/gpio446/value",
		"/sys/class/gpio/gpio446/direction",
		"/sys/class/gpio/gpio463/value",
		"/sys/class/gpio/gpio463/direction",
		"/sys/class/gpio/gpio421/value",
		"/sys/class/gpio/gpio421/direction",
		"/sys/class/gpio/gpio221/value",
		"/sys/class/gpio/gpio221/direction",
		"/sys/class/gpio/gpio243/value",
		"/sys/class/gpio/gpio243/direction",
		"/sys/class/gpio/gpio229/value",
		"/sys/class/gpio/gpio229/direction",
		"/sys/class/gpio/gpio253/value",
		"/sys/class/gpio/gpio253/direction",
		"/sys/class/gpio/gpio261/value",
		"/sys/class/gpio/gpio261/direction",
		"/sys/class/gpio/gpio214/value",
		"/sys/class/gpio/gpio214/direction",
		"/sys/class/gpio/gpio14/direction",
		"/sys/class/gpio/gpio14/value",
		"/sys/class/gpio/gpio165/direction",
		"/sys/class/gpio/gpio165/value",
		"/sys/class/gpio/gpio212/direction",
		"/sys/class/gpio/gpio212/value",
		"/sys/class/gpio/gpio213/direction",
		"/sys/class/gpio/gpio213/value",
		"/sys/class/gpio/gpio236/direction",
		"/sys/class/gpio/gpio236/value",
		"/sys/class/gpio/gpio237/direction",
		"/sys/class/gpio/gpio237/value",
		"/sys/class/gpio/gpio204/direction",
		"/sys/class/gpio/gpio204/value",
		"/sys/class/gpio/gpio205/direction",
		"/sys/class/gpio/gpio205/value",
		"/sys/class/gpio/gpio263/direction",
		"/sys/class/gpio/gpio263/value",
		"/sys/class/gpio/gpio262/direction",
		"/sys/class/gpio/gpio262/value",
		"/sys/class/gpio/gpio240/direction",
		"/sys/class/gpio/gpio240/value",
		"/sys/class/gpio/gpio241/direction",
		"/sys/class/gpio/gpio241/value",
		"/sys/class/gpio/gpio242/direction",
		"/sys/class/gpio/gpio242/value",
		"/sys/class/gpio/gpio218/direction",
		"/sys/class/gpio/gpio218/value",
		"/sys/class/gpio/gpio250/direction",
		"/sys/class/gpio/gpio250/value",
		"/dev/i2c-0",
	})
	sysfs.SetFilesystem(fs)
	fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "5000\n"
	a.Connect()
	return a, fs
}

func TestAdaptorConnect(t *testing.T) {
	a, _ := initTestAdaptor()
	gobottest.Assert(t, a.Connect(), nil)
}

func TestAdaptorFinalize(t *testing.T) {
	a, _ := initTestAdaptor()
	a.DigitalWrite("1", 1)
	a.PwmWrite("25", 100)

	sysfs.SetSyscall(&sysfs.MockSyscall{})
	a.GetConnection(0xff, 0)

	gobottest.Assert(t, a.Finalize(), nil)

	sysfs.SetFilesystem(sysfs.NewMockFilesystem([]string{}))
	gobottest.Refute(t, a.Finalize(), nil)
}

func TestAdaptorDigitalIO(t *testing.T) {
	a, fs := initTestAdaptor()

	a.DigitalWrite("1", 1)
	gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio446/value"].Contents, "1")

	a.DigitalWrite("2", 0)
	i, err := a.DigitalRead("2")
	gobottest.Assert(t, err, nil)
	gobottest.Assert(t, i, 0)
}

func TestAdaptorI2c(t *testing.T) {
	a, _ := initTestAdaptor()

	sysfs.SetSyscall(&sysfs.MockSyscall{})
	con, err := a.GetConnection(0xff, 0)
	gobottest.Assert(t, err, nil)

	con.Write([]byte{0x00, 0x01})
	data := []byte{42, 42}
	con.Read(data)
	gobottest.Assert(t, data, []byte{0x00, 0x01})
}

func TestAdaptorPwm(t *testing.T) {
	a, fs := initTestAdaptor()

	err := a.PwmWrite("25", 100)
	gobottest.Assert(t, err, nil)
	gobottest.Assert(t, fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents, "1960")

	err = a.PwmWrite("4", 100)
	gobottest.Assert(t, err, errors.New("Not a PWM pin"))
}
<commit_msg>joule: increase test coverage<commit_after>package joule

import (
	"errors"
	"strings"
	"testing"

	"gobot.io/x/gobot"
	"gobot.io/x/gobot/drivers/gpio"
	"gobot.io/x/gobot/drivers/i2c"
	"gobot.io/x/gobot/gobottest"
	"gobot.io/x/gobot/sysfs"
)

// make sure that this Adaptor fullfills all the required interfaces
var _ gobot.Adaptor = (*Adaptor)(nil)
var _ gpio.DigitalReader = (*Adaptor)(nil)
var _ gpio.DigitalWriter = (*Adaptor)(nil)
var _ gpio.PwmWriter = (*Adaptor)(nil)
var _ i2c.Connector = (*Adaptor)(nil)

func initTestAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
	a := NewAdaptor()
	fs := sysfs.NewMockFilesystem([]string{
		"/sys/class/pwm/pwmchip0/export",
		"/sys/class/pwm/pwmchip0/unexport",
		"/sys/class/pwm/pwmchip0/pwm0/duty_cycle",
		"/sys/class/pwm/pwmchip0/pwm0/period",
		"/sys/class/pwm/pwmchip0/pwm0/enable",
		"/sys/class/gpio/export",
		"/sys/class/gpio/unexport",
		"/sys/class/gpio/gpio13/value",
		"/sys/class/gpio/gpio13/direction",
		"/sys/class/gpio/gpio40/value",
		"/sys/class/gpio/gpio40/direction",
		"/sys/class/gpio/gpio446/value",
		"/sys/class/gpio/gpio446/direction",
		"/sys/class/gpio/gpio463/value",
		"/sys/class/gpio/gpio463/direction",
		"/sys/class/gpio/gpio421/value",
		"/sys/class/gpio/gpio421/direction",
		"/sys/class/gpio/gpio221/value",
		"/sys/class/gpio/gpio221/direction",
		"/sys/class/gpio/gpio243/value",
		"/sys/class/gpio/gpio243/direction",
		"/sys/class/gpio/gpio229/value",
		"/sys/class/gpio/gpio229/direction",
		"/sys/class/gpio/gpio253/value",
		"/sys/class/gpio/gpio253/direction",
		"/sys/class/gpio/gpio261/value",
		"/sys/class/gpio/gpio261/direction",
		"/sys/class/gpio/gpio214/value",
		"/sys/class/gpio/gpio214/direction",
		"/sys/class/gpio/gpio14/direction",
		"/sys/class/gpio/gpio14/value",
		"/sys/class/gpio/gpio165/direction",
		"/sys/class/gpio/gpio165/value",
		"/sys/class/gpio/gpio212/direction",
		"/sys/class/gpio/gpio212/value",
		"/sys/class/gpio/gpio213/direction",
		"/sys/class/gpio/gpio213/value",
		"/sys/class/gpio/gpio236/direction",
		"/sys/class/gpio/gpio236/value",
		"/sys/class/gpio/gpio237/direction",
		"/sys/class/gpio/gpio237/value",
		"/sys/class/gpio/gpio204/direction",
		"/sys/class/gpio/gpio204/value",
		"/sys/class/gpio/gpio205/direction",
		"/sys/class/gpio/gpio205/value",
		"/sys/class/gpio/gpio263/direction",
		"/sys/class/gpio/gpio263/value",
		"/sys/class/gpio/gpio262/direction",
		"/sys/class/gpio/gpio262/value",
		"/sys/class/gpio/gpio240/direction",
		"/sys/class/gpio/gpio240/value",
		"/sys/class/gpio/gpio241/direction",
		"/sys/class/gpio/gpio241/value",
		"/sys/class/gpio/gpio242/direction",
		"/sys/class/gpio/gpio242/value",
		"/sys/class/gpio/gpio218/direction",
		"/sys/class/gpio/gpio218/value",
		"/sys/class/gpio/gpio250/direction",
		"/sys/class/gpio/gpio250/value",
		"/dev/i2c-0",
	})
	sysfs.SetFilesystem(fs)
	fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "5000\n"
	a.Connect()
	return a, fs
}

func TestJouleAdaptorName(t *testing.T) {
	a, _ := initTestAdaptor()
	gobottest.Assert(t, strings.HasPrefix(a.Name(), "Joule"), true)
	a.SetName("NewName")
	gobottest.Assert(t, a.Name(), "NewName")
}

func TestAdaptorConnect(t *testing.T) {
	a, _ := initTestAdaptor()
	gobottest.Assert(t, a.Connect(), nil)
}

func TestAdaptorFinalize(t *testing.T) {
	a, _ := initTestAdaptor()
	a.DigitalWrite("1", 1)
	a.PwmWrite("25", 100)

	sysfs.SetSyscall(&sysfs.MockSyscall{})
	a.GetConnection(0xff, 0)

	gobottest.Assert(t, a.Finalize(), nil)

	sysfs.SetFilesystem(sysfs.NewMockFilesystem([]string{}))
	gobottest.Refute(t, a.Finalize(), nil)
}

func TestAdaptorDigitalIO(t *testing.T) {
	a, fs := initTestAdaptor()

	a.DigitalWrite("1", 1)
	gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio446/value"].Contents, "1")

	a.DigitalWrite("2", 0)
	i, err := a.DigitalRead("2")
	gobottest.Assert(t, err, nil)
	gobottest.Assert(t, i, 0)
}

func TestAdaptorI2c(t *testing.T) {
	a, _ := initTestAdaptor()

	sysfs.SetSyscall(&sysfs.MockSyscall{})
	con, err := a.GetConnection(0xff, 0)
	gobottest.Assert(t, err, nil)

	con.Write([]byte{0x00, 0x01})
	data := []byte{42, 42}
	con.Read(data)
	gobottest.Assert(t, data, []byte{0x00, 0x01})
}

func TestAdaptorPwm(t *testing.T) {
	a, fs := initTestAdaptor()

	err := a.PwmWrite("25", 100)
	gobottest.Assert(t, err, nil)
	gobottest.Assert(t, fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents, "1960")

	err = a.PwmWrite("4", 100)
	gobottest.Assert(t, err, errors.New("Not a PWM pin"))
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package invite provides the JSON handlers to send invitations to gonawin app.
package invite

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"appengine"
	"appengine/taskqueue"

	"github.com/taironas/gonawin/helpers"
	"github.com/taironas/gonawin/helpers/log"
	templateshlp "github.com/taironas/gonawin/helpers/templates"

	mdl "github.com/taironas/gonawin/models"
)

// Invite handler, use it to invite users to use gonawin.
// It expects a list of emails using the url param 'emails'
//
func Invite(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	desc := "invite handler:"
	c := appengine.NewContext(r)

	var emailsList string
	if emailsList = r.FormValue("emails"); len(emailsList) <= 0 {
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInviteNoEmailAddr)}
	}

	emails := parseEmails(emailsList)

	if !helpers.AreEmailsValid(emails) {
		log.Errorf(c, "%s emails are not valid", desc, emails)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInviteEmailsInvalid)}
	}

	body := buildEmailBody(r)

	// send tasks to send emails
	processEmails(c, desc, emails, body, u)

	vm := buildInviteViewModel()

	return templateshlp.RenderJson(w, c, vm)
}

func processEmails(c appengine.Context, desc string, emails []string, body string, u *mdl.User) error {

	bname := encode(c, desc, u.Name)
	bbody := encode(c, desc, body)

	for _, email := range emails {
		bemail := encode(c, desc, email)

		task := taskqueue.NewPOSTTask("/a/invite/", url.Values{
			"email": []string{string(bemail)},
			"name":  []string{string(bname)},
			"body":  []string{string(bbody)},
		})
		if _, err := taskqueue.Add(c, task, ""); err != nil {
			log.Errorf(c, "%s unable to add task to taskqueue %v", desc, err)
			return err
		}
	}
	return nil
}

type inviteViewModel struct {
	MessageInfo string `json:",omitempty"`
}

func buildInviteViewModel() inviteViewModel {
	msg := fmt.Sprintf("Email invitations have been successfully sent.")
	return inviteViewModel{msg}
}

// parseEmails split string by ',' and
// removes the leading and trailing spaces from each email.
//
func parseEmails(emailsList string) []string {
	rawEmails := strings.Split(emailsList, ",")
	emails := make([]string, 0)
	for _, e := range rawEmails {
		emails = append(emails, strings.Trim(e, " "))
	}
	return emails
}

func encode(c appengine.Context, desc, s string) []byte {
	var b []byte
	var err error
	if b, err = json.Marshal(s); err != nil {
		log.Errorf(c, "%s Error marshaling %v", desc, err)
	}
	return b
}

const inviteMessage = `
Hi there,
Join us at gonawin.

You will be able to join your friends and compete with them by predicting the results of your favorite sports events!

Sign in here: %s

Have fun,
Your friends @ Gonawin

`

func buildEmailBody(r *http.Request) string {
	currenturl := fmt.Sprintf("http://%s/#", r.Host)
	return fmt.Sprintf(inviteMessage, currenturl)
}
<commit_msg>go lint controllers/invite/invite.go<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package invite provides the JSON handlers to send invitations to gonawin app.
package invite

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"appengine"
	"appengine/taskqueue"

	"github.com/taironas/gonawin/helpers"
	"github.com/taironas/gonawin/helpers/log"
	templateshlp "github.com/taironas/gonawin/helpers/templates"

	mdl "github.com/taironas/gonawin/models"
)

// Invite handler, use it to invite users to use gonawin.
// It expects a list of emails using the url param 'emails'
//
func Invite(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	desc := "invite handler:"
	c := appengine.NewContext(r)

	var emailsList string
	if emailsList = r.FormValue("emails"); len(emailsList) <= 0 {
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInviteNoEmailAddr)}
	}

	emails := parseEmails(emailsList)

	if !helpers.AreEmailsValid(emails) {
		log.Errorf(c, "%s emails are not valid", desc, emails)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInviteEmailsInvalid)}
	}

	body := buildEmailBody(r)

	// send tasks to send emails
	processEmails(c, desc, emails, body, u)

	vm := buildInviteViewModel()

	return templateshlp.RenderJson(w, c, vm)
}

func processEmails(c appengine.Context, desc string, emails []string, body string, u *mdl.User) error {

	bname := encode(c, desc, u.Name)
	bbody := encode(c, desc, body)

	for _, email := range emails {
		bemail := encode(c, desc, email)

		task := taskqueue.NewPOSTTask("/a/invite/", url.Values{
			"email": []string{string(bemail)},
			"name":  []string{string(bname)},
			"body":  []string{string(bbody)},
		})
		if _, err := taskqueue.Add(c, task, ""); err != nil {
			log.Errorf(c, "%s unable to add task to taskqueue %v", desc, err)
			return err
		}
	}
	return nil
}

type inviteViewModel struct {
	MessageInfo string `json:",omitempty"`
}

func buildInviteViewModel() inviteViewModel {
	msg := fmt.Sprintf("Email invitations have been successfully sent.")
	return inviteViewModel{msg}
}

// parseEmails split string by ',' and
// removes the leading and trailing spaces from each email.
//
func parseEmails(emailsList string) []string {
	rawEmails := strings.Split(emailsList, ",")
	var emails []string
	for _, e := range rawEmails {
		emails = append(emails, strings.Trim(e, " "))
	}
	return emails
}

func encode(c appengine.Context, desc, s string) []byte {
	var b []byte
	var err error
	if b, err = json.Marshal(s); err != nil {
		log.Errorf(c, "%s Error marshaling %v", desc, err)
	}
	return b
}

const inviteMessage = `
Hi there,
Join us at gonawin.

You will be able to join your friends and compete with them by predicting the results of your favorite sports events!

Sign in here: %s

Have fun,
Your friends @ Gonawin

`

func buildEmailBody(r *http.Request) string {
	currenturl := fmt.Sprintf("http://%s/#", r.Host)
	return fmt.Sprintf(inviteMessage, currenturl)
}
<|endoftext|>


<commit_before>package convey_test

import (
	"errors"
	"math"
	"reflect"
	"testing"

	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/arbitrary"
	. "github.com/leanovate/gopter/convey"
	"github.com/leanovate/gopter/gen"
	. "github.com/smartystreets/goconvey/convey"
)

type QudraticEquation struct {
	A, B, C float64
}

func (q *QudraticEquation) Eval(x float64) float64 {
	return q.A*x*x + q.B*x + q.C
}

func (q *QudraticEquation) Solve() (float64, float64, error) {
	if q.A == 0 {
		return 0, 0, errors.New("No solution")
	}
	v := q.B*q.B - 4*q.A*q.C
	if v < 0 {
		return 0, 0, errors.New("No solution")
	}
	v = math.Sqrt(v)
	return (-q.B + v) / 2 / q.A, (-q.B - v) / 2 / q.A, nil
}

func TestShouldSucceedForAll(t *testing.T) {
	Convey("Given a check for quadratic equations", t, func() {
		checkSolve := func(quadratic *QudraticEquation) bool {
			x1, x2, err := quadratic.Solve()
			if err != nil {
				return true
			}

			return math.Abs(quadratic.Eval(x1)) < 1e-5 && math.Abs(quadratic.Eval(x2)) < 1e-5
		}

		Convey("Then check with arbitraries succeeds", func() {
			arbitraries := arbitrary.DefaultArbitraries()
			arbitraries.RegisterGen(gen.Float64Range(-1e7, 1e7))

			So(checkSolve, ShouldSucceedForAll, arbitraries)

			Convey("And test parameters may be modified", func() {
				parameters := gopter.DefaultTestParameters()
				parameters.MinSuccessfulTests = 200

				So(checkSolve, ShouldSucceedForAll, arbitraries, parameters)
			})
		})

		Convey("Then check with explicit generator succeeds", func() {
			anyQudraticEquation := gen.StructPtr(reflect.TypeOf(QudraticEquation{}), map[string]gopter.Gen{
				"A": gen.Float64Range(-1e7, 1e7),
				"B": gen.Float64Range(-1e7, 1e7),
				"C": gen.Float64Range(-1e7, 1e7),
			})

			So(checkSolve, ShouldSucceedForAll, anyQudraticEquation)
		})
	})
}
<commit_msg>Lower bounds even further<commit_after>package convey_test

import (
	"errors"
	"math"
	"reflect"
	"testing"

	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/arbitrary"
	. "github.com/leanovate/gopter/convey"
	"github.com/leanovate/gopter/gen"
	. "github.com/smartystreets/goconvey/convey"
)

type QudraticEquation struct {
	A, B, C float64
}

func (q *QudraticEquation) Eval(x float64) float64 {
	return q.A*x*x + q.B*x + q.C
}

func (q *QudraticEquation) Solve() (float64, float64, error) {
	if q.A == 0 {
		return 0, 0, errors.New("No solution")
	}
	v := q.B*q.B - 4*q.A*q.C
	if v < 0 {
		return 0, 0, errors.New("No solution")
	}
	v = math.Sqrt(v)
	return (-q.B + v) / 2 / q.A, (-q.B - v) / 2 / q.A, nil
}

func TestShouldSucceedForAll(t *testing.T) {
	Convey("Given a check for quadratic equations", t, func() {
		checkSolve := func(quadratic *QudraticEquation) bool {
			x1, x2, err := quadratic.Solve()
			if err != nil {
				return true
			}

			return math.Abs(quadratic.Eval(x1)) < 1e-5 && math.Abs(quadratic.Eval(x2)) < 1e-5
		}

		Convey("Then check with arbitraries succeeds", func() {
			arbitraries := arbitrary.DefaultArbitraries()
			arbitraries.RegisterGen(gen.Float64Range(-1e5, 1e5))

			So(checkSolve, ShouldSucceedForAll, arbitraries)

			Convey("And test parameters may be modified", func() {
				parameters := gopter.DefaultTestParameters()
				parameters.MinSuccessfulTests = 200

				So(checkSolve, ShouldSucceedForAll, arbitraries, parameters)
			})
		})

		Convey("Then check with explicit generator succeeds", func() {
			anyQudraticEquation := gen.StructPtr(reflect.TypeOf(QudraticEquation{}), map[string]gopter.Gen{
				"A": gen.Float64Range(-1e5, 1e5),
				"B": gen.Float64Range(-1e5, 1e5),
				"C": gen.Float64Range(-1e5, 1e5),
			})

			So(checkSolve, ShouldSucceedForAll, anyQudraticEquation)
		})
	})
}
<|endoftext|>


<commit_before>package main_test

import (
	"reflect"
	"testing"

	. "github.com/maxcnunes/waitforit"
)

func TestBuildConn(t *testing.T) {
	type input struct {
		host     string
		port     int
		fullConn string
	}

	testCases := []struct {
		title    string
		data     input
		expected *Connection
	}{
		{
			"Should create a default connection when only host and port are given",
			input{host: "localhost", port: 80},
			&Connection{Type: "tcp", Scheme: "", Port: 80, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a connection with different host",
			input{host: "localhost", port: 80},
			&Connection{Type: "tcp", Scheme: "", Port: 80, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a connection with different port",
			input{host: "localhost", port: 90},
			&Connection{Type: "tcp", Scheme: "", Port: 90, Host: "localhost", Path: ""},
		},
		{
			"Should ignore the fullConn when the host is given",
			input{host: "localhost", port: 90, fullConn: "tcp://remotehost:10"},
			&Connection{Type: "tcp", Scheme: "", Port: 90, Host: "localhost", Path: ""},
		},
		{
			"Should be able to craete a connection given a fullConn",
			input{fullConn: "tcp://remotehost:10"},
			&Connection{Type: "tcp", Scheme: "", Port: 10, Host: "remotehost", Path: ""},
		},
		{
			"Should be able to create a http connection through the fullConn",
			input{fullConn: "http://localhost"},
			&Connection{Type: "tcp", Scheme: "http", Port: 80, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a https connection through the fullConn",
			input{fullConn: "https://localhost"},
			&Connection{Type: "tcp", Scheme: "https", Port: 443, Host: "localhost", Path: ""},
		},
		{
			"Should support fullConn to https with custom port",
			input{fullConn: "https://localhost:444"},
			&Connection{Type: "tcp", Scheme: "https", Port: 444, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a http connection with a path through the fullConn",
			input{fullConn: "https://localhost/cars"},
			&Connection{Type: "tcp", Scheme: "https", Port: 443, Host: "localhost", Path: "/cars"},
		},
		{
			"Should fail when host and full connection are not provided",
			input{},
			nil,
		},
		{
			"Should fail when full connection is not a valid address format",
			input{fullConn: ":/localhost;80"},
			nil,
		},
	}

	for _, v := range testCases {
		cfg := &Config{
			Host:    v.data.host,
			Port:    v.data.port,
			Address: v.data.fullConn,
		}
		conn := BuildConn(cfg)
		t.Run(v.title, func(t *testing.T) {
			if !reflect.DeepEqual(conn, v.expected) {
				t.Errorf("Expected to %#v to be deep equal %#v", conn, v.expected)
			}
		})
	}
}
<commit_msg>Add test inner paths<commit_after>package main_test

import (
	"reflect"
	"testing"

	. "github.com/maxcnunes/waitforit"
)

func TestBuildConn(t *testing.T) {
	type input struct {
		host     string
		port     int
		fullConn string
	}

	testCases := []struct {
		title    string
		data     input
		expected *Connection
	}{
		{
			"Should create a default connection when only host and port are given",
			input{host: "localhost", port: 80},
			&Connection{Type: "tcp", Scheme: "", Port: 80, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a connection with different host",
			input{host: "localhost", port: 80},
			&Connection{Type: "tcp", Scheme: "", Port: 80, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a connection with different port",
			input{host: "localhost", port: 90},
			&Connection{Type: "tcp", Scheme: "", Port: 90, Host: "localhost", Path: ""},
		},
		{
			"Should ignore the fullConn when the host is given",
			input{host: "localhost", port: 90, fullConn: "tcp://remotehost:10"},
			&Connection{Type: "tcp", Scheme: "", Port: 90, Host: "localhost", Path: ""},
		},
		{
			"Should be able to craete a connection given a fullConn",
			input{fullConn: "tcp://remotehost:10"},
			&Connection{Type: "tcp", Scheme: "", Port: 10, Host: "remotehost", Path: ""},
		},
		{
			"Should be able to create a http connection through the fullConn",
			input{fullConn: "http://localhost"},
			&Connection{Type: "tcp", Scheme: "http", Port: 80, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a https connection through the fullConn",
			input{fullConn: "https://localhost"},
			&Connection{Type: "tcp", Scheme: "https", Port: 443, Host: "localhost", Path: ""},
		},
		{
			"Should support fullConn to https with custom port",
			input{fullConn: "https://localhost:444"},
			&Connection{Type: "tcp", Scheme: "https", Port: 444, Host: "localhost", Path: ""},
		},
		{
			"Should be able to create a http connection with a path through the fullConn",
			input{fullConn: "https://localhost/cars"},
			&Connection{Type: "tcp", Scheme: "https", Port: 443, Host: "localhost", Path: "/cars"},
		},
		{
			"Should be able to create a http connection with a path with inner paths",
			input{fullConn: "http://backend:8182/backend/tunnel/tunnel.nocache.js"},
			&Connection{
				Type: "tcp", Scheme: "http", Port: 8182, Host: "backend",
				Path: "/backend/tunnel/tunnel.nocache.js",
			},
		},
		{
			"Should fail when host and full connection are not provided",
			input{},
			nil,
		},
		{
			"Should fail when full connection is not a valid address format",
			input{fullConn: ":/localhost;80"},
			nil,
		},
	}

	for _, v := range testCases {
		cfg := &Config{
			Host:    v.data.host,
			Port:    v.data.port,
			Address: v.data.fullConn,
		}
		conn := BuildConn(cfg)
		t.Run(v.title, func(t *testing.T) {
			if !reflect.DeepEqual(conn, v.expected) {
				t.Errorf("Expected to %#v to be deep equal %#v", conn, v.expected)
			}
		})
	}
}
<|endoftext|>


<commit_before>package fakku

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"
	"time"
)

const (
	ErrorContentDoesntExist = "Content doesn't exist"
	ErrorUnknownJsonData    = "Got unknown json data back from content request. API Change?"
	ErrorUnknownJsonLayout  = "Got an unknown layout back from content request. API Change?"
)

type Content struct {
	Name         string
	Url          string
	Description  string
	Language     string
	Category     string
	Date         float64
	FileSize     float64
	Favorites    float64
	CommentCount float64
	Pages        float64
	Poster       string
	PosterUrl    string
	Tags         []*Attribute `json:"content_tags"`
	Translators  []*Attribute `json:"content_translators"`
	Series       []*Attribute `json:"content_series"`
	Artists      []*Attribute `json:"content_artists"`
	Images       struct {
		Cover  string
		Sample string
	}
}
type ContentList []Content

func (c *Content) UnmarshalJSON(b []byte) error {
	var f interface{}
	json.Unmarshal(b, &f)
	switch f.(type) {
	case map[string]interface{}:
		m := f.(map[string]interface{})
		contents := m["content"]
		switch contents.(type) {
		case map[string]interface{}:
			v := contents.(map[string]interface{})
			c.populateContent(v)
			return nil
		case []interface{}:
			q := contents.([]interface{})
			if len(q) == 0 {
				// doesn't exist
				return fmt.Errorf(ErrorContentDoesntExist)
			} else {
				return fmt.Errorf(ErrorUnknownJsonData)
			}
		default:
			return fmt.Errorf(ErrorUnknownJsonLayout)
		}
	case []interface{}:
		q := f.([]interface{})
		if len(q) == 0 {
			// doesn't exist
			return fmt.Errorf(ErrorContentDoesntExist)
		} else {
			return fmt.Errorf(ErrorUnknownJsonData)
		}
	default:
		return fmt.Errorf(ErrorUnknownJsonLayout)
	}
}

func (c *Content) populateContent(v map[string]interface{}) {
	c.Name = v["content_name"].(string)
	c.Url = v["content_url"].(string)
	c.Description = v["content_description"].(string)
	c.Language = v["content_language"].(string)
	c.Category = v["content_category"].(string)
	c.Date = v["content_date"].(float64)
	c.FileSize = v["content_filesize"].(float64)
	c.Favorites = v["content_favorites"].(float64)
	c.CommentCount = v["content_comments"].(float64)
	c.Pages = v["content_pages"].(float64)
	c.Poster = v["content_poster"].(string)
	c.PosterUrl = v["content_poster_url"].(string)
	c.Tags = constructAttributeFields(v, "content_tags")
	c.Translators = constructAttributeFields(v, "content_translators")
	c.Series = constructAttributeFields(v, "content_series")
	c.Artists = constructAttributeFields(v, "content_artists")

	tmp := v["content_images"]
	z := tmp.(map[string]interface{})
	c.Images.Cover = z["cover"].(string)
	c.Images.Sample = z["sample"].(string)
}

func GetContent(category, name string) (*Content, error) {
	var c Content
	url := contentApiFunction{Category: category, Name: name}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

type contentApiFunction struct {
	Category string
	Name     string
}

func (a contentApiFunction) Construct() string {
	return fmt.Sprintf("%s/%s/%s", ApiHeader, a.Category, a.Name)
}

type contentCommentApiFunction struct {
	contentApiFunction
	TopComments bool
	SupportsPagination
}

func (a contentCommentApiFunction) Construct() string {
	base := fmt.Sprintf("%s/comments", a.contentApiFunction.Construct())
	if a.TopComments {
		return fmt.Sprintf("%s/top", base)
	} else {
		return PaginateString(base, a.Page)
	}
}

func getContentCommentsGeneric(url ApiFunction) (*Comments, error) {
	var c Comments
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func ContentComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	return getContentCommentsGeneric(url)
}

func ContentCommentsPage(category, name string, page uint) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		SupportsPagination: SupportsPagination{Page: page},
	}
	return getContentCommentsGeneric(url)
}

func ContentTopComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		TopComments: true,
	}
	return getContentCommentsGeneric(url)
}

func (this *Content) TopComments() (*Comments, error) {
	return ContentTopComments(this.Category, this.Name)
}
func (this *Content) CommentsPage(page uint) (*Comments, error) {
	return ContentCommentsPage(this.Category, this.Name, page)
}
func (this *Content) Comments() (*Comments, error) {
	return ContentComments(this.Category, this.Name)
}

type Attribute struct {
	Attribute     string `json:"attribute"`
	AttributeLink string `json:"attribute_link"`
}

func NewAttribute(c map[string]interface{}) *Attribute {
	return &Attribute{
		Attribute:     c["attribute"].(string),
		AttributeLink: c["attribute_link"].(string),
	}
}

func (a *Attribute) String() string {
	return a.Attribute
}

func constructAttributeFields(c map[string]interface{}, field string) []*Attribute {
	try, ok := c[field]
	if !ok {
		return nil
	}
	tmp := try.([]interface{})
	size := len(tmp)
	attrs := make([]*Attribute, size)
	for i := 0; i < size; i++ {
		attrs[i] = NewAttribute(tmp[i].(map[string]interface{}))
	}
	return attrs
}

type Comment struct {
	Id         float64 `json:"comment_id"`
	AttachedId string  `json:"comment_attached_id"`
	Poster     string  `json:"comment_poster"`
	PosterUrl  string  `json:"comment_poster_url"`
	Reputation float64 `json:"comment_reputation"`
	Text       string  `json:"comment_text"`
	Date       float64 `json:"comment_date"`
}

type Comments struct {
	Comments   []*Comment `json:"comments"`
	PageNumber float64    `json:"page"`
	Total      float64    `json:"total"`
	Pages      float64    `json:"pages"`
}

type ReadOnlineContent struct {
	Content *Content `json:"content"`
	Pages   []*Page  `json:"pages"`
}

func (r *ReadOnlineContent) UnmarshalJSON(b []byte) error {
	var f interface{}
	if err := json.Unmarshal(b, &r.Content); err != nil {
		return err
	}
	json.Unmarshal(b, &f)
	// need to check and make sure that the content exists
	switch f.(type) {
	case map[string]interface{}:
		m := f.(map[string]interface{})
		pages := m["pages"]
		v := pages.(map[string]interface{})
		r.Pages = make([]*Page, len(v))
		for i := 0; i < len(v); i++ {
			ind := strconv.Itoa(i + 1)
			r.Pages[i] = NewPage(ind, v[ind].(map[string]interface{}))
		}
		return nil
	case []interface{}:
		q := f.([]interface{})
		if len(q) == 0 {
			// doesn't exist
			return fmt.Errorf("Content doesn't exist")
		} else {
			return fmt.Errorf("Got unknown json data back from content request. API Change?")
		}
	default:
		return fmt.Errorf("Got an unknown layout back from content request. API Change?")
	}
}

type Page struct {
	Id    string
	Thumb string
	Image string
}

func NewPage(id string, c map[string]interface{}) *Page {
	return &Page{
		Id:    id,
		Thumb: c["thumb"].(string),
		Image: c["image"].(string),
	}
}

type ContentReadOnlineApiFunction struct {
	contentApiFunction
}

func (a ContentReadOnlineApiFunction) Construct() string {
	return fmt.Sprintf("%s/read", a.contentApiFunction.Construct())
}

func GetContentReadOnline(category, name string) (*ReadOnlineContent, error) {
	var c ReadOnlineContent
	url := ContentReadOnlineApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

func GetContentDownloads(category, name string) (*DownloadContent, error) {
	var c DownloadContent
	url := ContentDownloadsApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

type ContentDownloadsApiFunction struct {
	contentApiFunction
}

func (a ContentDownloadsApiFunction) Construct() string {
	return fmt.Sprintf("%s/download", a.contentApiFunction.Construct())
}

type DownloadContent struct {
	Downloads []*Download `json:"downloads"`
	Total     uint        `json:"total"`
}

func (this *DownloadContent) HasDownloads() bool {
	return this.Total > 0
}

type Download struct {
	Type          string  `json:"download_type"`
	RawUrl        string  `json:"download_url"`
	Info          string  `json:"download_info"`
	DownloadCount float64 `json:"download_count"`
	RawTime       float64 `json:"download_time"`
	Poster        string  `json:"download_poster"`
	RawPosterUrl  string  `json:"download_poster_url"`
}

func (this *Download) Url() (*url.URL, error) {
	return url.Parse(this.RawUrl)
}
func (this *Download) PosterUrl() (*url.URL, error) {
	return url.Parse(this.RawPosterUrl)
}
func (this *Download) Time() time.Time {
	return time.Unix(int64(this.RawTime), 0)
}

type contentRelatedApiFunction struct {
	contentApiFunction
	SupportsPagination
}

func (a contentRelatedApiFunction) Construct() string {
	base := fmt.Sprintf("%s/related", a.contentApiFunction.Construct())
	return PaginateString(base, a.Page)
}

type RelatedContent struct {
	Related ContentList `json:"related"`
	Total   uint        `json:"total"`
	Pages   uint        `json:"pages"`
}

func GetRelatedContentAll(category, name string) (*RelatedContent, error) {
	return GetRelatedContent(category, name, 0)
}

func GetRelatedContent(category, name string, page uint) (*RelatedContent, error) {
	var c RelatedContent
	url := contentRelatedApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		SupportsPagination: SupportsPagination{Page: page},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func (this *Content) RelatedContent() (*RelatedContent, error) {
	return GetRelatedContentAll(this.Category, this.Name)
}
func (this *Content) RelatedContentPage(page uint) (*RelatedContent, error) {
	return GetRelatedContent(this.Category, this.Name, page)
}

func (c *RelatedContent) UnmarshalJSON(b []byte) error {
	// slightly different
	var f interface{}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})
	related := m["related"]
	v := related.([]interface{})
	c.Related = make(ContentList, len(v))
	for i := 0; i < len(v); i++ {
		c.Related[i].populateContent(v[i].(map[string]interface{}))
	}
	c.Total = uint(m["total"].(float64))
	c.Pages = uint(m["pages"].(float64))
	return nil
}
<commit_msg>Cleaned up the functions for getting downloads<commit_after>package fakku

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"
	"time"
)

const (
	ErrorContentDoesntExist = "Content doesn't exist"
	ErrorUnknownJsonData    = "Got unknown json data back from content request. API Change?"
	ErrorUnknownJsonLayout  = "Got an unknown layout back from content request. API Change?"
)

type Content struct {
	Name         string
	Url          string
	Description  string
	Language     string
	Category     string
	Date         float64
	FileSize     float64
	Favorites    float64
	CommentCount float64
	Pages        float64
	Poster       string
	PosterUrl    string
	Tags         []*Attribute `json:"content_tags"`
	Translators  []*Attribute `json:"content_translators"`
	Series       []*Attribute `json:"content_series"`
	Artists      []*Attribute `json:"content_artists"`
	Images       struct {
		Cover  string
		Sample string
	}
}
type ContentList []Content

func (c *Content) UnmarshalJSON(b []byte) error {
	var f interface{}
	json.Unmarshal(b, &f)
	switch f.(type) {
	case map[string]interface{}:
		m := f.(map[string]interface{})
		contents := m["content"]
		switch contents.(type) {
		case map[string]interface{}:
			v := contents.(map[string]interface{})
			c.populateContent(v)
			return nil
		case []interface{}:
			q := contents.([]interface{})
			if len(q) == 0 {
				// doesn't exist
				return fmt.Errorf(ErrorContentDoesntExist)
			} else {
				return fmt.Errorf(ErrorUnknownJsonData)
			}
		default:
			return fmt.Errorf(ErrorUnknownJsonLayout)
		}
	case []interface{}:
		q := f.([]interface{})
		if len(q) == 0 {
			// doesn't exist
			return fmt.Errorf(ErrorContentDoesntExist)
		} else {
			return fmt.Errorf(ErrorUnknownJsonData)
		}
	default:
		return fmt.Errorf(ErrorUnknownJsonLayout)
	}
}

func (c *Content) populateContent(v map[string]interface{}) {
	c.Name = v["content_name"].(string)
	c.Url = v["content_url"].(string)
	c.Description = v["content_description"].(string)
	c.Language = v["content_language"].(string)
	c.Category = v["content_category"].(string)
	c.Date = v["content_date"].(float64)
	c.FileSize = v["content_filesize"].(float64)
	c.Favorites = v["content_favorites"].(float64)
	c.CommentCount = v["content_comments"].(float64)
	c.Pages = v["content_pages"].(float64)
	c.Poster = v["content_poster"].(string)
	c.PosterUrl = v["content_poster_url"].(string)
	c.Tags = constructAttributeFields(v, "content_tags")
	c.Translators = constructAttributeFields(v, "content_translators")
	c.Series = constructAttributeFields(v, "content_series")
	c.Artists = constructAttributeFields(v, "content_artists")

	tmp := v["content_images"]
	z := tmp.(map[string]interface{})
	c.Images.Cover = z["cover"].(string)
	c.Images.Sample = z["sample"].(string)
}

func GetContent(category, name string) (*Content, error) {
	var c Content
	url := contentApiFunction{Category: category, Name: name}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

type contentApiFunction struct {
	Category string
	Name     string
}

func (a contentApiFunction) Construct() string {
	return fmt.Sprintf("%s/%s/%s", ApiHeader, a.Category, a.Name)
}

type contentCommentApiFunction struct {
	contentApiFunction
	TopComments bool
	SupportsPagination
}

func (a contentCommentApiFunction) Construct() string {
	base := fmt.Sprintf("%s/comments", a.contentApiFunction.Construct())
	if a.TopComments {
		return fmt.Sprintf("%s/top", base)
	} else {
		return PaginateString(base, a.Page)
	}
}

func getContentCommentsGeneric(url ApiFunction) (*Comments, error) {
	var c Comments
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func ContentComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	return getContentCommentsGeneric(url)
}

func ContentCommentsPage(category, name string, page uint) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		SupportsPagination: SupportsPagination{Page: page},
	}
	return getContentCommentsGeneric(url)
}

func ContentTopComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		TopComments: true,
	}
	return getContentCommentsGeneric(url)
}

func (this *Content) TopComments() (*Comments, error) {
	return ContentTopComments(this.Category, this.Name)
}
func (this *Content) CommentsPage(page uint) (*Comments, error) {
	return ContentCommentsPage(this.Category, this.Name, page)
}
func (this *Content) Comments() (*Comments, error) {
	return ContentComments(this.Category, this.Name)
}

type Attribute struct {
	Attribute     string `json:"attribute"`
	AttributeLink string `json:"attribute_link"`
}

func NewAttribute(c map[string]interface{}) *Attribute {
	return &Attribute{
		Attribute:     c["attribute"].(string),
		AttributeLink: c["attribute_link"].(string),
	}
}

func (a *Attribute) String() string {
	return a.Attribute
}

func constructAttributeFields(c map[string]interface{}, field string) []*Attribute {
	try, ok := c[field]
	if !ok {
		return nil
	}
	tmp := try.([]interface{})
	size := len(tmp)
	attrs := make([]*Attribute, size)
	for i := 0; i < size; i++ {
		attrs[i] = NewAttribute(tmp[i].(map[string]interface{}))
	}
	return attrs
}

type Comment struct {
	Id         float64 `json:"comment_id"`
	AttachedId string  `json:"comment_attached_id"`
	Poster     string  `json:"comment_poster"`
	PosterUrl  string  `json:"comment_poster_url"`
	Reputation float64 `json:"comment_reputation"`
	Text       string  `json:"comment_text"`
	Date       float64 `json:"comment_date"`
}

type Comments struct {
	Comments   []*Comment `json:"comments"`
	PageNumber float64    `json:"page"`
	Total      float64    `json:"total"`
	Pages      float64    `json:"pages"`
}

type ReadOnlineContent struct {
	Content *Content `json:"content"`
	Pages   []*Page  `json:"pages"`
}

func (r *ReadOnlineContent) UnmarshalJSON(b []byte) error {
	var f interface{}
	if err := json.Unmarshal(b, &r.Content); err != nil {
		return err
	}
	json.Unmarshal(b, &f)
	// need to check and make sure that the content exists
	switch f.(type) {
	case map[string]interface{}:
		m := f.(map[string]interface{})
		pages := m["pages"]
		v := pages.(map[string]interface{})
		r.Pages = make([]*Page, len(v))
		for i := 0; i < len(v); i++ {
			ind := strconv.Itoa(i + 1)
			r.Pages[i] = NewPage(ind, v[ind].(map[string]interface{}))
		}
		return nil
	case []interface{}:
		q := f.([]interface{})
		if len(q) == 0 {
			// doesn't exist
			return fmt.Errorf("Content doesn't exist")
		} else {
			return fmt.Errorf("Got unknown json data back from content request. API Change?")
		}
	default:
		return fmt.Errorf("Got an unknown layout back from content request. API Change?")
	}
}

type Page struct {
	Id    string
	Thumb string
	Image string
}

func NewPage(id string, c map[string]interface{}) *Page {
	return &Page{
		Id:    id,
		Thumb: c["thumb"].(string),
		Image: c["image"].(string),
	}
}

type ContentReadOnlineApiFunction struct {
	contentApiFunction
}

func (a ContentReadOnlineApiFunction) Construct() string {
	return fmt.Sprintf("%s/read", a.contentApiFunction.Construct())
}

func GetContentReadOnline(category, name string) (*ReadOnlineContent, error) {
	var c ReadOnlineContent
	url := ContentReadOnlineApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

type contentDownloadsApiFunction struct {
	contentApiFunction
}

func (a contentDownloadsApiFunction) Construct() string {
	return fmt.Sprintf("%s/download", a.contentApiFunction.Construct())
}

type DownloadList []Download

func (this DownloadList) HasDownloads() bool {
	return len(this) > 0
}

type downloadContent struct {
	Downloads DownloadList `json:"downloads"`
	Total     uint         `json:"total"`
}

func ContentDownloads(category, name string) (DownloadList, error) {
	var c downloadContent
	url := contentDownloadsApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return c.Downloads, nil
	}
}

func (this *Content) Downloads() (DownloadList, error) {
	return ContentDownloads(this.Category, this.Name)
}

type Download struct {
	Type          string  `json:"download_type"`
	RawUrl        string  `json:"download_url"`
	Info          string  `json:"download_info"`
	DownloadCount float64 `json:"download_count"`
	RawTime       float64 `json:"download_time"`
	Poster        string  `json:"download_poster"`
	RawPosterUrl  string  `json:"download_poster_url"`
}

func (this *Download) Url() (*url.URL, error) {
	return url.Parse(this.RawUrl)
}
func (this *Download) PosterUrl() (*url.URL, error) {
	return url.Parse(this.RawPosterUrl)
}
func (this *Download) Time() time.Time {
	return time.Unix(int64(this.RawTime), 0)
}

type contentRelatedApiFunction struct {
	contentApiFunction
	SupportsPagination
}

func (a contentRelatedApiFunction) Construct() string {
	base := fmt.Sprintf("%s/related", a.contentApiFunction.Construct())
	return PaginateString(base, a.Page)
}

type RelatedContent struct {
	Related ContentList `json:"related"`
	Total   uint        `json:"total"`
	Pages   uint        `json:"pages"`
}

func GetRelatedContentAll(category, name string) (*RelatedContent, error) {
	return GetRelatedContent(category, name, 0)
}

func GetRelatedContent(category, name string, page uint) (*RelatedContent, error) {
	var c RelatedContent
	url := contentRelatedApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		SupportsPagination: SupportsPagination{Page: page},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func (this *Content) RelatedContent() (*RelatedContent, error) {
	return GetRelatedContentAll(this.Category, this.Name)
}
func (this *Content) RelatedContentPage(page uint) (*RelatedContent, error) {
	return GetRelatedContent(this.Category, this.Name, page)
}

func (c *RelatedContent) UnmarshalJSON(b []byte) error {
	// slightly different
	var f interface{}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})
	related := m["related"]
	v := related.([]interface{})
	c.Related = make(ContentList, len(v))
	for i := 0; i < len(v); i++ {
		c.Related[i].populateContent(v[i].(map[string]interface{}))
	}
	c.Total = uint(m["total"].(float64))
	c.Pages = uint(m["pages"].(float64))
	return nil
}
<|endoftext|>


<commit_before>package steam

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type LoginResponse struct {
	Success      bool   `json:"success"`
	PublicKeyMod string `json:"publickey_mod"`
	PublicKeyExp string `json:"publickey_exp"`
	Timestamp    string
	TokenGID     string
}

type OAuth struct {
	SteamID       SteamID `json:"steamid,string"`
	Token         string  `json:"oauth_token"`
	WGToken       string  `json:"wgtoken"`
	WGTokenSecure string  `json:"wgtoken_secure"`
	WebCookie     string  `json:"webcookie"`
}

type LoginSession struct {
	Success           bool   `json:"success"`
	LoginComplete     bool   `json:"login_complete"`
	RequiresTwoFactor bool   `json:"requires_twofactor"`
	Message           string `json:"message"`
	RedirectURI       string `json:"redirect_uri"`
	OAuthInfo         string `json:"oauth"`
}

type Session struct {
	client      *http.Client
	oauth       OAuth
	sessionID   string
	apiKey      string
	deviceID    string
	umqID       string
	chatMessage int
}

const (
	httpXRequestedWithValue = "com.valvesoftware.android.steam.community"
	httpUserAgentValue      = "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"
	httpAcceptValue         = "text/javascript, text/html, application/xml, text/xml, */*"
)

var (
	ErrUnableToLogin   = errors.New("unable to login")
	ErrInvalidUsername = errors.New("invalid username")
	ErrNeedTwoFactor   = errors.New("invalid twofactor code")
)

func (session *Session) proceedDirectLogin(response *LoginResponse, accountName, password, sharedSecret string, timeOffset time.Duration) error {
	n := &big.Int{}
	n.SetString(response.PublicKeyMod, 16)

	exp, err := strconv.ParseInt(response.PublicKeyExp, 16, 32)
	if err != nil {
		return err
	}

	pub := &rsa.PublicKey{N: n, E: int(exp)}
	rsaOut, err := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(password))
	if err != nil {
		return err
	}

	var twoFactorCode string
	if len(sharedSecret) != 0 {
		if twoFactorCode, err = GenerateTwoFactorCode(sharedSecret, time.Now().Add(timeOffset).Unix()); err != nil {
			return err
		}
	}

	req, err := http.NewRequest(
		http.MethodPost,
		"https://steamcommunity.com/login/dologin/?"+url.Values{
			"captcha_text":      {""},
			"captchagid":        {"-1"},
			"emailauth":         {""},
			"emailsteamid":      {""},
			"password":          {base64.StdEncoding.EncodeToString(rsaOut)},
			"remember_login":    {"true"},
			"rsatimestamp":      {response.Timestamp},
			"twofactorcode":     {twoFactorCode},
			"username":          {accountName},
			"oauth_client_id":   {"DE45CD61"},
			"oauth_scope":       {"read_profile write_profile read_client write_client"},
			"loginfriendlyname": {"#login_emailauth_friendlyname_mobile"},
			"donotcache":        {strconv.FormatInt(time.Now().Unix()*1000, 10)},
		}.Encode(),
		nil,
	)
	if err != nil {
		return err
	}

	req.Header.Add("X-Requested-With", httpXRequestedWithValue)
	req.Header.Add("Referer", "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client")
	req.Header.Add("User-Agent", httpUserAgentValue)
	req.Header.Add("Accept", httpAcceptValue)

	resp, err := session.client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}

	if err != nil {
		return err
	}

	var loginSession LoginSession
	if err := json.NewDecoder(resp.Body).Decode(&loginSession); err != nil {
		return err
	}

	if !loginSession.Success {
		if loginSession.RequiresTwoFactor {
			return ErrNeedTwoFactor
		}

		return ErrUnableToLogin
	}

	if err := json.Unmarshal([]byte(loginSession.OAuthInfo), &session.oauth); err != nil {
		return err
	}

	randomBytes := make([]byte, 6)
	if _, err := rand.Read(randomBytes); err != nil {
		return err
	}

	sessionID := make([]byte, hex.EncodedLen(len(randomBytes)))
	hex.Encode(sessionID, randomBytes)
	session.sessionID = string(sessionID)

	url, _ := url.Parse("https://steamcommunity.com")
	cookies := session.client.Jar.Cookies(url)
	for _, cookie := range cookies {
		if cookie.Name == "mobileClient" || cookie.Name == "mobileClientVersion" || cookie.Name == "steamCountry" || strings.Contains(cookie.Name, "steamMachineAuth") {
			// remove by setting max age -1
			cookie.MaxAge = -1
		}
	}

	sum := md5.Sum([]byte(sharedSecret))
	session.deviceID = fmt.Sprintf(
		"android:%x-%x-%x-%x-%x",
		sum[:2], sum[2:4], sum[4:6], sum[6:8], sum[8:10],
	)

	session.client.Jar.SetCookies(
		url,
		append(cookies, &http.Cookie{
			Name:  "sessionid",
			Value: session.sessionID,
		}),
	)

	io.Copy(ioutil.Discard, resp.Body)
	return nil
}

func (session *Session) Login(accountName, password, sharedSecret string, timeOffset time.Duration) error {
	req, err := http.NewRequest(http.MethodPost, "https://steamcommunity.com/login/getrsakey?username="+accountName, nil)
	if err != nil {
		return err
	}

	jar, err := cookiejar.New(nil)
	if err != nil {
		return err
	}

	req.Header.Add("X-Requested-With", httpXRequestedWithValue)
	req.Header.Add("Referer", "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client")
	req.Header.Add("User-Agent", httpUserAgentValue)
	req.Header.Add("Accept", httpAcceptValue)

	cookies := []*http.Cookie{
		&http.Cookie{Name: "mobileClientVersion", Value: "0 (2.1.3)"},
		&http.Cookie{Name: "mobileClient", Value: "android"},
		&http.Cookie{Name: "Steam_Language", Value: "english"},
		&http.Cookie{Name: "timezoneOffset", Value: "0,0"},
	}
	url, _ := url.Parse("https://steamcommunity.com")
	jar.SetCookies(url, cookies)

	// Construct the client
	session.client = &http.Client{Jar: jar}

	resp, err := session.client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}

	if err != nil {
		return err
	}

	var response LoginResponse
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return err
	}

	if !response.Success {
		return ErrInvalidUsername
	}

	io.Copy(ioutil.Discard, resp.Body)
	return session.proceedDirectLogin(&response, accountName, password, sharedSecret, timeOffset)
}

func (session *Session) GetSteamID() SteamID {
	return session.oauth.SteamID
}
<commit_msg>Allow constructing a session from an API key<commit_after>package steam

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type LoginResponse struct {
	Success      bool   `json:"success"`
	PublicKeyMod string `json:"publickey_mod"`
	PublicKeyExp string `json:"publickey_exp"`
	Timestamp    string
	TokenGID     string
}

type OAuth struct {
	SteamID       SteamID `json:"steamid,string"`
	Token         string  `json:"oauth_token"`
	WGToken       string  `json:"wgtoken"`
	WGTokenSecure string  `json:"wgtoken_secure"`
	WebCookie     string  `json:"webcookie"`
}

type LoginSession struct {
	Success           bool   `json:"success"`
	LoginComplete     bool   `json:"login_complete"`
	RequiresTwoFactor bool   `json:"requires_twofactor"`
	Message           string `json:"message"`
	RedirectURI       string `json:"redirect_uri"`
	OAuthInfo         string `json:"oauth"`
}

type Session struct {
	client      *http.Client
	oauth       OAuth
	sessionID   string
	apiKey      string
	deviceID    string
	umqID       string
	chatMessage int
}

const (
	httpXRequestedWithValue = "com.valvesoftware.android.steam.community"
	httpUserAgentValue      = "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"
	httpAcceptValue         = "text/javascript, text/html, application/xml, text/xml, */*"
)

var (
	ErrUnableToLogin   = errors.New("unable to login")
	ErrInvalidUsername = errors.New("invalid username")
	ErrNeedTwoFactor   = errors.New("invalid twofactor code")
)

func (session *Session) proceedDirectLogin(response *LoginResponse, accountName, password, sharedSecret string, timeOffset time.Duration) error {
	n := &big.Int{}
	n.SetString(response.PublicKeyMod, 16)

	exp, err := strconv.ParseInt(response.PublicKeyExp, 16, 32)
	if err != nil {
		return err
	}

	pub := &rsa.PublicKey{N: n, E: int(exp)}
	rsaOut, err := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(password))
	if err != nil {
		return err
	}

	var twoFactorCode string
	if len(sharedSecret) != 0 {
		if twoFactorCode, err = GenerateTwoFactorCode(sharedSecret, time.Now().Add(timeOffset).Unix()); err != nil {
			return err
		}
	}

	req, err := http.NewRequest(
		http.MethodPost,
		"https://steamcommunity.com/login/dologin/?"+url.Values{
			"captcha_text":      {""},
			"captchagid":        {"-1"},
			"emailauth":         {""},
			"emailsteamid":      {""},
			"password":          {base64.StdEncoding.EncodeToString(rsaOut)},
			"remember_login":    {"true"},
			"rsatimestamp":      {response.Timestamp},
			"twofactorcode":     {twoFactorCode},
			"username":          {accountName},
			"oauth_client_id":   {"DE45CD61"},
			"oauth_scope":       {"read_profile write_profile read_client write_client"},
			"loginfriendlyname": {"#login_emailauth_friendlyname_mobile"},
			"donotcache":        {strconv.FormatInt(time.Now().Unix()*1000, 10)},
		}.Encode(),
		nil,
	)
	if err != nil {
		return err
	}

	req.Header.Add("X-Requested-With", httpXRequestedWithValue)
	req.Header.Add("Referer", "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client")
	req.Header.Add("User-Agent", httpUserAgentValue)
	req.Header.Add("Accept", httpAcceptValue)

	resp, err := session.client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}

	if err != nil {
		return err
	}

	var loginSession LoginSession
	if err := json.NewDecoder(resp.Body).Decode(&loginSession); err != nil {
		return err
	}

	if !loginSession.Success {
		if loginSession.RequiresTwoFactor {
			return ErrNeedTwoFactor
		}

		return ErrUnableToLogin
	}

	if err := json.Unmarshal([]byte(loginSession.OAuthInfo), &session.oauth); err != nil {
		return err
	}

	randomBytes := make([]byte, 6)
	if _, err := rand.Read(randomBytes); err != nil {
		return err
	}

	sessionID := make([]byte, hex.EncodedLen(len(randomBytes)))
	hex.Encode(sessionID, randomBytes)
	session.sessionID = string(sessionID)

	url, _ := url.Parse("https://steamcommunity.com")
	cookies := session.client.Jar.Cookies(url)
	for _, cookie := range cookies {
		if cookie.Name == "mobileClient" || cookie.Name == "mobileClientVersion" || cookie.Name == "steamCountry" || strings.Contains(cookie.Name, "steamMachineAuth") {
			// remove by setting max age -1
			cookie.MaxAge = -1
		}
	}

	sum := md5.Sum([]byte(sharedSecret))
	session.deviceID = fmt.Sprintf(
		"android:%x-%x-%x-%x-%x",
		sum[:2], sum[2:4], sum[4:6], sum[6:8], sum[8:10],
	)

	session.client.Jar.SetCookies(
		url,
		append(cookies, &http.Cookie{
			Name:  "sessionid",
			Value: session.sessionID,
		}),
	)

	io.Copy(ioutil.Discard, resp.Body)
	return nil
}

func (session *Session) Login(accountName, password, sharedSecret string, timeOffset time.Duration) error {
	req, err := http.NewRequest(http.MethodPost, "https://steamcommunity.com/login/getrsakey?username="+accountName, nil)
	if err != nil {
		return err
	}

	jar, err := cookiejar.New(nil)
	if err != nil {
		return err
	}

	req.Header.Add("X-Requested-With", httpXRequestedWithValue)
	req.Header.Add("Referer", "https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client")
	req.Header.Add("User-Agent", httpUserAgentValue)
	req.Header.Add("Accept", httpAcceptValue)

	cookies := []*http.Cookie{
		&http.Cookie{Name: "mobileClientVersion", Value: "0 (2.1.3)"},
		&http.Cookie{Name: "mobileClient", Value: "android"},
		&http.Cookie{Name: "Steam_Language", Value: "english"},
		&http.Cookie{Name: "timezoneOffset", Value: "0,0"},
	}
	url, _ := url.Parse("https://steamcommunity.com")
	jar.SetCookies(url, cookies)

	// Construct the client
	session.client = &http.Client{Jar: jar}

	resp, err := session.client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}

	if err != nil {
		return err
	}

	var response LoginResponse
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return err
	}

	if !response.Success {
		return ErrInvalidUsername
	}

	io.Copy(ioutil.Discard, resp.Body)
	return session.proceedDirectLogin(&response, accountName, password, sharedSecret, timeOffset)
}

func (session *Session) GetSteamID() SteamID {
	return session.oauth.SteamID
}

func NewSessionWithAPIKey(apiKey string) *Session {
	return &Session{
		client: &http.Client{},
		apiKey: apiKey,
	}
}
<|endoftext|>


<commit_before>package vm

import (
	"crypto/sha1"
	"crypto/sha256"
	"hash"
)

func opHash(e *ExecutionEngine) (VMState, error) {
	if e.evaluationStack.Count() < 1 {
		return FAULT, nil
	}
	x := AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	err := pushData(e, Hash(x, e))
	if err != nil {
		return FAULT, err
	}
	return NONE, nil
}

func opCheckSig(e *ExecutionEngine) (VMState, error) {
	if e.evaluationStack.Count() < 2 {
		return FAULT, nil
	}
	pubkey := AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	signature := AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	ver, err := e.crypto.VerifySignature(e.scriptContainer.GetMessage(), signature, pubkey)
	err = pushData(e, ver)
	if err != nil {
		return FAULT, err
	}
	return NONE, nil
}

func opCheckMultiSig(e *ExecutionEngine) (VMState, error) {
	if e.evaluationStack.Count() < 4 {
		return FAULT, nil
	}
	n := int(AssertStackItem(e.evaluationStack.Pop()).GetBigInteger().Int64())
	if n < 1 {
		return FAULT, nil
	}
	if e.evaluationStack.Count() < n+2 {
		return FAULT, nil
	}
	e.opCount += n
	if e.opCount > e.maxSteps {
		return FAULT, nil
	}

	pubkeys := make([][]byte, n)
	for i := 0; i < n; i++ {
		pubkeys[i] = AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	}

	m := int(AssertStackItem(e.evaluationStack.Pop()).GetBigInteger().Int64())
	if m < 1 || m > n {
		return FAULT, nil
	}
	if e.evaluationStack.Count() < m {
		return FAULT, nil
	}

	signatures := make([][]byte, m)
	for i := 0; i < n; i++ {
		signatures[i] = AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	}

	message := e.scriptContainer.GetMessage()
	fSuccess := true

	for i, j := 0, 0; fSuccess && i < m && j < n; {
		ver, err := e.crypto.VerifySignature(message, signatures[i], pubkeys[j])
		if err != nil {
			return FAULT, err
		}
		if ver {
			i++
		}
		j++
		if m-i > n-j {
			fSuccess = false
		}
	}
	err := pushData(e, fSuccess)
	if err != nil {
		return FAULT, err
	}
	return NONE, nil
}

func Hash(b []byte, e *ExecutionEngine) []byte {
	var sh hash.Hash
	var bt []byte
	switch e.opCode {
	case SHA1:
		sh = sha1.New()
		sh.Write(b)
		bt = sh.Sum(nil)
	case SHA256:
		sh = sha256.New()
		sh.Write(b)
		bt = sh.Sum(nil)
	case HASH160:
		bt = e.crypto.Hash160(b)
	case HASH256:
		bt = e.crypto.Hash256(b)
	}
	return bt
}
<commit_msg>Fix vm verify multi signature bug<commit_after>package vm

import (
	"crypto/sha1"
	"crypto/sha256"
	"hash"
)

func opHash(e *ExecutionEngine) (VMState, error) {
	if e.evaluationStack.Count() < 1 {
		return FAULT, nil
	}
	x := AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	err := pushData(e, Hash(x, e))
	if err != nil {
		return FAULT, err
	}
	return NONE, nil
}

func opCheckSig(e *ExecutionEngine) (VMState, error) {
	if e.evaluationStack.Count() < 2 {
		return FAULT, nil
	}
	pubkey := AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	signature := AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	ver, err := e.crypto.VerifySignature(e.scriptContainer.GetMessage(), signature, pubkey)
	err = pushData(e, ver)
	if err != nil {
		return FAULT, err
	}
	return NONE, nil
}

func opCheckMultiSig(e *ExecutionEngine) (VMState, error) {
	if e.evaluationStack.Count() < 4 {
		return FAULT, nil
	}
	n := int(AssertStackItem(e.evaluationStack.Pop()).GetBigInteger().Int64())
	if n < 1 {
		return FAULT, nil
	}
	if e.evaluationStack.Count() < n+2 {
		return FAULT, nil
	}
	e.opCount += n
	if e.opCount > e.maxSteps {
		return FAULT, nil
	}

	pubkeys := make([][]byte, n)
	for i := 0; i < n; i++ {
		pubkeys[i] = AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	}

	m := int(AssertStackItem(e.evaluationStack.Pop()).GetBigInteger().Int64())
	if m < 1 || m > n {
		return FAULT, nil
	}
	if e.evaluationStack.Count() < m {
		return FAULT, nil
	}

	signatures := make([][]byte, m)
	for i := 0; i < m; i++ {
		signatures[i] = AssertStackItem(e.evaluationStack.Pop()).GetByteArray()
	}

	message := e.scriptContainer.GetMessage()
	fSuccess := true

	for i, j := 0, 0; fSuccess && i < m && j < n; {
		ver, _ := e.crypto.VerifySignature(message, signatures[i], pubkeys[j])
		if ver {
			i++
		}
		j++
		if m-i > n-j {
			fSuccess = false
		}
	}
	err := pushData(e, fSuccess)
	if err != nil {
		return FAULT, err
	}
	return NONE, nil
}

func Hash(b []byte, e *ExecutionEngine) []byte {
	var sh hash.Hash
	var bt []byte
	switch e.opCode {
	case SHA1:
		sh = sha1.New()
		sh.Write(b)
		bt = sh.Sum(nil)
	case SHA256:
		sh = sha256.New()
		sh.Write(b)
		bt = sh.Sum(nil)
	case HASH160:
		bt = e.crypto.Hash160(b)
	case HASH256:
		bt = e.crypto.Hash256(b)
	}
	return bt
}
<|endoftext|>


<commit_before>package core

// TODO consumer.SetLogger

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/nsqio/go-nsq"
)

/*type deliverd struct {
}

func New() *deliverd {
	return &deliverd{}
}*/

// LaunchDeliverd
func LaunchDeliverd() {
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	cfg := nsq.NewConfig()

	cfg.UserAgent = "tmail/deliverd"
	cfg.MaxInFlight = ((Cfg.GetDeliverdConcurrencyLocal() + Cfg.GetDeliverdConcurrencyRemote()) * 200) / 100
	// MaxAttempts: number of attemps for a message before sending a
	// 1 [queueRemote/deliverd] msg 07814777d6312000 attempted 6 times, giving up
	cfg.MaxAttempts = 0

	// create consummer
	// TODO creation de plusieurs consumer: local, remote, ...
	consumer, err := nsq.NewConsumer("todeliver", "deliverd", cfg)
	if err != nil {
		log.Fatalln(err)
	}
	if Cfg.GetDebugEnabled() {
		consumer.SetLogger(NewNSQLogger(), nsq.LogLevelDebug)
	} else {
		consumer.SetLogger(NewNSQLogger(), nsq.LogLevelError)
	}
	// Bind handler
	consumer.AddHandler(&deliveryHandler{})

	// connect
	if Cfg.GetClusterModeEnabled() {
		err = consumer.ConnectToNSQLookupds(Cfg.GetNSQLookupdHttpAddresses())
	} else {
		err = consumer.ConnectToNSQDs([]string{"127.0.0.1:4150"})
	}
	if err != nil {
		log.Fatalln(err)
	}

	Logger.Info("deliverd launched")

	for {
		select {
		case <-consumer.StopChan:
			return
		case <-sigChan:
			consumer.Stop()
		}
	}
}
<commit_msg>add comment<commit_after>package core

// TODO consumer.SetLogger

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/nsqio/go-nsq"
)

/*type deliverd struct {
}

func New() *deliverd {
	return &deliverd{}
}*/

// LaunchDeliverd launch deliverd
func LaunchDeliverd() {
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	cfg := nsq.NewConfig()

	cfg.UserAgent = "tmail/deliverd"
	cfg.MaxInFlight = ((Cfg.GetDeliverdConcurrencyLocal() + Cfg.GetDeliverdConcurrencyRemote()) * 200) / 100
	// MaxAttempts: number of attemps for a message before sending a
	// 1 [queueRemote/deliverd] msg 07814777d6312000 attempted 6 times, giving up
	cfg.MaxAttempts = 0

	// create consummer
	// TODO creation de plusieurs consumer: local, remote, ...
	consumer, err := nsq.NewConsumer("todeliver", "deliverd", cfg)
	if err != nil {
		log.Fatalln(err)
	}
	if Cfg.GetDebugEnabled() {
		consumer.SetLogger(NewNSQLogger(), nsq.LogLevelDebug)
	} else {
		consumer.SetLogger(NewNSQLogger(), nsq.LogLevelError)
	}
	// Bind handler
	consumer.AddHandler(&deliveryHandler{})

	// connect
	if Cfg.GetClusterModeEnabled() {
		err = consumer.ConnectToNSQLookupds(Cfg.GetNSQLookupdHttpAddresses())
	} else {
		err = consumer.ConnectToNSQDs([]string{"127.0.0.1:4150"})
	}
	if err != nil {
		log.Fatalln(err)
	}

	Logger.Info("deliverd launched")

	for {
		select {
		case <-consumer.StopChan:
			return
		case <-sigChan:
			consumer.Stop()
		}
	}
}
<|endoftext|>