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

package pipoint

import (
	"log"
	"time"

	common "gobot.io/x/gobot/platforms/mavlink/common"
	"gobot.io/x/gobot/platforms/mqtt"
)

const (
	dt = time.Millisecond * 20
)

var (
	// Version is the overall binary version.  Set from the
	// build.
	Version = "dev"
)

// State is a handler for the current state of the system.
type State interface {
	Update(param *Param)
}

// PiPoint is an automatic, GPS based system that points a camera at the rover.
type PiPoint struct {
	Params *Params

	state *Param

	version    *Param
	tick       *Param
	messages   *Param
	heartbeats *Param
	heartbeat  *Param
	attitude   *Param
	gps        *Param
	neu        *Param
	baseOffset *Param
	pred       *Param
	rover      *Param
	base       *Param
	sysStatus  *Param

	sp     *Param
	offset *Param

	pan  *Servo
	tilt *Servo

	latPred *LinPred
	lonPred *LinPred
	altPred *LinPred

	states []State

	elog *EventLogger
	log  *log.Logger

	param ParamChannel
}

// NewPiPoint creates a new camera pointer.
func NewPiPoint() *PiPoint {
	p := &PiPoint{
		Params:  NewParams("pipoint"),
		latPred: &LinPred{},
		lonPred: &LinPred{},
		altPred: &LinPred{},
		elog:    NewEventLogger("pipoint"),
		param:   make(ParamChannel, 10),
	}

	p.log = p.elog.logger

	p.states = []State{
		&LocateState{pi: p},
		&RunState{pi: p},
		&CycleState{pi: p},
	}

	p.version = p.Params.NewWith("build_label", Version)
	p.tick = p.Params.NewNum("tick")
	p.messages = p.Params.NewNum("rover.messages")

	p.state = p.Params.NewNum("state")
	p.heartbeat = p.Params.NewWith("heartbeat", &common.Heartbeat{})
	p.heartbeats = p.Params.NewNum("heartbeat")

	p.gps = p.Params.New("gps")
	p.neu = p.Params.New("position")
	p.pred = p.Params.New("pred")

	p.attitude = p.Params.New("rover.attitude")
	p.rover = p.Params.New("rover.position")
	p.base = p.Params.New("base.position")
	p.baseOffset = p.Params.NewWith("base.offset", &NEUPosition{})

	p.sysStatus = p.Params.New("rover.status")

	p.sp = p.Params.NewWith("pantilt.sp", &Attitude{})
	p.offset = p.Params.NewWith("pantilt.offset", &Attitude{})

	p.pan = NewServo("pantilt.pan", p.Params)
	p.tilt = NewServo("pantilt.tilt", p.Params)

	p.Params.Listen(p.param)
	p.Params.Load()
	return p
}

// AddMQTT adds a new MQTT connection that bridges between MQTT and
// params.
func (pi *PiPoint) AddMQTT(mqtt *mqtt.Adaptor) {
	NewParamMQTTBridge(pi.Params, mqtt, "")
}

// Run is the main entry point that runs forever.
func (pi *PiPoint) Run() {
	tick := time.NewTicker(dt)

	for {
		select {
		case param := <-pi.param:
			pi.update(param)
		case <-tick.C:
			pi.ticked()
		}
	}
}

func (pi *PiPoint) ticked() {
	now := Now()
	pi.tick.SetFloat64(now)

	pred := &Position{
		Time: now,
		Lat:  pi.latPred.GetEx(now),
		Lon:  pi.lonPred.GetEx(now),
		Alt:  pi.altPred.GetEx(now),
	}

	pi.pred.Set(pred)

	pi.pan.Tick()
	pi.tilt.Tick()
}

func (pi *PiPoint) predict(gps *Position) {
	now := pi.tick.GetFloat64()

	pi.latPred.SetEx(gps.Lat, now, gps.Time)
	pi.lonPred.SetEx(gps.Lon, now, gps.Time)
	pi.altPred.SetEx(gps.Alt, now, gps.Time)
}

func (pi *PiPoint) update(param *Param) {
	state := pi.state.GetInt()

	if state >= 0 && state < len(pi.states) {
		pi.states[state].Update(param)
	}

	pi.log.Printf("%s %T %#v\n", param.Name, param.Get(), param.Get())
}

// Message handles a MAVLink message.
func (pi *PiPoint) Message(msg interface{}) {
	switch msg.(type) {
	case *common.Heartbeat:
		pi.heartbeats.Inc()
		pi.heartbeat.Set(msg.(*common.Heartbeat))
	case *common.SysStatus:
		pi.sysStatus.Set(msg.(*common.SysStatus))
	case *common.GpsRawInt:
		gps := msg.(*common.GpsRawInt)
		pi.gps.Set(&Position{
			Time:    float64(gps.TIME_USEC) * 1e-6,
			Lat:     float64(gps.LAT) * 1e-7,
			Lon:     float64(gps.LON) * 1e-7,
			Alt:     float64(gps.ALT) * 1e-3,
			Heading: float64(gps.COG) * 1e-2,
		})
		pi.neu.Set(pi.gps.Get().(*Position).ToNEU())
	case *common.Attitude:
		att := msg.(*common.Attitude)
		pi.attitude.Set(&Attitude{
			float64(att.ROLL),
			float64(att.PITCH),
			float64(att.YAW),
		})
	default:
	}

	pi.messages.Inc()
	pi.log.Printf("%s %T %#v\n", "message", msg, msg)
}
<commit_msg>pipoint: add basic audio output.<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package pipoint

import (
	"log"
	"time"

	common "gobot.io/x/gobot/platforms/mavlink/common"
	"gobot.io/x/gobot/platforms/mqtt"
)

const (
	dt = time.Millisecond * 20
)

var (
	// Version is the overall binary version.  Set from the
	// build.
	Version = "dev"
)

// State is a handler for the current state of the system.
type State interface {
	Update(param *Param)
}

// PiPoint is an automatic, GPS based system that points a camera at the rover.
type PiPoint struct {
	Params *Params

	state *Param

	version    *Param
	tick       *Param
	messages   *Param
	heartbeats *Param
	heartbeat  *Param
	attitude   *Param
	gps        *Param
	neu        *Param
	baseOffset *Param
	pred       *Param
	rover      *Param
	base       *Param
	sysStatus  *Param

	sp     *Param
	offset *Param

	pan  *Servo
	tilt *Servo

	latPred *LinPred
	lonPred *LinPred
	altPred *LinPred

	states []State

	elog *EventLogger
	log  *log.Logger

	param ParamChannel

	audio *AudioOut
}

// NewPiPoint creates a new camera pointer.
func NewPiPoint() *PiPoint {
	p := &PiPoint{
		Params:  NewParams("pipoint"),
		latPred: &LinPred{},
		lonPred: &LinPred{},
		altPred: &LinPred{},
		elog:    NewEventLogger("pipoint"),
		param:   make(ParamChannel, 10),
		audio:   NewAudioOut(),
	}

	p.log = p.elog.logger

	p.states = []State{
		&LocateState{pi: p},
		&RunState{pi: p},
		&CycleState{pi: p},
	}

	p.version = p.Params.NewWith("build_label", Version)
	p.tick = p.Params.NewNum("tick")
	p.messages = p.Params.NewNum("rover.messages")

	p.state = p.Params.NewNum("state")
	p.heartbeat = p.Params.NewWith("heartbeat", &common.Heartbeat{})
	p.heartbeats = p.Params.NewNum("heartbeat")

	p.gps = p.Params.New("gps")
	p.neu = p.Params.New("position")
	p.pred = p.Params.New("pred")

	p.attitude = p.Params.New("rover.attitude")
	p.rover = p.Params.New("rover.position")
	p.base = p.Params.New("base.position")
	p.baseOffset = p.Params.NewWith("base.offset", &NEUPosition{})

	p.sysStatus = p.Params.New("rover.status")

	p.sp = p.Params.NewWith("pantilt.sp", &Attitude{})
	p.offset = p.Params.NewWith("pantilt.offset", &Attitude{})

	p.pan = NewServo("pantilt.pan", p.Params)
	p.tilt = NewServo("pantilt.tilt", p.Params)

	p.Params.Listen(p.param)
	p.Params.Load()
	return p
}

// AddMQTT adds a new MQTT connection that bridges between MQTT and
// params.
func (pi *PiPoint) AddMQTT(mqtt *mqtt.Adaptor) {
	NewParamMQTTBridge(pi.Params, mqtt, "")
}

// Run is the main entry point that runs forever.
func (pi *PiPoint) Run() {
	tick := time.NewTicker(dt)

	pi.audio.Say("Base ready")

	for {
		select {
		case param := <-pi.param:
			pi.update(param)
		case <-tick.C:
			pi.ticked()
		}
	}
}

func (pi *PiPoint) ticked() {
	now := Now()
	pi.tick.SetFloat64(now)

	pred := &Position{
		Time: now,
		Lat:  pi.latPred.GetEx(now),
		Lon:  pi.lonPred.GetEx(now),
		Alt:  pi.altPred.GetEx(now),
	}

	pi.pred.Set(pred)

	pi.pan.Tick()
	pi.tilt.Tick()
}

func (pi *PiPoint) predict(gps *Position) {
	now := pi.tick.GetFloat64()

	pi.latPred.SetEx(gps.Lat, now, gps.Time)
	pi.lonPred.SetEx(gps.Lon, now, gps.Time)
	pi.altPred.SetEx(gps.Alt, now, gps.Time)
}

func (pi *PiPoint) update(param *Param) {
	state := pi.state.GetInt()

	if state >= 0 && state < len(pi.states) {
		pi.states[state].Update(param)
	}

	pi.log.Printf("%s %T %#v\n", param.Name, param.Get(), param.Get())
}

// Message handles a MAVLink message.
func (pi *PiPoint) Message(msg interface{}) {
	switch msg.(type) {
	case *common.Heartbeat:
		if !pi.heartbeats.Ok() {
			pi.audio.Say("Rover online")
		}
		pi.heartbeats.Inc()
		pi.heartbeat.Set(msg.(*common.Heartbeat))
	case *common.SysStatus:
		pi.sysStatus.Set(msg.(*common.SysStatus))
	case *common.GpsRawInt:
		gps := msg.(*common.GpsRawInt)
		pi.gps.Set(&Position{
			Time:    float64(gps.TIME_USEC) * 1e-6,
			Lat:     float64(gps.LAT) * 1e-7,
			Lon:     float64(gps.LON) * 1e-7,
			Alt:     float64(gps.ALT) * 1e-3,
			Heading: float64(gps.COG) * 1e-2,
		})
		pi.neu.Set(pi.gps.Get().(*Position).ToNEU())
	case *common.Attitude:
		att := msg.(*common.Attitude)
		pi.attitude.Set(&Attitude{
			float64(att.ROLL),
			float64(att.PITCH),
			float64(att.YAW),
		})
	default:
	}

	pi.messages.Inc()
	pi.log.Printf("%s %T %#v\n", "message", msg, msg)
}
<|endoftext|>


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

// Gocyclo calculates the cyclomatic complexities of functions and
// methods in Go source code.
//
// Usage:
//      gocyclo [<flag> ...] <Go file or directory> ...
//
// Flags:
//      -over N   show functions with complexity > N only and
//                return exit code 1 if the output is non-empty
//      -top N    show the top N most complex functions only
//      -avg      show the average complexity
//      -total    show the total complexity
//
// The output fields for each line are:
// <complexity> <package> <function> <file:row:column>
package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

const usageDoc = `Calculate cyclomatic complexities of Go functions.
Usage:
        gocyclo [flags] <Go file or directory> ...

Flags:
        -over N   show functions with complexity > N only and
                  return exit code 1 if the set is non-empty
        -top N    show the top N most complex functions only
        -avg      show the average complexity over all functions,
                  not depending on whether -over or -top are set
        -total    show the total complexity for all functions

The output fields for each line are:
<complexity> <package> <function> <file:row:column>
`

func usage() {
	fmt.Fprintf(os.Stderr, usageDoc)
	os.Exit(2)
}

var (
	over  = flag.Int("over", 0, "show functions with complexity > N only")
	top   = flag.Int("top", -1, "show the top N most complex functions only")
	avg   = flag.Bool("avg", false, "show the average complexity")
	total = flag.Bool("total", false, "show the total complexity")
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("gocyclo: ")
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		usage()
	}

	stats := analyze(args)
	sort.Sort(byComplexity(stats))
	written := writeStats(os.Stdout, stats)

	if *avg {
		showAverage(stats)
	}

	if *total {
		showTotal(stats)
	}

	if *over > 0 && written > 0 {
		os.Exit(1)
	}
}

func analyze(paths []string) []stat {
	var stats []stat
	for _, path := range paths {
		if isDir(path) {
			stats = analyzeDir(path, stats)
		} else {
			stats = analyzeFile(path, stats)
		}
	}
	return stats
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func analyzeFile(fname string, stats []stat) []stat {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
	if err != nil {
		log.Fatal(err)
	}
	return buildStats(f, fset, stats)
}

func analyzeDir(dirname string, stats []stat) []stat {
	filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() && strings.HasSuffix(path, ".go") {
			stats = analyzeFile(path, stats)
		}
		return err
	})
	return stats
}

