<commit_before>package dog_pool

// import "os/exec"
// import "time"
import "testing"
import "github.com/orfjackal/gospec/src/gospec"

// import "github.com/alecthomas/log4go"

func TestMemcachedConnectionSpecs(t *testing.T) {
	r := gospec.NewRunner()
	r.AddSpec(MemcachedConnectionSpecs)
	gospec.MainGoTest(r, t)
}

// Helpers
func MemcachedConnectionSpecs(c gospec.Context) {
	// var memcached_connection_logger = log4go.NewDefaultLogger(log4go.FINEST)
	//
	// c.Specify("[MemcachedConnection] New connection is not open", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6990", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	open := connection.IsOpen()
	// 	closed := connection.IsClosed()
	//
	// 	// Should be opposite of each other:
	// 	c.Expect(open, gospec.Equals, false)
	// 	c.Expect(closed, gospec.Equals, true)
	// 	c.Expect(closed, gospec.Satisfies, open != closed)
	// })
	//
	// c.Specify("[MemcachedConnection] Opening connection to Invalid Host/Port has errors", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6991", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// The server is not running ...
	// 	// This should return an error
	// 	err := connection.Open()
	// 	c.Expect(err, gospec.Satisfies, err != nil)
	//
	// 	closed := connection.IsClosed()
	// 	c.Expect(closed, gospec.Equals, true)
	// })
	//
	// c.Specify("[MemcachedConnection] Opening connection to Valid Host/Port has no errors", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6992", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// Start the server ...
	// 	cmd := exec.Command("memcached", "-p", "11292")
	// 	err := cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	// 	defer cmd.Wait()
	// 	defer cmd.Process.Kill()
	//
	// 	err = connection.Open()
	// 	c.Expect(err, gospec.Equals, nil)
	//
	// 	open := connection.IsOpen()
	// 	closed := connection.IsClosed()
	// 	c.Expect(open, gospec.Equals, true)
	// 	c.Expect(closed, gospec.Equals, false)
	// 	c.Expect(closed, gospec.Satisfies, open != closed)
	// })
	//
	// c.Specify("[MemcachedConnection] Ping (-->Cmd-->Append+GetReply) (re-)opens the connection automatically", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6993", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// Start the server ...
	// 	cmd := exec.Command("memcached", "-p", "11293")
	// 	err := cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	// 	defer cmd.Wait()
	// 	defer cmd.Process.Kill()
	//
	// 	// Starts off closed ...
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Ping the server
	// 	// Should now be open
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	//
	// 	// Close the connection
	// 	err = connection.Close()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Ping the server again
	// 	// Should now be open again
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	// })
	//
	// c.Specify("[MemcachedConnection] Ping to invalid Host/Port has errors", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6994", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// Start the server ...
	// 	cmd := exec.Command("memcached", "-p", "11294")
	// 	err := cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	// 	// Defer the evaluation of cmd
	// 	defer func() { cmd.Wait() }()
	// 	defer func() { cmd.Process.Kill() }()
	//
	// 	// Starts off closed ...
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Ping the server
	// 	// Should now be open
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	//
	// 	// Kill the server
	// 	cmd.Process.Kill()
	// 	cmd.Wait()
	//
	// 	// Ping the server again
	// 	// Should return an error and now be closed
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Satisfies, err != nil)
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Re-Start the server ...
	// 	cmd = exec.Command("memcached-server", "--port", "6994")
	// 	err = cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	//
	// 	// Ping the server
	// 	// Should now be open
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	// })
}
<commit_msg>Working on memcached + tests<commit_after>package dog_pool

// import "os/exec"
// import "time"
import "testing"
import "github.com/orfjackal/gospec/src/gospec"
import "github.com/alecthomas/log4go"

func TestMemcachedConnectionSpecs(t *testing.T) {
	r := gospec.NewRunner()
	r.AddSpec(MemcachedConnectionSpecs)
	gospec.MainGoTest(r, t)
}

// Helpers
func MemcachedConnectionSpecs(c gospec.Context) {
	var memcached_connection_logger = log4go.NewDefaultLogger(log4go.FINEST)

	c.Specify("[MemcachedConnection] New connection is not open", func() {
		connection := MemcachedConnection{Url: "127.0.0.1:6990", Logger: &memcached_connection_logger}
		defer connection.Close()

		open := connection.IsOpen()
		closed := connection.IsClosed()

		// Should be opposite of each other:
		c.Expect(open, gospec.Equals, false)
		c.Expect(closed, gospec.Equals, true)
		c.Expect(closed, gospec.Satisfies, open != closed)
	})

	// c.Specify("[MemcachedConnection] Opening connection to Invalid Host/Port has errors", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6991", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// The server is not running ...
	// 	// This should return an error
	// 	err := connection.Open()
	// 	c.Expect(err, gospec.Satisfies, err != nil)
	//
	// 	closed := connection.IsClosed()
	// 	c.Expect(closed, gospec.Equals, true)
	// })
	//
	// c.Specify("[MemcachedConnection] Opening connection to Valid Host/Port has no errors", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6992", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// Start the server ...
	// 	cmd := exec.Command("memcached", "-p", "11292")
	// 	err := cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	// 	defer cmd.Wait()
	// 	defer cmd.Process.Kill()
	//
	// 	err = connection.Open()
	// 	c.Expect(err, gospec.Equals, nil)
	//
	// 	open := connection.IsOpen()
	// 	closed := connection.IsClosed()
	// 	c.Expect(open, gospec.Equals, true)
	// 	c.Expect(closed, gospec.Equals, false)
	// 	c.Expect(closed, gospec.Satisfies, open != closed)
	// })
	//
	// c.Specify("[MemcachedConnection] Ping (-->Cmd-->Append+GetReply) (re-)opens the connection automatically", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6993", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// Start the server ...
	// 	cmd := exec.Command("memcached", "-p", "11293")
	// 	err := cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	// 	defer cmd.Wait()
	// 	defer cmd.Process.Kill()
	//
	// 	// Starts off closed ...
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Ping the server
	// 	// Should now be open
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	//
	// 	// Close the connection
	// 	err = connection.Close()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Ping the server again
	// 	// Should now be open again
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	// })
	//
	// c.Specify("[MemcachedConnection] Ping to invalid Host/Port has errors", func() {
	// 	connection := MemcachedConnection{Url: "127.0.0.1:6994", Logger: &memcached_connection_logger}
	// 	defer connection.Close()
	//
	// 	// Start the server ...
	// 	cmd := exec.Command("memcached", "-p", "11294")
	// 	err := cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	// 	// Defer the evaluation of cmd
	// 	defer func() { cmd.Wait() }()
	// 	defer func() { cmd.Process.Kill() }()
	//
	// 	// Starts off closed ...
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Ping the server
	// 	// Should now be open
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	//
	// 	// Kill the server
	// 	cmd.Process.Kill()
	// 	cmd.Wait()
	//
	// 	// Ping the server again
	// 	// Should return an error and now be closed
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Satisfies, err != nil)
	// 	c.Expect(connection.IsClosed(), gospec.Equals, true)
	//
	// 	// Re-Start the server ...
	// 	cmd = exec.Command("memcached-server", "--port", "6994")
	// 	err = cmd.Start()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	if err != nil {
	// 		// Abort on errors
	// 		return
	// 	}
	// 	time.Sleep(time.Duration(1) * time.Second)
	//
	// 	// Ping the server
	// 	// Should now be open
	// 	err = connection.Ping()
	// 	c.Expect(err, gospec.Equals, nil)
	// 	c.Expect(connection.IsOpen(), gospec.Equals, true)
	// })
}
<|endoftext|>


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

package gm

import "github.com/cpmech/gosl/utl"

// HashPoint returns a unique id of a point
func HashPoint(x, y, z float64) int {
	return int(x*100001 + y*10000001 + z*1000000001)
}

// HashPoint returns a unique id of a point (given slice of coordinates)
func HashPointC(c []float64) int {
	var x, y, z float64
	n := len(c)
	if n > 0 {
		x = c[0]
	}
	if n > 1 {
		y = c[1]
	}
	if n > 2 {
		z = c[2]
	}
	return HashPoint(x, y, z)
}

/*
//    FAST_32_hash
//    A very fast 2D hashing function.  Requires 32bit support.
//
//    The hash formula takes the form....
//    hash = mod( coord.x * coord.x * coord.y * coord.y, SOMELARGEFLOAT ) / SOMELARGEFLOAT
//    We truncate and offset the domain to the most interesting part of the noise.
//
vec4 FAST_32_hash( vec2 gridcell )
{
//    gridcell is assumed to be an integer coordinate
const vec2 OFFSET = vec2( 26.0, 161.0 );
const float DOMAIN = 71.0;
const float SOMELARGEFLOAT = 951.135664;
vec4 P = vec4( gridcell.xy, gridcell.xy + 1.0.xx );
P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN;    //    truncate the domain
P += OFFSET.xyxy;                                //    offset to interesting part of the noise
P *= P;                                          //    calculate and return the hash
return fract( P.xzxz * P.yyww * ( 1.0 / SOMELARGEFLOAT.x ).xxxx );
}
*/

type BinEntry struct {
	Id  int // object Id
	Idx int // index in Entries slice
}

type Bins struct {
	Ndim      int         // space dimension
	Xi        []float64   // [ndim] left/lower-most point
	Xf        []float64   // [ndim] right/upper-most point
	L         []float64   // [ndim] whole box lengths
	N         []int       // [ndim] number of divisions
	S         float64     // size of bins
	Entries   []*BinEntry // entries
	Idx2entry []int       // maps idx to entry in Entries
	tmp       []int       // [ndim] temporary (auxiliary) slice
}

// xi   -- [ndim] initial positions
// l    -- [ndim] whole box lengths
// ndiv -- number of divisions
func (o *Bins) Init(xi, l []float64, ndiv int) (err error) {
	o.Ndim = len(xi)
	o.Xi, o.L = xi, l
	if len(xi) != len(l) || len(l) < 2 || len(l) > 3 {
		return utl.Err("sizes of xi and l must be the same and equal to either 2 or 3")
	}
	o.Xf = make([]float64, o.Ndim)
	for k := 0; k < o.Ndim; k++ {
		o.Xf[k] = o.Xi[k] + o.L[k]
		o.N[k] = int(o.L[k])/ndiv + 1
	}
	return
}

func (o *Bins) Append(x []float64, id int) (err error) {
	idx := o.CalcIdx(x)
	if idx < 0 {
		return utl.Err("point %v is out of range", x)
	}
	entry := o.FindByIndex(idx)
	if entry == nil {
		o.Entries = append(o.Entries, &BinEntry{id, idx})
		return
	}
	entry.Id = id
	return
}

func (o *Bins) Clear() {
	o.Entries = make([]*BinEntry, 0)
	o.Idx2entry = make([]int, 0)
}

func (o Bins) FindByIndex(idx int) *BinEntry {
	if idx < 0 || idx >= len(o.Idx2entry) {
		return nil
	}
	i := o.Idx2entry[idx]
	return o.Entries[i]
}

func (o Bins) FindByCoords(x []float64) *BinEntry {
	idx := o.CalcIdx(x)
	if idx < 0 {
		return nil // out-of-range
	}
	i := o.Idx2entry[idx]
	return o.Entries[i]
}

// returns -1 if out-of-range
func (o Bins) CalcIdx(x []float64) int {
	for k := 0; k < o.Ndim; k++ {
		if x[k] < o.Xi[k] || x[k] > o.Xf[k] {
			return -1
		}
		o.tmp[k] = int((x[k] - o.Xi[k]) / o.S)
	}
	idx := o.tmp[0] + o.tmp[1]*o.N[0]
	if o.Ndim > 2 {
		idx += o.tmp[2] * o.N[0] * o.N[1]
	}
	return idx
}
<commit_msg>search updated<commit_after>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gm

import "github.com/cpmech/gosl/utl"

// HashPoint returns a unique id of a point
func HashPoint(x, y, z float64) int {
	return int(x*100001 + y*10000001 + z*1000000001)
}

// HashPoint returns a unique id of a point (given slice of coordinates)
func HashPointC(c []float64) int {
	var x, y, z float64
	n := len(c)
	if n > 0 {
		x = c[0]
	}
	if n > 1 {
		y = c[1]
	}
	if n > 2 {
		z = c[2]
	}
	return HashPoint(x, y, z)
}

