<commit_before>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}.
package pinata

import (
	"bytes"
	"fmt"
)

// Pinata holds a value and offers methods for extracting data from it.
type Pinata interface {
	Contents() interface{}
	Error() error
	ClearError()
	StringAtPath(string, ...string) string
	String() string
	StringAtIndex(int) string
	PinataAtPath(string, ...string) Pinata
	PinataAtIndex(int) Pinata
}

// New creates a new Pinata. Instances returned are not thread safe.
func New(contents interface{}) Pinata {
	switch t := contents.(type) {
	default:
		return &otherPinata{contents: t}
	case map[string]interface{}:
		return &mapPinata{contents: t}
	case []interface{}:
		return &slicePinata{}
	}
}

var _ = error(PinataError{})

type ErrorReason string

const (
	ErrorReasonUnknown         ErrorReason = "unknown"
	ErrorReasonIncompatbleType             = "incompatible type"
	ErrorReasonNotFound                    = "not found"
	ErrorReasonInvalidInput                = "invalid input"
)

type PinataError struct {
	Reason ErrorReason
	Method string
	Input  []interface{}
	Advice string
}

func (p PinataError) Error() string {
	var input string
	if len(p.Input) > 0 {
		var buf bytes.Buffer
		for i := range p.Input {
			buf.WriteString("%#v")
			if i < len(p.Input)-1 {
				buf.WriteString(", ")
			}
		}
		input = fmt.Sprintf(buf.String(), p.Input...)
	}
	return fmt.Sprintf("pinata: %s(%s): %s - %s", p.Method, input, p.Reason, p.Advice)
}

type basePinata struct {
	err error
}

func (p *basePinata) Error() error {
	return p.err
}

func (p *basePinata) ClearError() {
	p.err = nil
}

func (p *basePinata) String() string {
	if p.err != nil {
		return ""
	}
	p.err = &PinataError{
		Method: "String",
		Reason: ErrorReasonIncompatbleType,
		Input:  nil,
		Advice: "call this method on a string pinata",
	}
	return ""
}

func (p *basePinata) PinataAtIndex(index int) Pinata {
	p.indexUnsupported("PinataAtIndex", index)
	return nil
}

func (p *basePinata) PinataAtPath(pathStart string, path ...string) Pinata {
	p.pathUnsupported("PinataAtPath", pathStart, path)
	return nil
}

func (p *basePinata) StringAtPath(pathStart string, path ...string) string {
	p.pathUnsupported("StringAtPath", pathStart, path)
	return ""
}

func (p *basePinata) StringAtIndex(index int) string {
	p.indexUnsupported("StringAtIndex", index)
	return ""
}

func (p *basePinata) Contents() interface{} {
	return nil
}

func (p *basePinata) indexErrorf(method string, index int, reason ErrorReason, advice string) error {
	return &PinataError{
		Method: method,
		Reason: reason,
		Input:  []interface{}{index},
		Advice: advice,
	}

	//return fmt.Errorf("%s(%d): %s", method, index, msg)
}

func (p *basePinata) indexUnsupported(method string, index int) {
	if p.err != nil {
		return
	}
	p.err = p.indexErrorf(method, index, ErrorReasonIncompatbleType, "call this method on a slice pinata")
}

func (p *basePinata) setIndexOutOfRange(method string, index int, contents []interface{}) bool {
	if index < 0 || index >= len(contents) {
		p.err = p.indexErrorf(method, index, ErrorReasonInvalidInput,
			fmt.Sprintf("specify an index from 0 to %d", len(contents)-1))
		return true
	}
	return false
}

func (p *basePinata) pathErrorf(method, pathStart string, path []string, reason ErrorReason, advice string) error {
	return &PinataError{
		Method: method,
		Reason: reason,
		Input:  toSlice(pathStart, path),
		Advice: advice,
	}
}

func (p *basePinata) pathUnsupported(method, pathStart string, path []string) {
	if p.err != nil {
		return
	}
	p.err = p.pathErrorf(method, pathStart, path, ErrorReasonIncompatbleType, "call this method on a map pinata")
}

type otherPinata struct {
	basePinata
	contents interface{}
}

func (p *otherPinata) String() string {
	if p.err != nil {
		return ""
	}
	if v, ok := p.contents.(string); ok {
		return v
	}
	return p.basePinata.String()
}

func (p *otherPinata) Contents() interface{} {
	return p.contents
}

type slicePinata struct {
	basePinata
	contents []interface{}
}

func (p *slicePinata) pinataAtIndex(method string, index int) Pinata {
	if p.err != nil {
		return nil
	}
	if p.setIndexOutOfRange(method, index, p.contents) {
		return nil
	}
	return New(p.contents[index])
}

func (p *slicePinata) PinataAtIndex(index int) Pinata {
	return p.pinataAtIndex("PinataAtIndex", index)
}

func (p *slicePinata) StringAtIndex(index int) string {
	const method = "StringAtIndex"
	pinata := p.pinataAtIndex(method, index)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = p.indexErrorf(method, index, ErrorReasonIncompatbleType, "not a string, try another type")
	}
	return s
}

func (p *slicePinata) Contents() interface{} {
	return p.contents
}

type mapPinata struct {
	basePinata
	contents map[string]interface{}
}

func (p *mapPinata) pinataAtPath(method, pathStart string, path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	if v, ok := p.contents[pathStart]; ok {
		//if v, ok := v.(map[string]interface{})
		currentPinata := New(v)
		rest := path
		for len(rest) > 0 {
			tmp := currentPinata.PinataAtPath(rest[0])
			rest = rest[1:len(rest)]
			if currentPinata.Error() != nil {
				// TODO need to customise the message based on the returned error
				//sofar := path[:len(path)-len(rest)]
				p.err = p.pathErrorf(method, pathStart, path, ErrorReasonNotFound, "can't find that, sorry")
				return nil
			}
			currentPinata = tmp
		}
		return currentPinata
	}
	p.err = p.pathErrorf(method, pathStart, path, ErrorReasonNotFound, fmt.Sprintf(`no "%s" in this pinata`, pathStart))
	return nil
}

func (p *mapPinata) PinataAtPath(pathStart string, path ...string) Pinata {
	return p.pinataAtPath("PinataAtPath", pathStart, path...)
}

func (p *mapPinata) StringAtPath(pathStart string, path ...string) string {
	const method = "StringAtPath"
	pinata := p.pinataAtPath(method, pathStart, path...)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = p.pathErrorf(method, pathStart, path, ErrorReasonIncompatbleType, "not a string, try another type")
	}
	return s
}

func (p *mapPinata) Contents() interface{} {
	return p.contents
}

func toSlice(first string, rest []string) []interface{} {
	slice := make([]interface{}, len(rest)+1)
	i := 0
	slice[i] = first
	for _, v := range rest {
		i++
		slice[i] = v
	}
	return slice
}
<commit_msg>don't need errorf methods any more<commit_after>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}.
package pinata

import (
	"bytes"
	"fmt"
)

// Pinata holds a value and offers methods for extracting data from it.
type Pinata interface {
	Contents() interface{}
	Error() error
	ClearError()
	StringAtPath(string, ...string) string
	String() string
	StringAtIndex(int) string
	PinataAtPath(string, ...string) Pinata
	PinataAtIndex(int) Pinata
}

// New creates a new Pinata. Instances returned are not thread safe.
func New(contents interface{}) Pinata {
	switch t := contents.(type) {
	default:
		return &otherPinata{contents: t}
	case map[string]interface{}:
		return &mapPinata{contents: t}
	case []interface{}:
		return &slicePinata{}
	}
}

var _ = error(PinataError{})

type ErrorReason string

const (
	ErrorReasonUnknown         ErrorReason = "unknown"
	ErrorReasonIncompatbleType             = "incompatible type"
	ErrorReasonNotFound                    = "not found"
	ErrorReasonInvalidInput                = "invalid input"
)

type PinataError struct {
	Reason ErrorReason
	Method string
	Input  []interface{}
	Advice string
}

func (p PinataError) Error() string {
	var input string
	if len(p.Input) > 0 {
		var buf bytes.Buffer
		for i := range p.Input {
			buf.WriteString("%#v")
			if i < len(p.Input)-1 {
				buf.WriteString(", ")
			}
		}
		input = fmt.Sprintf(buf.String(), p.Input...)
	}
	return fmt.Sprintf("pinata: %s(%s): %s - %s", p.Method, input, p.Reason, p.Advice)
}

type basePinata struct {
	err error
}

func (p *basePinata) Error() error {
	return p.err
}

func (p *basePinata) ClearError() {
	p.err = nil
}

func (p *basePinata) String() string {
	if p.err != nil {
		return ""
	}
	p.err = &PinataError{
		Method: "String",
		Reason: ErrorReasonIncompatbleType,
		Input:  nil,
		Advice: "call this method on a string pinata",
	}
	return ""
}

func (p *basePinata) PinataAtIndex(index int) Pinata {
	p.indexUnsupported("PinataAtIndex", index)
	return nil
}

func (p *basePinata) PinataAtPath(pathStart string, path ...string) Pinata {
	p.pathUnsupported("PinataAtPath", pathStart, path)
	return nil
}

func (p *basePinata) StringAtPath(pathStart string, path ...string) string {
	p.pathUnsupported("StringAtPath", pathStart, path)
	return ""
}

func (p *basePinata) StringAtIndex(index int) string {
	p.indexUnsupported("StringAtIndex", index)
	return ""
}

func (p *basePinata) Contents() interface{} {
	return nil
}

func (p *basePinata) indexUnsupported(method string, index int) {
	if p.err != nil {
		return
	}
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatbleType,
		Input:  []interface{}{index},
		Advice: "call this method on a slice pinata",
	}
}

func (p *basePinata) setIndexOutOfRange(method string, index int, contents []interface{}) bool {
	if index < 0 || index >= len(contents) {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  []interface{}{index},
			Advice: fmt.Sprintf("specify an index from 0 to %d", len(contents)-1),
		}
		return true
	}
	return false
}

func (p *basePinata) pathUnsupported(method, pathStart string, path []string) {
	if p.err != nil {
		return
	}
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatbleType,
		Input:  toSlice(pathStart, path),
		Advice: "call this method on a map pinata",
	}
}

type otherPinata struct {
	basePinata
	contents interface{}
}

func (p *otherPinata) String() string {
	if p.err != nil {
		return ""
	}
	if v, ok := p.contents.(string); ok {
		return v
	}
	return p.basePinata.String()
}

func (p *otherPinata) Contents() interface{} {
	return p.contents
}

type slicePinata struct {
	basePinata
	contents []interface{}
}

func (p *slicePinata) pinataAtIndex(method string, index int) Pinata {
	if p.err != nil {
		return nil
	}
	if p.setIndexOutOfRange(method, index, p.contents) {
		return nil
	}
	return New(p.contents[index])
}

func (p *slicePinata) PinataAtIndex(index int) Pinata {
	return p.pinataAtIndex("PinataAtIndex", index)
}

func (p *slicePinata) StringAtIndex(index int) string {
	const method = "StringAtIndex"
	pinata := p.pinataAtIndex(method, index)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatbleType,
			Input:  []interface{}{index},
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *slicePinata) Contents() interface{} {
	return p.contents
}

type mapPinata struct {
	basePinata
	contents map[string]interface{}
}

func (p *mapPinata) pinataAtPath(method, pathStart string, path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	if v, ok := p.contents[pathStart]; ok {
		//if v, ok := v.(map[string]interface{})
		currentPinata := New(v)
		rest := path
		for len(rest) > 0 {
			tmp := currentPinata.PinataAtPath(rest[0])
			rest = rest[1:len(rest)]
			if currentPinata.Error() != nil {
				// TODO need to customise the message based on the returned error
				//sofar := path[:len(path)-len(rest)]
				p.err = &PinataError{
					Method: method,
					Reason: ErrorReasonNotFound,
					Input:  toSlice(pathStart, path),
					Advice: "can't find that, sorry",
				}
				return nil
			}
			currentPinata = tmp
		}
		return currentPinata
	}
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonNotFound,
		Input:  toSlice(pathStart, path),
		Advice: fmt.Sprintf(`no "%s" in this pinata`, pathStart),
	}
	return nil
}