func writeStats(w io.Writer, sortedStats []stat) int {
	for i, stat := range sortedStats {
		if i == *top {
			return i
		}
		if stat.Complexity <= *over {
			return i
		}
		fmt.Fprintln(w, stat)
	}
	return len(sortedStats)
}

func showAverage(stats []stat) {
	fmt.Printf("Average: %.3g\n", average(stats))
}

func average(stats []stat) float64 {
	total := 0
	for _, s := range stats {
		total += s.Complexity
	}
	return float64(total) / float64(len(stats))
}

func showTotal(stats []stat) {
	fmt.Printf("Total: %d\n", sumtotal(stats))
}

func sumtotal(stats []stat) uint64 {
	total := uint64(0)
	for _, s := range stats {
		total += uint64(s.Complexity)
	}
	return total
}

type stat struct {
	PkgName    string
	FuncName   string
	Complexity int
	Pos        token.Position
}

func (s stat) String() string {
	return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
}

type byComplexity []stat

func (s byComplexity) Len() int      { return len(s) }
func (s byComplexity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byComplexity) Less(i, j int) bool {
	return s[i].Complexity >= s[j].Complexity
}

func buildStats(f *ast.File, fset *token.FileSet, stats []stat) []stat {
	for _, declaration := range f.Decls {
		switch decl := declaration.(type) {
		case *ast.FuncDecl:
			stats = addStatIfNotIgnored(stats, decl, funcName(decl), decl.Doc, f, fset)
		case *ast.GenDecl:
			for _, spec := range decl.Specs {
				valueSpec, ok := spec.(*ast.ValueSpec)
				if !ok {
					continue
				}
				for _, value := range valueSpec.Values {
					funcLit, ok := value.(*ast.FuncLit)
					if !ok {
						continue
					}
					stats = addStatIfNotIgnored(stats, funcLit, valueSpec.Names[0].Name, decl.Doc, f, fset)
				}
			}
		}
	}
	return stats
}

func addStatIfNotIgnored(stats []stat, funcNode ast.Node, funcName string, doc *ast.CommentGroup, f *ast.File, fset *token.FileSet) []stat {
	if parseDirectives(doc).HasIgnore() {
		return stats
	}
	return append(stats, statForFunc(funcNode, funcName, f, fset))
}

func statForFunc(funcNode ast.Node, funcName string, f *ast.File, fset *token.FileSet) stat {
	return stat{
		PkgName:    f.Name.Name,
		FuncName:   funcName,
		Complexity: complexity(funcNode),
		Pos:        fset.Position(funcNode.Pos()),
	}
}

// funcName returns the name representation of a function or method:
// "(Type).Name" for methods or simply "Name" for functions.
func funcName(fn *ast.FuncDecl) string {
	if fn.Recv != nil {
		if fn.Recv.NumFields() > 0 {
			typ := fn.Recv.List[0].Type
			return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
		}
	}
	return fn.Name.Name
}

// recvString returns a string representation of recv of the
// form "T", "*T", or "BADRECV" (if not a proper receiver type).
func recvString(recv ast.Expr) string {
	switch t := recv.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.StarExpr:
		return "*" + recvString(t.X)
	}
	return "BADRECV"
}

// complexity calculates the cyclomatic complexity of a function.
func complexity(fn ast.Node) int {
	v := complexityVisitor{}
	ast.Walk(&v, fn)
	return v.Complexity
}

type complexityVisitor struct {
	// Complexity is the cyclomatic complexity
	Complexity int
}

// Visit implements the ast.Visitor interface.
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.FuncDecl, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.CaseClause, *ast.CommClause:
		v.Complexity++
	case *ast.BinaryExpr:
		if n.Op == token.LAND || n.Op == token.LOR {
			v.Complexity++
		}
	}
	return v
}

type directives []string

func (ds directives) HasIgnore() bool {
	return ds.isPresent("ignore")
}

func (ds directives) isPresent(name string) bool {
	for _, d := range ds {
		if d == name {
			return true
		}
	}
	return false
}

func parseDirectives(doc *ast.CommentGroup) directives {
	if doc == nil {
		return directives{}
	}
	const prefix = "//gocyclo:"
	var ds directives
	for _, comment := range doc.List {
		if strings.HasPrefix(comment.Text, prefix) {
			ds = append(ds, strings.TrimPrefix(comment.Text, prefix))
		}
	}
	return ds
}
<commit_msg>Rename type for sorting by complexity<commit_after>// Copyright 2013 Frederik Zipp. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Gocyclo calculates the cyclomatic complexities of functions and
// methods in Go source code.
//
// Usage:
//      gocyclo [<flag> ...] <Go file or directory> ...
//
// Flags:
//      -over N   show functions with complexity > N only and
//                return exit code 1 if the output is non-empty
//      -top N    show the top N most complex functions only
//      -avg      show the average complexity
//      -total    show the total complexity
//
// The output fields for each line are:
// <complexity> <package> <function> <file:row:column>
package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

const usageDoc = `Calculate cyclomatic complexities of Go functions.
Usage:
        gocyclo [flags] <Go file or directory> ...

Flags:
        -over N   show functions with complexity > N only and
                  return exit code 1 if the set is non-empty
        -top N    show the top N most complex functions only
        -avg      show the average complexity over all functions,
                  not depending on whether -over or -top are set
        -total    show the total complexity for all functions

The output fields for each line are:
<complexity> <package> <function> <file:row:column>
`

func usage() {
	fmt.Fprintf(os.Stderr, usageDoc)
	os.Exit(2)
}

var (
	over  = flag.Int("over", 0, "show functions with complexity > N only")
	top   = flag.Int("top", -1, "show the top N most complex functions only")
	avg   = flag.Bool("avg", false, "show the average complexity")
	total = flag.Bool("total", false, "show the total complexity")
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("gocyclo: ")
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		usage()
	}

	stats := analyze(args)
	sort.Sort(byComplexityDesc(stats))
	written := writeStats(os.Stdout, stats)

	if *avg {
		showAverage(stats)
	}

	if *total {
		showTotal(stats)
	}

	if *over > 0 && written > 0 {
		os.Exit(1)
	}
}

func analyze(paths []string) []stat {
	var stats []stat
	for _, path := range paths {
		if isDir(path) {
			stats = analyzeDir(path, stats)
		} else {
			stats = analyzeFile(path, stats)
		}
	}
	return stats
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func analyzeFile(fname string, stats []stat) []stat {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
	if err != nil {
		log.Fatal(err)
	}
	return buildStats(f, fset, stats)
}

func analyzeDir(dirname string, stats []stat) []stat {
	filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() && strings.HasSuffix(path, ".go") {
			stats = analyzeFile(path, stats)
		}
		return err
	})
	return stats
}

func writeStats(w io.Writer, sortedStats []stat) int {
	for i, stat := range sortedStats {
		if i == *top {
			return i
		}
		if stat.Complexity <= *over {
			return i
		}
		fmt.Fprintln(w, stat)
	}
	return len(sortedStats)
}

func showAverage(stats []stat) {
	fmt.Printf("Average: %.3g\n", average(stats))
}

func average(stats []stat) float64 {
	total := 0
	for _, s := range stats {
		total += s.Complexity
	}
	return float64(total) / float64(len(stats))
}

func showTotal(stats []stat) {
	fmt.Printf("Total: %d\n", sumtotal(stats))
}

func sumtotal(stats []stat) uint64 {
	total := uint64(0)
	for _, s := range stats {
		total += uint64(s.Complexity)
	}
	return total
}

type stat struct {
	PkgName    string
	FuncName   string
	Complexity int
	Pos        token.Position
}

func (s stat) String() string {
	return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
}

type byComplexityDesc []stat

func (s byComplexityDesc) Len() int      { return len(s) }
func (s byComplexityDesc) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byComplexityDesc) Less(i, j int) bool {
	return s[i].Complexity >= s[j].Complexity
}

func buildStats(f *ast.File, fset *token.FileSet, stats []stat) []stat {
	for _, declaration := range f.Decls {
		switch decl := declaration.(type) {
		case *ast.FuncDecl:
			stats = addStatIfNotIgnored(stats, decl, funcName(decl), decl.Doc, f, fset)
		case *ast.GenDecl:
			for _, spec := range decl.Specs {
				valueSpec, ok := spec.(*ast.ValueSpec)
				if !ok {
					continue
				}
				for _, value := range valueSpec.Values {
					funcLit, ok := value.(*ast.FuncLit)
					if !ok {
						continue
					}
					stats = addStatIfNotIgnored(stats, funcLit, valueSpec.Names[0].Name, decl.Doc, f, fset)
				}
			}
		}
	}
	return stats
}

func addStatIfNotIgnored(stats []stat, funcNode ast.Node, funcName string, doc *ast.CommentGroup, f *ast.File, fset *token.FileSet) []stat {
	if parseDirectives(doc).HasIgnore() {
		return stats
	}
	return append(stats, statForFunc(funcNode, funcName, f, fset))
}

func statForFunc(funcNode ast.Node, funcName string, f *ast.File, fset *token.FileSet) stat {
	return stat{
		PkgName:    f.Name.Name,
		FuncName:   funcName,
		Complexity: complexity(funcNode),
		Pos:        fset.Position(funcNode.Pos()),
	}
}

// funcName returns the name representation of a function or method:
// "(Type).Name" for methods or simply "Name" for functions.
func funcName(fn *ast.FuncDecl) string {
	if fn.Recv != nil {
		if fn.Recv.NumFields() > 0 {
			typ := fn.Recv.List[0].Type
			return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
		}
	}
	return fn.Name.Name
}

// recvString returns a string representation of recv of the
// form "T", "*T", or "BADRECV" (if not a proper receiver type).
func recvString(recv ast.Expr) string {
	switch t := recv.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.StarExpr:
		return "*" + recvString(t.X)
	}
	return "BADRECV"
}

// complexity calculates the cyclomatic complexity of a function.
func complexity(fn ast.Node) int {
	v := complexityVisitor{}
	ast.Walk(&v, fn)
	return v.Complexity
}

type complexityVisitor struct {
	// Complexity is the cyclomatic complexity
	Complexity int
}

// Visit implements the ast.Visitor interface.
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.FuncDecl, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.CaseClause, *ast.CommClause:
		v.Complexity++
	case *ast.BinaryExpr:
		if n.Op == token.LAND || n.Op == token.LOR {
			v.Complexity++
		}
	}
	return v
}

type directives []string

func (ds directives) HasIgnore() bool {
	return ds.isPresent("ignore")
}

func (ds directives) isPresent(name string) bool {
	for _, d := range ds {
		if d == name {
			return true
		}
	}
	return false
}

func parseDirectives(doc *ast.CommentGroup) directives {
	if doc == nil {
		return directives{}
	}
	const prefix = "//gocyclo:"
	var ds directives
	for _, comment := range doc.List {
		if strings.HasPrefix(comment.Text, prefix) {
			ds = append(ds, strings.TrimPrefix(comment.Text, prefix))
		}
	}
	return ds
}
<|endoftext|>


<commit_before>package goinout

import (
	"path/filepath"
	"plugin"
	"strings"
	"sync"
	"time"

	"github.com/drkaka/lg"
	"github.com/rjeczalik/notify"
	"go.uber.org/zap"
	"golang.org/x/sys/unix"
)

type loadFunc func(*plugin.Plugin, string)

// move event
type move struct {
	from string
	to   string
}

type moves struct {
	all map[uint32]move
	l   *sync.RWMutex
}

// Start the service
func Start(input, output string) {
	inputsPath = input
	outputsPath = output

	getOutputPlugins()
	startInputPlugins()

	observeInputs()
	observeOutputs()
	lg.L(nil).Info("started", zap.String("inputsPath", input), zap.String("outputsPath", output))
}

// Stop and cleanup
func Stop() {
	lg.L(nil).Info("stopped")
}

func extOK(file string) bool {
	return filepath.Ext(file) == ".so"
}

func pluginName(file string) string {
	return strings.TrimSuffix(file, filepath.Ext(file))
}

func loadPlugin(file string, load loadFunc) {
	if !extOK(file) {
		lg.L(nil).Debug("invalid input ext", zap.String("file", file))
		return
	}

	p, err := plugin.Open(file)
	if err != nil {
		lg.L(nil).Error("open file wrong", zap.Error(err))
		return
	}

	load(p, pluginName(filepath.Base(file)))
}