/*
//    FAST_32_hash
//    A very fast 2D hashing function.  Requires 32bit support.
//
//    The hash formula takes the form....
//    hash = mod( coord.x * coord.x * coord.y * coord.y, SOMELARGEFLOAT ) / SOMELARGEFLOAT
//    We truncate and offset the domain to the most interesting part of the noise.
//
vec4 FAST_32_hash( vec2 gridcell )
{
//    gridcell is assumed to be an integer coordinate
const vec2 OFFSET = vec2( 26.0, 161.0 );
const float DOMAIN = 71.0;
const float SOMELARGEFLOAT = 951.135664;
vec4 P = vec4( gridcell.xy, gridcell.xy + 1.0.xx );
P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN;    //    truncate the domain
P += OFFSET.xyxy;                                //    offset to interesting part of the noise
P *= P;                                          //    calculate and return the hash
return fract( P.xzxz * P.yyww * ( 1.0 / SOMELARGEFLOAT.x ).xxxx );
}
*/

type BinEntry struct {
	Id  int // object Id
	Idx int // index of bin
}

type Bin struct {
	Idx     int         // index of bin
	Entries []*BinEntry // entries
}

type Bins struct {
	Ndim    int       // space dimension
	Xi      []float64 // [ndim] left/lower-most point
	Xf      []float64 // [ndim] right/upper-most point
	L       []float64 // [ndim] whole box lengths
	N       []int     // [ndim] number of divisions
	S       float64   // size of bins
	All     []*Bin    // [nbins] all bins
	Idx2bin []int     // maps idx of bin to item in All
	tmp     []int     // [ndim] temporary (auxiliary) slice
}

// xi   -- [ndim] initial positions
// l    -- [ndim] whole box lengths
// ndiv -- number of divisions
func (o *Bins) Init(xi, l []float64, ndiv int) (err error) {
	o.Ndim = len(xi)
	o.Xi, o.L = xi, l
	if len(xi) != len(l) || len(l) < 2 || len(l) > 3 {
		return utl.Err("sizes of xi and l must be the same and equal to either 2 or 3")
	}
	o.Xf = make([]float64, o.Ndim)
	for k := 0; k < o.Ndim; k++ {
		o.Xf[k] = o.Xi[k] + o.L[k]
		o.N[k] = int(o.L[k])/ndiv + 1
	}
	return
}

func (o *Bins) Append(x []float64, id int) (err error) {
	idx := o.CalcIdx(x)
	if idx < 0 {
		return utl.Err("point %v is out of range", x)
	}
	bin := o.FindBinByIndex(idx)
	if len(bin) == 0 {
		entrynumber := len(o.Entries)
		o.Entries = append(o.Entries, []*BinEntry{&BinEntry{id, idx}})
		o.Idx2entry[idx] = entrynumber
		return
	}

	entry.Id = id
	return
}

func (o *Bins) Clear() {
	o.Entries = make([]*BinEntry, 0)
	o.Idx2entry = make([]int, 0)
}

func (o Bins) FindBinByIndex(idx int) *Bin {
	if idx < 0 || idx >= len(o.Idx2bin) {
		return nil
	}
	k := o.Idx2bin[idx]
	return o.All[k]
}

func (o Bins) FindByCoords(x []float64) *BinEntry {
	idx := o.CalcIdx(x)
	if idx < 0 {
		return nil // out-of-range
	}
	return o.FindByIndex(idx)
}

func (o Bins) FindCloseTo(x []float64) *BinEntry {
	return nil
}

// returns -1 if out-of-range
func (o Bins) CalcIdx(x []float64) int {
	for k := 0; k < o.Ndim; k++ {
		if x[k] < o.Xi[k] || x[k] > o.Xf[k] {
			return -1
		}
		o.tmp[k] = int((x[k] - o.Xi[k]) / o.S)
	}
	idx := o.tmp[0] + o.tmp[1]*o.N[0]
	if o.Ndim > 2 {
		idx += o.tmp[2] * o.N[0] * o.N[1]
	}
	return idx
}
<|endoftext|>


<commit_before>package gobot

import (
	"fmt"
	"time"

	"github.com/bbqgophers/qpid"
	"github.com/felixge/pidctrl"
	gb "github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/api"
	"github.com/hybridgroup/gobot/platforms/raspi"
	"github.com/pkg/errors"
)

// i2cAddress is the location that we read
// to get the temperatures from the i2c bus
const i2cAddress = 0x4d

var (
	// Sleep is the duration in seconds we hold when
	// temperature is met
	Sleep = 10
	// P is the P in PID :)
	P = 3.0
	// I is the I in PID
	I = .05
	// B is a booster.  Currently unused
	B = 0.0
	// MetricsIntervalSeconds is the metric reporting interval
	MetricsIntervalSeconds = 1
)

// Controller represents all the electronics that
// make the PID work
type Controller struct {
	grillProbe    *Probe
	gobot         *gb.Gobot
	pi            *raspi.RaspiAdaptor
	api           *api.API
	pid           *pidctrl.PIDController
	heating       bool
	notifications chan qpid.Notification
	metrics       chan qpid.GrillStatus
}

// NewController returns a new Controller
// initialized.
func NewController() *Controller {
	n := make(chan qpid.Notification)
	metrics := make(chan qpid.GrillStatus)
	g := gb.NewGobot()
	r := raspi.NewRaspiAdaptor("qpid")
	robot := gb.NewRobot("qpid",
		[]gb.Connection{r},
		[]gb.Device{},
		nil,
	)
	errs := r.Connect()
	if errs != nil {
		panic(errs)
	}
	g.AddRobot(robot)

	a := api.NewAPI(g)
	a.Port = "4000"
	a.AddHandler(api.BasicAuth("bbq", "gopher"))
	a.Start()
	e := r.I2cStart(i2cAddress)
	if e != nil {
		panic(e)
	}
	pid := pidctrl.NewPIDController(P, I, B)
	pid.SetOutputLimits(-50.0, 50.0)
	return &Controller{
		grillProbe:    NewProbe(r),
		gobot:         g,
		pi:            r,
		pid:           pid,
		api:           a,
		notifications: n,
		metrics:       metrics,
	}
}

// FoodMonitors returns the food monitors
func (g *Controller) FoodMonitors() []qpid.Monitor {
	panic("not implemented")
}

// GrillMonitor returns the grill probe
func (g *Controller) GrillMonitor() qpid.Monitor {
	return g.grillProbe
}

// Run starts the grill's run loop and blocks
func (g *Controller) Run() error {

	go func() {
		errs := g.gobot.Start()
		if errs != nil {
			// hack - maybe change interface?
			panic(errs)
		}
	}()

	// TODO: Decide where the blocking happens.
	// is this routine where we block and run until
	// receiving some signal to exit?  Or do we block in main?
	target, err := g.grillProbe.Setpoint()
	if err != nil {
		return err
	}
	g.pid.Set(float64(target))

	// start goroutine to send status on interval
	go func() {
		for {
			status, err := g.Status()
			if err != nil {
				g.notify(qpid.Critical, errors.Wrap(err, "grill status").Error())
			}
			g.metrics <- status
			time.Sleep(time.Duration(MetricsIntervalSeconds) * time.Second)
		}
	}()

	for { // block here for now
		time.Sleep(1 * time.Second)
		temp, err := g.grillProbe.Temperature()
		if err != nil {
			return err
		}
		output := g.pid.Update(float64(temp.C()))
		message := fmt.Sprintf("Temp: %d, Integral: %f", temp, output)
		g.notify(qpid.Info, message)

		for x := 1; x < 10; x++ {

			if output > float64(x^2) {
				if !g.heating {
					g.heating = true

					g.notify(qpid.Info, "Turning on Blower")
					err := g.pi.DigitalWrite("15", 0x1)
					if err != nil {
						g.notify(qpid.Critical, errors.Wrap(err, "turning on blower").Error())
					}
				}

				g.notify(qpid.Info, "Leaving Blower On")
			} else {
				if g.heating {
					g.heating = false
					g.notify(qpid.Info, "Turning off Blower")
					err := g.pi.DigitalWrite("15", 0x0)
					if err != nil {
						g.notify(qpid.Critical, errors.Wrap(err, "turning off blower").Error())
					}
				}
			}
		}
		if output < float64(10) {

			g.notify(qpid.Info, "Temp Good, Sleep 10")
			time.Sleep(10 * time.Second)
		}
	}
	return nil
}

// Stop stops the grill's run loop
// but actually probably wont.  because
// there's nothing to do that yet.
func (g *Controller) Stop() error {

	g.notify(qpid.Info, "Received Stop Request")
	errs := g.gobot.Stop()
	if errs != nil {
		// hack - maybe change interface?
		return errs[0]
	}

	return nil
}

// Status returns the current Grill status.
func (g *Controller) Status() (qpid.GrillStatus, error) {
	return qpid.GrillStatus{
		Time:         time.Now(),
		GrillSensors: []qpid.Sensor{g.grillProbe},
	}, nil
}

// Notifications returns the Grill's notification channel
func (g *Controller) Notifications() chan qpid.Notification {
	return g.notifications
}

// notify sends a message on the grill's notification channel
func (g *Controller) notify(mt qpid.MessageType, message string) {
	n := qpid.Notification{
		Time:        time.Now(),
		Message:     message,
		MessageType: mt,
		Source:      g,
	}
	g.notifications <- n

}

// Metrics returns the grill's metric channel
func (g *Controller) Metrics() chan qpid.GrillStatus {
	return g.metrics
}

// Source implements Sourcer for pretty printing of events
// and notifications
func (g *Controller) Source() string {
	return fmt.Sprintf("Pi Grill Controller")
}
<commit_msg>setting min & max output values<commit_after>package gobot

import (
	"fmt"
	"time"

	"github.com/bbqgophers/qpid"
	"github.com/felixge/pidctrl"
	gb "github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/api"
	"github.com/hybridgroup/gobot/platforms/raspi"
	"github.com/pkg/errors"
)

// i2cAddress is the location that we read
// to get the temperatures from the i2c bus
const i2cAddress = 0x4d

var (
	// Sleep is the duration in seconds we hold when
	// temperature is met
	Sleep = 10
	// P is the P in PID :)
	P = 3.0
	// I is the I in PID
	I = .05
	// B is a booster.  Currently unused
	B = 0.0
	// MetricsIntervalSeconds is the metric reporting interval
	MetricsIntervalSeconds = 1
)

// Controller represents all the electronics that
// make the PID work
type Controller struct {
	grillProbe    *Probe
	gobot         *gb.Gobot
	pi            *raspi.RaspiAdaptor
	api           *api.API
	pid           *pidctrl.PIDController
	heating       bool
	notifications chan qpid.Notification
	metrics       chan qpid.GrillStatus
}

// NewController returns a new Controller
// initialized.
func NewController() *Controller {
	n := make(chan qpid.Notification)
	metrics := make(chan qpid.GrillStatus)
	g := gb.NewGobot()
	r := raspi.NewRaspiAdaptor("qpid")
	robot := gb.NewRobot("qpid",
		[]gb.Connection{r},
		[]gb.Device{},
		nil,
	)
	errs := r.Connect()
	if errs != nil {
		panic(errs)
	}
	g.AddRobot(robot)

	a := api.NewAPI(g)
	a.Port = "4000"
	a.AddHandler(api.BasicAuth("bbq", "gopher"))
	a.Start()
	e := r.I2cStart(i2cAddress)
	if e != nil {
		panic(e)
	}
	pid := pidctrl.NewPIDController(P, I, B)
	pid.SetOutputLimits(-100.0, 100.0)
	return &Controller{
		grillProbe:    NewProbe(r),
		gobot:         g,
		pi:            r,
		pid:           pid,
		api:           a,
		notifications: n,
		metrics:       metrics,
	}
}

// FoodMonitors returns the food monitors
func (g *Controller) FoodMonitors() []qpid.Monitor {
	panic("not implemented")
}

// GrillMonitor returns the grill probe
func (g *Controller) GrillMonitor() qpid.Monitor {
	return g.grillProbe
}

// Run starts the grill's run loop and blocks
func (g *Controller) Run() error {

	go func() {
		errs := g.gobot.Start()
		if errs != nil {
			// hack - maybe change interface?
			panic(errs)
		}
	}()

	// TODO: Decide where the blocking happens.
	// is this routine where we block and run until
	// receiving some signal to exit?  Or do we block in main?
	target, err := g.grillProbe.Setpoint()
	if err != nil {
		return err
	}
	g.pid.Set(float64(target))

	// start goroutine to send status on interval
	go func() {
		for {
			status, err := g.Status()
			if err != nil {
				g.notify(qpid.Critical, errors.Wrap(err, "grill status").Error())
			}
			g.metrics <- status
			time.Sleep(time.Duration(MetricsIntervalSeconds) * time.Second)
		}
	}()

	for { // block here for now
		time.Sleep(1 * time.Second)
		temp, err := g.grillProbe.Temperature()
		if err != nil {
			return err
		}
		output := g.pid.Update(float64(temp.C()))
		message := fmt.Sprintf("Temp: %d, Integral: %f", temp, output)
		g.notify(qpid.Info, message)

		for x := 1; x < 10; x++ {

			if output > float64(x^2) {
				if !g.heating {
					g.heating = true

					g.notify(qpid.Info, "Turning on Blower")
					err := g.pi.DigitalWrite("15", 0x1)
					if err != nil {
						g.notify(qpid.Critical, errors.Wrap(err, "turning on blower").Error())
					}
				}

				g.notify(qpid.Info, "Leaving Blower On")
			} else {
				if g.heating {
					g.heating = false
					g.notify(qpid.Info, "Turning off Blower")
					err := g.pi.DigitalWrite("15", 0x0)
					if err != nil {
						g.notify(qpid.Critical, errors.Wrap(err, "turning off blower").Error())
					}
				}
			}
		}
		if output < float64(10) {

			g.notify(qpid.Info, "Temp Good, Sleep 10")
			time.Sleep(10 * time.Second)
		}
	}
	return nil
}