func (p *mapPinata) PinataAtPath(pathStart string, path ...string) Pinata {
	return p.pinataAtPath("PinataAtPath", pathStart, path...)
}

func (p *mapPinata) StringAtPath(pathStart string, path ...string) string {
	const method = "StringAtPath"
	pinata := p.pinataAtPath(method, pathStart, path...)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatbleType,
			Input:  toSlice(pathStart, path),
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *mapPinata) Contents() interface{} {
	return p.contents
}

func toSlice(first string, rest []string) []interface{} {
	slice := make([]interface{}, len(rest)+1)
	i := 0
	slice[i] = first
	for _, v := range rest {
		i++
		slice[i] = v
	}
	return slice
}
<|endoftext|>


<commit_before>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}.
package pinata

import (
	"bytes"
	"fmt"
	"strings"
)

// Pinata holds a value and offers methods for extracting data from it.
type Pinata interface {
	Contents() interface{}
	Error() error
	ClearError()
	StringAtPath(...string) string
	String() string
	StringAtIndex(int) string
	PinataAtPath(...string) Pinata
	PinataAtIndex(int) Pinata
}

// New creates a new Pinata. Instances returned are not thread safe.
func New(contents interface{}) Pinata {
	switch t := contents.(type) {
	default:
		return &otherPinata{contents: t}
	case map[string]interface{}:
		return &mapPinata{contents: t}
	case []interface{}:
		return &slicePinata{}
	}
}

var _ = error(PinataError{})

type ErrorReason string

const (
	ErrorReasonIncompatibleType ErrorReason = "incompatible type"
	ErrorReasonNotFound                     = "not found"
	ErrorReasonInvalidInput                 = "invalid input"
)

type PinataError struct {
	Reason ErrorReason
	Method string
	Input  []interface{}
	Advice string
}

func (p PinataError) Error() string {
	var input string
	if len(p.Input) > 0 {
		var buf bytes.Buffer
		for i := range p.Input {
			buf.WriteString("%#v")
			if i < len(p.Input)-1 {
				buf.WriteString(", ")
			}
		}
		input = fmt.Sprintf(buf.String(), p.Input...)
	}
	return fmt.Sprintf("pinata: %s(%s) - %s (%s)", p.Method, input, p.Reason, p.Advice)
}

type basePinata struct {
	err error
}

func (p *basePinata) Error() error {
	return p.err
}

func (p *basePinata) ClearError() {
	p.err = nil
}

func (p *basePinata) String() string {
	if p.err != nil {
		return ""
	}
	p.err = &PinataError{
		Method: "String",
		Reason: ErrorReasonIncompatibleType,
		Input:  nil,
		Advice: "call this method on a string pinata",
	}
	return ""
}

func (p *basePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	p.indexUnsupported("PinataAtIndex", index)
	return nil
}

func (p *basePinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	p.pathUnsupported("PinataAtPath", path)
	return nil
}

func (p *basePinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	p.pathUnsupported("StringAtPath", path)
	return ""
}

func (p *basePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	p.indexUnsupported("StringAtIndex", index)
	return ""
}

func (p *basePinata) Contents() interface{} {
	return nil // should always override this method
}

// this method assumes p.err != nil
func (p *basePinata) indexUnsupported(method string, index int) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  []interface{}{index},
		Advice: "call this method on a slice pinata",
	}
}

// this method assumes p.err != nil
func (p *basePinata) setIndexOutOfRange(method string, index int, contents []interface{}) bool {
	if index < 0 || index >= len(contents) {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  []interface{}{index},
			Advice: fmt.Sprintf("specify an index from 0 to %d", len(contents)-1),
		}
		return true
	}
	return false
}

// this method assumes p.err != nil
func (p *basePinata) pathUnsupported(method string, path []string) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  toInterfaceSlice(path),
		Advice: "call this method on a map pinata",
	}
}

type otherPinata struct {
	basePinata
	contents interface{}
}

func (p *otherPinata) String() string {
	if p.err != nil {
		return ""
	}
	if v, ok := p.contents.(string); ok {
		return v
	}
	return p.basePinata.String()
}

func (p *otherPinata) Contents() interface{} {
	return p.contents
}

type slicePinata struct {
	basePinata
	contents []interface{}
}

// this method assumes p.err != nil
func (p *slicePinata) pinataAtIndex(method string, index int) Pinata {
	if p.setIndexOutOfRange(method, index, p.contents) {
		return nil
	}
	return New(p.contents[index])
}

func (p *slicePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtIndex("PinataAtIndex", index)
}

func (p *slicePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtIndex"
	pinata := p.pinataAtIndex(method, index)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  []interface{}{index},
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *slicePinata) Contents() interface{} {
	return p.contents
}

type mapPinata struct {
	basePinata
	contents map[string]interface{}
}

// this method assumes p.err != nil
func (p *mapPinata) pinataAtPath(method string, path ...string) Pinata {
	if len(path) == 0 {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  toInterfaceSlice(path),
			Advice: "specify a path",
		}
		return nil
	}

	contents := p.contents
	for i := 0; i < len(path)-1; i++ {
		current := path[i]
		if v, ok := contents[current]; ok {
			if v, ok := v.(map[string]interface{}); ok {
				contents = v
			} else {
				p.err = &PinataError{
					Method: method,
					Reason: ErrorReasonIncompatibleType,
					Input:  toInterfaceSlice(path),
					Advice: fmt.Sprintf(`path "%s" does not hold a pinata`, strings.Join(path[:i+1], `", "`)),
				}
				return nil
			}
		} else {
			p.err = &PinataError{
				Method: method,
				Reason: ErrorReasonNotFound,
				Input:  toInterfaceSlice(path),
				Advice: fmt.Sprintf(`path "%s" does not exist`, strings.Join(path[:i+1], `", "`)),
			}
			return nil
		}
	}

	if v, ok := contents[path[len(path)-1]]; ok {
		return New(v)
	}

	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonNotFound,
		Input:  toInterfaceSlice(path),
		Advice: fmt.Sprintf(`path "%s" does not exist`, strings.Join(path, `", "`)),
	}
	return nil
}

func (p *mapPinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtPath("PinataAtPath", path...)
}

func (p *mapPinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtPath"
	pinata := p.pinataAtPath(method, path...)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  toInterfaceSlice(path),
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *mapPinata) Contents() interface{} {
	return p.contents
}

func toInterfaceSlice(c []string) []interface{} {
	ifaces := make([]interface{}, len(c))
	for i := range c {
		ifaces[i] = c[i]
	}
	return ifaces
}
<commit_msg>offer a terser error message for path errors<commit_after>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}.
package pinata

import (
	"bytes"
	"fmt"
	"strings"
)

// Pinata holds a value and offers methods for extracting data from it.
type Pinata interface {
	Contents() interface{}
	Error() error
	ClearError()
	StringAtPath(...string) string
	String() string
	StringAtIndex(int) string
	PinataAtPath(...string) Pinata
	PinataAtIndex(int) Pinata
}

// New creates a new Pinata. Instances returned are not thread safe.
func New(contents interface{}) Pinata {
	switch t := contents.(type) {
	default:
		return &otherPinata{contents: t}
	case map[string]interface{}:
		return &mapPinata{contents: t}
	case []interface{}:
		return &slicePinata{}
	}
}

var _ = error(PinataError{})

type ErrorReason string

const (
	ErrorReasonIncompatibleType ErrorReason = "incompatible type"
	ErrorReasonNotFound                     = "not found"
	ErrorReasonInvalidInput                 = "invalid input"
)

type PinataError struct {
	Reason ErrorReason
	Method string
	Input  []interface{}
	Advice string
}

func (p PinataError) Error() string {
	var input string
	if len(p.Input) > 0 {
		var buf bytes.Buffer
		for i := range p.Input {
			buf.WriteString("%#v")
			if i < len(p.Input)-1 {
				buf.WriteString(", ")
			}
		}
		input = fmt.Sprintf(buf.String(), p.Input...)
	}
	return fmt.Sprintf("pinata: %s(%s) - %s (%s)", p.Method, input, p.Reason, p.Advice)
}

type basePinata struct {
	err error
}

func (p *basePinata) Error() error {
	return p.err
}

func (p *basePinata) ClearError() {
	p.err = nil
}

func (p *basePinata) String() string {
	if p.err != nil {
		return ""
	}
	p.err = &PinataError{
		Method: "String",
		Reason: ErrorReasonIncompatibleType,
		Input:  nil,
		Advice: "call this method on a string pinata",
	}
	return ""
}

func (p *basePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	p.indexUnsupported("PinataAtIndex", index)
	return nil
}

func (p *basePinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	p.pathUnsupported("PinataAtPath", path)
	return nil
}

func (p *basePinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	p.pathUnsupported("StringAtPath", path)
	return ""
}

func (p *basePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	p.indexUnsupported("StringAtIndex", index)
	return ""
}

func (p *basePinata) Contents() interface{} {
	return nil // should always override this method
}

// this method assumes p.err != nil
func (p *basePinata) indexUnsupported(method string, index int) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  []interface{}{index},
		Advice: "call this method on a slice pinata",
	}
}

// this method assumes p.err != nil
func (p *basePinata) setIndexOutOfRange(method string, index int, contents []interface{}) bool {
	if index < 0 || index >= len(contents) {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  []interface{}{index},
			Advice: fmt.Sprintf("specify an index from 0 to %d", len(contents)-1),
		}
		return true
	}
	return false
}

// this method assumes p.err != nil
func (p *basePinata) pathUnsupported(method string, path []string) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  toInterfaceSlice(path),
		Advice: "call this method on a map pinata",
	}
}

type otherPinata struct {
	basePinata
	contents interface{}
}

func (p *otherPinata) String() string {
	if p.err != nil {
		return ""
	}
	if v, ok := p.contents.(string); ok {
		return v
	}
	return p.basePinata.String()
}

func (p *otherPinata) Contents() interface{} {
	return p.contents
}

type slicePinata struct {
	basePinata
	contents []interface{}
}

// this method assumes p.err != nil
func (p *slicePinata) pinataAtIndex(method string, index int) Pinata {
	if p.setIndexOutOfRange(method, index, p.contents) {
		return nil
	}
	return New(p.contents[index])
}

func (p *slicePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtIndex("PinataAtIndex", index)
}

func (p *slicePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtIndex"
	pinata := p.pinataAtIndex(method, index)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  []interface{}{index},
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *slicePinata) Contents() interface{} {
	return p.contents
}

type mapPinata struct {
	basePinata
	contents map[string]interface{}
}

// this method assumes p.err != nil
func (p *mapPinata) pinataAtPath(method string, path ...string) Pinata {
	if len(path) == 0 {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  toInterfaceSlice(path),
			Advice: "specify a path",
		}
		return nil
	}

	contents := p.contents
	for i := 0; i < len(path)-1; i++ {
		current := path[i]
		if v, ok := contents[current]; ok {
			if v, ok := v.(map[string]interface{}); ok {
				contents = v
			} else {
				p.err = &PinataError{
					Method: method,
					Reason: ErrorReasonIncompatibleType,
					Input:  toInterfaceSlice(path),
					Advice: fmt.Sprintf(`"%s" does not hold a pinata`, strings.Join(path[:i+1], `", "`)),
				}
				return nil
			}
		} else {
			p.err = &PinataError{
				Method: method,
				Reason: ErrorReasonNotFound,
				Input:  toInterfaceSlice(path),
				Advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path[:i+1], `", "`)),
			}
			return nil
		}
	}

	if v, ok := contents[path[len(path)-1]]; ok {
		return New(v)
	}

	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonNotFound,
		Input:  toInterfaceSlice(path),
		Advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path, `", "`)),
	}
	return nil
}