func observe(folderPath string, load loadFunc, delete func(string), rename func(string, string)) {
	c := make(chan notify.EventInfo, 1)

	if err := notify.Watch(folderPath, c, notify.InCloseWrite, notify.InDelete, notify.InMovedTo, notify.InMovedFrom); err != nil {
		lg.L(nil).Panic("watcher wrong", zap.Error(err))
	}

	// Process events
	go func() {
		moving := moves{
			all: make(map[uint32]move),
			l:   new(sync.RWMutex),
		}
		for {
			ei := <-c
			fileName := filepath.Base(ei.Path())
			name := pluginName(fileName)
			lg.L(nil).Debug("file changed", zap.String("path", ei.Path()), zap.String("event", ei.Event().String()))

			switch ei.Event() {
			case notify.InDelete:
				delete(name)
			case notify.InCloseWrite:
				loadPlugin(ei.Path(), load)
			case notify.InMovedTo:
				cookie := ei.Sys().(*unix.InotifyEvent).Cookie
				if cookie == uint32(0) {
					lg.L(nil).Error("cookie is 0", zap.Any("event", ei))
				} else {
					// set to value
					moving.l.Lock()
					info := moving.all[cookie]
					info.to = ei.Path()
					moving.all[cookie] = info
					moving.l.Unlock()

					handleMoveing(&moving, cookie, load, delete, rename)
				}
			case notify.InMovedFrom:
				cookie := ei.Sys().(*unix.InotifyEvent).Cookie
				if cookie == uint32(0) {
					lg.L(nil).Error("cookie is 0", zap.Any("event", ei))
				} else {
					// set from value
					moving.l.Lock()
					info := moving.all[cookie]
					info.from = ei.Path()
					moving.all[cookie] = info
					moving.l.Unlock()

					handleMoveing(&moving, cookie, load, delete, rename)
				}
			}
		}
	}()
}

func handleMoveing(m *moves, ck uint32, load loadFunc, del func(string), ren func(string, string)) {
	m.l.RLock()
	info := m.all[ck]
	m.l.RUnlock()

	if info.from != "" && info.to != "" {
		// rename event generated
		ren(filepath.Base(pluginName(info.from)), filepath.Base(pluginName(info.to)))

		// delete this record
		m.l.Lock()
		delete(m.all, ck)
		m.l.Unlock()
	} else {
		go func() {
			// final check after 0.5s, because move job can be done between different folders
			<-time.After(500 * time.Millisecond)
			finalCheck(m, ck, load, del, ren)
		}()
	}
}

func finalCheck(m *moves, ck uint32, load loadFunc, del func(string), ren func(string, string)) {
	m.l.RLock()
	info, ok := m.all[ck]
	m.l.RUnlock()

	// the info still existed
	if ok {
		if info.to != "" {
			// to not empty means file moved to this place
			loadPlugin(info.to, load)
		} else if info.from != "" {
			// from not empty means the file moved away
			del(filepath.Base(pluginName(info.from)))
		}

		// delete this record
		m.l.Lock()
		delete(m.all, ck)
		m.l.Unlock()
	}
}
<commit_msg>Add already loaded error detection.<commit_after>package goinout

import (
	"path/filepath"
	"plugin"
	"strings"
	"sync"
	"time"

	"github.com/drkaka/lg"
	"github.com/rjeczalik/notify"
	"go.uber.org/zap"
	"golang.org/x/sys/unix"
)

type loadFunc func(*plugin.Plugin, string)

// move event
type move struct {
	from string
	to   string
}

type moves struct {
	all map[uint32]move
	l   *sync.RWMutex
}

// Start the service
func Start(input, output string) {
	inputsPath = input
	outputsPath = output

	getOutputPlugins()
	startInputPlugins()

	observeInputs()
	observeOutputs()
	lg.L(nil).Info("started", zap.String("inputsPath", input), zap.String("outputsPath", output))
}

// Stop and cleanup
func Stop() {
	lg.L(nil).Info("stopped")
}

func extOK(file string) bool {
	return filepath.Ext(file) == ".so"
}

func pluginName(file string) string {
	return strings.TrimSuffix(file, filepath.Ext(file))
}

func loadPlugin(file string, load loadFunc) {
	if !extOK(file) {
		lg.L(nil).Debug("invalid input ext", zap.String("file", file))
		return
	}

	p, err := plugin.Open(file)
	if err != nil {
		if strings.Contains(err.Error(), "plugin already loaded") {
			lg.L(nil).Warn(err.Error(), zap.String("file", file))
			return
		}
		lg.L(nil).Error("open file wrong", zap.Error(err))
		return
	}

	load(p, pluginName(filepath.Base(file)))
}

func observe(folderPath string, load loadFunc, delete func(string), rename func(string, string)) {
	c := make(chan notify.EventInfo, 1)

	if err := notify.Watch(folderPath, c, notify.InCloseWrite, notify.InDelete, notify.InMovedTo, notify.InMovedFrom); err != nil {
		lg.L(nil).Panic("watcher wrong", zap.Error(err))
	}

	// Process events
	go func() {
		moving := moves{
			all: make(map[uint32]move),
			l:   new(sync.RWMutex),
		}
		for {
			ei := <-c
			fileName := filepath.Base(ei.Path())
			name := pluginName(fileName)
			lg.L(nil).Debug("file changed", zap.String("path", ei.Path()), zap.String("event", ei.Event().String()))

			switch ei.Event() {
			case notify.InDelete:
				delete(name)
			case notify.InCloseWrite:
				loadPlugin(ei.Path(), load)
			case notify.InMovedTo:
				cookie := ei.Sys().(*unix.InotifyEvent).Cookie
				if cookie == uint32(0) {
					lg.L(nil).Error("cookie is 0", zap.Any("event", ei))
				} else {
					// set to value
					moving.l.Lock()
					info := moving.all[cookie]
					info.to = ei.Path()
					moving.all[cookie] = info
					moving.l.Unlock()

					handleMoveing(&moving, cookie, load, delete, rename)
				}
			case notify.InMovedFrom:
				cookie := ei.Sys().(*unix.InotifyEvent).Cookie
				if cookie == uint32(0) {
					lg.L(nil).Error("cookie is 0", zap.Any("event", ei))
				} else {
					// set from value
					moving.l.Lock()
					info := moving.all[cookie]
					info.from = ei.Path()
					moving.all[cookie] = info
					moving.l.Unlock()

					handleMoveing(&moving, cookie, load, delete, rename)
				}
			}
		}
	}()
}

func handleMoveing(m *moves, ck uint32, load loadFunc, del func(string), ren func(string, string)) {
	m.l.RLock()
	info := m.all[ck]
	m.l.RUnlock()

	if info.from != "" && info.to != "" {
		// rename event generated
		ren(filepath.Base(pluginName(info.from)), filepath.Base(pluginName(info.to)))

		// delete this record
		m.l.Lock()
		delete(m.all, ck)
		m.l.Unlock()
	} else {
		go func() {
			// final check after 0.5s, because move job can be done between different folders
			<-time.After(500 * time.Millisecond)
			finalCheck(m, ck, load, del, ren)
		}()
	}
}

func finalCheck(m *moves, ck uint32, load loadFunc, del func(string), ren func(string, string)) {
	m.l.RLock()
	info, ok := m.all[ck]
	m.l.RUnlock()

	// the info still existed
	if ok {
		if info.to != "" {
			// to not empty means file moved to this place
			loadPlugin(info.to, load)
		} else if info.from != "" {
			// from not empty means the file moved away
			del(filepath.Base(pluginName(info.from)))
		}

		// delete this record
		m.l.Lock()
		delete(m.all, ck)
		m.l.Unlock()
	}
}
<|endoftext|>


<commit_before>// Package golfram provides a go interface with the wolfram alpha api
package golfram

import (
	"encoding/xml"
	"errors"
	//"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
)

const (
	libraryVersion = "0.1"
	// Wolfram api url
)

// Client that connects to the wolfram api
type Client struct {
	client     *http.Client
	AppID      string
	Results    []*Queryresult
	WolframURL string
}

// Pod generated by wolfram for the query
// Contains subpods, and title of the pod
type Pod struct {
	Error      string    `xml:"error,attr"`
	Id         string    `xml:"id,attr"`
	Title      string    `xml:"title,attr"`
	Numsubpods int       `xml:"numsubpods,attr"`
	Subpod     []*Subpod `xml:"subpod"`
}

type Source struct {
	Url  string `xml:"url,attr"`
	Text string `xml:"text,attr"`
}

type Assumption struct {
	Type     string   `xml:"type,attr"`
	Word     string   `xml:"word,attr"`
	Template string   `xml:"template,attr"`
	Values   []*Value `xml:"value"`
}

type Value struct {
	Name  string `xml:"name,attr"`
	Desc  string `xml:"desc,attr"`
	Input string `xml:"input,attr"`
}

// Subpod in pod
// Img: Image inside of subpod(if exists)
// Title: Title of subpod
// Plaintext: Plaintext response for subpod(if exists)
type Subpod struct {
	Title     string `xml:"title,attr"`
	Plaintext string `xml:"plaintext"`
	Img       Img    `xml:"img"`
}

// Image in subpod
// Src: Url of image
type Img struct {
	Src    string `xml:"src,attr"`
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
}

// Result of query
// Input: query string
// Success
// Error
// Datatypes: types of pods returned
// Pod[]: array of pods returned
// Podtitles[]: array of titles of pods(not to be used externally instead use result.GetPodByTitle(title)
type Queryresult struct {
	Input       string
	Success     string `xml:"success,attr"`
	Error       string `xml:"error,attr"`
	Numpods     int    `xml:"numpods,attr"`
	Datatypes   string `xml:"datatypes,attr"`
	Pod         []*Pod `xml:"pod"`
	Podtitles   []string
	Assumptions []*Assumption `xml:"assumptions>assumption"`
	Sources     []*Source     `xml:"sources>source"`
}

// Constructs a new client given an api key
// Returns pointer to client
func NewClient(appID string, wolframURL string) *Client {
	httpClient := http.DefaultClient
	if wolframURL == "" {
		wolframURL = "http://api.wolframalpha.com/v2/query"
	}
	c := &Client{client: httpClient, AppID: appID, WolframURL: wolframURL}
	return c
}

// Constructs and sends a query to wolfram api from given string
// Returns pointer to query result and error.
func (c *Client) NewQuery(query string) (*Queryresult, error) {
	urlStr := c.WolframURL + "?input=" + url.QueryEscape(query) + "&appid=" + c.AppID + "&scantimeout=3"
	//fmt.Println(urlStr)
	req, err := http.NewRequest("GET", urlStr, nil)
	if err != nil {
		return nil, err
	}
	resp, _ := c.client.Do(req)

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	result := &Queryresult{Input: query}

	//fmt.Println(string(body))

	err = xml.Unmarshal(body, &result)
	if err != nil {
		return nil, err
	}

	result = result.GenerateTitles()

	c.Results = append(c.Results, result)

	return result, nil
}

// Not to be used externally called when result is being unmarshalled in NewQuery
// Generates the Podtitles array of the Queryresult
func (r *Queryresult) GenerateTitles() *Queryresult {
	r.Podtitles = make([]string, r.Numpods)
	for index, pod := range r.Pod {
		r.Podtitles[index] = pod.Title
	}
	return r
}

// Returns pod with given title
// Used to find which pod contains plots
func (r *Queryresult) GetPodByTitle(title string) (*Pod, error) {
	for _, pod := range r.Pod {
		if pod.Title == title {
			return pod, nil
		}
	}
	return nil, errors.New("No pod found")
}

func (r *Queryresult) String() string {
	rets := []string{}
	for index, pod := range r.Pod {
		rets = append(rets, "Pod"+string(index)+": "+pod.String())
		rets = append(rets, "\n")
	}
	return strings.Join(rets, "")
}

func (p *Pod) String() string {
	title := ""
	if p.Title != "" {
		title = p.Title + ": "
	}
	rets := []string{title}
	for index, subpod := range p.Subpod {
		if p.Numsubpods > 1 {
			rets = append(rets, "\n\tSubpod"+string(index)+": "+subpod.String())
		} else {
			rets = append(rets, "\n"+subpod.String())
		}
	}
	return strings.Join(rets, "")
}

func (s *Subpod) String() string {
	title := ""
	body := ""
	if s.Title != "" {
		title = s.Title + ": "
	}
	if s.Plaintext != "" {
		body = s.Plaintext
	} else if s.Img.Src != "" {
		body = s.Img.Src
	}
	return title + body
}

// Downloads the plot from the given queryresult at the given index
// Most cases will want to use index of 0(e.q. c.GetPlot(result, 0)
// Returns path to saved plot image and error
func (c *Client) GetPlot(result *Queryresult, index int, filename string) (string, error) {
	return c.GetImage(result, "Plots", index, filename)
}

// Downloads image from subpod at given index of pod in given result with given title
// Most cases will want to use result.GetPlot instead
func (c *Client) GetImage(result *Queryresult, title string, subpod int, filename string) (string, error) {
	pod, err := result.GetPodByTitle(title)
	if err != nil {
		return "No pod found", err
	}
	img := pod.Subpod[subpod].Img
	urlStr := img.Src
	path := filename
	if path == "" {
		path = "imgs/" + strings.Replace(result.Input, " ", "_", -1)
	}
	file, err := os.Create(path)

	req, err := http.NewRequest("GET", urlStr, nil)
	if err != nil {
		return "", err
	}
	resp, _ := c.client.Do(req)

	defer resp.Body.Close()
	_, err = io.Copy(file, resp.Body)

	return path, nil
}
<commit_msg>Bumped Version<commit_after>// Package golfram provides a go interface with the wolfram alpha api
package golfram