// Stop stops the grill's run loop
// but actually probably wont.  because
// there's nothing to do that yet.
func (g *Controller) Stop() error {

	g.notify(qpid.Info, "Received Stop Request")
	errs := g.gobot.Stop()
	if errs != nil {
		// hack - maybe change interface?
		return errs[0]
	}

	return nil
}

// Status returns the current Grill status.
func (g *Controller) Status() (qpid.GrillStatus, error) {
	return qpid.GrillStatus{
		Time:         time.Now(),
		GrillSensors: []qpid.Sensor{g.grillProbe},
	}, nil
}

// Notifications returns the Grill's notification channel
func (g *Controller) Notifications() chan qpid.Notification {
	return g.notifications
}

// notify sends a message on the grill's notification channel
func (g *Controller) notify(mt qpid.MessageType, message string) {
	n := qpid.Notification{
		Time:        time.Now(),
		Message:     message,
		MessageType: mt,
		Source:      g,
	}
	g.notifications <- n

}

// Metrics returns the grill's metric channel
func (g *Controller) Metrics() chan qpid.GrillStatus {
	return g.metrics
}

// Source implements Sourcer for pretty printing of events
// and notifications
func (g *Controller) Source() string {
	return fmt.Sprintf("Pi Grill Controller")
}
<|endoftext|>


<commit_before>// (c) 2011-2014 Alexander Solovyov
// under terms of ISC license

package main

import (
	"bytes"
	"fmt"
	flags "github.com/jessevdk/go-flags"
	"math"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
)

const (
	Author  = "Alexander Solovyov"
	Version = "2.0"
)

var byteNewLine = []byte("\n")
var NoColors = false

var opts struct {
	Replace         *string  `short:"r" long:"replace" description:"replace found substrings with RE" value-name:"RE"`
	Force           bool     `short:""  long:"force" description:"force replacement in binary files"`
	IgnoreCase      bool     `short:"i" long:"ignore-case" description:"ignore pattern case"`
	SingleLine      bool     `short:"s" long:"singleline" description:"match single line (^/$ will match beginning/end of line)"`
	PlainText       bool     `short:"p" long:"plain" description:"treat pattern as plain text"`
	IgnoreFiles     []string `short:"x" long:"exclude" description:"exclude files with names that match regexp RE from search" value-name:"RE"`
	AcceptFiles     []string `short:"o" long:"only" description:"search only in files with names that match regexp RE" value-name:"RE"`
	NoGlobalIgnores bool     `short:"I" long:"no-autoignore" description:"do not read .git/.hgignore files"`
	FindFiles       bool     `short:"f" long:"find-files" description:"search in file names"`
	OnlyName        bool     `short:"n" long:"filename" description:"print only filenames"`
	Verbose         bool     `short:"v" long:"verbose" description:"be verbose (show non-fatal errors, like unreadable files)"`
	NoColors        bool     `short:"c" long:"no-colors" description:"do not show colors in output"`
	NoGroup         bool     `short:"N" long:"no-group" description:"print file name before each line"`
	ShowVersion     bool     `short:"V" long:"version" description:"show version and exit"`
	ShowHelp        bool     `short:"h" long:"help" description:"show this help message"`
}

func main() {
	argparser := flags.NewParser(&opts, flags.PrintErrors|flags.PassDoubleDash)

	args, err := argparser.Parse()
	if err != nil {
		return
	}

	if opts.ShowVersion {
		fmt.Printf("goreplace %s\n", Version)
		return
	}

	NoColors = opts.NoColors || runtime.GOOS == "windows"

	cwd, _ := os.Getwd()
	ignoreFileMatcher := NewMatcher(cwd, opts.NoGlobalIgnores)
	ignoreFileMatcher.Append(opts.IgnoreFiles)

	acceptedFileMatcher := NewGeneralMatcher([]string{}, []string{})
	if len(opts.AcceptFiles) > 0 {
		acceptedFileMatcher.Append(opts.AcceptFiles)
	} else {
		acceptedFileMatcher.Append([]string{".*"})
	}

	argparser.Usage = fmt.Sprintf("[OPTIONS] string-to-search\n\n%s",
		ignoreFileMatcher)

	if opts.ShowHelp || len(args) == 0 {
		argparser.WriteHelp(os.Stdout)
		return
	}

	arg := args[0]
	if opts.PlainText {
		arg = regexp.QuoteMeta(arg)
	}
	if opts.IgnoreCase {
		arg = "(?i:" + arg + ")"
	}

	pattern, err := regexp.Compile(arg)
	errhandle(err, true)

	if pattern.Match([]byte("")) {
		errhandle(fmt.Errorf("Your pattern matches empty string"), true)
	}

	if opts.Replace != nil {
		s, err := strconv.Unquote(`"` + *opts.Replace + `"`)
		if err != nil {
			errhandle(err, true)
		}
		*opts.Replace = s
	}

	searchFiles(pattern, ignoreFileMatcher, acceptedFileMatcher)
}

func errhandle(err error, exit bool) bool {
	if err == nil {
		return false
	}
	fmt.Fprintf(os.Stderr, "%s\n", err)
	if exit {
		os.Exit(1)
	}
	return true
}

func searchFiles(pattern *regexp.Regexp, ignoreFileMatcher Matcher,
	acceptedFileMatcher Matcher) {

	printer := &Printer{NoColors, opts.NoGroup, ""}
	v := &GRVisitor{printer, pattern, ignoreFileMatcher, acceptedFileMatcher}

	err := filepath.Walk(".", v.Walk)
	errhandle(err, false)
}

type GRVisitor struct {
	printer             *Printer
	pattern             *regexp.Regexp
	ignoreFileMatcher   Matcher
	acceptedFileMatcher Matcher
	// errors              chan error
}

func (v *GRVisitor) Walk(fn string, fi os.FileInfo, err error) error {
	if err != nil {
		if opts.Verbose {
			errhandle(err, false)
		}
		return nil
	}

	if fi.IsDir() {
		if !v.VisitDir(fn, fi) {
			return filepath.SkipDir
		}
		return nil
	}

	v.VisitFile(fn, fi)
	return nil
}

func (v *GRVisitor) VisitDir(fn string, fi os.FileInfo) bool {
	return !v.ignoreFileMatcher.Match(fn, true)
}

func (v *GRVisitor) VisitFile(fn string, fi os.FileInfo) {
	if fi.Size() == 0 && !opts.FindFiles {
		return
	}

	if v.ignoreFileMatcher.Match(fn, false) {
		return
	}

	if !v.acceptedFileMatcher.Match(fn, false) {
		return
	}

	if opts.FindFiles {
		v.SearchFileName(fn)
		return
	}

	if fi.Size() >= 1024*1024*10 {
		errhandle(fmt.Errorf("Skipping %s, too big: %d\n", fn, fi.Size()),
			false)
		return
	}

	// just skip invalid symlinks
	if fi.Mode()&os.ModeSymlink != 0 {
		if _, err := os.Stat(fn); err != nil {
			if opts.Verbose {
				errhandle(err, false)
			}
			return
		}
	}

	f, content := v.GetFileAndContent(fn, fi)
	if f == nil {
		return
	}
	defer f.Close()

	if opts.Replace == nil {
		v.SearchFile(fn, content)
		return
	}

	changed, result := v.ReplaceInFile(fn, content)
	if changed {
		f.Seek(0, 0)
		n, err := f.Write(result)
		if err != nil {
			errhandle(fmt.Errorf("Error writing replacement to file '%s': %s",
				fn, err), true)
		}
		if int64(n) < fi.Size() {
			err := f.Truncate(int64(n))
			if err != nil {
				errhandle(fmt.Errorf("Error truncating file '%s' to size %d",
					f, n), true)
			}
		}
	}
}

func (v *GRVisitor) GetFileAndContent(fn string, fi os.FileInfo) (f *os.File, content []byte) {
	var err error

	if opts.Replace != nil {
		f, err = os.OpenFile(fn, os.O_RDWR, 0666)
	} else {
		f, err = os.Open(fn)
	}

	if err != nil {
		if opts.Verbose {
			errhandle(err, false)
		}
		return
	}

	content = make([]byte, fi.Size())
	n, err := f.Read(content)
	if err != nil {
		errhandle(fmt.Errorf("Error %s", err), false)
		return
	}
	if int64(n) != fi.Size() {
		errhandle(fmt.Errorf("Not whole file '%s' was read, only %d from %d",
			fn, n, fi.Size()), true)
	}

	return
}

func (v *GRVisitor) SearchFile(fn string, content []byte) {
	seen := NewIntSet()
	binary := bytes.IndexByte(content, 0) != -1
	found := v.FindAllIndex(content)
	idxFmt := "%d:"

	if !opts.NoGroup {
		maxVal := 0
		for _, info := range found {
			if info.num > maxVal {
				maxVal = info.num
			}
		}
		idxLength := int(math.Ceil(math.Log10(float64(maxVal))))
		idxFmt = fmt.Sprintf("%%%dd:", idxLength)
	}

	for _, info := range found {
		if !seen.Add(info.num) {
			continue
		}

		if binary && !opts.OnlyName {
			fmt.Printf("Binary file '%s' matches", fn)
			return
		}

		if opts.OnlyName {
			v.printer.Printf("@g%s\n", "%s\n", fn)
			return
		}

		colored := v.pattern.ReplaceAllStringFunc(string(info.line),
			func(wrap string) string {
				return v.printer.Sprintf("@Y%s", "%s", wrap)
			})

		v.printer.FilePrintf(fn,
			"@!@y" + idxFmt + "@|" + colored + "\n",
			idxFmt + colored + "\n",
			info.num)
	}
}

func (v *GRVisitor) SearchFileName(fn string) {
	if !v.pattern.MatchString(fn) {
		return
	}
	colored := v.pattern.ReplaceAllStringFunc(fn,
		func(wrap string) string {
			return v.printer.Sprintf("@Y%s", "%s", wrap)
		})
	fmt.Println(colored)
}

func getSuffix(num int) string {
	if num > 1 {
		return "s"
	}
	return ""
}

func (v *GRVisitor) ReplaceInFile(fn string, content []byte) (changed bool, result []byte) {
	if opts.SingleLine {
		errhandle(fmt.Errorf("Can't handle singleline replacements"),
			true)
	}

	if opts.PlainText {
		errhandle(fmt.Errorf("Can't handle plain text replacements"),
			true)
	}

	changed = false
	changenum := 0
	binary := bytes.IndexByte(content, 0) != -1

	result = v.pattern.ReplaceAllFunc(content, func(s []byte) []byte {
		if binary && !opts.Force {
			errhandle(
				fmt.Errorf("supply --force to force change of binary file"),
				false)
		}
		if !changed {
			changed = true
			v.printer.Printf("@g%s", "%s", fn)
		}

		changenum += 1
		return v.pattern.ReplaceAll(s, []byte(*opts.Replace))
	})

	if changenum > 0 {
		v.printer.Printf("@!@y - %d change%s made\n", " - %d change%s made\n",
			changenum, getSuffix(changenum))
	}

	return changed, result
}

type LineInfo struct {
	num  int
	line []byte
}

func (v *GRVisitor) FindAllIndex(content []byte) (res []*LineInfo) {
	if opts.SingleLine {
		return v.singlelineFindAllIndex(content)
	}

	linenum, last := 1, 0
	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])
		res = append(res, &LineInfo{linenum, content[begin:end]})
	}
	return res
}

func (v *GRVisitor) singlelineFindAllIndex(content []byte) (res []*LineInfo) {
	linenum, begin, end := 1, 0, 0
	for i := 0; i < len(content); i++ {
		if content[i] == '\n' {
			end = i
			line := content[begin:end]
			if v.pattern.Match(line) {
				res = append(res, &LineInfo{linenum, line})
			}
			linenum += 1
			begin = end + 1
		}
	}
	return res
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice to contain this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start - 1; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			begin = i + 1
			break
		}
	}

	// -1 to check if current location is the end of a string
	for i := finish - 1; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return begin, end
}