func (p *mapPinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtPath("PinataAtPath", path...)
}

func (p *mapPinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtPath"
	pinata := p.pinataAtPath(method, path...)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  toInterfaceSlice(path),
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *mapPinata) Contents() interface{} {
	return p.contents
}

func toInterfaceSlice(c []string) []interface{} {
	ifaces := make([]interface{}, len(c))
	for i := range c {
		ifaces[i] = c[i]
	}
	return ifaces
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hellofs

import (
	"io"
	"os"
	"strings"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/fuseutil"
)

// Create a file system with a fixed structure that looks like this:
//
//     hello
//     dir/
//         world
//
// Each file contains the string "Hello, world!".
func NewHelloFS(clock timeutil.Clock) (server fuse.Server, err error) {
	fs := &helloFS{
		Clock: clock,
	}

	server = fuseutil.NewFileSystemServer(fs)
	return
}

type helloFS struct {
	fuseutil.NotImplementedFileSystem

	Clock timeutil.Clock
}

const (
	rootInode fuseops.InodeID = fuseops.RootInodeID + iota
	helloInode
	dirInode
	worldInode
)

type inodeInfo struct {
	attributes fuseops.InodeAttributes

	// File or directory?
	dir bool

	// For directories, children.
	children []fuseutil.Dirent
}

// We have a fixed directory structure.
var gInodeInfo = map[fuseops.InodeID]inodeInfo{
	// root
	rootInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0555 | os.ModeDir,
		},
		dir: true,
		children: []fuseutil.Dirent{
			fuseutil.Dirent{
				Offset: 1,
				Inode:  helloInode,
				Name:   "hello",
				Type:   fuseutil.DT_File,
			},
			fuseutil.Dirent{
				Offset: 2,
				Inode:  dirInode,
				Name:   "dir",
				Type:   fuseutil.DT_Directory,
			},
		},
	},

	// hello
	helloInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0444,
			Size:  uint64(len("Hello, world!")),
		},
	},

	// dir
	dirInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0555 | os.ModeDir,
		},
		dir: true,
		children: []fuseutil.Dirent{
			fuseutil.Dirent{
				Offset: 1,
				Inode:  worldInode,
				Name:   "world",
				Type:   fuseutil.DT_File,
			},
		},
	},

	// world
	worldInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0444,
			Size:  uint64(len("Hello, world!")),
		},
	},
}

func findChildInode(
	name string,
	children []fuseutil.Dirent) (inode fuseops.InodeID, err error) {
	for _, e := range children {
		if e.Name == name {
			inode = e.Inode
			return
		}
	}

	err = fuse.ENOENT
	return
}

func (fs *helloFS) patchAttributes(
	attr *fuseops.InodeAttributes) {
	now := fs.Clock.Now()
	attr.Atime = now
	attr.Mtime = now
	attr.Crtime = now
}

func (fs *helloFS) Init(op *fuseops.InitOp) (err error) {
	return
}

func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) (err error) {
	// Find the info for the parent.
	parentInfo, ok := gInodeInfo[op.Parent]
	if !ok {
		err = fuse.ENOENT
		return
	}

	// Find the child within the parent.
	childInode, err := findChildInode(op.Name, parentInfo.children)
	if err != nil {
		return
	}

	// Copy over information.
	op.Entry.Child = childInode
	op.Entry.Attributes = gInodeInfo[childInode].attributes

	// Patch attributes.
	fs.patchAttributes(&op.Entry.Attributes)

	return
}

func (fs *helloFS) GetInodeAttributes(
	op *fuseops.GetInodeAttributesOp) (err error) {
	// Find the info for this inode.
	info, ok := gInodeInfo[op.Inode]
	if !ok {
		err = fuse.ENOENT
		return
	}

	// Copy over its attributes.
	op.Attributes = info.attributes

	// Patch attributes.
	fs.patchAttributes(&op.Attributes)

	return
}

func (fs *helloFS) OpenDir(
	op *fuseops.OpenDirOp) (err error) {
	// Allow opening any directory.
	return
}

func (fs *helloFS) ReadDir(
	op *fuseops.ReadDirOp) (err error) {
	// Find the info for this inode.
	info, ok := gInodeInfo[op.Inode]
	if !ok {
		err = fuse.ENOENT
		return
	}

	if !info.dir {
		err = fuse.EIO
		return
	}

	entries := info.children

	// Grab the range of interest.
	if op.Offset > fuseops.DirOffset(len(entries)) {
		err = fuse.EIO
		return
	}

	entries = entries[op.Offset:]

	// Resume at the specified offset into the array.
	for _, e := range entries {
		op.Data = fuseutil.AppendDirent(op.Data, e)
		if len(op.Data) > op.Size {
			op.Data = op.Data[:op.Size]
			break
		}
	}

	return
}

func (fs *helloFS) OpenFile(
	op *fuseops.OpenFileOp) (err error) {
	// Allow opening any file.
	return
}

func (fs *helloFS) ReadFile(
	op *fuseops.ReadFileOp) (err error) {
	// Let io.ReaderAt deal with the semantics.
	reader := strings.NewReader("Hello, world!")

	op.Data = make([]byte, op.Size)
	n, err := reader.ReadAt(op.Data, op.Offset)
	op.Data = op.Data[:n]

	// Special case: FUSE doesn't expect us to return io.EOF.
	if err == io.EOF {
		err = nil
	}

	return
}
<commit_msg>Fixed hellofs.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hellofs

import (
	"io"
	"os"
	"strings"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/fuseutil"
)

// Create a file system with a fixed structure that looks like this:
//
//     hello
//     dir/
//         world
//
// Each file contains the string "Hello, world!".
func NewHelloFS(clock timeutil.Clock) (server fuse.Server, err error) {
	fs := &helloFS{
		Clock: clock,
	}

	server = fuseutil.NewFileSystemServer(fs)
	return
}

type helloFS struct {
	fuseutil.NotImplementedFileSystem

	Clock timeutil.Clock
}

const (
	rootInode fuseops.InodeID = fuseops.RootInodeID + iota
	helloInode
	dirInode
	worldInode
)

type inodeInfo struct {
	attributes fuseops.InodeAttributes

	// File or directory?
	dir bool

	// For directories, children.
	children []fuseutil.Dirent
}

// We have a fixed directory structure.
var gInodeInfo = map[fuseops.InodeID]inodeInfo{
	// root
	rootInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0555 | os.ModeDir,
		},
		dir: true,
		children: []fuseutil.Dirent{
			fuseutil.Dirent{
				Offset: 1,
				Inode:  helloInode,
				Name:   "hello",
				Type:   fuseutil.DT_File,
			},
			fuseutil.Dirent{
				Offset: 2,
				Inode:  dirInode,
				Name:   "dir",
				Type:   fuseutil.DT_Directory,
			},
		},
	},

	// hello
	helloInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0444,
			Size:  uint64(len("Hello, world!")),
		},
	},

	// dir
	dirInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0555 | os.ModeDir,
		},
		dir: true,
		children: []fuseutil.Dirent{
			fuseutil.Dirent{
				Offset: 1,
				Inode:  worldInode,
				Name:   "world",
				Type:   fuseutil.DT_File,
			},
		},
	},

	// world
	worldInode: inodeInfo{
		attributes: fuseops.InodeAttributes{
			Nlink: 1,
			Mode:  0444,
			Size:  uint64(len("Hello, world!")),
		},
	},
}

func findChildInode(
	name string,
	children []fuseutil.Dirent) (inode fuseops.InodeID, err error) {
	for _, e := range children {
		if e.Name == name {
			inode = e.Inode
			return
		}
	}

	err = fuse.ENOENT
	return
}

func (fs *helloFS) patchAttributes(
	attr *fuseops.InodeAttributes) {
	now := fs.Clock.Now()
	attr.Atime = now
	attr.Mtime = now
	attr.Crtime = now
}

func (fs *helloFS) Init(op *fuseops.InitOp) {
	var err error
	defer func() { op.Respond(err) }()

	return
}

func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) {
	var err error
	defer func() { op.Respond(err) }()

	// Find the info for the parent.
	parentInfo, ok := gInodeInfo[op.Parent]
	if !ok {
		err = fuse.ENOENT
		return
	}

	// Find the child within the parent.
	childInode, err := findChildInode(op.Name, parentInfo.children)
	if err != nil {
		return
	}

	// Copy over information.
	op.Entry.Child = childInode
	op.Entry.Attributes = gInodeInfo[childInode].attributes

	// Patch attributes.
	fs.patchAttributes(&op.Entry.Attributes)

	return
}

func (fs *helloFS) GetInodeAttributes(
	op *fuseops.GetInodeAttributesOp) {
	var err error
	defer func() { op.Respond(err) }()

	// Find the info for this inode.
	info, ok := gInodeInfo[op.Inode]
	if !ok {
		err = fuse.ENOENT
		return
	}

	// Copy over its attributes.
	op.Attributes = info.attributes

	// Patch attributes.
	fs.patchAttributes(&op.Attributes)

	return
}

func (fs *helloFS) OpenDir(
	op *fuseops.OpenDirOp) {
	var err error
	defer func() { op.Respond(err) }()

	// Allow opening any directory.
	return
}

func (fs *helloFS) ReadDir(
	op *fuseops.ReadDirOp) {
	var err error
	defer func() { op.Respond(err) }()

	// Find the info for this inode.
	info, ok := gInodeInfo[op.Inode]
	if !ok {
		err = fuse.ENOENT
		return
	}

	if !info.dir {
		err = fuse.EIO
		return
	}

	entries := info.children

	// Grab the range of interest.
	if op.Offset > fuseops.DirOffset(len(entries)) {
		err = fuse.EIO
		return
	}

	entries = entries[op.Offset:]

	// Resume at the specified offset into the array.
	for _, e := range entries {
		op.Data = fuseutil.AppendDirent(op.Data, e)
		if len(op.Data) > op.Size {
			op.Data = op.Data[:op.Size]
			break
		}
	}

	return
}

func (fs *helloFS) OpenFile(
	op *fuseops.OpenFileOp) {
	var err error
	defer func() { op.Respond(err) }()

	// Allow opening any file.
	return
}

func (fs *helloFS) ReadFile(
	op *fuseops.ReadFileOp) {
	var err error
	defer func() { op.Respond(err) }()

	// Let io.ReaderAt deal with the semantics.
	reader := strings.NewReader("Hello, world!")

	op.Data = make([]byte, op.Size)
	n, err := reader.ReadAt(op.Data, op.Offset)
	op.Data = op.Data[:n]

	// Special case: FUSE doesn't expect us to return io.EOF.
	if err == io.EOF {
		err = nil
	}

	return
}
<|endoftext|>


<commit_before>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}.
package pinata

import (
	"bytes"
	"fmt"
	"strings"
)

// Pinata holds a value and offers methods for extracting data from it.
type Pinata interface {
	Contents() interface{}
	Error() error
	ClearError()
	StringAtPath(...string) string
	String() string
	StringAtIndex(int) string
	PinataAtPath(...string) Pinata
	PinataAtIndex(int) Pinata
}

// New creates a new Pinata. Instances returned are not thread safe.
func New(contents interface{}) Pinata {
	switch t := contents.(type) {
	default:
		return &otherPinata{contents: t}
	case map[string]interface{}:
		return &mapPinata{contents: t}
	case []interface{}:
		return &slicePinata{}
	}
}

var _ = error(PinataError{})

// ErrorReason describes the reason for returning a PinataError.
type ErrorReason string