import (
	"encoding/xml"
	"errors"
	//"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
)

const (
	libraryVersion = "0.2"
)

// Client that connects to the wolfram api
type Client struct {
	client     *http.Client
	AppID      string
	Results    []*Queryresult
	WolframURL string
}

// Pod generated by wolfram for the query
// Contains subpods, and title of the pod
type Pod struct {
	Error      string    `xml:"error,attr"`
	Id         string    `xml:"id,attr"`
	Title      string    `xml:"title,attr"`
	Numsubpods int       `xml:"numsubpods,attr"`
	Subpod     []*Subpod `xml:"subpod"`
}

type Source struct {
	Url  string `xml:"url,attr"`
	Text string `xml:"text,attr"`
}

type Assumption struct {
	Type     string   `xml:"type,attr"`
	Word     string   `xml:"word,attr"`
	Template string   `xml:"template,attr"`
	Values   []*Value `xml:"value"`
}

type Value struct {
	Name  string `xml:"name,attr"`
	Desc  string `xml:"desc,attr"`
	Input string `xml:"input,attr"`
}

// Subpod in pod
// Img: Image inside of subpod(if exists)
// Title: Title of subpod
// Plaintext: Plaintext response for subpod(if exists)
type Subpod struct {
	Title     string `xml:"title,attr"`
	Plaintext string `xml:"plaintext"`
	Img       Img    `xml:"img"`
}

// Image in subpod
// Src: Url of image
type Img struct {
	Src    string `xml:"src,attr"`
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
}

// Result of query
// Input: query string
// Success
// Error
// Datatypes: types of pods returned
// Pod[]: array of pods returned
// Podtitles[]: array of titles of pods(not to be used externally instead use result.GetPodByTitle(title)
type Queryresult struct {
	Input       string
	Success     string `xml:"success,attr"`
	Error       string `xml:"error,attr"`
	Numpods     int    `xml:"numpods,attr"`
	Datatypes   string `xml:"datatypes,attr"`
	Pod         []*Pod `xml:"pod"`
	Podtitles   []string
	Assumptions []*Assumption `xml:"assumptions>assumption"`
	Sources     []*Source     `xml:"sources>source"`
}

// Constructs a new client given an api key
// Returns pointer to client
func NewClient(appID string, wolframURL string) *Client {
	httpClient := http.DefaultClient
	if wolframURL == "" {
		wolframURL = "http://api.wolframalpha.com/v2/query"
	}
	c := &Client{client: httpClient, AppID: appID, WolframURL: wolframURL}
	return c
}

// Constructs and sends a query to wolfram api from given string
// Returns pointer to query result and error.
func (c *Client) NewQuery(query string) (*Queryresult, error) {
	urlStr := c.WolframURL + "?input=" + url.QueryEscape(query) + "&appid=" + c.AppID + "&scantimeout=3"
	//fmt.Println(urlStr)
	req, err := http.NewRequest("GET", urlStr, nil)
	if err != nil {
		return nil, err
	}
	resp, _ := c.client.Do(req)

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	result := &Queryresult{Input: query}

	//fmt.Println(string(body))

	err = xml.Unmarshal(body, &result)
	if err != nil {
		return nil, err
	}

	result = result.GenerateTitles()

	c.Results = append(c.Results, result)

	return result, nil
}

// Not to be used externally called when result is being unmarshalled in NewQuery
// Generates the Podtitles array of the Queryresult
func (r *Queryresult) GenerateTitles() *Queryresult {
	r.Podtitles = make([]string, r.Numpods)
	for index, pod := range r.Pod {
		r.Podtitles[index] = pod.Title
	}
	return r
}

// Returns pod with given title
// Used to find which pod contains plots
func (r *Queryresult) GetPodByTitle(title string) (*Pod, error) {
	for _, pod := range r.Pod {
		if pod.Title == title {
			return pod, nil
		}
	}
	return nil, errors.New("No pod found")
}

func (r *Queryresult) String() string {
	rets := []string{}
	for index, pod := range r.Pod {
		rets = append(rets, "Pod"+string(index)+": "+pod.String())
		rets = append(rets, "\n")
	}
	return strings.Join(rets, "")
}

func (p *Pod) String() string {
	title := ""
	if p.Title != "" {
		title = p.Title + ": "
	}
	rets := []string{title}
	for index, subpod := range p.Subpod {
		if p.Numsubpods > 1 {
			rets = append(rets, "\n\tSubpod"+string(index)+": "+subpod.String())
		} else {
			rets = append(rets, "\n"+subpod.String())
		}
	}
	return strings.Join(rets, "")
}

func (s *Subpod) String() string {
	title := ""
	body := ""
	if s.Title != "" {
		title = s.Title + ": "
	}
	if s.Plaintext != "" {
		body = s.Plaintext
	} else if s.Img.Src != "" {
		body = s.Img.Src
	}
	return title + body
}

// Downloads the plot from the given queryresult at the given index
// Most cases will want to use index of 0(e.q. c.GetPlot(result, 0)
// Returns path to saved plot image and error
func (c *Client) GetPlot(result *Queryresult, index int, filename string) (string, error) {
	return c.GetImage(result, "Plots", index, filename)
}

// Downloads image from subpod at given index of pod in given result with given title
// Most cases will want to use result.GetPlot instead
func (c *Client) GetImage(result *Queryresult, title string, subpod int, filename string) (string, error) {
	pod, err := result.GetPodByTitle(title)
	if err != nil {
		return "No pod found", err
	}
	img := pod.Subpod[subpod].Img
	urlStr := img.Src
	path := filename
	if path == "" {
		path = "imgs/" + strings.Replace(result.Input, " ", "_", -1)
	}
	file, err := os.Create(path)

	req, err := http.NewRequest("GET", urlStr, nil)
	if err != nil {
		return "", err
	}
	resp, _ := c.client.Do(req)

	defer resp.Body.Close()
	_, err = io.Copy(file, resp.Body)

	return path, nil
}
<|endoftext|>


<commit_before>package promptui

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	"github.com/chzyer/readline"
	"github.com/manifoldco/promptui/screenbuf"
)

const cursor = "\u2588"

// Prompt represents a single line text field input.
type Prompt struct {
	// Label is the value displayed on the command line prompt. It can be any
	// value one would pass to a text/template Execute(), including just a string.
	Label interface{}

	Default string // Default is the initial value to populate in the prompt

	// AllowEdit lets the user edit the default value. If false, any key press
	// other than <Enter> automatically clears the default value.
	AllowEdit bool

	// Validate is optional. If set, this function is used to validate the input
	// after each character entry.
	Validate ValidateFunc

	// If mask is set, this value is displayed instead of the actual input
	// characters.
	Mask rune

	// Templates can be used to customize the prompt output. If nil is passed, the
	// default templates are used.
	Templates *PromptTemplates

	// IsConfirm sets the prompt to be a [y/N] question.
	IsConfirm bool

	// IsVimMode enables vi-like movements (hjkl) and editing.
	IsVimMode bool

	stdin  io.ReadCloser
	stdout io.WriteCloser
}

// PromptTemplates allow a prompt to be customized following stdlib
// text/template syntax. If any field is blank a default template is used.
type PromptTemplates struct {
	// Prompt is a text/template for the initial prompt question.
	Prompt string

	// Prompt is a text/template if the prompt is a confirmation.
	Confirm string

	// Valid is a text/template for when the current input is valid.
	Valid string

	// Invalid is a text/template for when the current input is invalid.
	Invalid string

	// Success is a text/template for the successful result.
	Success string

	// Prompt is a text/template when there is a validation error.
	ValidationError string

	// FuncMap is a map of helpers for the templates. If nil, the default helpers
	// are used.
	FuncMap template.FuncMap

	prompt     *template.Template
	valid      *template.Template
	invalid    *template.Template
	validation *template.Template
	success    *template.Template
}

// Run runs the prompt, returning the validated input.
func (p *Prompt) Run() (string, error) {
	c := &readline.Config{}
	err := c.Init()
	if err != nil {
		return "", err
	}

	err = p.prepareTemplates()
	if err != nil {
		return "", err
	}

	if p.stdin != nil {
		c.Stdin = p.stdin
	}

	if p.stdout != nil {
		c.Stdout = p.stdout
	}

	if p.Mask != 0 {
		c.EnableMask = true
		c.MaskRune = p.Mask
	}

	if p.IsVimMode {
		c.VimMode = true
	}

	c.HistoryLimit = -1
	c.UniqueEditLine = true

	rl, err := readline.NewEx(c)
	if err != nil {
		return "", err
	}

	rl.Write([]byte(hideCursor))
	sb := screenbuf.New(rl)

	validFn := func(x string) error {
		return nil
	}

	if p.Validate != nil {
		validFn = p.Validate
	}

	var inputErr error
	input := p.Default
	if p.IsConfirm {
		input = ""
	}
	eraseDefault := input != "" && !p.AllowEdit

	c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
		if line != nil {
			input += string(line)
		}

		switch key {
		case 0: // empty
		case KeyEnter:
			return nil, 0, false
		case KeyBackspace:
			if eraseDefault {
				eraseDefault = false
				input = ""
			}
			if len(input) > 0 {
				r := []rune(input)
				input = string(r[:len(r)-1])
			}
		default:
			if eraseDefault {
				eraseDefault = false
				input = string(line)
			}
		}

		err := validFn(input)
		var prompt []byte

		if err != nil {
			prompt = render(p.Templates.invalid, p.Label)
		} else {
			prompt = render(p.Templates.valid, p.Label)
			if p.IsConfirm {
				prompt = render(p.Templates.prompt, p.Label)
			}
		}

		echo := input
		if p.Mask != 0 {
			echo = strings.Repeat(string(p.Mask), len(echo))
		}

		prompt = append(prompt, []byte(echo+cursor)...)

		sb.Reset()
		sb.Write(prompt)

		if inputErr != nil {
			validation := render(p.Templates.validation, inputErr)
			sb.Write(validation)
			inputErr = nil
		}

		sb.Flush()

		return nil, 0, true
	})

	for {
		_, err = rl.Readline()

		inputErr = validFn(input)
		if inputErr == nil {
			break
		}

		if err != nil {
			switch err {
			case readline.ErrInterrupt:
				err = ErrInterrupt
			case io.EOF:
				err = ErrEOF
			}
			break
		}
	}

	if err != nil {
		if err.Error() == "Interrupt" {
			err = ErrInterrupt
		}
		sb.Reset()
		sb.WriteString("")
		sb.Flush()
		rl.Write([]byte(showCursor))
		rl.Close()
		return "", err
	}

	echo := input
	if p.Mask != 0 {
		echo = strings.Repeat(string(p.Mask), len(echo))
	}

	prompt := render(p.Templates.valid, p.Label)
	prompt = append(prompt, []byte(echo)...)

	if p.IsConfirm {
		lowerDefault := strings.ToLower(p.Default)
		if strings.ToLower(echo) != "y" && (lowerDefault != "y" || (lowerDefault == "y" && echo != "")) {
			prompt = render(p.Templates.invalid, p.Label)
			err = ErrAbort
		}
	}

	sb.Reset()
	sb.Write(prompt)
	sb.Flush()
	rl.Write([]byte(showCursor))
	rl.Close()

	return input, err
}

func (p *Prompt) prepareTemplates() error {
	tpls := p.Templates
	if tpls == nil {
		tpls = &PromptTemplates{}
	}

	if tpls.FuncMap == nil {
		tpls.FuncMap = FuncMap
	}

	bold := Styler(FGBold)

	if p.IsConfirm {
		if tpls.Confirm == "" {
			confirm := "y/N"
			if strings.ToLower(p.Default) == "y" {
				confirm = "Y/n"
			}
			tpls.Confirm = fmt.Sprintf(`{{ "%s" | bold }} {{ . | bold }}? {{ "[%s]" | faint }} `, IconInitial, confirm)
		}

		tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Confirm)
		if err != nil {
			return err
		}

		tpls.prompt = tpl
	} else {
		if tpls.Prompt == "" {
			tpls.Prompt = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconInitial), bold(":"))
		}

		tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Prompt)
		if err != nil {
			return err
		}

		tpls.prompt = tpl
	}

	if tpls.Valid == "" {
		tpls.Valid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":"))
	}

	tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Valid)
	if err != nil {
		return err
	}

	tpls.valid = tpl

	if tpls.Invalid == "" {
		tpls.Invalid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconBad), bold(":"))
	}

	tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Invalid)
	if err != nil {
		return err
	}

	tpls.invalid = tpl

	if tpls.ValidationError == "" {
		tpls.ValidationError = `{{ ">>" | red }} {{ . | red }}`
	}

	tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.ValidationError)
	if err != nil {
		return err
	}

	tpls.validation = tpl

	if tpls.Success == "" {
		tpls.Success = `{{ . | faint }}`
	}

	tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Success)
	if err != nil {
		return err
	}

	tpls.success = tpl

	p.Templates = tpls

	return nil
}
<commit_msg>render prompt success template once prompt completes<commit_after>package promptui

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	"github.com/chzyer/readline"
	"github.com/manifoldco/promptui/screenbuf"
)