type IntSet struct {
    set map[int]bool
}

func NewIntSet() *IntSet {
	return &IntSet{make(map[int]bool)}
}

func (set *IntSet) Add(i int) bool {
    _, found := set.set[i]
    set.set[i] = true
    return !found   // False if it existed already
}
<commit_msg>set exit flag 1 on error<commit_after>// (c) 2011-2014 Alexander Solovyov
// under terms of ISC license

package main

import (
	"bytes"
	"fmt"
	flags "github.com/jessevdk/go-flags"
	"math"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
)

const (
	Author  = "Alexander Solovyov"
	Version = "2.0"
)

var byteNewLine = []byte("\n")
var NoColors = false

var opts struct {
	Replace         *string  `short:"r" long:"replace" description:"replace found substrings with RE" value-name:"RE"`
	Force           bool     `short:""  long:"force" description:"force replacement in binary files"`
	IgnoreCase      bool     `short:"i" long:"ignore-case" description:"ignore pattern case"`
	SingleLine      bool     `short:"s" long:"singleline" description:"match single line (^/$ will match beginning/end of line)"`
	PlainText       bool     `short:"p" long:"plain" description:"treat pattern as plain text"`
	IgnoreFiles     []string `short:"x" long:"exclude" description:"exclude files with names that match regexp RE from search" value-name:"RE"`
	AcceptFiles     []string `short:"o" long:"only" description:"search only in files with names that match regexp RE" value-name:"RE"`
	NoGlobalIgnores bool     `short:"I" long:"no-autoignore" description:"do not read .git/.hgignore files"`
	FindFiles       bool     `short:"f" long:"find-files" description:"search in file names"`
	OnlyName        bool     `short:"n" long:"filename" description:"print only filenames"`
	Verbose         bool     `short:"v" long:"verbose" description:"be verbose (show non-fatal errors, like unreadable files)"`
	NoColors        bool     `short:"c" long:"no-colors" description:"do not show colors in output"`
	NoGroup         bool     `short:"N" long:"no-group" description:"print file name before each line"`
	ShowVersion     bool     `short:"V" long:"version" description:"show version and exit"`
	ShowHelp        bool     `short:"h" long:"help" description:"show this help message"`
}

func main() {
	argparser := flags.NewParser(&opts, flags.PrintErrors|flags.PassDoubleDash)

	args, err := argparser.Parse()
	if err != nil {
		os.Exit(1)
	}

	if opts.ShowVersion {
		fmt.Printf("goreplace %s\n", Version)
		return
	}

	NoColors = opts.NoColors || runtime.GOOS == "windows"

	cwd, _ := os.Getwd()
	ignoreFileMatcher := NewMatcher(cwd, opts.NoGlobalIgnores)
	ignoreFileMatcher.Append(opts.IgnoreFiles)

	acceptedFileMatcher := NewGeneralMatcher([]string{}, []string{})
	if len(opts.AcceptFiles) > 0 {
		acceptedFileMatcher.Append(opts.AcceptFiles)
	} else {
		acceptedFileMatcher.Append([]string{".*"})
	}

	argparser.Usage = fmt.Sprintf("[OPTIONS] string-to-search\n\n%s",
		ignoreFileMatcher)

	if opts.ShowHelp || len(args) == 0 {
		argparser.WriteHelp(os.Stdout)
		return
	}

	arg := args[0]
	if opts.PlainText {
		arg = regexp.QuoteMeta(arg)
	}
	if opts.IgnoreCase {
		arg = "(?i:" + arg + ")"
	}

	pattern, err := regexp.Compile(arg)
	errhandle(err, true)

	if pattern.Match([]byte("")) {
		errhandle(fmt.Errorf("Your pattern matches empty string"), true)
	}

	if opts.Replace != nil {
		s, err := strconv.Unquote(`"` + *opts.Replace + `"`)
		if err != nil {
			errhandle(err, true)
		}
		*opts.Replace = s
	}

	searchFiles(pattern, ignoreFileMatcher, acceptedFileMatcher)
}

func errhandle(err error, exit bool) bool {
	if err == nil {
		return false
	}
	fmt.Fprintf(os.Stderr, "%s\n", err)
	if exit {
		os.Exit(1)
	}
	return true
}

func searchFiles(pattern *regexp.Regexp, ignoreFileMatcher Matcher,
	acceptedFileMatcher Matcher) {

	printer := &Printer{NoColors, opts.NoGroup, ""}
	v := &GRVisitor{printer, pattern, ignoreFileMatcher, acceptedFileMatcher}

	err := filepath.Walk(".", v.Walk)
	errhandle(err, false)
}

type GRVisitor struct {
	printer             *Printer
	pattern             *regexp.Regexp
	ignoreFileMatcher   Matcher
	acceptedFileMatcher Matcher
	// errors              chan error
}

func (v *GRVisitor) Walk(fn string, fi os.FileInfo, err error) error {
	if err != nil {
		if opts.Verbose {
			errhandle(err, false)
		}
		return nil
	}

	if fi.IsDir() {
		if !v.VisitDir(fn, fi) {
			return filepath.SkipDir
		}
		return nil
	}

	v.VisitFile(fn, fi)
	return nil
}

func (v *GRVisitor) VisitDir(fn string, fi os.FileInfo) bool {
	return !v.ignoreFileMatcher.Match(fn, true)
}

func (v *GRVisitor) VisitFile(fn string, fi os.FileInfo) {
	if fi.Size() == 0 && !opts.FindFiles {
		return
	}

	if v.ignoreFileMatcher.Match(fn, false) {
		return
	}

	if !v.acceptedFileMatcher.Match(fn, false) {
		return
	}

	if opts.FindFiles {
		v.SearchFileName(fn)
		return
	}

	if fi.Size() >= 1024*1024*10 {
		errhandle(fmt.Errorf("Skipping %s, too big: %d\n", fn, fi.Size()),
			false)
		return
	}

	// just skip invalid symlinks
	if fi.Mode()&os.ModeSymlink != 0 {
		if _, err := os.Stat(fn); err != nil {
			if opts.Verbose {
				errhandle(err, false)
			}
			return
		}
	}

	f, content := v.GetFileAndContent(fn, fi)
	if f == nil {
		return
	}
	defer f.Close()

	if opts.Replace == nil {
		v.SearchFile(fn, content)
		return
	}

	changed, result := v.ReplaceInFile(fn, content)
	if changed {
		f.Seek(0, 0)
		n, err := f.Write(result)
		if err != nil {
			errhandle(fmt.Errorf("Error writing replacement to file '%s': %s",
				fn, err), true)
		}
		if int64(n) < fi.Size() {
			err := f.Truncate(int64(n))
			if err != nil {
				errhandle(fmt.Errorf("Error truncating file '%s' to size %d",
					f, n), true)
			}
		}
	}
}

func (v *GRVisitor) GetFileAndContent(fn string, fi os.FileInfo) (f *os.File, content []byte) {
	var err error

	if opts.Replace != nil {
		f, err = os.OpenFile(fn, os.O_RDWR, 0666)
	} else {
		f, err = os.Open(fn)
	}

	if err != nil {
		if opts.Verbose {
			errhandle(err, false)
		}
		return
	}

	content = make([]byte, fi.Size())
	n, err := f.Read(content)
	if err != nil {
		errhandle(fmt.Errorf("Error %s", err), false)
		return
	}
	if int64(n) != fi.Size() {
		errhandle(fmt.Errorf("Not whole file '%s' was read, only %d from %d",
			fn, n, fi.Size()), true)
	}

	return
}

func (v *GRVisitor) SearchFile(fn string, content []byte) {
	seen := NewIntSet()
	binary := bytes.IndexByte(content, 0) != -1
	found := v.FindAllIndex(content)
	idxFmt := "%d:"

	if !opts.NoGroup {
		maxVal := 0
		for _, info := range found {
			if info.num > maxVal {
				maxVal = info.num
			}
		}
		idxLength := int(math.Ceil(math.Log10(float64(maxVal))))
		idxFmt = fmt.Sprintf("%%%dd:", idxLength)
	}

	for _, info := range found {
		if !seen.Add(info.num) {
			continue
		}

		if binary && !opts.OnlyName {
			fmt.Printf("Binary file '%s' matches", fn)
			return
		}

		if opts.OnlyName {
			v.printer.Printf("@g%s\n", "%s\n", fn)
			return
		}

		colored := v.pattern.ReplaceAllStringFunc(string(info.line),
			func(wrap string) string {
				return v.printer.Sprintf("@Y%s", "%s", wrap)
			})

		v.printer.FilePrintf(fn,
			"@!@y" + idxFmt + "@|" + colored + "\n",
			idxFmt + colored + "\n",
			info.num)
	}
}

func (v *GRVisitor) SearchFileName(fn string) {
	if !v.pattern.MatchString(fn) {
		return
	}
	colored := v.pattern.ReplaceAllStringFunc(fn,
		func(wrap string) string {
			return v.printer.Sprintf("@Y%s", "%s", wrap)
		})
	fmt.Println(colored)
}

func getSuffix(num int) string {
	if num > 1 {
		return "s"
	}
	return ""
}

func (v *GRVisitor) ReplaceInFile(fn string, content []byte) (changed bool, result []byte) {
	if opts.SingleLine {
		errhandle(fmt.Errorf("Can't handle singleline replacements"),
			true)
	}

	if opts.PlainText {
		errhandle(fmt.Errorf("Can't handle plain text replacements"),
			true)
	}

	changed = false
	changenum := 0
	binary := bytes.IndexByte(content, 0) != -1

	result = v.pattern.ReplaceAllFunc(content, func(s []byte) []byte {
		if binary && !opts.Force {
			errhandle(
				fmt.Errorf("supply --force to force change of binary file"),
				false)
		}
		if !changed {
			changed = true
			v.printer.Printf("@g%s", "%s", fn)
		}

		changenum += 1
		return v.pattern.ReplaceAll(s, []byte(*opts.Replace))
	})

	if changenum > 0 {
		v.printer.Printf("@!@y - %d change%s made\n", " - %d change%s made\n",
			changenum, getSuffix(changenum))
	}

	return changed, result
}

type LineInfo struct {
	num  int
	line []byte
}

func (v *GRVisitor) FindAllIndex(content []byte) (res []*LineInfo) {
	if opts.SingleLine {
		return v.singlelineFindAllIndex(content)
	}

	linenum, last := 1, 0
	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])
		res = append(res, &LineInfo{linenum, content[begin:end]})
	}
	return res
}

func (v *GRVisitor) singlelineFindAllIndex(content []byte) (res []*LineInfo) {
	linenum, begin, end := 1, 0, 0
	for i := 0; i < len(content); i++ {
		if content[i] == '\n' {
			end = i
			line := content[begin:end]
			if v.pattern.Match(line) {
				res = append(res, &LineInfo{linenum, line})
			}
			linenum += 1
			begin = end + 1
		}
	}
	return res
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice to contain this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start - 1; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			begin = i + 1
			break
		}
	}

	// -1 to check if current location is the end of a string
	for i := finish - 1; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return begin, end
}

type IntSet struct {
    set map[int]bool
}

func NewIntSet() *IntSet {
	return &IntSet{make(map[int]bool)}
}

func (set *IntSet) Add(i int) bool {
    _, found := set.set[i]
    set.set[i] = true
    return !found   // False if it existed already
}
<|endoftext|>


<commit_before>package main

import (
	"gost/api/appuserapi"
	"gost/api/transactionapi"
	"gost/api/userloginapi"
	"gost/cache"
	"gost/config"
	"gost/httphandle"
	"gost/servers"
	"gost/service"
	"log"
	"os"
	"os/signal"
	"runtime"
)

var numberOfProcessors = runtime.NumCPU()

// Add all the existing endpoints as part of this container
type ApiContainer struct {
	appuserapi.ApplicationUsersAPI
	transactionapi.TransactionsAPI
	userloginapi.UserSessionsAPI
}

func StartWebFramework() {
	// Start listener for performing a graceful shutdown of the server
	go listenForInterruptSignal()

	// Start a http or and https server depending on the program arguments
	if len(os.Args) <= 1 || os.Args[1] == "http" {
		servers.StartHTTPServer()
	} else if os.Args[1] == "https" {
		servers.StartHTTPSServer()
	}
}

// Function for performing automatic initializations at application startup
func init() {
	var emptyConfigParam string = ""

	// Initialize application configuration
	config.InitApp(emptyConfigParam)
	config.InitDatabase(emptyConfigParam)
	config.InitRoutes(emptyConfigParam)

	// Initialize the MongoDb service
	service.InitDbService()

	// Register the API endpoints
	httphandle.SetApiInterface(new(ApiContainer))

	// Start the caching system
	cache.StartCachingSystem(cache.CacheExpireTime)

	// Set the app to use all the available processors
	runtime.GOMAXPROCS(numberOfProcessors)
}