const (
	// ErrorReasonIncompatibleType indicates the contents of the Pinata is not compatible with the invoked method.
	ErrorReasonIncompatibleType ErrorReason = "incompatible type"
	// ErrorReasonNotFound indicates the input has not been found in the Pinata.
	ErrorReasonNotFound = "not found"
	// ErrorReasonInvalidInput indicates the input is not in the expected range or format.
	ErrorReasonInvalidInput = "invalid input"
)

// PinataError is set on the Pinata if something goes wrong.
type PinataError struct {
	Reason ErrorReason
	Method string
	Input  []interface{}
	Advice string
}

func (p PinataError) Error() string {
	var input string
	if len(p.Input) > 0 {
		var buf bytes.Buffer
		for i := range p.Input {
			buf.WriteString("%#v")
			if i < len(p.Input)-1 {
				buf.WriteString(", ")
			}
		}
		input = fmt.Sprintf(buf.String(), p.Input...)
	}
	return fmt.Sprintf("pinata: %s(%s) - %s (%s)", p.Method, input, p.Reason, p.Advice)
}

type basePinata struct {
	err error
}

func (p *basePinata) Error() error {
	return p.err
}

func (p *basePinata) ClearError() {
	p.err = nil
}

func (p *basePinata) String() string {
	if p.err != nil {
		return ""
	}
	p.err = &PinataError{
		Method: "String",
		Reason: ErrorReasonIncompatibleType,
		Input:  nil,
		Advice: "call this method on a string pinata",
	}
	return ""
}

func (p *basePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	p.indexUnsupported("PinataAtIndex", index)
	return nil
}

func (p *basePinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	p.pathUnsupported("PinataAtPath", path)
	return nil
}

func (p *basePinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	p.pathUnsupported("StringAtPath", path)
	return ""
}

func (p *basePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	p.indexUnsupported("StringAtIndex", index)
	return ""
}

func (p *basePinata) Contents() interface{} {
	return nil // should always override this method
}

// this method assumes p.err != nil
func (p *basePinata) indexUnsupported(method string, index int) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  []interface{}{index},
		Advice: "call this method on a slice pinata",
	}
}

// this method assumes p.err != nil
func (p *basePinata) setIndexOutOfRange(method string, index int, contents []interface{}) bool {
	if index < 0 || index >= len(contents) {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  []interface{}{index},
			Advice: fmt.Sprintf("specify an index from 0 to %d", len(contents)-1),
		}
		return true
	}
	return false
}

// this method assumes p.err != nil
func (p *basePinata) pathUnsupported(method string, path []string) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  toInterfaceSlice(path),
		Advice: "call this method on a map pinata",
	}
}

type otherPinata struct {
	basePinata
	contents interface{}
}

func (p *otherPinata) String() string {
	if p.err != nil {
		return ""
	}
	if v, ok := p.contents.(string); ok {
		return v
	}
	return p.basePinata.String()
}

func (p *otherPinata) Contents() interface{} {
	return p.contents
}

type slicePinata struct {
	basePinata
	contents []interface{}
}

// this method assumes p.err != nil
func (p *slicePinata) pinataAtIndex(method string, index int) Pinata {
	if p.setIndexOutOfRange(method, index, p.contents) {
		return nil
	}
	return New(p.contents[index])
}

func (p *slicePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtIndex("PinataAtIndex", index)
}

func (p *slicePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtIndex"
	pinata := p.pinataAtIndex(method, index)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  []interface{}{index},
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *slicePinata) Contents() interface{} {
	return p.contents
}

type mapPinata struct {
	basePinata
	contents map[string]interface{}
}

// this method assumes p.err != nil
func (p *mapPinata) pinataAtPath(method string, path ...string) Pinata {
	if len(path) == 0 {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  toInterfaceSlice(path),
			Advice: "specify a path",
		}
		return nil
	}

	contents := p.contents
	for i := 0; i < len(path)-1; i++ {
		current := path[i]
		if v, ok := contents[current]; ok {
			if v, ok := v.(map[string]interface{}); ok {
				contents = v
			} else {
				p.err = &PinataError{
					Method: method,
					Reason: ErrorReasonIncompatibleType,
					Input:  toInterfaceSlice(path),
					Advice: fmt.Sprintf(`"%s" does not hold a pinata`, strings.Join(path[:i+1], `", "`)),
				}
				return nil
			}
		} else {
			p.err = &PinataError{
				Method: method,
				Reason: ErrorReasonNotFound,
				Input:  toInterfaceSlice(path),
				Advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path[:i+1], `", "`)),
			}
			return nil
		}
	}

	if v, ok := contents[path[len(path)-1]]; ok {
		return New(v)
	}

	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonNotFound,
		Input:  toInterfaceSlice(path),
		Advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path, `", "`)),
	}
	return nil
}

func (p *mapPinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtPath("PinataAtPath", path...)
}

func (p *mapPinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtPath"
	pinata := p.pinataAtPath(method, path...)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  toInterfaceSlice(path),
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *mapPinata) Contents() interface{} {
	return p.contents
}

func toInterfaceSlice(c []string) []interface{} {
	ifaces := make([]interface{}, len(c))
	for i := range c {
		ifaces[i] = c[i]
	}
	return ifaces
}
<commit_msg>address errcheck warnings<commit_after>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}.
package pinata

import (
	"bytes"
	"fmt"
	"strings"
)

// Pinata holds a value and offers methods for extracting data from it.
type Pinata interface {
	Contents() interface{}
	Error() error
	ClearError()
	StringAtPath(...string) string
	String() string
	StringAtIndex(int) string
	PinataAtPath(...string) Pinata
	PinataAtIndex(int) Pinata
}

// New creates a new Pinata. Instances returned are not thread safe.
func New(contents interface{}) Pinata {
	switch t := contents.(type) {
	default:
		return &otherPinata{contents: t}
	case map[string]interface{}:
		return &mapPinata{contents: t}
	case []interface{}:
		return &slicePinata{}
	}
}

var _ = error(PinataError{})

// ErrorReason describes the reason for returning a PinataError.
type ErrorReason string

const (
	// ErrorReasonIncompatibleType indicates the contents of the Pinata is not compatible with the invoked method.
	ErrorReasonIncompatibleType ErrorReason = "incompatible type"
	// ErrorReasonNotFound indicates the input has not been found in the Pinata.
	ErrorReasonNotFound = "not found"
	// ErrorReasonInvalidInput indicates the input is not in the expected range or format.
	ErrorReasonInvalidInput = "invalid input"
)

// PinataError is set on the Pinata if something goes wrong.
type PinataError struct {
	Reason ErrorReason
	Method string
	Input  []interface{}
	Advice string
}

func (p PinataError) Error() string {
	var input string
	if len(p.Input) > 0 {
		var buf bytes.Buffer
		for i := range p.Input {
			_, _ = buf.WriteString("%#v")
			if i < len(p.Input)-1 {
				_, _ = buf.WriteString(", ")
			}
		}
		input = fmt.Sprintf(buf.String(), p.Input...)
	}
	return fmt.Sprintf("pinata: %s(%s) - %s (%s)", p.Method, input, p.Reason, p.Advice)
}

type basePinata struct {
	err error
}

func (p *basePinata) Error() error {
	return p.err
}

func (p *basePinata) ClearError() {
	p.err = nil
}

func (p *basePinata) String() string {
	if p.err != nil {
		return ""
	}
	p.err = &PinataError{
		Method: "String",
		Reason: ErrorReasonIncompatibleType,
		Input:  nil,
		Advice: "call this method on a string pinata",
	}
	return ""
}

func (p *basePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	p.indexUnsupported("PinataAtIndex", index)
	return nil
}

func (p *basePinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	p.pathUnsupported("PinataAtPath", path)
	return nil
}

func (p *basePinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	p.pathUnsupported("StringAtPath", path)
	return ""
}

func (p *basePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	p.indexUnsupported("StringAtIndex", index)
	return ""
}

func (p *basePinata) Contents() interface{} {
	return nil // should always override this method
}

// this method assumes p.err != nil
func (p *basePinata) indexUnsupported(method string, index int) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  []interface{}{index},
		Advice: "call this method on a slice pinata",
	}
}

// this method assumes p.err != nil
func (p *basePinata) setIndexOutOfRange(method string, index int, contents []interface{}) bool {
	if index < 0 || index >= len(contents) {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  []interface{}{index},
			Advice: fmt.Sprintf("specify an index from 0 to %d", len(contents)-1),
		}
		return true
	}
	return false
}

// this method assumes p.err != nil
func (p *basePinata) pathUnsupported(method string, path []string) {
	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonIncompatibleType,
		Input:  toInterfaceSlice(path),
		Advice: "call this method on a map pinata",
	}
}

type otherPinata struct {
	basePinata
	contents interface{}
}

func (p *otherPinata) String() string {
	if p.err != nil {
		return ""
	}
	if v, ok := p.contents.(string); ok {
		return v
	}
	return p.basePinata.String()
}

func (p *otherPinata) Contents() interface{} {
	return p.contents
}

type slicePinata struct {
	basePinata
	contents []interface{}
}

// this method assumes p.err != nil
func (p *slicePinata) pinataAtIndex(method string, index int) Pinata {
	if p.setIndexOutOfRange(method, index, p.contents) {
		return nil
	}
	return New(p.contents[index])
}

func (p *slicePinata) PinataAtIndex(index int) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtIndex("PinataAtIndex", index)
}

func (p *slicePinata) StringAtIndex(index int) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtIndex"
	pinata := p.pinataAtIndex(method, index)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  []interface{}{index},
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *slicePinata) Contents() interface{} {
	return p.contents
}

type mapPinata struct {
	basePinata
	contents map[string]interface{}
}

// this method assumes p.err != nil
func (p *mapPinata) pinataAtPath(method string, path ...string) Pinata {
	if len(path) == 0 {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonInvalidInput,
			Input:  toInterfaceSlice(path),
			Advice: "specify a path",
		}
		return nil
	}

	contents := p.contents
	for i := 0; i < len(path)-1; i++ {
		current := path[i]
		if v, ok := contents[current]; ok {
			if v, ok := v.(map[string]interface{}); ok {
				contents = v
			} else {
				p.err = &PinataError{
					Method: method,
					Reason: ErrorReasonIncompatibleType,
					Input:  toInterfaceSlice(path),
					Advice: fmt.Sprintf(`"%s" does not hold a pinata`, strings.Join(path[:i+1], `", "`)),
				}
				return nil
			}
		} else {
			p.err = &PinataError{
				Method: method,
				Reason: ErrorReasonNotFound,
				Input:  toInterfaceSlice(path),
				Advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path[:i+1], `", "`)),
			}
			return nil
		}
	}

	if v, ok := contents[path[len(path)-1]]; ok {
		return New(v)
	}

	p.err = &PinataError{
		Method: method,
		Reason: ErrorReasonNotFound,
		Input:  toInterfaceSlice(path),
		Advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path, `", "`)),
	}
	return nil
}

func (p *mapPinata) PinataAtPath(path ...string) Pinata {
	if p.err != nil {
		return nil
	}
	return p.pinataAtPath("PinataAtPath", path...)
}

func (p *mapPinata) StringAtPath(path ...string) string {
	if p.err != nil {
		return ""
	}
	const method = "StringAtPath"
	pinata := p.pinataAtPath(method, path...)
	if p.err != nil {
		return ""
	}
	s := pinata.String()
	if pinata.Error() != nil {
		p.err = &PinataError{
			Method: method,
			Reason: ErrorReasonIncompatibleType,
			Input:  toInterfaceSlice(path),
			Advice: "not a string, try another type",
		}
	}
	return s
}

func (p *mapPinata) Contents() interface{} {
	return p.contents
}

func toInterfaceSlice(c []string) []interface{} {
	ifaces := make([]interface{}, len(c))
	for i := range c {
		ifaces[i] = c[i]
	}
	return ifaces
}
<|endoftext|>


<commit_before>// Broadcast over channels.
package bcast