const cursor = "\u2588"

// Prompt represents a single line text field input.
type Prompt struct {
	// Label is the value displayed on the command line prompt. It can be any
	// value one would pass to a text/template Execute(), including just a string.
	Label interface{}

	Default string // Default is the initial value to populate in the prompt

	// AllowEdit lets the user edit the default value. If false, any key press
	// other than <Enter> automatically clears the default value.
	AllowEdit bool

	// Validate is optional. If set, this function is used to validate the input
	// after each character entry.
	Validate ValidateFunc

	// If mask is set, this value is displayed instead of the actual input
	// characters.
	Mask rune

	// Templates can be used to customize the prompt output. If nil is passed, the
	// default templates are used.
	Templates *PromptTemplates

	// IsConfirm sets the prompt to be a [y/N] question.
	IsConfirm bool

	// IsVimMode enables vi-like movements (hjkl) and editing.
	IsVimMode bool

	stdin  io.ReadCloser
	stdout io.WriteCloser
}

// PromptTemplates allow a prompt to be customized following stdlib
// text/template syntax. If any field is blank a default template is used.
type PromptTemplates struct {
	// Prompt is a text/template for the initial prompt question.
	Prompt string

	// Prompt is a text/template if the prompt is a confirmation.
	Confirm string

	// Valid is a text/template for when the current input is valid.
	Valid string

	// Invalid is a text/template for when the current input is invalid.
	Invalid string

	// Success is a text/template for the successful result.
	Success string

	// Prompt is a text/template when there is a validation error.
	ValidationError string

	// FuncMap is a map of helpers for the templates. If nil, the default helpers
	// are used.
	FuncMap template.FuncMap

	prompt     *template.Template
	valid      *template.Template
	invalid    *template.Template
	validation *template.Template
	success    *template.Template
}

// Run runs the prompt, returning the validated input.
func (p *Prompt) Run() (string, error) {
	c := &readline.Config{}
	err := c.Init()
	if err != nil {
		return "", err
	}

	err = p.prepareTemplates()
	if err != nil {
		return "", err
	}

	if p.stdin != nil {
		c.Stdin = p.stdin
	}

	if p.stdout != nil {
		c.Stdout = p.stdout
	}

	if p.Mask != 0 {
		c.EnableMask = true
		c.MaskRune = p.Mask
	}

	if p.IsVimMode {
		c.VimMode = true
	}

	c.HistoryLimit = -1
	c.UniqueEditLine = true

	rl, err := readline.NewEx(c)
	if err != nil {
		return "", err
	}

	rl.Write([]byte(hideCursor))
	sb := screenbuf.New(rl)

	validFn := func(x string) error {
		return nil
	}

	if p.Validate != nil {
		validFn = p.Validate
	}

	var inputErr error
	input := p.Default
	if p.IsConfirm {
		input = ""
	}
	eraseDefault := input != "" && !p.AllowEdit

	c.SetListener(func(line []rune, pos int, key rune) ([]rune, int, bool) {
		if line != nil {
			input += string(line)
		}

		switch key {
		case 0: // empty
		case KeyEnter:
			return nil, 0, false
		case KeyBackspace:
			if eraseDefault {
				eraseDefault = false
				input = ""
			}
			if len(input) > 0 {
				r := []rune(input)
				input = string(r[:len(r)-1])
			}
		default:
			if eraseDefault {
				eraseDefault = false
				input = string(line)
			}
		}

		err := validFn(input)
		var prompt []byte

		if err != nil {
			prompt = render(p.Templates.invalid, p.Label)
		} else {
			prompt = render(p.Templates.valid, p.Label)
			if p.IsConfirm {
				prompt = render(p.Templates.prompt, p.Label)
			}
		}

		echo := input
		if p.Mask != 0 {
			echo = strings.Repeat(string(p.Mask), len(echo))
		}

		prompt = append(prompt, []byte(echo+cursor)...)

		sb.Reset()
		sb.Write(prompt)

		if inputErr != nil {
			validation := render(p.Templates.validation, inputErr)
			sb.Write(validation)
			inputErr = nil
		}

		sb.Flush()

		return nil, 0, true
	})

	for {
		_, err = rl.Readline()

		inputErr = validFn(input)
		if inputErr == nil {
			break
		}

		if err != nil {
			switch err {
			case readline.ErrInterrupt:
				err = ErrInterrupt
			case io.EOF:
				err = ErrEOF
			}
			break
		}
	}

	if err != nil {
		if err.Error() == "Interrupt" {
			err = ErrInterrupt
		}
		sb.Reset()
		sb.WriteString("")
		sb.Flush()
		rl.Write([]byte(showCursor))
		rl.Close()
		return "", err
	}

	echo := input
	if p.Mask != 0 {
		echo = strings.Repeat(string(p.Mask), len(echo))
	}

	prompt := render(p.Templates.success, p.Label)
	prompt = append(prompt, []byte(echo)...)

	if p.IsConfirm {
		lowerDefault := strings.ToLower(p.Default)
		if strings.ToLower(echo) != "y" && (lowerDefault != "y" || (lowerDefault == "y" && echo != "")) {
			prompt = render(p.Templates.invalid, p.Label)
			err = ErrAbort
		}
	}

	sb.Reset()
	sb.Write(prompt)
	sb.Flush()
	rl.Write([]byte(showCursor))
	rl.Close()

	return input, err
}

func (p *Prompt) prepareTemplates() error {
	tpls := p.Templates
	if tpls == nil {
		tpls = &PromptTemplates{}
	}

	if tpls.FuncMap == nil {
		tpls.FuncMap = FuncMap
	}

	bold := Styler(FGBold)

	if p.IsConfirm {
		if tpls.Confirm == "" {
			confirm := "y/N"
			if strings.ToLower(p.Default) == "y" {
				confirm = "Y/n"
			}
			tpls.Confirm = fmt.Sprintf(`{{ "%s" | bold }} {{ . | bold }}? {{ "[%s]" | faint }} `, IconInitial, confirm)
		}

		tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Confirm)
		if err != nil {
			return err
		}

		tpls.prompt = tpl
	} else {
		if tpls.Prompt == "" {
			tpls.Prompt = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconInitial), bold(":"))
		}

		tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Prompt)
		if err != nil {
			return err
		}

		tpls.prompt = tpl
	}

	if tpls.Valid == "" {
		tpls.Valid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":"))
	}

	tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Valid)
	if err != nil {
		return err
	}

	tpls.valid = tpl

	if tpls.Invalid == "" {
		tpls.Invalid = fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconBad), bold(":"))
	}

	tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Invalid)
	if err != nil {
		return err
	}

	tpls.invalid = tpl

	if tpls.ValidationError == "" {
		tpls.ValidationError = `{{ ">>" | red }} {{ . | red }}`
	}

	tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.ValidationError)
	if err != nil {
		return err
	}

	tpls.validation = tpl

	if tpls.Success == "" {
		tpls.Success = `{{ . | faint }}`
	}

	tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Success)
	if err != nil {
		return err
	}

	tpls.success = tpl

	p.Templates = tpls

	return nil
}
<|endoftext|>


<commit_before>/*
Package gonexmo implements a simple client library for accessing the Nexmo API.

Usage is simple. Create a Nexmo instance with NexmoWithKeyAndSecret(), providing
your API key and API secret. Then send messages with SendTextMessage() or
SendFlashMessage(). The API will return a MessageResponse which you can
use to see if your message went through, how much it cost, etc.
*/
package nexmo

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	apiRoot = "https://rest.nexmo.com"
)

// MessageReport is the "status report" for a single SMS sent via the Nexmo API
type MessageReport struct {
	Status           string `json:"status"`
	MessageID        string `json:"message-id"`
	To               string `json:"to"`
	ClientReference  string `json:"client-ref"`
	RemainingBalance string `json:"remaining-balance"`
	MessagePrice     string `json:"message-price"`
	Network          string `json:"network"`
	ErrorText        string `json:"error-text"`
}

// MessageResponse contains the response from Nexmo's API after we attempt to
// send any kind of message.
// It will contain one MessageReport for every 160 chars sent.
type MessageResponse struct {
	MessageCount string          `json:"message-count"`
	Messages     []MessageReport `json:"messages"`
}

// AccountBalance represents the "balance" object we get back when calling
// GET /account/get-balance
type AccountBalance struct {
	Value float64 `json:"value"`
}

// Nexmo encapsulates the Nexmo functions - must be created with
// NexmoWithKeyAndSecret()
type Client struct {
	apiKey    string
	apiSecret string
	useOauth  bool
}

// NexmoWithKeyAndSecret creates a Nexmo object with the provided API key / API
// secret.
func NewClientFromAPI(apiKey, apiSecret string) (*Client, error) {
	if apiKey == "" {
		return nil, errors.New("apiKey can not be empty!")
	} else if apiSecret == "" {
		return nil, errors.New("apiSecret can not be empty!")
	}

	return &Client{apiKey, apiSecret, false}, nil
}

func (nexmo *Client) sendMessage(from, to, text, clientReference string,
	statusReportRequired bool, isFlashMessage bool) (*MessageResponse, error) {
	if len(clientReference) > 40 {
		return nil, errors.New("Client reference too long")
	}
	var messageResponse *MessageResponse

	values := make(url.Values)
	values.Set("api_key", nexmo.apiKey)
	values.Set("api_secret", nexmo.apiSecret)
	values.Set("type", "text")

	values.Set("to", to)
	values.Set("from", from)
	values.Set("text", text)
	values.Set("client_ref", clientReference)

	if statusReportRequired {
		values.Set("status_report_req", string(1))

	}
	if isFlashMessage {
		values.Set("message_class", "0")
	}

	client := &http.Client{}
	var r *http.Request
	r, _ = http.NewRequest("POST", apiRoot+"/sms/json", bytes.NewReader([]byte(values.Encode())))
	r.Header.Add("Accept", "application/json")
	r.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(r)
	defer resp.Body.Close()

	if err != nil {
		return nil, err
	}

	body, _ := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal(body, &messageResponse)
	if err != nil {
		return nil, err
	} else {
		return messageResponse, nil
	}
}

// SendTextMessage() sends a normal SMS
func (nexmo *Client) SendTextMessage(from, to, text, clientReference string,
	statusReportRequired bool) (*MessageResponse, error) {
	return nexmo.sendMessage(from, to, text, clientReference,
		statusReportRequired, false)
}

// SendFlashMessage() sends a class 0 SMS (Flash message).
func (nexmo *Client) SendFlashMessage(from, to, text, clientReference string,
	statusReportRequired bool) (*MessageResponse, error) {
	return nexmo.sendMessage(from, to, text, clientReference,
		statusReportRequired, true)
}

// GetBalance() retrieves the current balance of your Nexmo account in Euros (€)
func (nexmo *Client) GetBalance() (float64, error) {
	var accBalance *AccountBalance

	client := &http.Client{}
	r, _ := http.NewRequest("GET", apiRoot+"/account/get-balance/"+
		nexmo.apiKey+"/"+nexmo.apiSecret, nil)
	r.Header.Add("Accept", "application/json")

	resp, err := client.Do(r)
	defer resp.Body.Close()

	if err != nil {
		return 0.0, err
	}

	body, _ := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal(body, &accBalance)
	if err != nil {
		return 0.0, err
	} else {
		return accBalance.Value, nil
	}
}
<commit_msg>AccountBalance can be a function-local type<commit_after>/*
Package gonexmo implements a simple client library for accessing the Nexmo API.

Usage is simple. Create a Nexmo instance with NexmoWithKeyAndSecret(), providing
your API key and API secret. Then send messages with SendTextMessage() or
SendFlashMessage(). The API will return a MessageResponse which you can
use to see if your message went through, how much it cost, etc.
*/
package nexmo

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	apiRoot = "https://rest.nexmo.com"
)

// MessageReport is the "status report" for a single SMS sent via the Nexmo API
type MessageReport struct {
	Status           string `json:"status"`
	MessageID        string `json:"message-id"`
	To               string `json:"to"`
	ClientReference  string `json:"client-ref"`
	RemainingBalance string `json:"remaining-balance"`
	MessagePrice     string `json:"message-price"`
	Network          string `json:"network"`
	ErrorText        string `json:"error-text"`
}

// MessageResponse contains the response from Nexmo's API after we attempt to
// send any kind of message.
// It will contain one MessageReport for every 160 chars sent.
type MessageResponse struct {
	MessageCount string          `json:"message-count"`
	Messages     []MessageReport `json:"messages"`
}

// Nexmo encapsulates the Nexmo functions - must be created with
// NexmoWithKeyAndSecret()
type Client struct {
	apiKey    string
	apiSecret string
	useOauth  bool
}