// Application entry point - sets the behavior for the app
func main() {
	StartWebFramework()
}

func listenForInterruptSignal() {
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	<-signalChan

	log.Println("The server will now shut down gracefully...")

	service.CloseDbService()
	cache.StopCachingSystem()

	os.Exit(0)
}
<commit_msg>Added missing godoc and comments in the main (gost) package and also reordered the methods to have a more natura sequence in the file<commit_after>package main

import (
	"gost/api/appuserapi"
	"gost/api/transactionapi"
	"gost/api/userloginapi"
	"gost/cache"
	"gost/config"
	"gost/httphandle"
	"gost/servers"
	"gost/service"
	"log"
	"os"
	"os/signal"
	"runtime"
)

var numberOfProcessors = runtime.NumCPU()

// APIContainer is a struct used for boxing all the existing api endpoints. It is used for mapping requests to functions.
// Add all the existing endpoints as part of this container
type APIContainer struct {
	appuserapi.ApplicationUsersAPI
	transactionapi.TransactionsAPI
	userloginapi.UserSessionsAPI
}

// Application entry point - sets the behavior for the app
func main() {
	startWebFramework()
}

// startWebFramework performs the startup operations for the entire web framework
// and starts the actual http or https server used for listening for requests.
func startWebFramework() {
	// Start listener for performing a graceful shutdown of the server
	go listenForInterruptSignal()

	// Start a http or and https server depending on the program arguments
	if len(os.Args) <= 1 || os.Args[1] == "http" {
		servers.StartHTTPServer()
	} else if os.Args[1] == "https" {
		servers.StartHTTPSServer()
	}
}

// Function for performing automatic initializations at application startup
func init() {
	var emptyConfigParam string

	// Initialize application configuration
	config.InitApp(emptyConfigParam)
	config.InitDatabase(emptyConfigParam)
	config.InitRoutes(emptyConfigParam)

	// Initialize the MongoDb service
	service.InitDbService()

	// Register the API endpoints
	httphandle.SetApiInterface(new(APIContainer))

	// Start the caching system
	cache.StartCachingSystem(cache.CacheExpireTime)

	// Set the app to use all the available processors
	runtime.GOMAXPROCS(numberOfProcessors)
}

func listenForInterruptSignal() {
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	<-signalChan

	log.Println("")
	log.Println("The server will now shut down gracefully...")

	service.CloseDbService()
	cache.StopCachingSystem()

	os.Exit(0)
}
<|endoftext|>


<commit_before>package gpio

import (
	"fmt"
	"os"
	"syscall"

	"github.com/ungerik/go-quick"
)

type Value int

const (
	LOW  Value = 0
	HIGH Value = 1

	_EPOLLET = 1 << 31
)

type Edge string

const (
	EDGE_NONE    Edge = "none"
	EDGE_RISING  Edge = "rising"
	EDGE_FALLING Edge = "falling"
	EDGE_BOTH    Edge = "both"
)

type Direction string

const (
	DIRECTION_IN  Direction = "in"
	DIRECTION_OUT Direction = "out"
	// ALT0   Direction = 4
)

// TODO: How is this configured?
// Maybe see https://github.com/adafruit/PyBBIO/blob/master/bbio/bbio.py
type PullUpDown int

const (
	PUD_OFF  PullUpDown = 0
	PUD_DOWN PullUpDown = 1
	PUD_UP   PullUpDown = 2
)

type GPIO struct {
	nr        int
	valueFile *os.File
	epollFd   quick.SyncInt
	edge      Edge
}

// NewGPIO exports the GPIO pin nr.
func NewGPIO(nr int, direction Direction) (*GPIO, error) {
	gpio := &GPIO{nr: nr}

	err := quick.FilePrintf("/sys/class/gpio/export", "%d", gpio.nr)
	if err != nil {
		return nil, err
	}

	err = gpio.SetDirection(direction)
	if err != nil {
		return nil, err
	}

	return gpio, nil
}

// Close unexports the GPIO pin.
func (gpio *GPIO) Close() error {
	gpio.DisableEdgeDetect()

	if gpio.valueFile != nil {
		gpio.valueFile.Close()
	}

	return quick.FilePrintf("/sys/class/gpio/unexport", "%d", gpio.nr)
}

func (gpio *GPIO) Direction() (Direction, error) {
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/direction", gpio.nr)
	direction, err := quick.FileGetString(filename)
	return Direction(direction), err
}

func (gpio *GPIO) SetDirection(direction Direction) error {
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/direction", gpio.nr)
	return quick.FileSetString(filename, string(direction))
}

// func (gpio *GPIO) SetPullUpDown(pull PullUpDown) error {
// 	file, err := os.OpenFile("/sys/kernel/debug/omap_mux/", os.O_WRONLY, 0660)
// 	if err != nil {
// 		return err
// 	}
// 	defer file.Close()
// 	_, err = file.Write([]byte(fmt.Sprintf("%X", 0x07|1<<5|pull)))
// 	return err
// }

func (gpio *GPIO) ensureValueFileIsOpen() error {
	if gpio.valueFile != nil {
		return nil
	}
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/value", gpio.nr)
	file, err := os.OpenFile(filename, os.O_RDWR, 0660)
	if err == nil {
		gpio.valueFile = file
	}
	return err
}

func (gpio *GPIO) Value() (Value, error) {
	if err := gpio.ensureValueFileIsOpen(); err != nil {
		return 0, err
	}
	gpio.valueFile.Seek(0, os.SEEK_SET)
	val := make([]byte, 1)
	_, err := gpio.valueFile.Read(val)
	if err != nil {
		return 0, err
	}
	return Value(val[0] - '0'), nil
}

func (gpio *GPIO) SetValue(value Value) (err error) {
	if err = gpio.ensureValueFileIsOpen(); err != nil {
		return err
	}
	gpio.valueFile.Seek(0, os.SEEK_SET)
	_, err = gpio.valueFile.Write([]byte{'0' + byte(value)})
	return err
}

func (gpio *GPIO) setEdge(edge Edge) error {
	if edge == gpio.edge {
		return nil
	}
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/edge", gpio.nr)
	return quick.FileSetString(filename, string(edge))
}

// func (gpio *GPIO) EdgeDetectCallback(edge Edge, callback func(Value)) error {
// 	gpio.DisableEdgeDetect()

// 	err := gpio.SetDirection(DIRECTION_IN)
// 	if err != nil {
// 		return err
// 	}
// 	err = gpio.SetEdge(edge)
// 	if err != nil {
// 		return err
// 	}
// 	err = gpio.ensureValueFileIsOpen()
// 	if err != nil {
// 		return err
// 	}

// 	epollFd, err := syscall.EpollCreate(1)
// 	if err != nil {
// 		return err
// 	}

// 	event := &syscall.EpollEvent{
// 		Events: syscall.EPOLLIN | _EPOLLET | syscall.EPOLLPRI,
// 		Fd:     int32(gpio.valueFile.Fd()),
// 	}
// 	err = syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_ADD, int(gpio.valueFile.Fd()), event)
// 	if err != nil {
// 		syscall.Close(epollFd)
// 		return err
// 	}

// 	// / first time triggers with current state, so ignore
// 	_, err = syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
// 	if err != nil {
// 		syscall.Close(epollFd)
// 		return err
// 	}

// 	gpio.epollFd.Set(epollFd)

// 	go func() {
// 		for gpio.epollFd.Get() != 0 {
// 			n, _ := syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
// 			if n > 0 {
// 				value, err := gpio.Value()
// 				if err == nil {
// 					callback(value)
// 				}
// 			}
// 		}
// 	}()

// 	return nil
// }

// func (gpio *GPIO) EdgeDetect(edge Edge) (chan Value, error) {
// 	valueChan := make(chan Value)
// 	err := gpio.EdgeDetectCallback(edge, func(value Value) {
// 		valueChan <- value
// 	})
// 	if err != nil {
// 		return nil, err
// 	}
// 	return valueChan, nil
// }

func (gpio *GPIO) WaitForEdge(edge Edge) (value Value, err error) {
	// valueChan, err := gpio.EdgeDetect(edge)
	// if err == nil {
	// 	value = <-valueChan
	// 	gpio.DisableEdgeDetect()
	// }
	// return value, err

	err = gpio.setEdge(edge)
	if err != nil {
		return 0, err
	}

	err = gpio.ensureValueFileIsOpen()
	if err != nil {
		return 0, err
	}

	epollFd := gpio.epollFd.Get()
	if epollFd == 0 {
		epollFd, err = syscall.EpollCreate(1)
		if err != nil {
			return 0, err
		}

		event := &syscall.EpollEvent{
			Events: syscall.EPOLLIN | _EPOLLET | syscall.EPOLLPRI,
			Fd:     int32(gpio.valueFile.Fd()),
		}
		err = syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_ADD, int(gpio.valueFile.Fd()), event)
		if err != nil {
			syscall.Close(epollFd)
			return 0, err
		}

		// first time triggers with current state, so ignore
		_, err = syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
		if err != nil {
			syscall.Close(epollFd)
			return 0, err
		}

		gpio.epollFd.Set(epollFd)
	}

	_, err = syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
	if err != nil {
		return 0, err
	}
	return gpio.Value()
}

func (gpio *GPIO) IsEdgeDetectEnabled() bool {
	return gpio.epollFd.Get() != 0
}

func (gpio *GPIO) DisableEdgeDetect() {
	epollFd := gpio.epollFd.Swap(0)
	if epollFd != 0 {
		syscall.Close(epollFd)
	}
	gpio.setEdge(EDGE_NONE)
}
<commit_msg>O_NONBLOCK for GPIO.Value()<commit_after>package gpio

import (
	"fmt"
	"os"
	"syscall"

	"github.com/ungerik/go-quick"
)

type Value int

const (
	LOW  Value = 0
	HIGH Value = 1

	_EPOLLET = 1 << 31
)

type Edge string

const (
	EDGE_NONE    Edge = "none"
	EDGE_RISING  Edge = "rising"
	EDGE_FALLING Edge = "falling"
	EDGE_BOTH    Edge = "both"
)

type Direction string

const (
	DIRECTION_IN  Direction = "in"
	DIRECTION_OUT Direction = "out"
	// ALT0   Direction = 4
)

// TODO: How is this configured?
// Maybe see https://github.com/adafruit/PyBBIO/blob/master/bbio/bbio.py
type PullUpDown int

const (
	PUD_OFF  PullUpDown = 0
	PUD_DOWN PullUpDown = 1
	PUD_UP   PullUpDown = 2
)

type GPIO struct {
	nr        int
	valueFile *os.File
	epollFd   quick.SyncInt
	edge      Edge
}

// NewGPIO exports the GPIO pin nr.
func NewGPIO(nr int, direction Direction) (*GPIO, error) {
	gpio := &GPIO{nr: nr}

	err := quick.FilePrintf("/sys/class/gpio/export", "%d", gpio.nr)
	if err != nil {
		return nil, err
	}

	err = gpio.SetDirection(direction)
	if err != nil {
		return nil, err
	}

	return gpio, nil
}

// Close unexports the GPIO pin.
func (gpio *GPIO) Close() error {
	gpio.DisableEdgeDetect()

	if gpio.valueFile != nil {
		gpio.valueFile.Close()
	}

	return quick.FilePrintf("/sys/class/gpio/unexport", "%d", gpio.nr)
}

func (gpio *GPIO) Direction() (Direction, error) {
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/direction", gpio.nr)
	direction, err := quick.FileGetString(filename)
	return Direction(direction), err
}

func (gpio *GPIO) SetDirection(direction Direction) error {
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/direction", gpio.nr)
	return quick.FileSetString(filename, string(direction))
}

// func (gpio *GPIO) SetPullUpDown(pull PullUpDown) error {
// 	file, err := os.OpenFile("/sys/kernel/debug/omap_mux/", os.O_WRONLY, 0660)
// 	if err != nil {
// 		return err
// 	}
// 	defer file.Close()
// 	_, err = file.Write([]byte(fmt.Sprintf("%X", 0x07|1<<5|pull)))
// 	return err
// }

func (gpio *GPIO) ensureValueFileIsOpen() error {
	if gpio.valueFile != nil {
		return nil
	}
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/value", gpio.nr)
	file, err := os.OpenFile(filename, os.O_RDWR|syscall.O_NONBLOCK, 0660)
	if err == nil {
		gpio.valueFile = file
	}
	return err
}

func (gpio *GPIO) Value() (Value, error) {
	if err := gpio.ensureValueFileIsOpen(); err != nil {
		return 0, err
	}
	val := make([]byte, 1)
	_, err := gpio.valueFile.ReadAt(val, 0)
	if err != nil {
		return 0, err
	}
	return Value(val[0] - '0'), nil
}