/*
   bcast package for Go. Broadcasting on a set of channels.
   Copyright © 2013 Alexander I.Grafov <grafov@gmail.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see {http://www.gnu.org/licenses/}.
*/

import (
	// 	h "github.com/emicklei/hopwatch"
	"time"
)

// Internal structure to pack messages together wit info about sender.
type Message struct {
	sender  *chan interface{}
	payload interface{}
}

// Represents member of broadcast group.
type Member struct {
	group *Group            // send messages to others directly to group.In
	In    *chan interface{} // get messages from others to own channel
}

// Represents broadcast group.
type Group struct {
	in  *chan Message       // receive broadcasts from members
	out []*chan interface{} // broadcast messages to members
}

// Create new broadcast group.
func NewGroup() *Group {
	in := make(chan Message)
	return &Group{in: &in}
}

// Broadcast messages received from one group member to others.
// If incoming messages not arrived during `timeout` then function returns.
// Set `timeout` to zero to set unlimited timeout or use Broadcasting().
func (r *Group) BroadcastingTimeout(timeout time.Duration) {
	for {
		select {
		case received := <-*r.in:
			switch received.payload.(type) {
			case Member: // unjoining member

				for i, addr := range r.out {
					if addr == received.payload.(Member).In && received.sender == received.payload.(Member).In {
						r.out = append(r.out[:i], r.out[i+1:]...)
						break
					}
				}
			default: // receive payload and broadcast it

				for _, member := range r.out {
					if *received.sender != *member { // not return broadcast to sender

						go func(out *chan interface{}, received *Message) { // non blocking
							*out <- received.payload
						}(member, &received)

					}
				}
			}
		case <-time.After(timeout):
			if timeout > 0 {
				return
			}
		}
	}
}

// Join new member to broadcast.
func (r *Group) Join() *Member {
	out := make(chan interface{})
	r.out = append(r.out, &out)
	return &Member{group: r, In: &out}
}

// Unjoin member from broadcast group.
func (r *Member) Close() {
	*r.group.in <- Message{sender: r.In, payload: *r} // broadcasting of self means member closing
}

// Broadcast Message to others.
func (r *Member) Send(val interface{}) {
	*r.group.in <- Message{sender: r.In, payload: val}
}

// Get broadcast Message.
// As alternative you may get it from `In` channel.
func (r *Member) Recv() interface{} {
	return <-*r.In
}
<commit_msg>Wrong rename fixed.<commit_after>// Broadcast over channels.
package bcast

/*
   bcast package for Go. Broadcasting on a set of channels.
   Copyright © 2013 Alexander I.Grafov <grafov@gmail.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see {http://www.gnu.org/licenses/}.
*/

import (
	// 	h "github.com/emicklei/hopwatch"
	"time"
)

// Internal structure to pack messages together wit info about sender.
type Message struct {
	sender  *chan interface{}
	payload interface{}
}

// Represents member of broadcast group.
type Member struct {
	group *Group            // send messages to others directly to group.In
	In    *chan interface{} // get messages from others to own channel
}

// Represents broadcast group.
type Group struct {
	in  *chan Message       // receive broadcasts from members
	out []*chan interface{} // broadcast messages to members
}

// Create new broadcast group.
func NewGroup() *Group {
	in := make(chan Message)
	return &Group{in: &in}
}

// Broadcast messages received from one group member to others.
// If incoming messages not arrived during `timeout` then function returns.
// Set `timeout` to zero to set unlimited timeout or use Broadcasting().
func (r *Group) Broadcasting(timeout time.Duration) {
	for {
		select {
		case received := <-*r.in:
			switch received.payload.(type) {
			case Member: // unjoining member

				for i, addr := range r.out {
					if addr == received.payload.(Member).In && received.sender == received.payload.(Member).In {
						r.out = append(r.out[:i], r.out[i+1:]...)
						break
					}
				}
			default: // receive payload and broadcast it

				for _, member := range r.out {
					if *received.sender != *member { // not return broadcast to sender

						go func(out *chan interface{}, received *Message) { // non blocking
							*out <- received.payload
						}(member, &received)

					}
				}
			}
		case <-time.After(timeout):
			if timeout > 0 {
				return
			}
		}
	}
}

// Join new member to broadcast.
func (r *Group) Join() *Member {
	out := make(chan interface{})
	r.out = append(r.out, &out)
	return &Member{group: r, In: &out}
}

// Unjoin member from broadcast group.
func (r *Member) Close() {
	*r.group.in <- Message{sender: r.In, payload: *r} // broadcasting of self means member closing
}

// Broadcast Message to others.
func (r *Member) Send(val interface{}) {
	*r.group.in <- Message{sender: r.In, payload: val}
}

// Get broadcast Message.
// As alternative you may get it from `In` channel.
func (r *Member) Recv() interface{} {
	return <-*r.In
}
<|endoftext|>


<commit_before>package common

import (
	"regexp"
	"strings"

	"github.com/webx-top/com"
	"github.com/webx-top/db"
	"github.com/webx-top/db/lib/factory"
	mysqlUtil "github.com/webx-top/db/lib/factory/mysql"
	"github.com/webx-top/db/mysql"
	"github.com/webx-top/echo"
)

func SQLLineParser(exec func(string) error) func(string) error {
	var sqlStr string
	return func(line string) error {
		if strings.HasPrefix(line, `--`) {
			return nil
		}
		line = strings.TrimRight(line, "\r ")
		if strings.HasPrefix(line, `/*`) && strings.HasSuffix(line, `*/;`) {
			return nil
		}
		sqlStr += line
		if strings.HasSuffix(line, `;`) {
			defer func() {
				sqlStr = ``
			}()
			//println(sqlStr)
			if sqlStr == `;` {
				return nil
			}
			return exec(sqlStr)
		}
		sqlStr += "\n"
		return nil
	}
}

func ParseSQL(sqlFile string, isFile bool, installer func(string) error) (err error) {
	installFunction := SQLLineParser(installer)
	if isFile {
		return com.SeekFileLines(sqlFile, installFunction)
	}
	sqlContent := sqlFile
	for _, line := range strings.Split(sqlContent, "\n") {
		err = installFunction(line)
		if err != nil {
			return err
		}
	}
	return err
}

// ReplacePrefix 替换前缀数据
func ReplacePrefix(m factory.Model, field string, oldPrefix string, newPrefix string) error {
	oldPrefix = com.AddSlashes(oldPrefix, '_', '%')
	value := db.Raw("REPLACE(`"+field+"`, ?, ?)", oldPrefix, newPrefix)
	return m.SetField(nil, field, value, field, db.Like(oldPrefix+`%`))
}

var (
	sqlCharsetRegexp     = regexp.MustCompile(`(?i) (CHARACTER SET |CHARSET=)utf8mb4 `)
	sqlCollateRegexp     = regexp.MustCompile(`(?i) (COLLATE[= ])utf8mb4_general_ci`)
	sqlCreateTableRegexp = regexp.MustCompile(`(?i)^CREATE TABLE `)
	mysqlNetworkRegexp   = regexp.MustCompile(`^[/]{2,}`)
)

// ReplaceCharset 替换DDL语句中的字符集
func ReplaceCharset(sqlStr string, charset string, checkCreateDDL ...bool) string {
	if charset == `utf8mb4` {
		return sqlStr
	}
	if len(checkCreateDDL) > 0 && checkCreateDDL[0] {
		if !sqlCreateTableRegexp.MatchString(sqlStr) {
			return sqlStr
		}
	}
	sqlStr = sqlCharsetRegexp.ReplaceAllString(sqlStr, ` ${1}`+charset+` `)
	sqlStr = sqlCollateRegexp.ReplaceAllString(sqlStr, ` ${1}`+charset+`_general_ci`)
	return sqlStr
}

func ParseMysqlConnectionURL(settings *mysql.ConnectionURL) {
	if strings.HasPrefix(settings.Host, `unix:`) {
		settings.Socket = strings.TrimPrefix(settings.Host, `unix:`)
		settings.Socket = mysqlNetworkRegexp.ReplaceAllString(settings.Socket, `/`)
		settings.Host = ``
	}
}

func SelectPageCond(ctx echo.Context, cond *db.Compounds, pkAndLabelFields ...string) {
	pk := `id`
	lb := `name`
	switch len(pkAndLabelFields) {
	case 2:
		if len(pkAndLabelFields[1]) > 0 {
			lb = pkAndLabelFields[1]
		}
		fallthrough
	case 1:
		if len(pkAndLabelFields[0]) > 0 {
			pk = pkAndLabelFields[0]
		}
	}
	searchValue := ctx.Formx(`searchValue`).String()
	if len(searchValue) > 0 {
		cond.AddKV(pk, searchValue)
	} else {
		keywords := ctx.FormValues(`q_word[]`)
		q := strings.Join(keywords, ` `)
		if len(q) == 0 {
			q = ctx.Formx(`q`).String()
		}
		if len(q) > 0 {
			cond.From(mysqlUtil.SearchField(lb, q))
		}
	}
}
<commit_msg>update<commit_after>package common

import (
	"regexp"
	"strings"

	"github.com/webx-top/com"
	"github.com/webx-top/db"
	"github.com/webx-top/db/lib/factory"
	mysqlUtil "github.com/webx-top/db/lib/factory/mysql"
	"github.com/webx-top/db/mysql"
	"github.com/webx-top/echo"
)

func SQLLineParser(exec func(string) error) func(string) error {
	var sqlStr string
	return func(line string) error {
		if strings.HasPrefix(line, `--`) {
			return nil
		}
		line = strings.TrimRight(line, "\r ")
		if strings.HasPrefix(line, `/*`) && strings.HasSuffix(line, `*/;`) {
			return nil
		}
		sqlStr += line
		if strings.HasSuffix(line, `;`) {
			defer func() {
				sqlStr = ``
			}()
			//println(sqlStr)
			if sqlStr == `;` {
				return nil
			}
			return exec(sqlStr)
		}
		sqlStr += "\n"
		return nil
	}
}

func ParseSQL(sqlFile string, isFile bool, installer func(string) error) (err error) {
	installFunction := SQLLineParser(installer)
	if isFile {
		return com.SeekFileLines(sqlFile, installFunction)
	}
	sqlContent := sqlFile
	for _, line := range strings.Split(sqlContent, "\n") {
		err = installFunction(line)
		if err != nil {
			return err
		}
	}
	return err
}

// ReplacePrefix 替换前缀数据
func ReplacePrefix(m factory.Model, field string, oldPrefix string, newPrefix string) error {
	oldPrefix = com.AddSlashes(oldPrefix, '_', '%')
	value := db.Raw("REPLACE(`"+field+"`, ?, ?)", oldPrefix, newPrefix)
	return m.SetField(nil, field, value, field, db.Like(oldPrefix+`%`))
}

var (
	sqlCharsetRegexp     = regexp.MustCompile(`(?i) (CHARACTER SET |CHARSET=)utf8mb4 `)
	sqlCollateRegexp     = regexp.MustCompile(`(?i) (COLLATE[= ])utf8mb4_general_ci`)
	sqlCreateTableRegexp = regexp.MustCompile(`(?i)^CREATE TABLE `)
	mysqlNetworkRegexp   = regexp.MustCompile(`^[/]{2,}`)
)

// ReplaceCharset 替换DDL语句中的字符集
func ReplaceCharset(sqlStr string, charset string, checkCreateDDL ...bool) string {
	if charset == `utf8mb4` {
		return sqlStr
	}
	if len(checkCreateDDL) > 0 && checkCreateDDL[0] {
		if !sqlCreateTableRegexp.MatchString(sqlStr) {
			return sqlStr
		}
	}
	sqlStr = sqlCharsetRegexp.ReplaceAllString(sqlStr, ` ${1}`+charset+` `)
	sqlStr = sqlCollateRegexp.ReplaceAllString(sqlStr, ` ${1}`+charset+`_general_ci`)
	return sqlStr
}