// NexmoWithKeyAndSecret creates a Nexmo object with the provided API key / API
// secret.
func NewClientFromAPI(apiKey, apiSecret string) (*Client, error) {
	if apiKey == "" {
		return nil, errors.New("apiKey can not be empty!")
	} else if apiSecret == "" {
		return nil, errors.New("apiSecret can not be empty!")
	}

	return &Client{apiKey, apiSecret, false}, nil
}

func (nexmo *Client) sendMessage(from, to, text, clientReference string,
	statusReportRequired bool, isFlashMessage bool) (*MessageResponse, error) {
	if len(clientReference) > 40 {
		return nil, errors.New("Client reference too long")
	}
	var messageResponse *MessageResponse

	values := make(url.Values)
	values.Set("api_key", nexmo.apiKey)
	values.Set("api_secret", nexmo.apiSecret)
	values.Set("type", "text")

	values.Set("to", to)
	values.Set("from", from)
	values.Set("text", text)
	values.Set("client_ref", clientReference)

	if statusReportRequired {
		values.Set("status_report_req", string(1))

	}
	if isFlashMessage {
		values.Set("message_class", "0")
	}

	client := &http.Client{}
	var r *http.Request
	r, _ = http.NewRequest("POST", apiRoot+"/sms/json", bytes.NewReader([]byte(values.Encode())))
	r.Header.Add("Accept", "application/json")
	r.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(r)
	defer resp.Body.Close()

	if err != nil {
		return nil, err
	}

	body, _ := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal(body, &messageResponse)
	if err != nil {
		return nil, err
	} else {
		return messageResponse, nil
	}
}

// SendTextMessage() sends a normal SMS
func (nexmo *Client) SendTextMessage(from, to, text, clientReference string,
	statusReportRequired bool) (*MessageResponse, error) {
	return nexmo.sendMessage(from, to, text, clientReference,
		statusReportRequired, false)
}

// SendFlashMessage() sends a class 0 SMS (Flash message).
func (nexmo *Client) SendFlashMessage(from, to, text, clientReference string,
	statusReportRequired bool) (*MessageResponse, error) {
	return nexmo.sendMessage(from, to, text, clientReference,
		statusReportRequired, true)
}

// GetBalance() retrieves the current balance of your Nexmo account in Euros (€)
func (nexmo *Client) GetBalance() (float64, error) {
	// Declare this locally, since we are only going to return a float64.
	type AccountBalance struct {
		Value float64 `json:"value"`
	}

	var accBalance *AccountBalance

	client := &http.Client{}
	r, _ := http.NewRequest("GET", apiRoot+"/account/get-balance/"+
		nexmo.apiKey+"/"+nexmo.apiSecret, nil)
	r.Header.Add("Accept", "application/json")

	resp, err := client.Do(r)
	defer resp.Body.Close()

	if err != nil {
		return 0.0, err
	}

	body, _ := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal(body, &accBalance)
	if err != nil {
		return 0.0, err
	} else {
		return accBalance.Value, nil
	}
}
<|endoftext|>


<commit_before>package appdb

import (
	"reflect"
	"strings"
	"testing"
	"time"

	"chain/database/pg/pgtest"
	"chain/fedchain-sandbox/hdkey"
)

var accountFixture = `
	INSERT INTO manager_nodes (
		id, project_id, block_chain, sigs_required, key_index,
		label, current_rotation, next_asset_index, next_account_index,
		accounts_count, created_at, updated_at
	)
	VALUES ('mn1', 'proj-id-0', 'sandbox', 1, 1, 'foo', 'rot1', 0, 1, 1, now(), now());
	INSERT INTO rotations (id, manager_node_id, keyset)
	VALUES ('rot1', 'mn1', '{` + dummyXPub.String() + `}');
	INSERT INTO accounts (
		id, manager_node_id, key_index, created_at, updated_at,
		next_address_index, label
	)
	VALUES ('acc1', 'mn1', 0, now(), now(), 0, 'foo');
`

func TestAddressLoadNextIndex(t *testing.T) {
	ctx := pgtest.NewContext(t, sampleProjectFixture, accountFixture)
	defer pgtest.Finish(ctx)

	// Force predictable values.
	addrIndexNext, addrIndexCap = 1, 100

	exp := time.Now().Add(5 * time.Minute)
	addr := &Address{
		AccountID: "acc1",
		Amount:    100,
		Expires:   exp,
		IsChange:  false,
	}
	err := addr.LoadNextIndex(ctx) // get most fields from the db given AccountID
	if err != nil {
		t.Fatal(err)
	}

	want := &Address{
		AccountID: "acc1",
		Amount:    100,
		Expires:   exp,
		IsChange:  false,

		ManagerNodeID:    "mn1",
		ManagerNodeIndex: []uint32{0, 1},
		AccountIndex:     []uint32{0, 0},
		Index:            []uint32{0, 1},
		SigsRequired:     1,
		Keys:             []*hdkey.XKey{dummyXPub},
	}

	if !reflect.DeepEqual(addr, want) {
		t.Errorf("addr = %+v want %+v", addr, want)
	}
}

func TestAddressInsert(t *testing.T) {
	t0 := time.Now()
	ctx := pgtest.NewContext(t, sampleProjectFixture, accountFixture)
	defer pgtest.Finish(ctx)

	// Force predictable values.
	addrIndexNext, addrIndexCap = 1, 100

	addr := &Address{
		AccountID:        "acc1",
		Amount:           100,
		Expires:          t0.Add(5 * time.Minute),
		IsChange:         false,
		ManagerNodeID:    "mn1",
		ManagerNodeIndex: []uint32{0, 1},
		AccountIndex:     []uint32{0, 0},
		Index:            []uint32{0, 0},
		SigsRequired:     1,
		Keys:             []*hdkey.XKey{dummyXPub},

		RedeemScript: []byte{},
		PKScript:     []byte{},
	}

	err := addr.Insert(ctx) // get most fields from the db given AccountID
	if err != nil {
		t.Fatal(err)
	}

	if !strings.HasPrefix(addr.ID, "a") {
		t.Errorf("ID = %q want prefix 'a'", addr.ID)
	}
	if addr.Created.Before(t0) {
		t.Errorf("Created = %v want after %v", addr.Created, t0)
	}
}

var dummyXPub2, _ = hdkey.NewXKey("xpub661MyMwAqRbcFoBSqmqxsAGLAgoLBDHXgZutXooGvHGKXgqPK9HYiVZNoqhGuwzeFW27JBpgZZEabMZhFHkxehJmT8H3AfmfD4zhniw5jcw")

func TestCreateAddress(t *testing.T) {
	t0 := time.Now()
	ctx := pgtest.NewContext(t, `
		INSERT INTO projects (id, name) VALUES ('proj-id-0', 'proj-0');
	`)
	defer pgtest.Finish(ctx)

	// Force predictable values.
	addrIndexNext, addrIndexCap = 1, 100

	managerNode, err := InsertManagerNode(ctx, "proj-id-0", "foo", []*hdkey.XKey{dummyXPub2}, nil, 0, 1)
	if err != nil {
		t.Fatal(err)
	}
	account, err := CreateAccount(ctx, managerNode.ID, "foo", nil)
	if err != nil {
		t.Fatal(err)
	}

	exp := t0.Add(5 * time.Minute)
	addr := &Address{
		AccountID: account.ID,
		Amount:    100,
		Expires:   exp,
		IsChange:  false,
	}

	err = CreateAddress(ctx, addr, true)
	if err != nil {
		t.Fatal(err)
	}

	want := &Address{
		AccountID:        account.ID,
		Amount:           100,
		Expires:          exp,
		IsChange:         false,
		ManagerNodeID:    managerNode.ID,
		ManagerNodeIndex: []uint32{0, 10},
		AccountIndex:     []uint32{0, 0},
		Index:            []uint32{0, 1},
		SigsRequired:     1,
		Keys:             []*hdkey.XKey{dummyXPub2},

		RedeemScript: []byte{
			81, 33, 2, 241, 154, 202, 111, 123, 48, 123, 116, 244, 53,
			11, 207, 218, 165, 175, 26, 38, 65, 147, 76, 125, 77, 183,
			254, 50, 18, 62, 238, 216, 139, 92, 16, 81, 174,
		},
		PKScript: []byte{
			169, 20, 209, 12, 223, 249, 230, 16, 228, 14, 42, 205, 213, 7,
			90, 164, 51, 115, 60, 99, 212, 242, 135,
		},
	}

	if !strings.HasPrefix(addr.ID, "a") {
		t.Errorf("ID = %q want prefix 'a'", addr.ID)
	}
	addr.ID = ""
	if addr.Created.Before(t0) {
		t.Errorf("Created = %v want after %v", addr.Created, t0)
	}
	addr.Created = time.Time{}
	if !reflect.DeepEqual(addr, want) {
		t.Errorf("addr = %+v want %+v", addr, want)
	}
}
<commit_msg>api/appdb: make create address test predictable<commit_after>package appdb

import (
	"reflect"
	"strings"
	"testing"
	"time"

	"chain/database/pg"
	"chain/database/pg/pgtest"
	"chain/fedchain-sandbox/hdkey"
)

var accountFixture = `
	INSERT INTO manager_nodes (
		id, project_id, block_chain, sigs_required, key_index,
		label, current_rotation, next_asset_index, next_account_index,
		accounts_count, created_at, updated_at
	)
	VALUES ('mn1', 'proj-id-0', 'sandbox', 1, 1, 'foo', 'rot1', 0, 1, 1, now(), now());
	INSERT INTO rotations (id, manager_node_id, keyset)
	VALUES ('rot1', 'mn1', '{` + dummyXPub.String() + `}');
	INSERT INTO accounts (
		id, manager_node_id, key_index, created_at, updated_at,
		next_address_index, label
	)
	VALUES ('acc1', 'mn1', 0, now(), now(), 0, 'foo');
`

func TestAddressLoadNextIndex(t *testing.T) {
	ctx := pgtest.NewContext(t, sampleProjectFixture, accountFixture)
	defer pgtest.Finish(ctx)

	// Force predictable values.
	addrIndexNext, addrIndexCap = 1, 100

	exp := time.Now().Add(5 * time.Minute)
	addr := &Address{
		AccountID: "acc1",
		Amount:    100,
		Expires:   exp,
		IsChange:  false,
	}
	err := addr.LoadNextIndex(ctx) // get most fields from the db given AccountID
	if err != nil {
		t.Fatal(err)
	}

	want := &Address{
		AccountID: "acc1",
		Amount:    100,
		Expires:   exp,
		IsChange:  false,

		ManagerNodeID:    "mn1",
		ManagerNodeIndex: []uint32{0, 1},
		AccountIndex:     []uint32{0, 0},
		Index:            []uint32{0, 1},
		SigsRequired:     1,
		Keys:             []*hdkey.XKey{dummyXPub},
	}

	if !reflect.DeepEqual(addr, want) {
		t.Errorf("addr = %+v want %+v", addr, want)
	}
}

func TestAddressInsert(t *testing.T) {
	t0 := time.Now()
	ctx := pgtest.NewContext(t, sampleProjectFixture, accountFixture)
	defer pgtest.Finish(ctx)

	// Force predictable values.
	addrIndexNext, addrIndexCap = 1, 100

	addr := &Address{
		AccountID:        "acc1",
		Amount:           100,
		Expires:          t0.Add(5 * time.Minute),
		IsChange:         false,
		ManagerNodeID:    "mn1",
		ManagerNodeIndex: []uint32{0, 1},
		AccountIndex:     []uint32{0, 0},
		Index:            []uint32{0, 0},
		SigsRequired:     1,
		Keys:             []*hdkey.XKey{dummyXPub},

		RedeemScript: []byte{},
		PKScript:     []byte{},
	}

	err := addr.Insert(ctx) // get most fields from the db given AccountID
	if err != nil {
		t.Fatal(err)
	}

	if !strings.HasPrefix(addr.ID, "a") {
		t.Errorf("ID = %q want prefix 'a'", addr.ID)
	}
	if addr.Created.Before(t0) {
		t.Errorf("Created = %v want after %v", addr.Created, t0)
	}
}

var dummyXPub2, _ = hdkey.NewXKey("xpub661MyMwAqRbcFoBSqmqxsAGLAgoLBDHXgZutXooGvHGKXgqPK9HYiVZNoqhGuwzeFW27JBpgZZEabMZhFHkxehJmT8H3AfmfD4zhniw5jcw")