func (gpio *GPIO) SetValue(value Value) (err error) {
	if err = gpio.ensureValueFileIsOpen(); err != nil {
		return err
	}
	gpio.valueFile.Seek(0, os.SEEK_SET)
	_, err = gpio.valueFile.Write([]byte{'0' + byte(value)})
	return err
}

func (gpio *GPIO) setEdge(edge Edge) error {
	if edge == gpio.edge {
		return nil
	}
	filename := fmt.Sprintf("/sys/class/gpio/gpio%d/edge", gpio.nr)
	return quick.FileSetString(filename, string(edge))
}

// func (gpio *GPIO) EdgeDetectCallback(edge Edge, callback func(Value)) error {
// 	gpio.DisableEdgeDetect()

// 	err := gpio.SetDirection(DIRECTION_IN)
// 	if err != nil {
// 		return err
// 	}
// 	err = gpio.SetEdge(edge)
// 	if err != nil {
// 		return err
// 	}
// 	err = gpio.ensureValueFileIsOpen()
// 	if err != nil {
// 		return err
// 	}

// 	epollFd, err := syscall.EpollCreate(1)
// 	if err != nil {
// 		return err
// 	}

// 	event := &syscall.EpollEvent{
// 		Events: syscall.EPOLLIN | _EPOLLET | syscall.EPOLLPRI,
// 		Fd:     int32(gpio.valueFile.Fd()),
// 	}
// 	err = syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_ADD, int(gpio.valueFile.Fd()), event)
// 	if err != nil {
// 		syscall.Close(epollFd)
// 		return err
// 	}

// 	// / first time triggers with current state, so ignore
// 	_, err = syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
// 	if err != nil {
// 		syscall.Close(epollFd)
// 		return err
// 	}

// 	gpio.epollFd.Set(epollFd)

// 	go func() {
// 		for gpio.epollFd.Get() != 0 {
// 			n, _ := syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
// 			if n > 0 {
// 				value, err := gpio.Value()
// 				if err == nil {
// 					callback(value)
// 				}
// 			}
// 		}
// 	}()

// 	return nil
// }

// func (gpio *GPIO) EdgeDetect(edge Edge) (chan Value, error) {
// 	valueChan := make(chan Value)
// 	err := gpio.EdgeDetectCallback(edge, func(value Value) {
// 		valueChan <- value
// 	})
// 	if err != nil {
// 		return nil, err
// 	}
// 	return valueChan, nil
// }

func (gpio *GPIO) WaitForEdge(edge Edge) (value Value, err error) {
	// valueChan, err := gpio.EdgeDetect(edge)
	// if err == nil {
	// 	value = <-valueChan
	// 	gpio.DisableEdgeDetect()
	// }
	// return value, err

	err = gpio.setEdge(edge)
	if err != nil {
		return 0, err
	}

	err = gpio.ensureValueFileIsOpen()
	if err != nil {
		return 0, err
	}

	epollFd := gpio.epollFd.Get()
	if epollFd == 0 {
		epollFd, err = syscall.EpollCreate(1)
		if err != nil {
			return 0, err
		}

		event := &syscall.EpollEvent{
			Events: syscall.EPOLLIN | syscall.EPOLLPRI | _EPOLLET,
			Fd:     int32(gpio.valueFile.Fd()),
		}
		err = syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_ADD, int(gpio.valueFile.Fd()), event)
		if err != nil {
			syscall.Close(epollFd)
			return 0, err
		}

		// first time triggers with current state, so ignore
		_, err = syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
		if err != nil {
			syscall.Close(epollFd)
			return 0, err
		}

		gpio.epollFd.Set(epollFd)
	}

	_, err = syscall.EpollWait(epollFd, make([]syscall.EpollEvent, 1), -1)
	if err != nil {
		return 0, err
	}
	return gpio.Value()
}

func (gpio *GPIO) IsEdgeDetectEnabled() bool {
	return gpio.epollFd.Get() != 0
}

func (gpio *GPIO) DisableEdgeDetect() {
	epollFd := gpio.epollFd.Swap(0)
	if epollFd != 0 {
		syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_DEL, int(gpio.valueFile.Fd()), new(syscall.EpollEvent))
		syscall.Close(epollFd)
	}
	gpio.setEdge(EDGE_NONE)
}
<|endoftext|>


<commit_before>package main

import "os"

func main() {
	gvm_root := os.Getenv("GVM_ROOT")
	if gvm_root == "" {
		println("ERROR: gpkg requires gvm to run (http://github.com/moovweb/gvm)")
	} else {
		println("GVM Package Manager!")
	}
}
<commit_msg>Updated gpkg main<commit_after>package main

import "os"
import "github.com/moovweb/gvm/gpkg/pkgs"

func showUsage() {
	println("usage: gpkg list")
}

func main() {
	gvm_root := os.Getenv("GVM_ROOT")
	if gvm_root == "" {
		println("ERROR: gpkg requires gvm to run (http://github.com/moovweb/gvm)")
		os.Exit(1)
	}

	if len(os.Args) > 1 {
		if os.Args[1] == "list" {
			pkgs.List(gvm_root)
		} else {
			showUsage()
		}
	} else {
		showUsage()
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package mungers

import (
	"fmt"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"

	"github.com/spf13/cobra"
)

const (
	labelUnapprovedPicksName = "label-unapproved-picks"
)

// LabelUnapprovedPicks will remove the LGTM flag from an PR which has been
// updated since the reviewer added LGTM
type LabelUnapprovedPicks struct{}

func init() {
	RegisterMungerOrDie(LabelUnapprovedPicks{})
}

// Name is the name usable in --pr-mungers
func (LabelUnapprovedPicks) Name() string { return labelUnapprovedPicksName }

// RequiredFeatures is a slice of 'features' that must be provided
func (LabelUnapprovedPicks) RequiredFeatures() []string { return []string{} }

// Initialize will initialize the munger
func (LabelUnapprovedPicks) Initialize(config *github.Config, features *features.Features) error {
	return nil
}

// EachLoop is called at the start of every munge loop
func (LabelUnapprovedPicks) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (LabelUnapprovedPicks) AddFlags(cmd *cobra.Command, config *github.Config) {}

// Munge is the workhorse the will actually make updates to the PR
func (LabelUnapprovedPicks) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}

	if obj.IsForBranch("master") {
		return
	}

	if obj.HasLabel(cpApprovedLabel) {
		return
	}

	obj.AddLabel(doNotMergeLabel)

	msg := fmt.Sprintf("This PR is not for the master branch but does not have the `%s` label. Adding the `%s` label.", cpApprovedLabel, doNotMergeLabel)
	obj.WriteComment(msg)
}
<commit_msg>submit-queue: do not label/comment if issue already has label<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package mungers

import (
	"fmt"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"

	"github.com/spf13/cobra"
)

const (
	labelUnapprovedPicksName = "label-unapproved-picks"
)

// LabelUnapprovedPicks will remove the LGTM flag from an PR which has been
// updated since the reviewer added LGTM
type LabelUnapprovedPicks struct{}

func init() {
	RegisterMungerOrDie(LabelUnapprovedPicks{})
}

// Name is the name usable in --pr-mungers
func (LabelUnapprovedPicks) Name() string { return labelUnapprovedPicksName }

// RequiredFeatures is a slice of 'features' that must be provided
func (LabelUnapprovedPicks) RequiredFeatures() []string { return []string{} }

// Initialize will initialize the munger
func (LabelUnapprovedPicks) Initialize(config *github.Config, features *features.Features) error {
	return nil
}

// EachLoop is called at the start of every munge loop
func (LabelUnapprovedPicks) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (LabelUnapprovedPicks) AddFlags(cmd *cobra.Command, config *github.Config) {}

// Munge is the workhorse the will actually make updates to the PR
func (LabelUnapprovedPicks) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}

	if obj.IsForBranch("master") {
		return
	}

	if obj.HasLabel(cpApprovedLabel) {
		return
	}

	if obj.HasLabel(doNotMergeLabel) {
		return
	}

	obj.AddLabel(doNotMergeLabel)

	msg := fmt.Sprintf("This PR is not for the master branch but does not have the `%s` label. Adding the `%s` label.", cpApprovedLabel, doNotMergeLabel)
	obj.WriteComment(msg)
}
<|endoftext|>


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

// +build pprof

package api

import (
	"github.com/tsuru/tsuru/api"

	"net/http"
	"net/http/pprof"
)