func ParseMysqlConnectionURL(settings *mysql.ConnectionURL) {
	if strings.HasPrefix(settings.Host, `unix:`) {
		settings.Socket = strings.TrimPrefix(settings.Host, `unix:`)
		settings.Socket = mysqlNetworkRegexp.ReplaceAllString(settings.Socket, `/`)
		settings.Host = ``
	}
}

func SelectPageCond(ctx echo.Context, cond *db.Compounds, pkAndLabelFields ...string) {
	pk := `id`
	lb := `name`
	switch len(pkAndLabelFields) {
	case 2:
		if len(pkAndLabelFields[1]) > 0 {
			lb = pkAndLabelFields[1]
		}
		fallthrough
	case 1:
		if len(pkAndLabelFields[0]) > 0 {
			pk = pkAndLabelFields[0]
		}
	}
	searchValue := ctx.Formx(`searchValue`).String()
	if len(searchValue) > 0 {
		cond.AddKV(pk, searchValue)
	} else {
		keywords := ctx.FormValues(`q_word[]`)
		q := strings.Join(keywords, ` `)
		if len(q) == 0 {
			q = ctx.Formx(`q`).String()
		}
		if len(q) > 0 {
			cond.From(mysqlUtil.MatchAnyField(lb, q))
		}
	}
}
<|endoftext|>


<commit_before>package gocode

import (
	"go/build"
)

var bctx go_build_context

func InitDaemon(bc *build.Context) {
	bctx = pack_build_context(bc)
	g_config.ProposeBuiltins = true
	g_daemon = new(daemon)
	g_daemon.drop_cache()
}

func SetBuildContext(bc *build.Context) {
	bctx = pack_build_context(bc)
}

func AutoComplete(file []byte, filename string, offset int) ([]candidate, int) {
	return server_auto_complete(file, filename, offset, bctx)
}

// dumb vars for unused parts of the package
var (
	g_sock              *string
	g_addr              *string
	fals                = false
	g_debug             = &fals
	get_socket_filename func() string
	config_dir          func() string
	config_file         func() string
)