func TestCreateAddress(t *testing.T) {
	t0 := time.Now()
	ctx := pgtest.NewContext(t, `
		INSERT INTO projects (id, name) VALUES ('proj-id-0', 'proj-0');
	`)
	defer pgtest.Finish(ctx)

	// Force predictable values.
	addrIndexNext, addrIndexCap = 1, 100
	_, err := pg.FromContext(ctx).Exec(ctx, `ALTER SEQUENCE manager_nodes_key_index_seq RESTART`)
	if err != nil {
		t.Fatal(err)
	}

	managerNode, err := InsertManagerNode(ctx, "proj-id-0", "foo", []*hdkey.XKey{dummyXPub2}, nil, 0, 1)
	if err != nil {
		t.Fatal(err)
	}
	account, err := CreateAccount(ctx, managerNode.ID, "foo", nil)
	if err != nil {
		t.Fatal(err)
	}

	exp := t0.Add(5 * time.Minute)
	addr := &Address{
		AccountID: account.ID,
		Amount:    100,
		Expires:   exp,
		IsChange:  false,
	}

	err = CreateAddress(ctx, addr, true)
	if err != nil {
		t.Fatal(err)
	}

	want := &Address{
		AccountID:        account.ID,
		Amount:           100,
		Expires:          exp,
		IsChange:         false,
		ManagerNodeID:    managerNode.ID,
		ManagerNodeIndex: []uint32{0, 1},
		AccountIndex:     []uint32{0, 0},
		Index:            []uint32{0, 1},
		SigsRequired:     1,
		Keys:             []*hdkey.XKey{dummyXPub2},

		RedeemScript: []byte{
			81, 33, 2, 241, 154, 202, 111, 123, 48, 123, 116, 244, 53,
			11, 207, 218, 165, 175, 26, 38, 65, 147, 76, 125, 77, 183,
			254, 50, 18, 62, 238, 216, 139, 92, 16, 81, 174,
		},
		PKScript: []byte{
			169, 20, 209, 12, 223, 249, 230, 16, 228, 14, 42, 205, 213, 7,
			90, 164, 51, 115, 60, 99, 212, 242, 135,
		},
	}

	if !strings.HasPrefix(addr.ID, "a") {
		t.Errorf("ID = %q want prefix 'a'", addr.ID)
	}
	addr.ID = ""
	if addr.Created.Before(t0) {
		t.Errorf("Created = %v want after %v", addr.Created, t0)
	}
	addr.Created = time.Time{}
	if !reflect.DeepEqual(addr, want) {
		t.Errorf("addr = %+v want %+v", addr, want)
	}
}
<|endoftext|>


<commit_before>package graphql

import (
	"context"

	"github.com/sprucehealth/graphql/gqlerrors"
	"github.com/sprucehealth/graphql/language/parser"
	"github.com/sprucehealth/graphql/language/source"
)

type Params struct {
	// The GraphQL type system to use when validating and executing a query.
	Schema Schema

	// A GraphQL language formatted string representing the requested operation.
	RequestString string

	// The value provided as the first argument to resolver functions on the top
	// level type (e.g. the query object type).
	RootObject map[string]interface{}

	// A mapping of variable name to runtime value to use for all variables
	// defined in the requestString.
	VariableValues map[string]interface{}

	// The name of the operation to use if requestString contains multiple
	// possible operations. Can be omitted if requestString contains only
	// one operation.
	OperationName string

	// Context may be provided to pass application-specific per-request
	// information to resolve functions.
	Context context.Context
}

func Do(p Params) *Result {
	source := source.New("GraphQL request", p.RequestString)
	ast, err := parser.Parse(parser.ParseParams{Source: source})
	if err != nil {
		return &Result{
			Errors: gqlerrors.FormatErrors(err),
		}
	}
	validationResult := ValidateDocument(&p.Schema, ast, nil)

	if !validationResult.IsValid {
		return &Result{
			Errors: validationResult.Errors,
		}
	}

	return Execute(ExecuteParams{
		Schema:        p.Schema,
		Root:          p.RootObject,
		AST:           ast,
		OperationName: p.OperationName,
		Args:          p.VariableValues,
		Context:       p.Context,
	})
}
<commit_msg>Clean comment lint<commit_after>package graphql

import (
	"context"

	"github.com/sprucehealth/graphql/gqlerrors"
	"github.com/sprucehealth/graphql/language/parser"
	"github.com/sprucehealth/graphql/language/source"
)

type Params struct {
	// Schema is the GraphQL type system to use when validating and executing a query.
	Schema Schema

	// RequestString is a GraphQL language formatted string representing the requested operation.
	RequestString string

	// RootObject is the value provided as the first argument to resolver functions on the top
	// level type (e.g. the query object type).
	RootObject map[string]interface{}

	// VariableValues is a mapping of variable name to runtime value to use for all variables
	// defined in the requestString.
	VariableValues map[string]interface{}

	// OperationName is the name of the operation to use if requestString contains multiple
	// possible operations. Can be omitted if requestString contains only
	// one operation.
	OperationName string

	// Context may be provided to pass application-specific per-request
	// information to resolve functions.
	Context context.Context
}

func Do(p Params) *Result {
	source := source.New("GraphQL request", p.RequestString)
	ast, err := parser.Parse(parser.ParseParams{Source: source})
	if err != nil {
		return &Result{
			Errors: gqlerrors.FormatErrors(err),
		}
	}
	validationResult := ValidateDocument(&p.Schema, ast, nil)

	if !validationResult.IsValid {
		return &Result{
			Errors: validationResult.Errors,
		}
	}

	return Execute(ExecuteParams{
		Schema:        p.Schema,
		Root:          p.RootObject,
		AST:           ast,
		OperationName: p.OperationName,
		Args:          p.VariableValues,
		Context:       p.Context,
	})
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"testing"

	"github.com/libopenstorage/openstorage/api"
	volumeclient "github.com/libopenstorage/openstorage/api/client/volume"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

const (
	version = "v1"
)

func TestJunk(t *testing.T) {

	var err error
	ts, testVolDriver := Setup(t)
	defer ts.Close()
	defer testVolDriver.Stop()

	cl, err := volumeclient.NewDriverClient(ts.URL, mockDriverName, version, mockDriverName)
	require.NoError(t, err)

	// Setup request
	name := "myvol"
	size := uint64(1234)

	req := &api.VolumeCreateRequest{
		Locator: &api.VolumeLocator{Name: name},
		Source:  &api.Source{},
		Spec:    &api.VolumeSpec{Size: size},
	}

	// Setup mock functions
	id := "myid"
	testVolDriver.MockDriver().
		EXPECT().
		Create(req.GetLocator(), req.GetSource(), req.GetSpec()).
		Return(id, nil)

	// create a volume client
	driverclient := volumeclient.VolumeDriver(cl)
	res, err := driverclient.Create(req.GetLocator(), req.GetSource(), req.GetSpec())

	assert.Nil(t, err)
	assert.Equal(t, id, res)

	fmt.Println("Yay -0---- ", ts.URL, " --- ", res)
}
<commit_msg>Renaming Test.<commit_after>package server

import (
	"testing"

	"github.com/libopenstorage/openstorage/api"
	volumeclient "github.com/libopenstorage/openstorage/api/client/volume"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

const (
	version = "v1"
)

func TestVolumeCreateSuccess(t *testing.T) {

	var err error

	ts, testVolDriver := Setup(t)

	defer ts.Close()
	defer testVolDriver.Stop()

	cl, err := volumeclient.NewDriverClient(ts.URL, mockDriverName, version, mockDriverName)
	require.NoError(t, err)

	// Setup request
	name := "myvol"
	size := uint64(1234)

	req := &api.VolumeCreateRequest{
		Locator: &api.VolumeLocator{Name: name},
		Source:  &api.Source{},
		Spec:    &api.VolumeSpec{Size: size},
	}

	// Setup mock functions
	id := "myid"
	testVolDriver.MockDriver().
		EXPECT().
		Create(req.GetLocator(), req.GetSource(), req.GetSpec()).
		Return(id, nil)

	// create a volume client
	driverclient := volumeclient.VolumeDriver(cl)

	res, err := driverclient.Create(req.GetLocator(), req.GetSource(), req.GetSpec())

	assert.Nil(t, err)
	assert.Equal(t, id, res)
}
<|endoftext|>


<commit_before>package stl

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"unsafe"
)

const SizeOfTriangle = 4*3*4 + 2

func readPoint(a []byte, p *Point) []byte {
	for i := 0; i < 3; i++ {
		cur := uint32(a[0]) + uint32(a[1])<<8 + uint32(a[2])<<16 + uint32(a[3])<<24
		p[i] = *(*float32)(unsafe.Pointer(&cur))
		a = a[4:]
	}
	return a
}

func readLineWithPrefix(r *bufio.Reader, prefixes ...string) (prefix, str string, err error) {
	var line []byte
	if line, _, err = r.ReadLine(); err != nil {
		return
	}
	str = string(line)
	str = strings.Replace(str, "\t", " ", -1)
	str = strings.Replace(str, "        ", " ", -1)
	str = strings.Replace(str, "    ", " ", -1)
	str = strings.Replace(str, "    ", " ", -1)
	str = strings.Replace(str, "  ", " ", -1)
	str = strings.Replace(str, "  ", " ", -1)
	str = strings.TrimSpace(str)
	for _, pp := range prefixes {
		if strings.HasPrefix(str, pp) {
			return pp, str[len(pp):], nil
		}
	}
	return "", "", fmt.Errorf("Line expected to start with one of the prefixes: %v, the actual line is: '%s'", prefixes, str)
}

func consumeLine(r *bufio.Reader, want string) (err error) {
	var str string
	if _, str, err = readLineWithPrefix(r, want); err != nil {
		return
	}
	if str != "" {
		return fmt.Errorf("Line contains unexpected symbols after the right prefix: '%s', symbols: '%s'", want, str)
	}
	return nil
}

func readASCII(data []byte) (res []Triangle, err error) {
	r := bufio.NewReader(bytes.NewBuffer(data))
	if _, _, err = readLineWithPrefix(r, "solid"); err != nil {
		return nil, err
	}
	lineno := 2
	for {
		var prefix, str string
		var t Triangle
		if prefix, str, err = readLineWithPrefix(r, "facet normal ", "endsolid"); err != nil {
			if err == io.EOF {
				return res, nil
			}
			return nil, err
		}
		lineno++

		if prefix == "endsolid" {
			return
		}
		fields := strings.Fields(str)
		if len(fields) != 3 {
			return nil, fmt.Errorf("[line=%d] Normal definition is broken: '%s'", lineno, str)
		}
		for i := 0; i < 3; i++ {
			var v float64
			if v, err = strconv.ParseFloat(fields[i], 32); err != nil {
				return nil, err
			}
			t.N[i] = float32(v)
		}
		if err = consumeLine(r, "outer loop"); err != nil {
			return nil, err
		}
		lineno++
		for i := 0; i < 3; i++ {
			if _, str, err = readLineWithPrefix(r, "vertex "); err != nil {
				return nil, err
			}
			lineno++

			fields = strings.Fields(str)
			if len(fields) != 3 {
				return nil, fmt.Errorf("[line=%d] Vertex definition is broken: '%s'", lineno, str)
			}
			for j := 0; j < 3; j++ {
				var v float64
				if v, err = strconv.ParseFloat(fields[j], 32); err != nil {
					return nil, err
				}
				t.V[i][j] = float32(v)
			}
		}
		if err = consumeLine(r, "endloop"); err != nil {
			return nil, err
		}
		lineno++

		if err = consumeLine(r, "endfacet"); err != nil {
			return nil, err
		}
		lineno++

		res = append(res, t)

	}
	return
}

// isASCII detects if the data represents an ASCII STL file (as opposed to binary STL file).
func isASCII(data []byte) bool {
	if len(data) < 14 {
		return false
	}
	magic := strings.TrimSpace(string(data[:14]))
	if !strings.HasPrefix(magic, "solid") {
		return false
	}
	for _, v := range data {
		if v < 32 && v != '\n' && v != '\r' && v != '\t' {
			// non-printable chars are a good indicator of a binary STL.
			return false
		}
	}
	return true
}

// Read reads STL file from the reader.
func Read(r io.Reader) (t []Triangle, err error) {
	var data []byte
	if data, err = ioutil.ReadAll(r); err != nil {
		return
	}
	if isASCII(data) {
		return readASCII(data)
	}
	if len(data) < 84 {
		return nil, fmt.Errorf("The file is too short: %d bytes", len(data))
	}
	// Skip STL header
	data = data[80:]
	n := uint32(data[0]) + uint32(data[1])<<8 + uint32(data[2])<<16 + uint32(data[3])<<24
	data = data[4:]

	if len(data) < int(SizeOfTriangle*n) {
		return nil, fmt.Errorf("Read: unexpected end of file: want %d bytes to read triangle data, but only %d bytes is available", SizeOfTriangle*n, len(data))
	}
	for i := 0; i < int(n); i++ {
		var cur Triangle
		data = readPoint(data, &cur.N)
		for j := 0; j < 3; j++ {
			data = readPoint(data, &cur.V[j])
		}
		data = data[2:]
		t = append(t, cur)
	}
	return
}
<commit_msg>output line number in one more error message.<commit_after>package stl

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"unsafe"
)

const SizeOfTriangle = 4*3*4 + 2

func readPoint(a []byte, p *Point) []byte {
	for i := 0; i < 3; i++ {
		cur := uint32(a[0]) + uint32(a[1])<<8 + uint32(a[2])<<16 + uint32(a[3])<<24
		p[i] = *(*float32)(unsafe.Pointer(&cur))
		a = a[4:]
	}
	return a
}