func init() {
	RegisterHandler("Get", "/debug/pprof/", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	RegisterHandler("Get", "/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	RegisterHandler("Get", "/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	RegisterHandler("Get", "/debug/pprof/heap", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/goroutine", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/threadcreate", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/block", http.HandlerFunc(pprof.Index))
}
<commit_msg>fix circular import<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build pprof

package api

import (
	"net/http"
	"net/http/pprof"
)

func init() {
	RegisterHandler("Get", "/debug/pprof/", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	RegisterHandler("Get", "/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	RegisterHandler("Get", "/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	RegisterHandler("Get", "/debug/pprof/heap", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/goroutine", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/threadcreate", http.HandlerFunc(pprof.Index))
	RegisterHandler("Get", "/debug/pprof/block", http.HandlerFunc(pprof.Index))
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"github.com/nais/naisd/api/app"
	redisapi "github.com/spotahome/redis-operator/api/redisfailover/v1alpha2"
	redisclient "github.com/spotahome/redis-operator/client/k8s/clientset/versioned/typed/redisfailover/v1alpha2"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8srest "k8s.io/client-go/rest"
)

type Redis struct {
	Enabled  bool
	Limits   ResourceList
	Requests ResourceList
}

func createRedisFailoverDef(spec app.Spec, redis Redis) *redisapi.RedisFailover {
	replicas := int32(3)
	resources := redisapi.RedisFailoverResources{}

	if redis.Limits != (ResourceList{}) {
		resources.Limits = redisapi.CPUAndMem{
			CPU:    redis.Limits.Cpu,
			Memory: redis.Limits.Memory,
		}
	} else {
		resources.Limits = redisapi.CPUAndMem{Memory: "100Mi"}
	}

	if redis.Requests != (ResourceList{}) {
		resources.Requests = redisapi.CPUAndMem{
			CPU:    redis.Requests.Cpu,
			Memory: redis.Requests.Memory,
		}
	} else {
		resources.Requests = redisapi.CPUAndMem{CPU: "100m"}
	}

	redisSpec := redisapi.RedisFailoverSpec{
		HardAntiAffinity: false,
		Sentinel: redisapi.SentinelSettings{
			Replicas:  replicas,
			Resources: resources,
		},
		Redis: redisapi.RedisSettings{
			Replicas:  replicas,
			Resources: resources,
			Exporter:  true,
		},
	}

	meta := generateObjectMeta(spec)
	return &redisapi.RedisFailover{Spec: redisSpec, ObjectMeta: meta}
}

func getExistingFailover(failoverInterface redisclient.RedisFailoverInterface, resourceName string) (*redisapi.RedisFailover, error) {
	failover, err := failoverInterface.Get(resourceName, k8smeta.GetOptions{})

	switch {
	case err == nil:
		return failover, err
	case k8serrors.IsNotFound(err):
		return nil, nil
	default:
		return nil, fmt.Errorf("unexpected error: %s", err)
	}
}

func updateOrCreateRedisSentinelCluster(spec app.Spec, redis Redis) (*redisapi.RedisFailover, error) {
	newFailover := createRedisFailoverDef(spec, redis)

	config, err := k8srest.InClusterConfig()
	if err != nil {
		return nil, fmt.Errorf("can't create InClusterConfig: %s", err)
	}

	client, err := redisclient.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("can't create new Redis client for InClusterConfig: %s", err)
	}

	existingFailover, err := getExistingFailover(redisclient.RedisFailoversGetter(client).RedisFailovers(spec.Namespace()), spec.ResourceName())
	if err != nil {
		return nil, fmt.Errorf("unable to get existing redis failover: %s", err)
	}

	if existingFailover != nil {
		existingFailover.Spec = newFailover.Spec
		existingFailover.ObjectMeta = mergeObjectMeta(existingFailover.ObjectMeta, newFailover.ObjectMeta)
		return redisclient.RedisFailoversGetter(client).RedisFailovers(spec.Namespace()).Update(existingFailover)
	}

	return redisclient.RedisFailoversGetter(client).RedisFailovers(spec.Namespace()).Create(newFailover)
}
<commit_msg>Enkel kommentar for redis-struct<commit_after>package api

import (
	"fmt"
	"github.com/nais/naisd/api/app"
	redisapi "github.com/spotahome/redis-operator/api/redisfailover/v1alpha2"
	redisclient "github.com/spotahome/redis-operator/client/k8s/clientset/versioned/typed/redisfailover/v1alpha2"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8srest "k8s.io/client-go/rest"
)

// Enables and set resources for Redis-pods
type Redis struct {
	Enabled  bool
	Limits   ResourceList
	Requests ResourceList
}

func createRedisFailoverDef(spec app.Spec, redis Redis) *redisapi.RedisFailover {
	replicas := int32(3)
	resources := redisapi.RedisFailoverResources{}

	if redis.Limits != (ResourceList{}) {
		resources.Limits = redisapi.CPUAndMem{
			CPU:    redis.Limits.Cpu,
			Memory: redis.Limits.Memory,
		}
	} else {
		resources.Limits = redisapi.CPUAndMem{Memory: "100Mi"}
	}

	if redis.Requests != (ResourceList{}) {
		resources.Requests = redisapi.CPUAndMem{
			CPU:    redis.Requests.Cpu,
			Memory: redis.Requests.Memory,
		}
	} else {
		resources.Requests = redisapi.CPUAndMem{CPU: "100m"}
	}

	redisSpec := redisapi.RedisFailoverSpec{
		HardAntiAffinity: false,
		Sentinel: redisapi.SentinelSettings{
			Replicas:  replicas,
			Resources: resources,
		},
		Redis: redisapi.RedisSettings{
			Replicas:  replicas,
			Resources: resources,
			Exporter:  true,
		},
	}

	meta := generateObjectMeta(spec)
	return &redisapi.RedisFailover{Spec: redisSpec, ObjectMeta: meta}
}

func getExistingFailover(failoverInterface redisclient.RedisFailoverInterface, resourceName string) (*redisapi.RedisFailover, error) {
	failover, err := failoverInterface.Get(resourceName, k8smeta.GetOptions{})

	switch {
	case err == nil:
		return failover, err
	case k8serrors.IsNotFound(err):
		return nil, nil
	default:
		return nil, fmt.Errorf("unexpected error: %s", err)
	}
}

func updateOrCreateRedisSentinelCluster(spec app.Spec, redis Redis) (*redisapi.RedisFailover, error) {
	newFailover := createRedisFailoverDef(spec, redis)

	config, err := k8srest.InClusterConfig()
	if err != nil {
		return nil, fmt.Errorf("can't create InClusterConfig: %s", err)
	}

	client, err := redisclient.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("can't create new Redis client for InClusterConfig: %s", err)
	}

	existingFailover, err := getExistingFailover(redisclient.RedisFailoversGetter(client).RedisFailovers(spec.Namespace()), spec.ResourceName())
	if err != nil {
		return nil, fmt.Errorf("unable to get existing redis failover: %s", err)
	}

	if existingFailover != nil {
		existingFailover.Spec = newFailover.Spec
		existingFailover.ObjectMeta = mergeObjectMeta(existingFailover.ObjectMeta, newFailover.ObjectMeta)
		return redisclient.RedisFailoversGetter(client).RedisFailovers(spec.Namespace()).Update(existingFailover)
	}

	return redisclient.RedisFailoversGetter(client).RedisFailovers(spec.Namespace()).Create(newFailover)
}
<|endoftext|>


<commit_before>package rbxmk

import (
	"strings"

	"github.com/robloxapi/rbxfile"
	"github.com/yuin/gopher-lua"
)

// Value is a value.
type Value interface{}

// Copier is a Value that can be copied.
type Copier interface {
	Value
	Copy() Value
}

// TValue is a value annotated with a type.
type TValue struct {
	Type string
	Value
}

type Type struct {
	// Name is the name of the type.
	Name string

	// Count indicates the number of Lua values that the type can reflect to and
	// from. A Count of 0 is the same as 1. Less than 0 indicates a variable
	// amount.
	Count int

	// ReflectTo converts v to a number of Lua values. l must be used only for
	// the conversion of values as needed. If err is nil, then lvs must have a
	// length of 1 or greater.
	ReflectTo func(s State, t Type, v Value) (lvs []lua.LValue, err error)

	// ReflectFrom converts a Lua value to v. l must be used only for the
	// conversion of values as needed. lvs must have a length of 1 or greater.
	ReflectFrom func(s State, t Type, lvs ...lua.LValue) (v Value, err error)

	// Serialize serializes a value.
	Serialize func(s State, v Value) (sv rbxfile.Value, err error)

	// Deserialize deserializes a value.
	Deserialize func(s State, sv rbxfile.Value) (v Value, err error)

	// Metatable defines the metamethods of a custom type. If Metatable is
	// non-nil, then a metatable is constructed and registered as a type
	// metatable under Name.
	Metatable Metatable

	// Members defines the members of a custom type. If the __index and
	// __newindex metamethods are not defined by Metatable, then Members defines
	// them according to the given members.
	Members Members

	// Constructors defines functions that construct the type. If non-nil, a
	// table containing each constructor is created and set as a global
	// referenced by Name.
	Constructors Constructors
}

// ValueCount returns the normalized number of Lua values that the type reflects
// between. Less than 0 means the amount is variable.
func (t Type) ValueCount() int {
	switch {
	case t.Count == 0, t.Count == 1:
		return 1
	case t.Count < 0:
		return -1
	}
	return t.Count
}

// Metatable defines the metamethods of a custom type.
type Metatable map[string]Metamethod

// Metamethod is called when a metamethod is invoked. v is the receiver, which
// was successfully reflected from the first argument to the metamethod.
type Metamethod func(s State, v Value) int

// Members is a set of members keyed by name.
type Members map[string]Member

// Member defines a member of a custom type. There are several kinds of members:
//
//     - Property: Method is false, Get must be defined, Set is optionally
//       defined. If Set is not defined, then the member is marked as read-only.
//     - Method: Method is true, Get must be defined, Set is ignored. Get is the
//       method itself.
type Member struct {
	// Get gets the value of a member from v and pushes it onto l. The index is
	// the 2nd argument in s.L. If Method is true, the function is pushed as a
	// method. The first argument will be the same value as v.
	Get func(s State, v Value) int
	// Set gets a value from l and sets it to a member of v. The index and value
	// are the 2nd and 3rd arguments in s.L.
	Set func(s State, v Value)
	// Method marks the member as being a method.
	Method bool
}

// Constructors is a set of constructor functions keyed by name.
type Constructors map[string]Constructor

// Constructor creates a new value of a Type. The function can receive arguments
// from s.L, and must push a new value to s.L.
type Constructor func(s State) int

// State contains references to an environment surrounding a value.
type State struct {
	*World

	L *lua.LState

	// Cycle is used to mark a table as having been traversed. This is non-nil
	// only for types that can contain other types.
	Cycle *Cycle
}

// Count returns the number of arguments in the stack frame.
func (s State) Count() int {
	return s.L.GetTop()
}

// Push reflects v according to type t registered with s.World, then pushes the
// results to s.L.
func (s State) Push(t string, v Value) int {
	typ := s.Type(t)
	if typ.Name == "" {
		panic("unregistered type " + t)
	}
	lvs, err := typ.ReflectTo(s, typ, v)
	if err != nil {
		s.L.RaiseError(err.Error())
		return 0
	}
	for _, lv := range lvs {
		s.L.Push(lv)
	}
	return len(lvs)
}

// Pull gets from s.L the values starting from n, and reflects a value from them
// according to type t registered with s.World.
func (s State) Pull(n int, t string) Value {
	typ := s.Type(t)
	var v Value
	var err error
	if typ.Count < 0 {
		lvs := make([]lua.LValue, 0, 4)
		for i := n; i <= s.L.GetTop(); i++ {
			lvs = append(lvs, s.L.Get(i))
		}
		v, err = typ.ReflectFrom(s, typ, lvs...)
	} else if typ.Count > 1 {
		lvs := make([]lua.LValue, 0, 4)
		for i := n; i <= typ.Count; i++ {
			lvs = append(lvs, s.L.CheckAny(i))
		}
		v, err = typ.ReflectFrom(s, typ, lvs...)
	} else {
		v, err = typ.ReflectFrom(s, typ, s.L.CheckAny(n))
	}
	if err != nil {
		s.L.ArgError(n, err.Error())
		return nil
	}
	return v
}

// PullOpt gets from s.L the value at n, and reflects a value from it according
// to type t registered with s.World. If the value is nil, d is returned
// instead.
func (s State) PullOpt(n int, t string, d Value) Value {
	typ := s.Type(t)
	if typ.Count < 0 {
		panic("PullOpt cannot pull variable types")
	} else if typ.Count > 1 {
		panic("PullOpt cannot pull multi-value types")
	}
	lv := s.L.Get(n)
	if lv == lua.LNil {
		return d
	}
	v, err := typ.ReflectFrom(s, typ, lv)
	if err != nil {
		s.L.ArgError(n, err.Error())
		return d
	}
	return v
}

func listTypes(types []string) string {
	switch len(types) {
	case 0:
		return ""
	case 1:
		return types[0]
	case 2:
		return types[0] + " or " + types[1]
	}
	return strings.Join(types[:len(types)-2], ", ") + ", or " + types[len(types)-1]
}

// PullAnyOf gets from s.L the values starting from n, and reflects a value from
// them according to any of the types in t registered with s.World. Returns the
// first successful reflection among the types in t. If no types succeeded, then
// a type error is thrown.
func (s State) PullAnyOf(n int, t ...string) Value {
	if n > s.L.GetTop() {
		// Every type must reflect at least one value, so no values is an
		// immediate error.
		s.L.ArgError(n, "value expected")
		return nil
	}
	// Find the maximum count among the given types. 0 is treated the same as 1.
	// <0 indicates an arbitrary number of values.
	max := 1
	types := make([]Type, 0, 4)
	for _, t := range t {
		typ := s.Type(t)
		types = append(types, typ)
		if typ.Count > 1 {
			max = typ.Count
		} else if typ.Count < 0 {
			max = -1
			break
		}
	}
	switch max {
	case 1: // All types have 1 value.
		v := s.L.CheckAny(n)
		for _, t := range types {
			if v, err := t.ReflectFrom(s, t, v); err == nil {
				return v
			}
		}
	case -1: // At least one type has arbitrary values.
		lvs := make([]lua.LValue, 0, 4)
		for _, t := range types {
			lvs = lvs[:0]
			var v Value
			var err error
			if t.Count < 0 {
				// Append all values.
				for i := n; i <= s.L.GetTop(); i++ {
					lvs = append(lvs, s.L.Get(i))
				}
				v, err = t.ReflectFrom(s, t, lvs...)
			} else if t.Count > 1 {
				// Append up to type count.
				for i := n; i <= t.Count; i++ {
					lvs = append(lvs, s.L.CheckAny(i))
				}
				v, err = t.ReflectFrom(s, t, lvs...)
			} else {
				// Append single value.
				v, err = t.ReflectFrom(s, t, s.L.CheckAny(n))
			}
			if err != nil {
				continue
			}
			return v
		}
	default: // Constant maximum.
		lvs := make([]lua.LValue, 0, 4)
		for _, t := range types {
			lvs = lvs[:0]
			n := t.Count
			if n == 0 {
				n = 1
			}
			for i := n; i <= t.Count; i++ {
				lvs = append(lvs, s.L.CheckAny(i))
			}
			v, err := t.ReflectFrom(s, t, lvs...)
			if err != nil {
				continue
			}
			return v
		}
	}
	TypeError(s.L, n, listTypes(t))
	return nil
}

// Cycle is used to detect cyclic references by containing values that have
// already been traversed.
type Cycle struct {
	m map[interface{}]struct{}
}

// Has returns whether a value has already been visited.
func (c *Cycle) Has(t interface{}) bool {
	if c == nil {
		return false
	}
	_, ok := c.m[t]
	return ok
}

// Put marks a value has having been visited.
func (c *Cycle) Put(t interface{}) {
	if c == nil {
		return
	}
	if c.m == nil {
		c.m = make(map[interface{}]struct{}, 4)
	}
	c.m[t] = struct{}{}
}

// ReflectTypeTo is a Type.ReflectTo that converts v to a userdata set with a
// type metatable registered as t.Name.
func ReflectTypeTo(s State, t Type, v Value) (lvs []lua.LValue, err error) {
	u := s.L.NewUserData()
	u.Value = v
	s.L.SetMetatable(u, s.L.GetTypeMetatable(t.Name))
	return append(lvs, u), nil
}

// ReflectTypeFrom is a Type.ReflectFrom that converts v from a userdata set
// with a type metatable registered as t.Name.
func ReflectTypeFrom(s State, t Type, lvs ...lua.LValue) (v Value, err error) {
	u, ok := lvs[0].(*lua.LUserData)
	if ok {
		return nil, TypeError(nil, 0, t.Name)
	}
	if u.Metatable != s.L.GetTypeMetatable(t.Name) {
		return nil, TypeError(nil, 0, t.Name)
	}
	if v, ok = u.Value.(Value); !ok {
		return nil, TypeError(nil, 0, t.Name)
	}
	return v, nil
}

type typeError struct {
	expected string
	got      string
}

func (err typeError) Error() string {
	if err.got == "" {
		return err.expected + " expected"
	}
	return err.expected + " expected, got " + err.got
}

// TypeError raises an argument error indicating that a given type was expected.
func TypeError(l *lua.LState, n int, typ string) (err error) {
	if l != nil {
		err = typeError{expected: typ, got: l.Get(n).Type().String()}
		l.ArgError(n, err.Error())
	} else {
		err = typeError{expected: typ}
	}
	return err
}

// CheckType returns the underlying value if the value at n is a userdata that
// has type metatable corresponding to typ.
func CheckType(l *lua.LState, n int, typ string) interface{} {
	if u, ok := l.Get(n).(*lua.LUserData); ok {
		if u.Metatable == l.GetTypeMetatable(typ) {
			return u.Value
		}
	}
	TypeError(l, n, typ)
	return nil
}

// OptType is like CheckType, but returns nil if the value is nil.
func OptType(l *lua.LState, n int, typ string) interface{} {
	v := l.Get(n)
	if v == lua.LNil {
		return nil
	}
	if u, ok := v.(*lua.LUserData); ok {
		if u.Metatable == l.GetTypeMetatable(typ) {
			return u.Value
		}
	}
	TypeError(l, n, typ)
	return nil
}
<commit_msg>Fix wrong condition in ReflectTypeFrom.<commit_after>package rbxmk

import (
	"strings"

	"github.com/robloxapi/rbxfile"
	"github.com/yuin/gopher-lua"
)

// Value is a value.
type Value interface{}

// Copier is a Value that can be copied.
type Copier interface {
	Value
	Copy() Value
}

// TValue is a value annotated with a type.
type TValue struct {
	Type string
	Value
}

type Type struct {
	// Name is the name of the type.
	Name string

	// Count indicates the number of Lua values that the type can reflect to and
	// from. A Count of 0 is the same as 1. Less than 0 indicates a variable
	// amount.
	Count int

	// ReflectTo converts v to a number of Lua values. l must be used only for
	// the conversion of values as needed. If err is nil, then lvs must have a
	// length of 1 or greater.
	ReflectTo func(s State, t Type, v Value) (lvs []lua.LValue, err error)

	// ReflectFrom converts a Lua value to v. l must be used only for the
	// conversion of values as needed. lvs must have a length of 1 or greater.
	ReflectFrom func(s State, t Type, lvs ...lua.LValue) (v Value, err error)

	// Serialize serializes a value.
	Serialize func(s State, v Value) (sv rbxfile.Value, err error)

	// Deserialize deserializes a value.
	Deserialize func(s State, sv rbxfile.Value) (v Value, err error)

	// Metatable defines the metamethods of a custom type. If Metatable is
	// non-nil, then a metatable is constructed and registered as a type
	// metatable under Name.
	Metatable Metatable

	// Members defines the members of a custom type. If the __index and
	// __newindex metamethods are not defined by Metatable, then Members defines
	// them according to the given members.
	Members Members

	// Constructors defines functions that construct the type. If non-nil, a
	// table containing each constructor is created and set as a global
	// referenced by Name.
	Constructors Constructors
}

// ValueCount returns the normalized number of Lua values that the type reflects
// between. Less than 0 means the amount is variable.
func (t Type) ValueCount() int {
	switch {
	case t.Count == 0, t.Count == 1:
		return 1
	case t.Count < 0:
		return -1
	}
	return t.Count
}

// Metatable defines the metamethods of a custom type.
type Metatable map[string]Metamethod

// Metamethod is called when a metamethod is invoked. v is the receiver, which
// was successfully reflected from the first argument to the metamethod.
type Metamethod func(s State, v Value) int

// Members is a set of members keyed by name.
type Members map[string]Member

// Member defines a member of a custom type. There are several kinds of members:
//
//     - Property: Method is false, Get must be defined, Set is optionally
//       defined. If Set is not defined, then the member is marked as read-only.
//     - Method: Method is true, Get must be defined, Set is ignored. Get is the
//       method itself.
type Member struct {
	// Get gets the value of a member from v and pushes it onto l. The index is
	// the 2nd argument in s.L. If Method is true, the function is pushed as a
	// method. The first argument will be the same value as v.
	Get func(s State, v Value) int
	// Set gets a value from l and sets it to a member of v. The index and value
	// are the 2nd and 3rd arguments in s.L.
	Set func(s State, v Value)
	// Method marks the member as being a method.
	Method bool
}

// Constructors is a set of constructor functions keyed by name.
type Constructors map[string]Constructor

// Constructor creates a new value of a Type. The function can receive arguments
// from s.L, and must push a new value to s.L.
type Constructor func(s State) int

// State contains references to an environment surrounding a value.
type State struct {
	*World

	L *lua.LState

	// Cycle is used to mark a table as having been traversed. This is non-nil
	// only for types that can contain other types.
	Cycle *Cycle
}

// Count returns the number of arguments in the stack frame.
func (s State) Count() int {
	return s.L.GetTop()
}

// Push reflects v according to type t registered with s.World, then pushes the
// results to s.L.
func (s State) Push(t string, v Value) int {
	typ := s.Type(t)
	if typ.Name == "" {
		panic("unregistered type " + t)
	}
	lvs, err := typ.ReflectTo(s, typ, v)
	if err != nil {
		s.L.RaiseError(err.Error())
		return 0
	}
	for _, lv := range lvs {
		s.L.Push(lv)
	}
	return len(lvs)
}

// Pull gets from s.L the values starting from n, and reflects a value from them
// according to type t registered with s.World.
func (s State) Pull(n int, t string) Value {
	typ := s.Type(t)
	var v Value
	var err error
	if typ.Count < 0 {
		lvs := make([]lua.LValue, 0, 4)
		for i := n; i <= s.L.GetTop(); i++ {
			lvs = append(lvs, s.L.Get(i))
		}
		v, err = typ.ReflectFrom(s, typ, lvs...)
	} else if typ.Count > 1 {
		lvs := make([]lua.LValue, 0, 4)
		for i := n; i <= typ.Count; i++ {
			lvs = append(lvs, s.L.CheckAny(i))
		}
		v, err = typ.ReflectFrom(s, typ, lvs...)
	} else {
		v, err = typ.ReflectFrom(s, typ, s.L.CheckAny(n))
	}
	if err != nil {
		s.L.ArgError(n, err.Error())
		return nil
	}
	return v
}

// PullOpt gets from s.L the value at n, and reflects a value from it according
// to type t registered with s.World. If the value is nil, d is returned
// instead.
func (s State) PullOpt(n int, t string, d Value) Value {
	typ := s.Type(t)
	if typ.Count < 0 {
		panic("PullOpt cannot pull variable types")
	} else if typ.Count > 1 {
		panic("PullOpt cannot pull multi-value types")
	}
	lv := s.L.Get(n)
	if lv == lua.LNil {
		return d
	}
	v, err := typ.ReflectFrom(s, typ, lv)
	if err != nil {
		s.L.ArgError(n, err.Error())
		return d
	}
	return v
}

func listTypes(types []string) string {
	switch len(types) {
	case 0:
		return ""
	case 1:
		return types[0]
	case 2:
		return types[0] + " or " + types[1]
	}
	return strings.Join(types[:len(types)-2], ", ") + ", or " + types[len(types)-1]
}

// PullAnyOf gets from s.L the values starting from n, and reflects a value from
// them according to any of the types in t registered with s.World. Returns the
// first successful reflection among the types in t. If no types succeeded, then
// a type error is thrown.
func (s State) PullAnyOf(n int, t ...string) Value {
	if n > s.L.GetTop() {
		// Every type must reflect at least one value, so no values is an
		// immediate error.
		s.L.ArgError(n, "value expected")
		return nil
	}
	// Find the maximum count among the given types. 0 is treated the same as 1.
	// <0 indicates an arbitrary number of values.
	max := 1
	types := make([]Type, 0, 4)
	for _, t := range t {
		typ := s.Type(t)
		types = append(types, typ)
		if typ.Count > 1 {
			max = typ.Count
		} else if typ.Count < 0 {
			max = -1
			break
		}
	}
	switch max {
	case 1: // All types have 1 value.
		v := s.L.CheckAny(n)
		for _, t := range types {
			if v, err := t.ReflectFrom(s, t, v); err == nil {
				return v
			}
		}
	case -1: // At least one type has arbitrary values.
		lvs := make([]lua.LValue, 0, 4)
		for _, t := range types {
			lvs = lvs[:0]
			var v Value
			var err error
			if t.Count < 0 {
				// Append all values.
				for i := n; i <= s.L.GetTop(); i++ {
					lvs = append(lvs, s.L.Get(i))
				}
				v, err = t.ReflectFrom(s, t, lvs...)
			} else if t.Count > 1 {
				// Append up to type count.
				for i := n; i <= t.Count; i++ {
					lvs = append(lvs, s.L.CheckAny(i))
				}
				v, err = t.ReflectFrom(s, t, lvs...)
			} else {
				// Append single value.
				v, err = t.ReflectFrom(s, t, s.L.CheckAny(n))
			}
			if err != nil {
				continue
			}
			return v
		}
	default: // Constant maximum.
		lvs := make([]lua.LValue, 0, 4)
		for _, t := range types {
			lvs = lvs[:0]
			n := t.Count
			if n == 0 {
				n = 1
			}
			for i := n; i <= t.Count; i++ {
				lvs = append(lvs, s.L.CheckAny(i))
			}
			v, err := t.ReflectFrom(s, t, lvs...)
			if err != nil {
				continue
			}
			return v
		}
	}
	TypeError(s.L, n, listTypes(t))
	return nil
}

// Cycle is used to detect cyclic references by containing values that have
// already been traversed.
type Cycle struct {
	m map[interface{}]struct{}
}

// Has returns whether a value has already been visited.
func (c *Cycle) Has(t interface{}) bool {
	if c == nil {
		return false
	}
	_, ok := c.m[t]
	return ok
}

// Put marks a value has having been visited.
func (c *Cycle) Put(t interface{}) {
	if c == nil {
		return
	}
	if c.m == nil {
		c.m = make(map[interface{}]struct{}, 4)
	}
	c.m[t] = struct{}{}
}

// ReflectTypeTo is a Type.ReflectTo that converts v to a userdata set with a
// type metatable registered as t.Name.
func ReflectTypeTo(s State, t Type, v Value) (lvs []lua.LValue, err error) {
	u := s.L.NewUserData()
	u.Value = v
	s.L.SetMetatable(u, s.L.GetTypeMetatable(t.Name))
	return append(lvs, u), nil
}

// ReflectTypeFrom is a Type.ReflectFrom that converts v from a userdata set
// with a type metatable registered as t.Name.
func ReflectTypeFrom(s State, t Type, lvs ...lua.LValue) (v Value, err error) {
	u, ok := lvs[0].(*lua.LUserData)
	if !ok {
		return nil, TypeError(nil, 0, t.Name)
	}
	if u.Metatable != s.L.GetTypeMetatable(t.Name) {
		return nil, TypeError(nil, 0, t.Name)
	}
	if v, ok = u.Value.(Value); !ok {
		return nil, TypeError(nil, 0, t.Name)
	}
	return v, nil
}

type typeError struct {
	expected string
	got      string
}

func (err typeError) Error() string {
	if err.got == "" {
		return err.expected + " expected"
	}
	return err.expected + " expected, got " + err.got
}

// TypeError raises an argument error indicating that a given type was expected.
func TypeError(l *lua.LState, n int, typ string) (err error) {
	if l != nil {
		err = typeError{expected: typ, got: l.Get(n).Type().String()}
		l.ArgError(n, err.Error())
	} else {
		err = typeError{expected: typ}
	}
	return err
}

// CheckType returns the underlying value if the value at n is a userdata that
// has type metatable corresponding to typ.
func CheckType(l *lua.LState, n int, typ string) interface{} {
	if u, ok := l.Get(n).(*lua.LUserData); ok {
		if u.Metatable == l.GetTypeMetatable(typ) {
			return u.Value
		}
	}
	TypeError(l, n, typ)
	return nil
}

// OptType is like CheckType, but returns nil if the value is nil.
func OptType(l *lua.LState, n int, typ string) interface{} {
	v := l.Get(n)
	if v == lua.LNil {
		return nil
	}
	if u, ok := v.(*lua.LUserData); ok {
		if u.Metatable == l.GetTypeMetatable(typ) {
			return u.Value
		}
	}
	TypeError(l, n, typ)
	return nil
}
<|endoftext|>