// dumb types for unused parts of the package
type (
	RPC struct{}
)
<commit_msg>set gocode Autobuild to true (#295)<commit_after>package gocode

import (
	"go/build"
)

var bctx go_build_context

func InitDaemon(bc *build.Context) {
	bctx = pack_build_context(bc)
	g_config.ProposeBuiltins = true
	g_config.Autobuild = true
	g_daemon = new(daemon)
	g_daemon.drop_cache()
}

func SetBuildContext(bc *build.Context) {
	bctx = pack_build_context(bc)
}

func AutoComplete(file []byte, filename string, offset int) ([]candidate, int) {
	return server_auto_complete(file, filename, offset, bctx)
}

// dumb vars for unused parts of the package
var (
	g_sock              *string
	g_addr              *string
	fals                = false
	g_debug             = &fals
	get_socket_filename func() string
	config_dir          func() string
	config_file         func() string
)

// dumb types for unused parts of the package
type (
	RPC struct{}
)
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/go.net/html"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

type Item struct {
	Link        string `xml:"link"`
	Title       string `xml:"title"`
	Guid        string `xml:"guid"`
	PubDate     string `xml:"pubDate"`
	Description string `xml:"description"`
}

type Channel struct {
	XMLName xml.Name `xml:"channel"`
	Title   string   `xml:"title"`
	Items   []Item   `xml:"item"`
}

type Rss struct {
	XMLName xml.Name `xml:"rss"`
	Channel Channel  `xml:"channel"`
}

type Description struct {
	Key   int
	Value string
}

func OriginalFeedBody() []byte {
	res, err := http.Get("http://www.bleedingcool.com/feed/")
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func FetchFullDescription(link string) string {
	res, err := http.Get(link)
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	doc, err := html.Parse(strings.NewReader(string(body)))
	content := ""
	var f func(*html.Node)
	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "div" {
			for _, a := range n.Attr {
				if a.Key == "class" && a.Val == "entry-content" {
					var buf bytes.Buffer
					html.Render(&buf, n)
					content = buf.String()
					break
				}
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}
	f(doc)
	return content
}

func Feed(w http.ResponseWriter, r *http.Request) {
	body := OriginalFeedBody()
	v := Rss{}
	err := xml.Unmarshal(body, &v)
	if err != nil {
		log.Fatal(err)
	}
	c := make(chan Description)
	for key, value := range v.Channel.Items {
		go func(key int, link string) {
			c <- Description{key, FetchFullDescription(link)}
		}(key, value.Link)
	}
	for _ = range v.Channel.Items {
		result := <-c
		v.Channel.Items[result.Key].Description = result.Value
	}
	b, err := xml.Marshal(v)
	if err != nil {
		log.Fatal(err)
	}
	w.Header().Set("Content-Type", "text/xml")
	fmt.Fprint(w, string(b))
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

func main() {
	http.HandleFunc("/feed", Feed)
	port := fmt.Sprintf(":%s", os.Getenv("PORT"))
	log.Printf("Starting on port %s ....", port)
	http.ListenAndServe(port, Log(http.DefaultServeMux))
}
<commit_msg>Try the fetching creator<commit_after>package main

import (
	"bytes"
	"code.google.com/p/go.net/html"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

type Item struct {
	Link        string `xml:"link"`
	Title       string `xml:"title"`
	Creator     string `xml:"creator"`
	Guid        string `xml:"guid"`
	PubDate     string `xml:"pubDate"`
	Description string `xml:"description"`
}

type Channel struct {
	XMLName xml.Name `xml:"channel"`
	Title   string   `xml:"title"`
	Items   []Item   `xml:"item"`
}

type Rss struct {
	XMLName xml.Name `xml:"rss"`
	Channel Channel  `xml:"channel"`
}

type Description struct {
	Key   int
	Value string
}

func OriginalFeedBody() []byte {
	res, err := http.Get("http://www.bleedingcool.com/feed/")
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func FetchFullDescription(link string) string {
	res, err := http.Get(link)
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	doc, err := html.Parse(strings.NewReader(string(body)))
	content := ""
	var f func(*html.Node)
	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "div" {
			for _, a := range n.Attr {
				if a.Key == "class" && a.Val == "entry-content" {
					var buf bytes.Buffer
					html.Render(&buf, n)
					content = buf.String()
					break
				}
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}
	f(doc)
	return content
}

func Feed(w http.ResponseWriter, r *http.Request) {
	body := OriginalFeedBody()
	v := Rss{}
	err := xml.Unmarshal(body, &v)
	if err != nil {
		log.Fatal(err)
	}
	c := make(chan Description)
	for key, value := range v.Channel.Items {
		go func(key int, link string) {
			c <- Description{key, FetchFullDescription(link)}
		}(key, value.Link)
	}
	for _ = range v.Channel.Items {
		result := <-c
		v.Channel.Items[result.Key].Description = result.Value
	}
	b, err := xml.Marshal(v)
	if err != nil {
		log.Fatal(err)
	}
	w.Header().Set("Content-Type", "text/xml")
	fmt.Fprint(w, string(b))
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

func main() {
	http.HandleFunc("/feed", Feed)
	port := fmt.Sprintf(":%s", os.Getenv("PORT"))
	log.Printf("Starting on port %s ....", port)
	http.ListenAndServe(port, Log(http.DefaultServeMux))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

type RequestEvent struct {
	Verb  string
	Path  string
	User  string
	Time  int
	Extra string
}

type RequestEventReader struct {
	r *csv.Reader
}

func newRequestEventReader(r io.Reader) *RequestEventReader {
	reader := &RequestEventReader{r: csv.NewReader(r)}
	reader.r.TrailingComma = true
	return reader
}

func (r *RequestEventReader) Read() (event RequestEvent, err error) {
	line, err := r.r.Read()
	if err != nil {
		return RequestEvent{}, err
	}

	time, err := strconv.Atoi(line[0])
	if err != nil {
		return RequestEvent{}, err
	}
	return RequestEvent{line[1], line[2], line[3], time, line[4]}, nil
}

func createDialFunc(startTime time.Time, endTimeResult *int64) func(network, addr string) (net.Conn, error) {
	return func(network, addr string) (net.Conn, error) {
		conn, err := net.Dial(network, addr)
		*endTimeResult = time.Now().Sub(startTime).Nanoseconds()
		return conn, err
	}
}

type RequestResult struct {
	Error           error
	ResponseCode    int
	ContentSize     int64
	ConnectTime     int64
	HeaderSendTime  int64
	ContentSendTime int64
}

func timeRequest(rootURL string, event RequestEvent) RequestResult {
	url := fmt.Sprintf("%s%s", rootURL, event.Path)
	req, _ := http.NewRequest(event.Verb, url, nil)
	if event.User != "" {
		req.Header.Set("Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(event.User+":"))))
	}

	var connectEndTime, headersEndTime, contentEndTime int64
	startTime := time.Now()

	client := &http.Client{
		Transport: &http.Transport{
			Dial: createDialFunc(startTime, &connectEndTime),
		},
	}

	r, err := client.Do(req)
	headersEndTime = time.Now().Sub(startTime).Nanoseconds()
	if err != nil {
		log.Fatalf("request err %#v: %s", req, err)
	}
	var contentSize int64 = 0
	defer r.Body.Close()
	if err == nil {
		buf := new(bytes.Buffer)
		contentSize, _ = io.Copy(buf, r.Body)
		contentEndTime = time.Now().Sub(startTime).Nanoseconds()
	}
	return RequestResult{err, r.StatusCode, contentSize, (connectEndTime) / 1000000,
		(headersEndTime - connectEndTime) / 1000000, (contentEndTime - headersEndTime) / 1000000}

}

func colorPrint(color int, str string) {
	if color > 7 {
		fmt.Print("\x1b[1m")
		color -= 7
	}
	fmt.Printf("\x1b[3%dm%s\x1b[0m", color, str)
}

var responseCodes [6]int
var statsMutex sync.Mutex

func addToStats(event RequestEvent, result RequestResult) {
	// To be implemented

	statsMutex.Lock()
	if outputWriter != nil {
		type ResultData struct {
			Verb string
			Path string
			RequestResult
			RequestTime int64
			Extra       string
		}
		data, err := json.Marshal(ResultData{event.Verb, event.Path, result, result.HeaderSendTime + result.ContentSendTime, event.Extra})
		if err != nil {
			panic(err)
		}
		outputWriter.Write(data)
		outputWriter.WriteRune('\n')
		outputWriter.Flush()
	}

	if result.ResponseCode/100 < 6 {
		responseCodes[result.ResponseCode/100]++
	} else {
		responseCodes[0]++
	}

	requestLine := fmt.Sprintf("%s %s [%s]\n", event.Verb, event.Path, event.Extra)
	if result.Error != nil {
		colorPrint(8, fmt.Sprintln("%sGot error:", requestLine, result.Error))
	} else {
		resultLine := fmt.Sprintf("%sGot %d (%d bytes) in %d ms, %d ms, %d ms (%d ms)\n",
			requestLine, result.ResponseCode, result.ContentSize, result.ConnectTime,
			result.HeaderSendTime, result.ContentSendTime, result.HeaderSendTime+result.ContentSendTime)
		if result.ResponseCode < 300 {
			colorPrint(9, resultLine)
		} else if result.ResponseCode < 400 {
			colorPrint(11, resultLine)
		} else {
			colorPrint(8, resultLine)
		}
	}

	statsMutex.Unlock()
}

func parseAndReplay(r io.Reader, rootURL string, speed float64) {
	var startTime time.Time
	in := newRequestEventReader(r)

	var mutex sync.Mutex
	count := 0
	for {
		rec, err := in.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}

		if startTime.IsZero() {
			startTime = time.Now()
		}

		for int(float64(time.Now().Sub(startTime)/time.Millisecond)*speed) < rec.Time {
			time.Sleep(time.Duration(100) * time.Millisecond)
		}
		mutex.Lock()
		count++
		mutex.Unlock()
		go func() { addToStats(rec, timeRequest(rootURL, rec)); mutex.Lock(); count--; mutex.Unlock() }()
	}

	for count > 0 {
		time.Sleep(time.Duration(100) * time.Millisecond)
	}
}

var outputWriter *bufio.Writer
var outputFile *os.File

func main() {
	speed := flag.Float64("speed", 1, "Sets multiplier for playback speed.")
	output := flag.String("output", "", "Output file for results, in json format.")
	rooturl := flag.String("root", "", "URL root for requests")
	flag.Parse()

	if *rooturl == "" {
		panic("root parameter is required")
	}

	if *output != "" {
		var err error
		outputFile, err = os.Create(*output)
		if err != nil {
			panic(err)
		}
		outputWriter = bufio.NewWriter(outputFile)
	}

	fmt.Println("Starting playback...")

	parseAndReplay(os.Stdin, *rooturl, *speed)
	fmt.Println("Done!\n")
	if outputWriter != nil {
		outputWriter.Flush()
		outputFile.Close()
	}

	for i := 1; i < 6; i++ {
		if responseCodes[i] != 0 {
			fmt.Printf("%dxx count: %d\n", i, responseCodes[i])
		}
	}
	if responseCodes[0] != 0 {
		fmt.Printf("??? count: %d\n", responseCodes[0])
	}
}
<commit_msg>Refactors bench HTTP request generation to ease testing in preparation for changing auth header handling<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

type RequestEvent struct {
	Verb  string
	Path  string
	User  string
	Time  int
	Extra string
}

type RequestEventReader struct {
	r *csv.Reader
}

func newRequestEventReader(r io.Reader) *RequestEventReader {
	reader := &RequestEventReader{r: csv.NewReader(r)}
	reader.r.TrailingComma = true
	return reader
}

func (r *RequestEventReader) Read() (event RequestEvent, err error) {
	line, err := r.r.Read()
	if err != nil {
		return RequestEvent{}, err
	}

	time, err := strconv.Atoi(line[0])
	if err != nil {
		return RequestEvent{}, err
	}
	return RequestEvent{line[1], line[2], line[3], time, line[4]}, nil
}

func createDialFunc(startTime time.Time, endTimeResult *int64) func(network, addr string) (net.Conn, error) {
	return func(network, addr string) (net.Conn, error) {
		conn, err := net.Dial(network, addr)
		*endTimeResult = time.Now().Sub(startTime).Nanoseconds()
		return conn, err
	}
}

type RequestResult struct {
	Error           error
	ResponseCode    int
	ContentSize     int64
	ConnectTime     int64
	HeaderSendTime  int64
	ContentSendTime int64
}

func eventToRequest(rootURL string, event RequestEvent) *http.Request {
	url := fmt.Sprintf("%s%s", rootURL, event.Path)
	req, err := http.NewRequest(event.Verb, url, nil)
	if err != nil {
		panic(err)
	}
	if event.User != "" {
		req.Header.Set("Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(event.User+":"))))
	}
	return req
}

func timeRequest(request *http.Request) RequestResult {
	var connectEndTime, headersEndTime, contentEndTime int64
	startTime := time.Now()

	client := &http.Client{
		Transport: &http.Transport{
			Dial: createDialFunc(startTime, &connectEndTime),
		},
	}

	r, err := client.Do(request)
	headersEndTime = time.Now().Sub(startTime).Nanoseconds()
	if err != nil {
		log.Fatalf("request err %#v: %s", request, err)
	}
	var contentSize int64 = 0
	defer r.Body.Close()
	if err == nil {
		buf := new(bytes.Buffer)
		contentSize, _ = io.Copy(buf, r.Body)
		contentEndTime = time.Now().Sub(startTime).Nanoseconds()
	}
	return RequestResult{err, r.StatusCode, contentSize, (connectEndTime) / 1000000,
		(headersEndTime - connectEndTime) / 1000000, (contentEndTime - headersEndTime) / 1000000}

}

func colorPrint(color int, str string) {
	if color > 7 {
		fmt.Print("\x1b[1m")
		color -= 7
	}
	fmt.Printf("\x1b[3%dm%s\x1b[0m", color, str)
}

var responseCodes [6]int
var statsMutex sync.Mutex

func addToStats(event RequestEvent, result RequestResult) {
	// To be implemented

	statsMutex.Lock()
	if outputWriter != nil {
		type ResultData struct {
			Verb string
			Path string
			RequestResult
			RequestTime int64
			Extra       string
		}
		data, err := json.Marshal(ResultData{event.Verb, event.Path, result, result.HeaderSendTime + result.ContentSendTime, event.Extra})
		if err != nil {
			panic(err)
		}
		outputWriter.Write(data)
		outputWriter.WriteRune('\n')
		outputWriter.Flush()
	}

	if result.ResponseCode/100 < 6 {
		responseCodes[result.ResponseCode/100]++
	} else {
		responseCodes[0]++
	}

	requestLine := fmt.Sprintf("%s %s [%s]\n", event.Verb, event.Path, event.Extra)
	if result.Error != nil {
		colorPrint(8, fmt.Sprintln("%sGot error:", requestLine, result.Error))
	} else {
		resultLine := fmt.Sprintf("%sGot %d (%d bytes) in %d ms, %d ms, %d ms (%d ms)\n",
			requestLine, result.ResponseCode, result.ContentSize, result.ConnectTime,
			result.HeaderSendTime, result.ContentSendTime, result.HeaderSendTime+result.ContentSendTime)
		if result.ResponseCode < 300 {
			colorPrint(9, resultLine)
		} else if result.ResponseCode < 400 {
			colorPrint(11, resultLine)
		} else {
			colorPrint(8, resultLine)
		}
	}

	statsMutex.Unlock()
}

func parseAndReplay(r io.Reader, rootURL string, speed float64) {
	var startTime time.Time
	in := newRequestEventReader(r)

	var mutex sync.Mutex
	count := 0
	for {
		rec, err := in.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}

		if startTime.IsZero() {
			startTime = time.Now()
		}

		for int(float64(time.Now().Sub(startTime)/time.Millisecond)*speed) < rec.Time {
			time.Sleep(time.Duration(100) * time.Millisecond)
		}
		mutex.Lock()
		count++
		mutex.Unlock()
		go func() { addToStats(rec, timeRequest(eventToRequest(rootURL, rec))); mutex.Lock(); count--; mutex.Unlock() }()
	}

	for count > 0 {
		time.Sleep(time.Duration(100) * time.Millisecond)
	}
}

var outputWriter *bufio.Writer
var outputFile *os.File

func main() {
	speed := flag.Float64("speed", 1, "Sets multiplier for playback speed.")
	output := flag.String("output", "", "Output file for results, in json format.")
	rooturl := flag.String("root", "", "URL root for requests")
	flag.Parse()

	if *rooturl == "" {
		panic("root parameter is required")
	}

	if *output != "" {
		var err error
		outputFile, err = os.Create(*output)
		if err != nil {
			panic(err)
		}
		outputWriter = bufio.NewWriter(outputFile)
	}

	fmt.Println("Starting playback...")

	parseAndReplay(os.Stdin, *rooturl, *speed)
	fmt.Println("Done!\n")
	if outputWriter != nil {
		outputWriter.Flush()
		outputFile.Close()
	}

	for i := 1; i < 6; i++ {
		if responseCodes[i] != 0 {
			fmt.Printf("%dxx count: %d\n", i, responseCodes[i])
		}
	}
	if responseCodes[0] != 0 {
		fmt.Printf("??? count: %d\n", responseCodes[0])
	}
}
<|endoftext|>


<commit_before>package bip39

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"errors"
	"fmt"
	"math/big"
	"strings"

	"golang.org/x/crypto/pbkdf2"
)

var (
	// Some bitwise operands for working with big.Ints
	Last11BitsMask          = big.NewInt(2047)
	RightShift11BitsDivider = big.NewInt(2048)
	BigOne                  = big.NewInt(1)
	BigTwo                  = big.NewInt(2)

	// Wordlist sets the language used for the mnemonic
	WordList = EnglishWordList

	// ReverseWordMap is a reverse lookup of Wordlist
	ReverseWordMap = map[string]int{}
)

func init() {
	for i, v := range WordList {
		ReverseWordMap[v] = i
	}
}

// NewEntropy will create random entropy bytes
// so long as the requested size bitSize is an appropriate size.
func NewEntropy(bitSize int) ([]byte, error) {
	err := validateEntropyBitSize(bitSize)
	if err != nil {
		return nil, err
	}

	entropy := make([]byte, bitSize/8)
	_, err = rand.Read(entropy)
	return entropy, err
}

// NewMnemonic will return a string consisting of the mnemonic words for
// the given entropy.
// If the provide entropy is invalid, an error will be returned.
func NewMnemonic(entropy []byte) (string, error) {
	// Compute some lengths for convenience
	entropyBitLength := len(entropy) * 8
	checksumBitLength := entropyBitLength / 32
	sentenceLength := (entropyBitLength + checksumBitLength) / 11

	err := validateEntropyBitSize(entropyBitLength)
	if err != nil {
		return "", err
	}

	// Add checksum to entropy
	entropy = addChecksum(entropy)

	// Break entropy up into sentenceLength chunks of 11 bits
	// For each word AND mask the rightmost 11 bits and find the word at that index
	// Then bitshift entropy 11 bits right and repeat
	// Add to the last empty slot so we can work with LSBs instead of MSB

	// Entropy as an int so we can bitmask without worrying about bytes slices
	entropyInt := new(big.Int).SetBytes(entropy)

	// Slice to hold words in
	words := make([]string, sentenceLength)

	// Throw away big int for AND masking
	word := big.NewInt(0)

	for i := sentenceLength - 1; i >= 0; i-- {
		// Get 11 right most bits and bitshift 11 to the right for next time
		word.And(entropyInt, Last11BitsMask)
		entropyInt.Div(entropyInt, RightShift11BitsDivider)

		// Get the bytes representing the 11 bits as a 2 byte slice
		wordBytes := padByteSlice(word.Bytes(), 2)

		// Convert bytes to an index and add that word to the list
		words[i] = WordList[binary.BigEndian.Uint16(wordBytes)]
	}

	return strings.Join(words, " "), nil
}

// MnemonicToByteArray takes a mnemonic string and turns it into a byte array
// suitable for creating another mnemonic.
// An error is returned if the mnemonic is invalid.
func MnemonicToByteArray(mnemonic string) ([]byte, error) {
	if IsMnemonicValid(mnemonic) == false {
		return nil, fmt.Errorf("Invalid mnemonic")
	}
	mnemonicSlice := strings.Split(mnemonic, " ")

	bitSize := len(mnemonicSlice) * 11
	err := validateEntropyWithChecksumBitSize(bitSize)
	if err != nil {
		return nil, err
	}
	checksumSize := bitSize % 32

	b := big.NewInt(0)
	modulo := big.NewInt(2048)
	for _, v := range mnemonicSlice {
		index, found := ReverseWordMap[v]
		if found == false {
			return nil, fmt.Errorf("Word `%v` not found in reverse map", v)
		}
		add := big.NewInt(int64(index))
		b = b.Mul(b, modulo)
		b = b.Add(b, add)
	}
	hex := b.Bytes()
	checksumModulo := big.NewInt(0).Exp(big.NewInt(2), big.NewInt(int64(checksumSize)), nil)
	entropy, _ := big.NewInt(0).DivMod(b, checksumModulo, big.NewInt(0))

	entropyHex := entropy.Bytes()

	// Add padding (an extra byte is for checksum)
	byteSize := (bitSize-checksumSize)/8 + 1
	if len(hex) != byteSize {
		tmp := make([]byte, byteSize)
		diff := byteSize - len(hex)
		for i := 0; i < len(hex); i++ {
			tmp[i+diff] = hex[i]
		}
		hex = tmp
	}

	otherSize := byteSize - (byteSize % 4)
	entropyHex = padByteSlice(entropyHex, otherSize)

	validationHex := addChecksum(entropyHex)
	validationHex = padByteSlice(validationHex, byteSize)

	if len(hex) != len(validationHex) {
		panic("[]byte len mismatch - it shouldn't happen")
	}
	for i := range validationHex {
		if hex[i] != validationHex[i] {
			return nil, fmt.Errorf("Mnemonic checksum error. Check words are in correct order. (decoded byte %v)", i)
		}
	}
	return hex, nil
}

// NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
// An error is returned if the mnemonic is not convertible to a byte array.
func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) {
	_, err := MnemonicToByteArray(mnemonic)
	if err != nil {
		return nil, err
	}
	return NewSeed(mnemonic, password), nil
}

// NewSeed creates a hashed seed output given a provided string and password.
// No checking is performed to validate that the string provided is a valid mnemonic.
func NewSeed(mnemonic string, password string) []byte {
	return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
}

// IsMnemonicValid attempts to verify that the provided mnemonic is valid.
// Validity is determined by both the number of words being appropriate,
// and that all the words in the mnemonic are present in the word list.
func IsMnemonicValid(mnemonic string) bool {
	// Create a list of all the words in the mnemonic sentence
	words := strings.Fields(mnemonic)

	//Get num of words
	numOfWords := len(words)

	// The number of words should be 12, 15, 18, 21 or 24
	if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {
		return false
	}

	// Check if all words belong in the wordlist
	for i := 0; i < numOfWords; i++ {
		if !contains(WordList, words[i]) {
			return false
		}
	}

	return true
}

// Appends to data the first (len(data) / 32)bits of the result of sha256(data)
// Currently only supports data up to 32 bytes
func addChecksum(data []byte) []byte {
	// Get first byte of sha256
	hasher := sha256.New()
	hasher.Write(data)
	hash := hasher.Sum(nil)
	firstChecksumByte := hash[0]

	// len() is in bytes so we divide by 4
	checksumBitLength := uint(len(data) / 4)

	// For each bit of check sum we want we shift the data one the left
	// and then set the (new) right most bit equal to checksum bit at that index
	// staring from the left
	dataBigInt := new(big.Int).SetBytes(data)
	for i := uint(0); i < checksumBitLength; i++ {
		// Bitshift 1 left
		dataBigInt.Mul(dataBigInt, bigTwo)

		// Set rightmost bit if leftmost checksum bit is set
		if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
			dataBigInt.Or(dataBigInt, bigOne)
		}
	}

	return dataBigInt.Bytes()
}

// validateEntropyBitSize ensures that entropy is the correct size for being a
// mnemonic.
func validateEntropyBitSize(bitSize int) error {
	if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
		return errors.New("Entropy length must be [128, 256] and a multiple of 32")
	}
	return nil
}

// validateEntropyWithChecksumBitSize ensures that the given number of bits is a
// valid length for seed entropy with an attached checksum.
func validateEntropyWithChecksumBitSize(bitSize int) error {
	if (bitSize != 128+4) && (bitSize != 160+5) && (bitSize != 192+6) && (bitSize != 224+7) && (bitSize != 256+8) {
		return fmt.Errorf("Wrong entropy + checksum size - expected %v, got %v", int((bitSize-bitSize%32)+(bitSize-bitSize%32)/32), bitSize)
	}
	return nil
}

// padByteSlice returns a byte slice of the given size with contents of the
// given slice left padded and any empty spaces filled with 0's.
func padByteSlice(slice []byte, length int) []byte {
	if len(slice) >= length {
		return slice
	}
	newSlice := make([]byte, length-len(slice))
	return append(newSlice, slice...)
}

// contains checks if a given string is in a given slice of strings.
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<commit_msg>BUGFIX: Fix new private constant names.<commit_after>package bip39

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"errors"
	"fmt"
	"math/big"
	"strings"

	"golang.org/x/crypto/pbkdf2"
)

var (
	// Some bitwise operands for working with big.Ints
	last11BitsMask          = big.NewInt(2047)
	rightShift11BitsDivider = big.NewInt(2048)
	bigOne                  = big.NewInt(1)
	bigTwo                  = big.NewInt(2)

	// WordList sets the language used for the mnemonic
	WordList = EnglishWordList

	// ReverseWordMap is a reverse lookup of Wordlist
	ReverseWordMap = map[string]int{}
)

func init() {
	for i, v := range WordList {
		ReverseWordMap[v] = i
	}
}

// NewEntropy will create random entropy bytes
// so long as the requested size bitSize is an appropriate size.
func NewEntropy(bitSize int) ([]byte, error) {
	err := validateEntropyBitSize(bitSize)
	if err != nil {
		return nil, err
	}

	entropy := make([]byte, bitSize/8)
	_, err = rand.Read(entropy)
	return entropy, err
}

// NewMnemonic will return a string consisting of the mnemonic words for
// the given entropy.
// If the provide entropy is invalid, an error will be returned.
func NewMnemonic(entropy []byte) (string, error) {
	// Compute some lengths for convenience
	entropyBitLength := len(entropy) * 8
	checksumBitLength := entropyBitLength / 32
	sentenceLength := (entropyBitLength + checksumBitLength) / 11

	err := validateEntropyBitSize(entropyBitLength)
	if err != nil {
		return "", err
	}

	// Add checksum to entropy
	entropy = addChecksum(entropy)

	// Break entropy up into sentenceLength chunks of 11 bits
	// For each word AND mask the rightmost 11 bits and find the word at that index
	// Then bitshift entropy 11 bits right and repeat
	// Add to the last empty slot so we can work with LSBs instead of MSB

	// Entropy as an int so we can bitmask without worrying about bytes slices
	entropyInt := new(big.Int).SetBytes(entropy)

	// Slice to hold words in
	words := make([]string, sentenceLength)

	// Throw away big int for AND masking
	word := big.NewInt(0)

	for i := sentenceLength - 1; i >= 0; i-- {
		// Get 11 right most bits and bitshift 11 to the right for next time
		word.And(entropyInt, last11BitsMask)
		entropyInt.Div(entropyInt, rightShift11BitsDivider)

		// Get the bytes representing the 11 bits as a 2 byte slice
		wordBytes := padByteSlice(word.Bytes(), 2)

		// Convert bytes to an index and add that word to the list
		words[i] = WordList[binary.BigEndian.Uint16(wordBytes)]
	}

	return strings.Join(words, " "), nil
}

// MnemonicToByteArray takes a mnemonic string and turns it into a byte array
// suitable for creating another mnemonic.
// An error is returned if the mnemonic is invalid.
func MnemonicToByteArray(mnemonic string) ([]byte, error) {
	if IsMnemonicValid(mnemonic) == false {
		return nil, fmt.Errorf("Invalid mnemonic")
	}
	mnemonicSlice := strings.Split(mnemonic, " ")

	bitSize := len(mnemonicSlice) * 11
	err := validateEntropyWithChecksumBitSize(bitSize)
	if err != nil {
		return nil, err
	}
	checksumSize := bitSize % 32

	b := big.NewInt(0)
	modulo := big.NewInt(2048)
	for _, v := range mnemonicSlice {
		index, found := ReverseWordMap[v]
		if found == false {
			return nil, fmt.Errorf("Word `%v` not found in reverse map", v)
		}
		add := big.NewInt(int64(index))
		b = b.Mul(b, modulo)
		b = b.Add(b, add)
	}
	hex := b.Bytes()
	checksumModulo := big.NewInt(0).Exp(big.NewInt(2), big.NewInt(int64(checksumSize)), nil)
	entropy, _ := big.NewInt(0).DivMod(b, checksumModulo, big.NewInt(0))

	entropyHex := entropy.Bytes()

	// Add padding (an extra byte is for checksum)
	byteSize := (bitSize-checksumSize)/8 + 1
	if len(hex) != byteSize {
		tmp := make([]byte, byteSize)
		diff := byteSize - len(hex)
		for i := 0; i < len(hex); i++ {
			tmp[i+diff] = hex[i]
		}
		hex = tmp
	}

	otherSize := byteSize - (byteSize % 4)
	entropyHex = padByteSlice(entropyHex, otherSize)

	validationHex := addChecksum(entropyHex)
	validationHex = padByteSlice(validationHex, byteSize)

	if len(hex) != len(validationHex) {
		panic("[]byte len mismatch - it shouldn't happen")
	}
	for i := range validationHex {
		if hex[i] != validationHex[i] {
			return nil, fmt.Errorf("Mnemonic checksum error. Check words are in correct order. (decoded byte %v)", i)
		}
	}
	return hex, nil
}

// NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
// An error is returned if the mnemonic is not convertible to a byte array.
func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) {
	_, err := MnemonicToByteArray(mnemonic)
	if err != nil {
		return nil, err
	}
	return NewSeed(mnemonic, password), nil
}

// NewSeed creates a hashed seed output given a provided string and password.
// No checking is performed to validate that the string provided is a valid mnemonic.
func NewSeed(mnemonic string, password string) []byte {
	return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
}

// IsMnemonicValid attempts to verify that the provided mnemonic is valid.
// Validity is determined by both the number of words being appropriate,
// and that all the words in the mnemonic are present in the word list.
func IsMnemonicValid(mnemonic string) bool {
	// Create a list of all the words in the mnemonic sentence
	words := strings.Fields(mnemonic)

	//Get num of words
	numOfWords := len(words)

	// The number of words should be 12, 15, 18, 21 or 24
	if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {
		return false
	}

	// Check if all words belong in the wordlist
	for i := 0; i < numOfWords; i++ {
		if !contains(WordList, words[i]) {
			return false
		}
	}

	return true
}

// Appends to data the first (len(data) / 32)bits of the result of sha256(data)
// Currently only supports data up to 32 bytes
func addChecksum(data []byte) []byte {
	// Get first byte of sha256
	hasher := sha256.New()
	hasher.Write(data)
	hash := hasher.Sum(nil)
	firstChecksumByte := hash[0]

	// len() is in bytes so we divide by 4
	checksumBitLength := uint(len(data) / 4)

	// For each bit of check sum we want we shift the data one the left
	// and then set the (new) right most bit equal to checksum bit at that index
	// staring from the left
	dataBigInt := new(big.Int).SetBytes(data)
	for i := uint(0); i < checksumBitLength; i++ {
		// Bitshift 1 left
		dataBigInt.Mul(dataBigInt, bigTwo)

		// Set rightmost bit if leftmost checksum bit is set
		if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
			dataBigInt.Or(dataBigInt, bigOne)
		}
	}

	return dataBigInt.Bytes()
}

// validateEntropyBitSize ensures that entropy is the correct size for being a
// mnemonic.
func validateEntropyBitSize(bitSize int) error {
	if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
		return errors.New("Entropy length must be [128, 256] and a multiple of 32")
	}
	return nil
}

// validateEntropyWithChecksumBitSize ensures that the given number of bits is a
// valid length for seed entropy with an attached checksum.
func validateEntropyWithChecksumBitSize(bitSize int) error {
	if (bitSize != 128+4) && (bitSize != 160+5) && (bitSize != 192+6) && (bitSize != 224+7) && (bitSize != 256+8) {
		return fmt.Errorf("Wrong entropy + checksum size - expected %v, got %v", int((bitSize-bitSize%32)+(bitSize-bitSize%32)/32), bitSize)
	}
	return nil
}

// padByteSlice returns a byte slice of the given size with contents of the
// given slice left padded and any empty spaces filled with 0's.
func padByteSlice(slice []byte, length int) []byte {
	if len(slice) >= length {
		return slice
	}
	newSlice := make([]byte, length-len(slice))
	return append(newSlice, slice...)
}

// contains checks if a given string is in a given slice of strings.
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<|endoftext|>