func readLineWithPrefix(r *bufio.Reader, prefixes ...string) (prefix, str string, err error) {
	var line []byte
	if line, _, err = r.ReadLine(); err != nil {
		return
	}
	str = string(line)
	str = strings.Replace(str, "\t", " ", -1)
	str = strings.Replace(str, "        ", " ", -1)
	str = strings.Replace(str, "    ", " ", -1)
	str = strings.Replace(str, "    ", " ", -1)
	str = strings.Replace(str, "  ", " ", -1)
	str = strings.Replace(str, "  ", " ", -1)
	str = strings.TrimSpace(str)
	for _, pp := range prefixes {
		if strings.HasPrefix(str, pp) {
			return pp, str[len(pp):], nil
		}
	}
	return "", "", fmt.Errorf("line expected to start with one of the prefixes: %v, the actual line is: '%s'", prefixes, str)
}

func consumeLine(r *bufio.Reader, want string) (err error) {
	var str string
	if _, str, err = readLineWithPrefix(r, want); err != nil {
		return
	}
	if str != "" {
		return fmt.Errorf("line contains unexpected symbols after the right prefix: '%s', symbols: '%s'", want, str)
	}
	return nil
}

func readASCII(data []byte) (res []Triangle, err error) {
	r := bufio.NewReader(bytes.NewBuffer(data))
	if _, _, err = readLineWithPrefix(r, "solid"); err != nil {
		return nil, err
	}
	lineno := 2
	for {
		var prefix, str string
		var t Triangle
		if prefix, str, err = readLineWithPrefix(r, "facet normal ", "endsolid"); err != nil {
			if err == io.EOF {
				return res, nil
			}
			return nil, fmt.Errorf("[line=%d] %v", lineno, err)
		}
		lineno++

		if prefix == "endsolid" {
			return
		}
		fields := strings.Fields(str)
		if len(fields) != 3 {
			return nil, fmt.Errorf("[line=%d] Normal definition is broken: '%s'", lineno, str)
		}
		for i := 0; i < 3; i++ {
			var v float64
			if v, err = strconv.ParseFloat(fields[i], 32); err != nil {
				return nil, err
			}
			t.N[i] = float32(v)
		}
		if err = consumeLine(r, "outer loop"); err != nil {
			return nil, err
		}
		lineno++
		for i := 0; i < 3; i++ {
			if _, str, err = readLineWithPrefix(r, "vertex "); err != nil {
				return nil, err
			}
			lineno++

			fields = strings.Fields(str)
			if len(fields) != 3 {
				return nil, fmt.Errorf("[line=%d] Vertex definition is broken: '%s'", lineno, str)
			}
			for j := 0; j < 3; j++ {
				var v float64
				if v, err = strconv.ParseFloat(fields[j], 32); err != nil {
					return nil, err
				}
				t.V[i][j] = float32(v)
			}
		}
		if err = consumeLine(r, "endloop"); err != nil {
			return nil, err
		}
		lineno++

		if err = consumeLine(r, "endfacet"); err != nil {
			return nil, err
		}
		lineno++

		res = append(res, t)

	}
	return
}

// isASCII detects if the data represents an ASCII STL file (as opposed to binary STL file).
func isASCII(data []byte) bool {
	if len(data) < 14 {
		return false
	}
	magic := strings.TrimSpace(string(data[:14]))
	if !strings.HasPrefix(magic, "solid") {
		return false
	}
	for _, v := range data {
		if v < 32 && v != '\n' && v != '\r' && v != '\t' {
			// non-printable chars are a good indicator of a binary STL.
			return false
		}
	}
	return true
}

// Read reads STL file from the reader.
func Read(r io.Reader) (t []Triangle, err error) {
	var data []byte
	if data, err = ioutil.ReadAll(r); err != nil {
		return
	}
	if isASCII(data) {
		return readASCII(data)
	}
	if len(data) < 84 {
		return nil, fmt.Errorf("The file is too short: %d bytes", len(data))
	}
	// Skip STL header
	data = data[80:]
	n := uint32(data[0]) + uint32(data[1])<<8 + uint32(data[2])<<16 + uint32(data[3])<<24
	data = data[4:]

	if len(data) < int(SizeOfTriangle*n) {
		return nil, fmt.Errorf("Read: unexpected end of file: want %d bytes to read triangle data, but only %d bytes is available", SizeOfTriangle*n, len(data))
	}
	for i := 0; i < int(n); i++ {
		var cur Triangle
		data = readPoint(data, &cur.N)
		for j := 0; j < 3; j++ {
			data = readPoint(data, &cur.V[j])
		}
		data = data[2:]
		t = append(t, cur)
	}
	return
}
<|endoftext|>


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

package main

/*  Filename:    gutterd.go
 *  Author:      Bryan Matsuo <bmatsuo@soe.ucsc.edu>
 *  Created:     2012-03-04 17:28:31.728667 -0800 PST
 *  Description: Main source file in gutterd
 */

import (
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"
)

var (
	config   *Config    // Deamon configuration.
	watching []string   // Base-level directories to watch for torrents.
	handlers []*Handler // The ordered set of torrent handlers.
	opt      Options    // Command line options.
)

// Return from a pollFunc type to stop poll().
var ErrPollStop = fmt.Errorf("STOP POLLING")

// A function that can be used polling.
type pollFunc func() (time.Duration, error)

// Repeatedly call fn until ErrPollStop is returned.
func poll(fn pollFunc) {
	for {
		d, err := fn()
		if err == ErrPollStop {
			break
		} else if err != nil {
			fmt.Printf("Error: %v\n", err)
		}
		time.Sleep(d)
	}
}

func HomeDirectory() (home string, err error) {
	if home = os.Getenv("HOME"); home == "" {
		err = errors.New("Environment variable HOME not set.")
	}
	return
}

// Read the config file and setup global variables.
func init() {
	var err error
	var config *Config
	defconfig := &Config{
		PollFrequency: 60,
		LogPath:       "&2",
	}

	opt = parseFlags()

	// Read the deamon configuration.
	if opt.ConfigPath != "" {
		if config, err = LoadConfig(opt.ConfigPath, defconfig); err != nil {
			fmt.Printf("gutterd\tERROR\t%s: %v", "Couldn't load configuration", err)
			os.Exit(1)
		}
	} else if home, err := HomeDirectory(); err != nil {
		fmt.Printf("gutterd\tERROR\t%v", err)
		os.Exit(1)
	} else if config, err = LoadConfig(home+"/.config/gutterd.json", defconfig); err != nil {
		fmt.Printf("gutterd\tERROR\t%s: %v", "Couldn't load configuration", err)
		os.Exit(1)
	}

	// Modify config according to command line flags.
	if opt.LogPath != "" {
		config.LogPath = opt.LogPath
	}
	if opt.PollFrequency > 0 {
		config.PollFrequency = opt.PollFrequency
	}
	if opt.Watch != nil {
		config.Watch = opt.Watch
	}

	// Setup the logging destination.
	var logfile io.Writer
	switch config.LogPath {
	case "":
		fallthrough
	case "&2":
		logfile = os.Stderr
	case "&1":
		logfile = os.Stdout
	default:
		logfile, err = os.OpenFile(config.LogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't open log file %s", config.LogPath)
			os.Exit(0)
		}
	}
	loggerMux.NewSink(log.New(logfile, "", log.LstdFlags), "gutterd")

	handlers = config.MakeHandlers()

	watching = config.Watch
}

// Handle a .torrent file.
func handleFile(path string) {
	torrent, err := ReadMetadataFile(path)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	Printf("%-8s%s", "TORRENT", torrent.Info.Name)
	// Find the first handler matching the supplied torrent.
	for _, handler := range handlers {
		if handler.Match(torrent) {
			Printf("%-8s%-14s", "MATCH", handler.Name)
			Printf("%-8s%s\n\n", "MOVING", handler.Watch)
			mvpath := filepath.Join(handler.Watch, filepath.Base(path))
			if err := os.Rename(path, mvpath); err != nil {
				Printf("%-8s%v", "ERROR", err)
			}
			return
		}
	}
	Printf("%-8s%-14s%s\n\n", "NO MATCH", "", torrent.Info.Name)
}

func main() {
	if len(watching) == 0 {
		Fatalf("%s\t%s", "ERROR", "Not watching any directories")
	}

	// Poll watch directories, handling all torrents found.
	poll(pollFunc(func() (time.Duration, error) {
		for _, watch := range watching {
			torrents, err := filepath.Glob(filepath.Join(watch, "*.torrent"))
			if err != nil {
				Printf("Error polling %s:\n%v", watch, err)
				continue
			}
			for _, _torrent := range torrents {
				handleFile(_torrent)
				continue
			}
		}
		return (config.PollFrequency * 1e9), nil
	}))
}
<commit_msg>Reorder some init code so it fits together better.<commit_after>// Copyright 2012, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

/*  Filename:    gutterd.go
 *  Author:      Bryan Matsuo <bmatsuo@soe.ucsc.edu>
 *  Created:     2012-03-04 17:28:31.728667 -0800 PST
 *  Description: Main source file in gutterd
 */

import (
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"
)

var (
	config   *Config    // Deamon configuration.
	watching []string   // Base-level directories to watch for torrents.
	handlers []*Handler // The ordered set of torrent handlers.
	opt      Options    // Command line options.
)

// Return from a pollFunc type to stop poll().
var ErrPollStop = fmt.Errorf("STOP POLLING")

// A function that can be used polling.
type pollFunc func() (time.Duration, error)

// Repeatedly call fn until ErrPollStop is returned.
func poll(fn pollFunc) {
	for {
		d, err := fn()
		if err == ErrPollStop {
			break
		} else if err != nil {
			fmt.Printf("Error: %v\n", err)
		}
		time.Sleep(d)
	}
}

func HomeDirectory() (home string, err error) {
	if home = os.Getenv("HOME"); home == "" {
		err = errors.New("Environment variable HOME not set.")
	}
	return
}

// Read the config file and setup global variables.
func init() {
	var err error
	var config *Config
	defconfig := &Config{
		PollFrequency: 60,
		LogPath:       "&2",
	}

	opt = parseFlags()

	// Read the deamon configuration.
	if opt.ConfigPath != "" {
		if config, err = LoadConfig(opt.ConfigPath, defconfig); err != nil {
			fmt.Printf("gutterd\tERROR\t%s: %v", "Couldn't load configuration", err)
			os.Exit(1)
		}
	} else if home, err := HomeDirectory(); err != nil {
		fmt.Printf("gutterd\tERROR\t%v", err)
		os.Exit(1)
	} else if config, err = LoadConfig(home+"/.config/gutterd.json", defconfig); err != nil {
		fmt.Printf("gutterd\tERROR\t%s: %v", "Couldn't load configuration", err)
		os.Exit(1)
	}

	// Modify config according to command line flags.
	if opt.PollFrequency > 0 {
		config.PollFrequency = opt.PollFrequency
	}
	if opt.Watch != nil {
		config.Watch = opt.Watch
	}
	if opt.LogPath != "" {
		config.LogPath = opt.LogPath
	}

	// Setup the logging destination.
	var logfile io.Writer
	switch config.LogPath {
	case "":
		fallthrough
	case "&2":
		logfile = os.Stderr
	case "&1":
		logfile = os.Stdout
	default:
		logfile, err = os.OpenFile(config.LogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't open log file %s", config.LogPath)
			os.Exit(0)
		}
	}
	loggerMux.NewSink(log.New(logfile, "", log.LstdFlags), "gutterd")

	handlers = config.MakeHandlers()

	watching = config.Watch
}

// Handle a .torrent file.
func handleFile(path string) {
	torrent, err := ReadMetadataFile(path)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	Printf("%-8s%s", "TORRENT", torrent.Info.Name)
	// Find the first handler matching the supplied torrent.
	for _, handler := range handlers {
		if handler.Match(torrent) {
			Printf("%-8s%-14s", "MATCH", handler.Name)
			Printf("%-8s%s\n\n", "MOVING", handler.Watch)
			mvpath := filepath.Join(handler.Watch, filepath.Base(path))
			if err := os.Rename(path, mvpath); err != nil {
				Printf("%-8s%v", "ERROR", err)
			}
			return
		}
	}
	Printf("%-8s%-14s%s\n\n", "NO MATCH", "", torrent.Info.Name)
}

func main() {
	if len(watching) == 0 {
		Fatalf("%s\t%s", "ERROR", "Not watching any directories")
	}

	// Poll watch directories, handling all torrents found.
	poll(pollFunc(func() (time.Duration, error) {
		for _, watch := range watching {
			torrents, err := filepath.Glob(filepath.Join(watch, "*.torrent"))
			if err != nil {
				Printf("Error polling %s:\n%v", watch, err)
				continue
			}
			for _, _torrent := range torrents {
				handleFile(_torrent)
				continue
			}
		}
		return (config.PollFrequency * 1e9), nil
	}))
}
<|endoftext|>