<commit_before>package main

import (
	"fmt"
	"time"
)

func pinger(c chan string) {
	for i := 0; ; i++ {
		c <- "ping"
	}
}

func ponger(c chan string) {
	for i := 0; ; i++ {
		c <- "pong"
	}
}

func printer(c chan string) {
	for {
		msg := <-c
		fmt.Println(msg)
		time.Sleep(time.Second * 1)
	}
}

func main() {
	var c chan string = make(chan string)

	go pinger(c)
	go ponger(c)
	go printer(c)

	var input string
	fmt.Scanln(&input)
}

/* A Channel Timeout example
select {
	case msg1 := < c1:
		fmt.Println("Message 1", msg1)
	case msg2 := < c1:
		fmt.Println("Message 2", msg1)
	case <- time.After(time.Second) * 8:
		fmt.Println("Timeout")
	default:
		fmt.Println("nothing ready")
}*/
<commit_msg>modif channel with timeout example<commit_after>package main

import (
	"fmt"
	"time"
)

func pinger(c chan string) {
	for i := 0; ; i++ {
		c <- "ping"
	}
}

func ponger(c chan string) {
	for i := 0; ; i++ {
		c <- "pong"
	}
}

func printer(c chan string) {
	for {
		msg := <-c
		fmt.Println(msg)
		time.Sleep(time.Second * 1)
	}
}

func main() {
	var c chan string = make(chan string)

	go pinger(c)
	go ponger(c)
	go printer(c)

	var input string
	fmt.Scanln(&input)
}

/* A Channel Timeout example
select {
	case msg1 := < c1:
		fmt.Println("Message 1", msg1)
	case msg2 := < c2:
		fmt.Println("Message 2", msg1)
	case <- time.After(time.Second * 8):
		fmt.Println("Timeout")
	default:
		fmt.Println("nothing ready")
}*/
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"errors"
)

type repoWorker interface {
	checkout() error
}

func (t *task) parseRepo() error {
	if t.Repo == "" {
		return errors.New("Repo needed")
	}

	switch {
	case strings.HasPrefix(t.Repo, "lp:"):
		t.RepoWorker = newBzrRepo(t.Repo, t.Rev, t.WorkingDir, t.Output)
	}
	return nil
}

<commit_msg>Support bzr repo addr bzr+ssh://<commit_after>package main

import (
	"errors"
	"strings"
)

type repoWorker interface {
	checkout() error
}

func (t *task) parseRepo() error {
	if t.Repo == "" {
		return errors.New("Repo needed")
	}

	switch {
	case strings.HasPrefix(t.Repo, "lp:"):
		fallthrough
	case strings.HasPrefix(t.Repo, "bzr+ssh://"):
		t.RepoWorker = newBzrRepo(t.Repo, t.Rev, t.WorkingDir, t.Output)
	}
	return nil
}
<|endoftext|>


<commit_before>// Package repr attempts to represent Go values in a form that can be copy-and-pasted into source
// code directly.
//
// Some values (such as pointers to basic types) can not be represented directly in
// Go. These values will be output as `&<value>`. eg. `&23`
package repr

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"reflect"
)

// "Real" names of basic kinds, used to differentiate type aliases.
var realKindName = map[reflect.Kind]string{
	reflect.Bool:       "bool",
	reflect.Int:        "int",
	reflect.Int8:       "int8",
	reflect.Int16:      "int16",
	reflect.Int32:      "int32",
	reflect.Int64:      "int64",
	reflect.Uint:       "uint",
	reflect.Uint8:      "uint8",
	reflect.Uint16:     "uint16",
	reflect.Uint32:     "uint32",
	reflect.Uint64:     "uint64",
	reflect.Uintptr:    "uintptr",
	reflect.Float32:    "float32",
	reflect.Float64:    "float64",
	reflect.Complex64:  "complex64",
	reflect.Complex128: "complex128",
	reflect.Array:      "array",
	reflect.Chan:       "chan",
	reflect.Func:       "func",
	reflect.Map:        "map",
	reflect.Slice:      "slice",
	reflect.String:     "string",
}

// Default prints to os.Stdout with two space indentation.
var Default = New(os.Stdout, Indent("  "))

// An Option modifies the default behaviour of a Printer.
type Option func(o *Printer)

// Indent output by this much.
func Indent(indent string) Option { return func(o *Printer) { o.indent = indent } }

// NoIndent disables indenting.
func NoIndent() Option { return Indent("") }

// OmitEmpty sets whether empty field members should be omitted from output.
func OmitEmpty(omitEmpty bool) Option { return func(o *Printer) { o.omitEmpty = omitEmpty } }

// Printer represents structs in a printable manner.
type Printer struct {
	indent    string
	omitEmpty bool
	w         io.Writer
}

// New creates a new Printer on w with the given Options.
func New(w io.Writer, options ...Option) *Printer {
	p := &Printer{
		w:         w,
		indent:    "  ",
		omitEmpty: true,
	}
	for _, option := range options {
		option(p)
	}
	return p
}

func (p *Printer) nextIndent(indent string) string {
	if p.indent != "" {
		return indent + p.indent
	}
	return ""
}

func (p *Printer) thisIndent(indent string) string {
	if p.indent != "" {
		return indent
	}
	return ""
}

// Print the values.
func (p *Printer) Print(vs ...interface{}) {
	for i, v := range vs {
		if i > 0 {
			fmt.Fprint(p.w, " ")
		}
		p.reprValue(reflect.ValueOf(v), "")
	}
}

// Println prints each value on a new line.
func (p *Printer) Println(vs ...interface{}) {
	for i, v := range vs {
		if i > 0 {
			fmt.Fprintln(p.w)
		}
		p.reprValue(reflect.ValueOf(v), "")
	}
}

func (p *Printer) reprValue(v reflect.Value, indent string) {
	in := p.thisIndent(indent)
	ni := p.nextIndent(indent)
	switch v.Kind() {
	case reflect.Slice, reflect.Array:
		if p.omitEmpty && v.Len() == 0 {
			return
		}
		fmt.Fprintf(p.w, "%s{", v.Type())
		if v.Len() == 0 {
			fmt.Fprint(p.w, "}")
		} else {
			if p.indent != "" {
				fmt.Fprintf(p.w, "\n")
			}
			for i := 0; i < v.Len(); i++ {
				e := v.Index(i)
				fmt.Fprintf(p.w, "%s", ni)
				p.reprValue(e, ni)
				if p.indent != "" {
					fmt.Fprintf(p.w, ",\n")
				} else if i < v.Len()-1 {
					fmt.Fprintf(p.w, ", ")
				}
			}
			fmt.Fprintf(p.w, "%s}", in)
		}
	case reflect.Chan:
		fmt.Fprintf(p.w, "make(")
		fmt.Fprintf(p.w, "%s", v.Type())
		fmt.Fprintf(p.w, ", %d)", v.Cap())
	case reflect.Map:
		fmt.Fprintf(p.w, "%s{", v.Type())
		if p.indent != "" && v.Len() != 0 {
			fmt.Fprintf(p.w, "\n")
		}
		for i, k := range v.MapKeys() {
			kv := v.MapIndex(k)
			fmt.Fprintf(p.w, "%s", ni)
			p.reprValue(k, ni)
			fmt.Fprintf(p.w, ": ")
			p.reprValue(kv, ni)
			if p.indent != "" {
				fmt.Fprintf(p.w, ",\n")
			} else if i < v.Len()-1 {
				fmt.Fprintf(p.w, ", ")
			}
		}
		fmt.Fprintf(p.w, "%s}", in)
	case reflect.Struct:
		fmt.Fprintf(p.w, "%s{", v.Type())
		if p.indent != "" && v.NumField() != 0 {
			fmt.Fprintf(p.w, "\n")
		}
		for i := 0; i < v.NumField(); i++ {
			t := v.Type().Field(i)
			f := v.Field(i)
			if p.omitEmpty && isZero(f) {
				continue
			}
			fmt.Fprintf(p.w, "%s%s: ", ni, t.Name)
			p.reprValue(f, ni)
			if p.indent != "" {
				fmt.Fprintf(p.w, ",\n")
			} else if i < v.NumField()-1 {
				fmt.Fprintf(p.w, ", ")
			}
		}
		fmt.Fprintf(p.w, "%s}", indent)
	case reflect.Ptr:
		if v.IsNil() {
			fmt.Fprintf(p.w, "nil")
			return
		}
		fmt.Fprintf(p.w, "&")
		p.reprValue(v.Elem(), indent)
	case reflect.String:
		t := v.Type()
		if t.Name() != "string" {
			fmt.Fprintf(p.w, "%s(%q)", t, v.String())
		} else {
			fmt.Fprintf(p.w, "%q", v.String())
		}
	case reflect.Interface:
		if v.IsNil() {
			fmt.Fprintf(p.w, "interface {}(nil)")
		} else {
			p.reprValue(v.Elem(), indent)
		}
	default:
		t := v.Type()
		if t.Name() != realKindName[t.Kind()] {
			fmt.Fprintf(p.w, "%s(%v)", t, v)
		} else {
			fmt.Fprintf(p.w, "%v", v)
		}
	}
}

// String returns a string representing v.
func String(v interface{}, options ...Option) string {
	w := bytes.NewBuffer(nil)
	options = append([]Option{NoIndent()}, options...)
	p := New(w, options...)
	p.Print(v)
	return w.String()
}

// Print v to os.Stdout, one per line.
func Println(v ...interface{}) {
	New(os.Stdout).Println(v...)
}

// Print writes a representation of v to os.Stdout, separated by spaces.
func Print(v ...interface{}) {
	New(os.Stdout).Print(v...)
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		return v.IsNil()
	}
	return false
}
<commit_msg>Correctly adhere to Println semantics.<commit_after>// Package repr attempts to represent Go values in a form that can be copy-and-pasted into source
// code directly.
//
// Some values (such as pointers to basic types) can not be represented directly in
// Go. These values will be output as `&<value>`. eg. `&23`
package repr

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"reflect"
)

// "Real" names of basic kinds, used to differentiate type aliases.
var realKindName = map[reflect.Kind]string{
	reflect.Bool:       "bool",
	reflect.Int:        "int",
	reflect.Int8:       "int8",
	reflect.Int16:      "int16",
	reflect.Int32:      "int32",
	reflect.Int64:      "int64",
	reflect.Uint:       "uint",
	reflect.Uint8:      "uint8",
	reflect.Uint16:     "uint16",
	reflect.Uint32:     "uint32",
	reflect.Uint64:     "uint64",
	reflect.Uintptr:    "uintptr",
	reflect.Float32:    "float32",
	reflect.Float64:    "float64",
	reflect.Complex64:  "complex64",
	reflect.Complex128: "complex128",
	reflect.Array:      "array",
	reflect.Chan:       "chan",
	reflect.Func:       "func",
	reflect.Map:        "map",
	reflect.Slice:      "slice",
	reflect.String:     "string",
}

// Default prints to os.Stdout with two space indentation.
var Default = New(os.Stdout, Indent("  "))

// An Option modifies the default behaviour of a Printer.
type Option func(o *Printer)

// Indent output by this much.
func Indent(indent string) Option { return func(o *Printer) { o.indent = indent } }

// NoIndent disables indenting.
func NoIndent() Option { return Indent("") }

// OmitEmpty sets whether empty field members should be omitted from output.
func OmitEmpty(omitEmpty bool) Option { return func(o *Printer) { o.omitEmpty = omitEmpty } }

// Printer represents structs in a printable manner.
type Printer struct {
	indent    string
	omitEmpty bool
	w         io.Writer
}

// New creates a new Printer on w with the given Options.
func New(w io.Writer, options ...Option) *Printer {
	p := &Printer{
		w:         w,
		indent:    "  ",
		omitEmpty: true,
	}
	for _, option := range options {
		option(p)
	}
	return p
}

func (p *Printer) nextIndent(indent string) string {
	if p.indent != "" {
		return indent + p.indent
	}
	return ""
}

func (p *Printer) thisIndent(indent string) string {
	if p.indent != "" {
		return indent
	}
	return ""
}

// Print the values.
func (p *Printer) Print(vs ...interface{}) {
	for i, v := range vs {
		if i > 0 {
			fmt.Fprint(p.w, " ")
		}
		p.reprValue(reflect.ValueOf(v), "")
	}
}

// Println prints each value on a new line.
func (p *Printer) Println(vs ...interface{}) {
	for i, v := range vs {
		if i > 0 {
			fmt.Fprint(p.w, " ")
		}
		p.reprValue(reflect.ValueOf(v), "")
	}
	fmt.Fprintln(p.w)
}

func (p *Printer) reprValue(v reflect.Value, indent string) {
	in := p.thisIndent(indent)
	ni := p.nextIndent(indent)
	switch v.Kind() {
	case reflect.Slice, reflect.Array:
		if p.omitEmpty && v.Len() == 0 {
			return
		}
		fmt.Fprintf(p.w, "%s{", v.Type())
		if v.Len() == 0 {
			fmt.Fprint(p.w, "}")
		} else {
			if p.indent != "" {
				fmt.Fprintf(p.w, "\n")
			}
			for i := 0; i < v.Len(); i++ {
				e := v.Index(i)
				fmt.Fprintf(p.w, "%s", ni)
				p.reprValue(e, ni)
				if p.indent != "" {
					fmt.Fprintf(p.w, ",\n")
				} else if i < v.Len()-1 {
					fmt.Fprintf(p.w, ", ")
				}
			}
			fmt.Fprintf(p.w, "%s}", in)
		}
	case reflect.Chan:
		fmt.Fprintf(p.w, "make(")
		fmt.Fprintf(p.w, "%s", v.Type())
		fmt.Fprintf(p.w, ", %d)", v.Cap())
	case reflect.Map:
		fmt.Fprintf(p.w, "%s{", v.Type())
		if p.indent != "" && v.Len() != 0 {
			fmt.Fprintf(p.w, "\n")
		}
		for i, k := range v.MapKeys() {
			kv := v.MapIndex(k)
			fmt.Fprintf(p.w, "%s", ni)
			p.reprValue(k, ni)
			fmt.Fprintf(p.w, ": ")
			p.reprValue(kv, ni)
			if p.indent != "" {
				fmt.Fprintf(p.w, ",\n")
			} else if i < v.Len()-1 {
				fmt.Fprintf(p.w, ", ")
			}
		}
		fmt.Fprintf(p.w, "%s}", in)
	case reflect.Struct:
		fmt.Fprintf(p.w, "%s{", v.Type())
		if p.indent != "" && v.NumField() != 0 {
			fmt.Fprintf(p.w, "\n")
		}
		for i := 0; i < v.NumField(); i++ {
			t := v.Type().Field(i)
			f := v.Field(i)
			if p.omitEmpty && isZero(f) {
				continue
			}
			fmt.Fprintf(p.w, "%s%s: ", ni, t.Name)
			p.reprValue(f, ni)
			if p.indent != "" {
				fmt.Fprintf(p.w, ",\n")
			} else if i < v.NumField()-1 {
				fmt.Fprintf(p.w, ", ")
			}
		}
		fmt.Fprintf(p.w, "%s}", indent)
	case reflect.Ptr:
		if v.IsNil() {
			fmt.Fprintf(p.w, "nil")
			return
		}
		fmt.Fprintf(p.w, "&")
		p.reprValue(v.Elem(), indent)
	case reflect.String:
		t := v.Type()
		if t.Name() != "string" {
			fmt.Fprintf(p.w, "%s(%q)", t, v.String())
		} else {
			fmt.Fprintf(p.w, "%q", v.String())
		}
	case reflect.Interface:
		if v.IsNil() {
			fmt.Fprintf(p.w, "interface {}(nil)")
		} else {
			p.reprValue(v.Elem(), indent)
		}
	default:
		t := v.Type()
		if t.Name() != realKindName[t.Kind()] {
			fmt.Fprintf(p.w, "%s(%v)", t, v)
		} else {
			fmt.Fprintf(p.w, "%v", v)
		}
	}
}

// String returns a string representing v.
func String(v interface{}, options ...Option) string {
	w := bytes.NewBuffer(nil)
	options = append([]Option{NoIndent()}, options...)
	p := New(w, options...)
	p.Print(v)
	return w.String()
}

// Print v to os.Stdout, one per line.
func Println(v ...interface{}) {
	New(os.Stdout).Println(v...)
}

// Print writes a representation of v to os.Stdout, separated by spaces.
func Print(v ...interface{}) {
	New(os.Stdout).Print(v...)
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		return v.IsNil()
	}
	return false
}
<|endoftext|>


<commit_before>/**
 *  queue reference implementation, using redis
 */
package ri

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/quexer/tok"
	"time"
)

func createPool(server, auth string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if auth != "" {
				if _, err := c.Do("AUTH", auth); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
	}
}

func qname(uid interface{}) string {
	return fmt.Sprintf("q%v", uid)
}

type queue struct {
	pool *redis.Pool
}

func (p *queue) Len(uid interface{}) (int, error) {
	c := p.pool.Get()
	defer c.Close()

	name := qname(uid)

	i, err := redis.Int(c.Do("LLEN", name))

	if err != nil && err.Error() == "redigo: nil returned" {
		//expire
		return 0, nil
	}

	return i, err
}

func (p *queue) Enq(uid interface{}, data []byte, ttl ...uint32) error {
	c := p.pool.Get()
	defer c.Close()

	name := qname(uid)
	c.Send("MULTI")
	c.Send("RPUSH", name, data)
	if len(ttl) > 0 && ttl[0] > 0 {
		c.Send("EXPIRE", name, ttl[0])
	}
	_, err := c.Do("EXEC")

	//	log.Println("enq", r)
	return err
}

func (p *queue) Deq(uid interface{}) ([]byte, error) {
	c := p.pool.Get()
	defer c.Close()

	name := qname(uid)
	c.Send("MULTI")
	c.Send("LPOP", name)
	r, err := redis.Values(c.Do("EXEC"))

	if err != nil && err != redis.ErrNil {
		return nil, err
	}
	b, err := redis.Bytes(r[0], err)
	if err != nil && err != redis.ErrNil {
		return nil, err
	}

	return b, nil
}

func CreateRedisQ(server, auth string) tok.Queue {
	pool := createPool(server, auth)
	return &queue{pool: pool}
}
<commit_msg>rollback: [redis] disable ping<commit_after>/**
 *  queue reference implementation, using redis
 */
package ri

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/quexer/tok"
	"time"
)

func createPool(server, auth string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if auth != "" {
				if _, err := c.Do("AUTH", auth); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func qname(uid interface{}) string {
	return fmt.Sprintf("q%v", uid)
}

type queue struct {
	pool *redis.Pool
}

func (p *queue) Len(uid interface{}) (int, error) {
	c := p.pool.Get()
	defer c.Close()

	name := qname(uid)

	i, err := redis.Int(c.Do("LLEN", name))

	if err != nil && err.Error() == "redigo: nil returned" {
		//expire
		return 0, nil
	}

	return i, err
}

func (p *queue) Enq(uid interface{}, data []byte, ttl ...uint32) error {
	c := p.pool.Get()
	defer c.Close()

	name := qname(uid)
	c.Send("MULTI")
	c.Send("RPUSH", name, data)
	if len(ttl) > 0 && ttl[0] > 0 {
		c.Send("EXPIRE", name, ttl[0])
	}
	_, err := c.Do("EXEC")

	//	log.Println("enq", r)
	return err
}

func (p *queue) Deq(uid interface{}) ([]byte, error) {
	c := p.pool.Get()
	defer c.Close()

	name := qname(uid)
	c.Send("MULTI")
	c.Send("LPOP", name)
	r, err := redis.Values(c.Do("EXEC"))

	if err != nil && err != redis.ErrNil {
		return nil, err
	}
	b, err := redis.Bytes(r[0], err)
	if err != nil && err != redis.ErrNil {
		return nil, err
	}

	return b, nil
}

func CreateRedisQ(server, auth string) tok.Queue {
	pool := createPool(server, auth)
	return &queue{pool: pool}
}
<|endoftext|>


<commit_before>package glfw

/*
// Windows Build Tags
// ----------------
// GLFW Options:
#cgo windows CFLAGS: -D_GLFW_WIN32 -Iglfw/deps/mingw

// Linker Options:
#cgo windows LDFLAGS: -lgdi32

#cgo !gles2,windows LDFLAGS: -lopengl32
#cgo gles2,windows LDFLAGS: -lGLESv2

// Darwin Build Tags
// ----------------
// GLFW Options:
#cgo darwin CFLAGS: -D_GLFW_COCOA -Wno-deprecated-declarations

// Linker Options:
#cgo darwin LDFLAGS: -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo

// Linux Build Tags
// ----------------
// GLFW Options:
#cgo linux,!wayland CFLAGS: -D_GLFW_X11 -D_GNU_SOURCE
#cgo linux,wayland CFLAGS: -D_GLFW_WAYLAND -D_GNU_SOURCE

// Linker Options:
#cgo linux,!gles1,!gles2,!gles3,!vulkan LDFLAGS: -lGL
#cgo linux,gles1 LDFLAGS: -lGLESv1
#cgo linux,gles2 LDFLAGS: -lGLESv2
#cgo linux,gles3 LDFLAGS: -lGLESv3
#cgo linux,vulkan LDFLAGS: -lvulkan
#cgo linux,!wayland LDFLAGS: -lX11 -lXrandr -lXxf86vm -lXi -lXcursor -lm -lXinerama -ldl -lrt
#cgo linux,wayland LDFLAGS: -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon -lm -ldl -lrt

// FreeBSD Build Tags
// ----------------
// GLFW Options:
#cgo freebsd pkg-config: glfw3
#cgo freebsd CFLAGS: -D_GLFW_HAS_DLOPEN
#cgo freebsd,!wayland CFLAGS: -D_GLFW_X11 -D_GLFW_HAS_GLXGETPROCADDRESSARB
#cgo freebsd,wayland CFLAGS: -D_GLFW_WAYLAND

// Linker Options:
#cgo freebsd,!wayland LDFLAGS: -lm -lGL -lX11 -lXrandr -lXxf86vm -lXi -lXcursor -lXinerama
#cgo freebsd,wayland LDFLAGS: -lm -lGL -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon
*/
import "C"
<commit_msg>Support using GLFW with ANGLE (OpenGLES 2) on macOS<commit_after>package glfw

/*
// Windows Build Tags
// ----------------
// GLFW Options:
#cgo windows CFLAGS: -D_GLFW_WIN32 -Iglfw/deps/mingw

// Linker Options:
#cgo windows LDFLAGS: -lgdi32

#cgo !gles2,windows LDFLAGS: -lopengl32
#cgo gles2,windows LDFLAGS: -lGLESv2

// Darwin Build Tags
// ----------------
// GLFW Options:
#cgo darwin CFLAGS: -D_GLFW_COCOA -Wno-deprecated-declarations

// Linker Options:
#cgo darwin LDFLAGS: -framework Cocoa -framework IOKit -framework CoreVideo

#cgo !gles2,darwin LDFLAGS: -framework OpenGL
#cgo gles2,darwin LDFLAGS: -lGLESv2

// Linux Build Tags
// ----------------
// GLFW Options:
#cgo linux,!wayland CFLAGS: -D_GLFW_X11 -D_GNU_SOURCE
#cgo linux,wayland CFLAGS: -D_GLFW_WAYLAND -D_GNU_SOURCE

// Linker Options:
#cgo linux,!gles1,!gles2,!gles3,!vulkan LDFLAGS: -lGL
#cgo linux,gles1 LDFLAGS: -lGLESv1
#cgo linux,gles2 LDFLAGS: -lGLESv2
#cgo linux,gles3 LDFLAGS: -lGLESv3
#cgo linux,vulkan LDFLAGS: -lvulkan
#cgo linux,!wayland LDFLAGS: -lX11 -lXrandr -lXxf86vm -lXi -lXcursor -lm -lXinerama -ldl -lrt
#cgo linux,wayland LDFLAGS: -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon -lm -ldl -lrt

// FreeBSD Build Tags
// ----------------
// GLFW Options:
#cgo freebsd pkg-config: glfw3
#cgo freebsd CFLAGS: -D_GLFW_HAS_DLOPEN
#cgo freebsd,!wayland CFLAGS: -D_GLFW_X11 -D_GLFW_HAS_GLXGETPROCADDRESSARB
#cgo freebsd,wayland CFLAGS: -D_GLFW_WAYLAND

// Linker Options:
#cgo freebsd,!wayland LDFLAGS: -lm -lGL -lX11 -lXrandr -lXxf86vm -lXi -lXcursor -lXinerama
#cgo freebsd,wayland LDFLAGS: -lm -lGL -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon
*/
import "C"
<|endoftext|>


<commit_before>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     September 28, 2022
;       related version of root zone:     2022092801
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<commit_msg>Automatic update for Sat Oct  8 08:20:42 UTC 2022<commit_after>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     October 07, 2022
;       related version of root zone:     2022100702
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<|endoftext|>


<commit_before>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     November 17, 2021
;       related version of root zone:     2021111701
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<commit_msg>Automatic update for Tue Nov 23 08:19:45 UTC 2021<commit_after>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     November 22, 2021
;       related version of root zone:     2021112201
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<|endoftext|>


<commit_before>/*

Package rpio provides GPIO access on the Raspberry PI without any need
for external c libraries (ex: WiringPI or BCM2835).

Supports simple operations such as:
- Pin mode/direction (input/output)
- Pin write (high/low)
- Pin read (high/low)
- Pull up/down/off

Example of use:

	rpio.Open()
	defer rpio.Close()

	pin := rpio.Pin(4)
	pin.Output()

	for {
		pin.Toggle()
		time.Sleep(time.Second)
	}

The library use the raw BCM2835 pinouts, not the ports as they are mapped
on the output pins for the raspberry pi

   Rev 1 Raspberry Pi
+------+------+--------+
| GPIO | Phys | Name   |
+------+------+--------+
|   0  |   3  | SDA    |
|   1  |   5  | SCL    |
|   4  |   7  | GPIO 7 |
|   7  |  26  | CE1    |
|   8  |  24  | CE0    |
|   9  |  21  | MISO   |
|  10  |  19  | MOSI   |
|  11  |  23  | SCLK   |
|  14  |   8  | TxD    |
|  15  |  10  | RxD    |
|  17  |  11  | GPIO 0 |
|  18  |  12  | GPIO 1 |
|  21  |  13  | GPIO 2 |
|  22  |  15  | GPIO 3 |
|  23  |  16  | GPIO 4 |
|  24  |  18  | GPIO 5 |
|  25  |  22  | GPIO 6 |
+------+------+--------+

See the spec for full details of the BCM2835 controller:
http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

*/

package rpio

import (
	"os"
	"reflect"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

type Direction uint8
type Pin uint8
type State uint8
type Pull uint8

// Memory offsets for gpio, see the spec for more details
const (
	bcm2835Base = 0x20000000
	gpioBase    = bcm2835Base + 0x200000
	memLength   = 4096

	pinMask uint32 = 7 // 0b111 - pinmode is 3 bits
)

// Pin direction, a pin can be set in Input or Output mode
const (
	Input Direction = iota
	Output
)

// State of pin, High / Low
const (
	Low State = iota
	High
)

// Pull Up / Down / Off
const (
	PullOff Pull = iota
	PullDown
	PullUp
)

// Arrays for 8 / 32 bit access to memory and a semaphore for write locking
var (
	memlock sync.Mutex
	mem     []uint32
	mem8    []uint8
)

// Set pin as Input
func (pin Pin) Input() {
	PinMode(pin, Input)
}

// Set pin as Output
func (pin Pin) Output() {
	PinMode(pin, Output)
}

// Set pin High
func (pin Pin) High() {
	WritePin(pin, High)
}

// Set pin Low
func (pin Pin) Low() {
	WritePin(pin, Low)
}

// Toggle pin state
func (pin Pin) Toggle() {
	TogglePin(pin)
}

// Set pin Direction
func (pin Pin) Mode(dir Direction) {
	PinMode(pin, dir)
}

// Set pin state (high/low)
func (pin Pin) Write(state State) {
	WritePin(pin, state)
}

// Read pin state (high/low)
func (pin Pin) Read() State {
	return ReadPin(pin)
}

// Set a given pull up/down mode
func (pin Pin) Pull(pull Pull) {
	PullMode(pin, pull)
}

// Pull up pin
func (pin Pin) PullUp() {
	PullMode(pin, PullUp)
}

// Pull down pin
func (pin Pin) PullDown() {
	PullMode(pin, PullDown)
}

// Disable pullup/down on pin
func (pin Pin) PullOff() {
	PullMode(pin, PullOff)
}

// PinMode sets the direction of a given pin (Input or Output)
func PinMode(pin Pin, direction Direction) {

	// Pin fsel register, 0 or 1 depending on bank
	fsel := uint8(pin) / 10
	shift := (uint8(pin) % 10) * 3

	memlock.Lock()
	defer memlock.Unlock()

	if direction == Input {
		mem[fsel] = mem[fsel] &^ (pinMask << shift)
	} else {
		mem[fsel] = (mem[fsel] &^ (pinMask << shift)) | (1 << shift)
	}

}

// WritePin sets a given pin High or Low
// by setting the clear or set registers respectively
func WritePin(pin Pin, state State) {

	p := uint8(pin)

	// Clear register, 10 / 11 depending on bank
	// Set register, 7 / 8 depending on bank
	clearReg := p/32 + 10
	setReg := p/32 + 7

	memlock.Lock()
	defer memlock.Unlock()

	if state == Low {
		mem[clearReg] = 1 << (p & 31)
	} else {
		mem[setReg] = 1 << (p & 31)
	}

}

// Read the state of a pin
func ReadPin(pin Pin) State {
	// Input level register offset (13 / 14 depending on bank)
	levelReg := uint8(pin)/32 + 13

	if (mem[levelReg] & (1 << uint8(pin))) != 0 {
		return High
	}

	return Low
}

// Toggle a pin state (high -> low -> high)
// TODO: probably possible to do this much faster without read
func TogglePin(pin Pin) {
	switch ReadPin(pin) {
	case Low:
		pin.High()
	case High:
		pin.Low()
	}
}

func PullMode(pin Pin, pull Pull) {
	// Pull up/down/off register has offset 38 / 39, pull is 37
	pullClkReg := uint8(pin)/32 + 38
	pullReg := 37
	shift := (uint8(pin) % 32)

	memlock.Lock()
	defer memlock.Unlock()

	switch pull {
	case PullDown, PullUp:
		mem[pullReg] = mem[pullReg]&^3 | uint32(pull)
	case PullOff:
		mem[pullReg] = mem[pullReg] &^ 3
	}

	// Wait for value to clock in, this is ugly, sorry :(
	time.Sleep(time.Microsecond)

	mem[pullClkReg] = 1 << shift

	// Wait for value to clock in
	time.Sleep(time.Microsecond)

	mem[pullReg] = mem[pullReg] &^ 3
	mem[pullClkReg] = 0

}

// Open and memory map GPIO memory range from /dev/mem .
// Some reflection magic is used to convert it to a unsafe []uint32 pointer
func Open() (err error) {
	var file *os.File

	// Open fd for rw mem access
	file, err = os.OpenFile(
		"/dev/mem",
		os.O_RDWR|os.O_SYNC,
		0)

	if err != nil {
		return
	}

	// FD can be closed after memory mapping
	defer file.Close()

	memlock.Lock()
	defer memlock.Unlock()

	// Memory map GPIO registers to byte array
	mem8, err = syscall.Mmap(
		int(file.Fd()),
		gpioBase,
		memLength,
		syscall.PROT_READ|syscall.PROT_WRITE,
		syscall.MAP_SHARED)

	if err != nil {
		return
	}

	// Convert mapped byte memory to unsafe []uint32 pointer, adjust length as needed
	header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem8))
	header.Len /= (32 / 8) // (32 bit = 4 bytes)
	header.Cap /= (32 / 8)

	mem = *(*[]uint32)(unsafe.Pointer(&header))

	return nil
}

// Close unmaps GPIO memory
func Close() error {
	memlock.Lock()
	defer memlock.Unlock()
	return syscall.Munmap(mem8)
}
<commit_msg>Support the new IO port range for raspberry pi 2.<commit_after>/*

Package rpio provides GPIO access on the Raspberry PI without any need
for external c libraries (ex: WiringPI or BCM2835).

Supports simple operations such as:
- Pin mode/direction (input/output)
- Pin write (high/low)
- Pin read (high/low)
- Pull up/down/off

Example of use:

	rpio.Open()
	defer rpio.Close()

	pin := rpio.Pin(4)
	pin.Output()

	for {
		pin.Toggle()
		time.Sleep(time.Second)
	}

The library use the raw BCM2835 pinouts, not the ports as they are mapped
on the output pins for the raspberry pi

   Rev 1 Raspberry Pi
+------+------+--------+
| GPIO | Phys | Name   |
+------+------+--------+
|   0  |   3  | SDA    |
|   1  |   5  | SCL    |
|   4  |   7  | GPIO 7 |
|   7  |  26  | CE1    |
|   8  |  24  | CE0    |
|   9  |  21  | MISO   |
|  10  |  19  | MOSI   |
|  11  |  23  | SCLK   |
|  14  |   8  | TxD    |
|  15  |  10  | RxD    |
|  17  |  11  | GPIO 0 |
|  18  |  12  | GPIO 1 |
|  21  |  13  | GPIO 2 |
|  22  |  15  | GPIO 3 |
|  23  |  16  | GPIO 4 |
|  24  |  18  | GPIO 5 |
|  25  |  22  | GPIO 6 |
+------+------+--------+

See the spec for full details of the BCM2835 controller:
http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

*/

package rpio

import (
	"bytes"
	"io/ioutil"
	"os"
	"reflect"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

type Direction uint8
type Pin uint8
type State uint8
type Pull uint8

// Memory offsets for gpio, see the spec for more details
const (
	bcm2835Base = 0x20000000
	pi1GPIOBase = bcm2835Base + 0x200000
	memLength   = 4096

	bcm2836Base = 0x3f000000
	pi2GPIOBase = bcm2836Base + 0x200000

	pinMask uint32 = 7 // 0b111 - pinmode is 3 bits
)

// Pin direction, a pin can be set in Input or Output mode
const (
	Input Direction = iota
	Output
)

// State of pin, High / Low
const (
	Low State = iota
	High
)

// Pull Up / Down / Off
const (
	PullOff Pull = iota
	PullDown
	PullUp
)

// Arrays for 8 / 32 bit access to memory and a semaphore for write locking
var (
	memlock sync.Mutex
	mem     []uint32
	mem8    []uint8
)

// Set pin as Input
func (pin Pin) Input() {
	PinMode(pin, Input)
}

// Set pin as Output
func (pin Pin) Output() {
	PinMode(pin, Output)
}

// Set pin High
func (pin Pin) High() {
	WritePin(pin, High)
}

// Set pin Low
func (pin Pin) Low() {
	WritePin(pin, Low)
}

// Toggle pin state
func (pin Pin) Toggle() {
	TogglePin(pin)
}

// Set pin Direction
func (pin Pin) Mode(dir Direction) {
	PinMode(pin, dir)
}

// Set pin state (high/low)
func (pin Pin) Write(state State) {
	WritePin(pin, state)
}

// Read pin state (high/low)
func (pin Pin) Read() State {
	return ReadPin(pin)
}

// Set a given pull up/down mode
func (pin Pin) Pull(pull Pull) {
	PullMode(pin, pull)
}

// Pull up pin
func (pin Pin) PullUp() {
	PullMode(pin, PullUp)
}

// Pull down pin
func (pin Pin) PullDown() {
	PullMode(pin, PullDown)
}

// Disable pullup/down on pin
func (pin Pin) PullOff() {
	PullMode(pin, PullOff)
}

// PinMode sets the direction of a given pin (Input or Output)
func PinMode(pin Pin, direction Direction) {

	// Pin fsel register, 0 or 1 depending on bank
	fsel := uint8(pin) / 10
	shift := (uint8(pin) % 10) * 3

	memlock.Lock()
	defer memlock.Unlock()

	if direction == Input {
		mem[fsel] = mem[fsel] &^ (pinMask << shift)
	} else {
		mem[fsel] = (mem[fsel] &^ (pinMask << shift)) | (1 << shift)
	}

}

// WritePin sets a given pin High or Low
// by setting the clear or set registers respectively
func WritePin(pin Pin, state State) {

	p := uint8(pin)

	// Clear register, 10 / 11 depending on bank
	// Set register, 7 / 8 depending on bank
	clearReg := p/32 + 10
	setReg := p/32 + 7

	memlock.Lock()
	defer memlock.Unlock()

	if state == Low {
		mem[clearReg] = 1 << (p & 31)
	} else {
		mem[setReg] = 1 << (p & 31)
	}

}

// Read the state of a pin
func ReadPin(pin Pin) State {
	// Input level register offset (13 / 14 depending on bank)
	levelReg := uint8(pin)/32 + 13

	if (mem[levelReg] & (1 << uint8(pin))) != 0 {
		return High
	}

	return Low
}

// Toggle a pin state (high -> low -> high)
// TODO: probably possible to do this much faster without read
func TogglePin(pin Pin) {
	switch ReadPin(pin) {
	case Low:
		pin.High()
	case High:
		pin.Low()
	}
}

func PullMode(pin Pin, pull Pull) {
	// Pull up/down/off register has offset 38 / 39, pull is 37
	pullClkReg := uint8(pin)/32 + 38
	pullReg := 37
	shift := (uint8(pin) % 32)

	memlock.Lock()
	defer memlock.Unlock()

	switch pull {
	case PullDown, PullUp:
		mem[pullReg] = mem[pullReg]&^3 | uint32(pull)
	case PullOff:
		mem[pullReg] = mem[pullReg] &^ 3
	}

	// Wait for value to clock in, this is ugly, sorry :(
	time.Sleep(time.Microsecond)

	mem[pullClkReg] = 1 << shift

	// Wait for value to clock in
	time.Sleep(time.Microsecond)

	mem[pullReg] = mem[pullReg] &^ 3
	mem[pullClkReg] = 0

}

// Open and memory map GPIO memory range from /dev/mem .
// Some reflection magic is used to convert it to a unsafe []uint32 pointer
func Open() (err error) {
	var file *os.File

	// Open fd for rw mem access
	file, err = os.OpenFile(
		"/dev/mem",
		os.O_RDWR|os.O_SYNC,
		0)

	if err != nil {
		return
	}

	// FD can be closed after memory mapping
	defer file.Close()

	memlock.Lock()
	defer memlock.Unlock()

	GPIOBase := int64(pi1GPIOBase)
	if detectPiVersion() == 2 {
		GPIOBase = pi2GPIOBase
	}

	// Memory map GPIO registers to byte array
	mem8, err = syscall.Mmap(
		int(file.Fd()),
		GPIOBase,
		memLength,
		syscall.PROT_READ|syscall.PROT_WRITE,
		syscall.MAP_SHARED)

	if err != nil {
		return
	}

	// Convert mapped byte memory to unsafe []uint32 pointer, adjust length as needed
	header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem8))
	header.Len /= (32 / 8) // (32 bit = 4 bytes)
	header.Cap /= (32 / 8)

	mem = *(*[]uint32)(unsafe.Pointer(&header))

	return nil
}

// Close unmaps GPIO memory
func Close() error {
	memlock.Lock()
	defer memlock.Unlock()
	return syscall.Munmap(mem8)
}

// Read /proc/cpuinfo and detect whether we're running on an RPI1 or RPI2.
// Returns 1 or 2 depending on platform.
func detectPiVersion() int {
	cpuinfo, err := os.Open("/proc/cpuinfo")
	if err != nil {
		panic(err)
	}
	data, err := ioutil.ReadAll(cpuinfo)
	if err != nil {
		panic(err)
	}
	if bytes.Contains(data, []byte("BCM2709")) {
		return 2
	} else {
		return 1
	}
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package utils

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/loggo/loggo"

	"launchpad.net/juju-core/juju/osenv"
)

var (
	aptLogger  = loggo.GetLogger("juju.utils.apt")
	aptProxyRE = regexp.MustCompile(`(?im)^\s*Acquire::(?P<protocol>[a-z]+)::Proxy\s+"(?P<proxy>[^"]+)";\s*$`)

	// AptConfFile is the full file path for the proxy settings that are
	// written by cloud-init and the machine environ worker.
	AptConfFile = "/etc/apt/apt.conf.d/42-juju-proxy-settings"
)

// Some helpful functions for running apt in a sane way

// AptCommandOutput calls cmd.Output, this is used as an overloading point so we
// can test what *would* be run without actually executing another program
var AptCommandOutput = (*exec.Cmd).CombinedOutput

// This is the default apt-get command used in cloud-init, the various settings
// mean that apt won't actually block waiting for a prompt from the user.
var aptGetCommand = []string{
	"apt-get", "--option=Dpkg::Options::=--force-confold",
	"--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet",
}

// aptEnvOptions are options we need to pass to apt-get to not have it prompt
// the user
var aptGetEnvOptions = []string{"DEBIAN_FRONTEND=noninteractive"}

// AptGetInstall runs 'apt-get install packages' for the packages listed here
func AptGetInstall(packages ...string) error {
	cmdArgs := append([]string(nil), aptGetCommand...)
	cmdArgs = append(cmdArgs, "install")
	cmdArgs = append(cmdArgs, packages...)
	aptLogger.Infof("Running: %s", cmdArgs)
	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
	cmd.Env = append(os.Environ(), aptGetEnvOptions...)
	out, err := AptCommandOutput(cmd)
	if err != nil {
		aptLogger.Errorf("apt-get command failed: %v\nargs: %#v\n%s",
			err, cmdArgs, string(out))
		return fmt.Errorf("apt-get failed: %v", err)
	}
	return nil
}

// AptConfigProxy will consult apt-config about the configured proxy
// settings. If there are no proxy settings configured, an empty string is
// returned.
func AptConfigProxy() (string, error) {
	cmdArgs := []string{
		"apt-config",
		"dump",
		"Acquire::http::Proxy",
		"Acquire::https::Proxy",
		"Acquire::ftp::Proxy",
	}
	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
	out, err := AptCommandOutput(cmd)
	if err != nil {
		aptLogger.Errorf("apt-config command failed: %v\nargs: %#v\n%s",
			err, cmdArgs, string(out))
		return "", fmt.Errorf("apt-config failed: %v", err)
	}
	return string(bytes.Join(aptProxyRE.FindAll(out, -1), []byte("\n"))), nil
}

// DetectAptProxies will parse the results of AptConfigProxy to return a
// ProxySettings instance.
func DetectAptProxies() (result osenv.ProxySettings, err error) {
	output, err := AptConfigProxy()
	if err != nil {
		return result, err
	}
	for _, match := range aptProxyRE.FindAllStringSubmatch(output, -1) {
		switch match[1] {
		case "http":
			result.Http = match[2]
		case "https":
			result.Https = match[2]
		case "ftp":
			result.Ftp = match[2]
		}
	}
	return result, nil
}

// AptProxyContent produces the format expected by the apt config files
// from the ProxySettings struct.
func AptProxyContent(proxy osenv.ProxySettings) string {
	lines := []string{}
	addLine := func(proxy, value string) {
		if value != "" {
			lines = append(lines, fmt.Sprintf(
				"Acquire::%s::Proxy %q;", proxy, value))
		}
	}
	addLine("http", proxy.Http)
	addLine("https", proxy.Https)
	addLine("ftp", proxy.Ftp)
	return strings.Join(lines, "\n")
}

// IsUbuntu executes lxb_release to see if the host OS is Ubuntu.
func IsUbuntu() bool {
	out, err := RunCommand("lsb_release", "-i", "-s")
	if err != nil {
		return false
	}
	return strings.TrimSpace(out) == "Ubuntu"
}

// IsPackageInstalled uses dpkg-query to determine if the `packageName`
// package is installed.
func IsPackageInstalled(packageName string) bool {
	_, err := RunCommand("dpkg-query", "--status", packageName)
	return err == nil
}
<commit_msg>initial changes to support juju's special copy of mongod<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package utils

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/loggo/loggo"

	"launchpad.net/juju-core/juju/osenv"
)

var (
	aptLogger  = loggo.GetLogger("juju.utils.apt")
	aptProxyRE = regexp.MustCompile(`(?im)^\s*Acquire::(?P<protocol>[a-z]+)::Proxy\s+"(?P<proxy>[^"]+)";\s*$`)

	// AptConfFile is the full file path for the proxy settings that are
	// written by cloud-init and the machine environ worker.
	AptConfFile = "/etc/apt/apt.conf.d/42-juju-proxy-settings"
)

// Some helpful functions for running apt in a sane way

// AptCommandOutput calls cmd.Output, this is used as an overloading point so we
// can test what *would* be run without actually executing another program
var AptCommandOutput = (*exec.Cmd).CombinedOutput

// This is the default apt-get command used in cloud-init, the various settings
// mean that apt won't actually block waiting for a prompt from the user.
var aptGetCommand = []string{
	"apt-get", "--option=Dpkg::Options::=--force-confold",
	"--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet",
}

// aptEnvOptions are options we need to pass to apt-get to not have it prompt
// the user
var aptGetEnvOptions = []string{"DEBIAN_FRONTEND=noninteractive"}

// AptGetInstall runs 'apt-get install packages' for the packages listed here
func AptGetInstall(packages ...string) error {
	cmdArgs := append([]string(nil), aptGetCommand...)
	cmdArgs = append(cmdArgs, "install")
	cmdArgs = append(cmdArgs, packages...)
	aptLogger.Infof("Running: %s", cmdArgs)
	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
	cmd.Env = append(os.Environ(), aptGetEnvOptions...)
	out, err := AptCommandOutput(cmd)
	if err != nil {
		aptLogger.Errorf("apt-get command failed: %v\nargs: %#v\n%s",
			err, cmdArgs, string(out))
		return fmt.Errorf("apt-get failed: %v", err)
	}
	return nil
}

// AptConfigProxy will consult apt-config about the configured proxy
// settings. If there are no proxy settings configured, an empty string is
// returned.
func AptConfigProxy() (string, error) {
	cmdArgs := []string{
		"apt-config",
		"dump",
		"Acquire::http::Proxy",
		"Acquire::https::Proxy",
		"Acquire::ftp::Proxy",
	}
	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
	out, err := AptCommandOutput(cmd)
	if err != nil {
		aptLogger.Errorf("apt-config command failed: %v\nargs: %#v\n%s",
			err, cmdArgs, string(out))
		return "", fmt.Errorf("apt-config failed: %v", err)
	}
	return string(bytes.Join(aptProxyRE.FindAll(out, -1), []byte("\n"))), nil
}

// DetectAptProxies will parse the results of AptConfigProxy to return a
// ProxySettings instance.
func DetectAptProxies() (result osenv.ProxySettings, err error) {
	output, err := AptConfigProxy()
	if err != nil {
		return result, err
	}
	for _, match := range aptProxyRE.FindAllStringSubmatch(output, -1) {
		switch match[1] {
		case "http":
			result.Http = match[2]
		case "https":
			result.Https = match[2]
		case "ftp":
			result.Ftp = match[2]
		}
	}
	return result, nil
}

// AptProxyContent produces the format expected by the apt config files
// from the ProxySettings struct.
func AptProxyContent(proxy osenv.ProxySettings) string {
	lines := []string{}
	addLine := func(proxy, value string) {
		if value != "" {
			lines = append(lines, fmt.Sprintf(
				"Acquire::%s::Proxy %q;", proxy, value))
		}
	}
	addLine("http", proxy.Http)
	addLine("https", proxy.Https)
	addLine("ftp", proxy.Ftp)
	return strings.Join(lines, "\n")
}

// IsUbuntu executes lxb_release to see if the host OS is Ubuntu.
func IsUbuntu() bool {
	out, err := RunCommand("lsb_release", "-i", "-s")
	if err != nil {
		return false
	}
	return strings.TrimSpace(out) == "Ubuntu"
}

// UbuntuRelease executes lsb_release to see if the host OS is Ubuntu.
func UbuntuRelease() (float, error) {
	if !IsUbuntu() {
		return 0, errors.New("not ubuntu")
	}
	out, err := RunCommand("lsb_release", "-r", "-s")
	if err != nil {
		return 0, err
	}
	release, err := strconv.ParseFloat(out, 10)
	if err != nil {
		return 0, err
	}
	return release, nil
}

// IsPackageInstalled uses dpkg-query to determine if the `packageName`
// package is installed.
func IsPackageInstalled(packageName string) bool {
	_, err := RunCommand("dpkg-query", "--status", packageName)
	return err == nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

import (
	"bytes"
	"fmt"
	"io"
)

type Prog struct {
	Stmts []Node
}

func (p Prog) String() string {
	return nodeJoin(p.Stmts, "; ")
}

type Node interface {
	fmt.Stringer
}

func nodeJoin(ns []Node, sep string) string {
	var b bytes.Buffer
	for i, n := range ns {
		if i > 0 {
			io.WriteString(&b, sep)
		}
		io.WriteString(&b, n.String())
	}
	return b.String()
}

func stmtJoin(ns []Node) string {
	return nodeJoin(ns, "; ")
}

type Command struct {
	Args []Node

	Background bool
}

func (c Command) String() string {
	nodes := make([]Node, 0, len(c.Args))
	for _, l := range c.Args {
		nodes = append(nodes, l)
	}
	suffix := ""
	if c.Background {
		suffix += " &"
	}
	return nodeJoin(nodes, " ") + suffix
}

type Redirect struct {
	Op  Token
	Obj Node
}

func (r Redirect) String() string {
	return r.Op.String() + r.Obj.String()
}

type Subshell struct {
	Stmts []Node
}

func (s Subshell) String() string {
	return "( " + stmtJoin(s.Stmts) + "; )"
}

type Block struct {
	Stmts []Node
}

func (b Block) String() string {
	return "{ " + stmtJoin(b.Stmts) + "; }"
}

type IfStmt struct {
	Cond      Node
	ThenStmts []Node
	Elifs     []Node
	ElseStmts []Node
}

func (s IfStmt) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "if ")
	io.WriteString(&b, s.Cond.String())
	io.WriteString(&b, "; then ")
	io.WriteString(&b, stmtJoin(s.ThenStmts))
	for _, n := range s.Elifs {
		e := n.(Elif)
		io.WriteString(&b, "; ")
		io.WriteString(&b, e.String())
	}
	if len(s.ElseStmts) > 0 {
		io.WriteString(&b, "; else ")
		io.WriteString(&b, stmtJoin(s.ElseStmts))
	}
	io.WriteString(&b, "; fi")
	return b.String()
}

type Elif struct {
	Cond      Node
	ThenStmts []Node
}

func (e Elif) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "elif ")
	io.WriteString(&b, e.Cond.String())
	io.WriteString(&b, "; then ")
	io.WriteString(&b, stmtJoin(e.ThenStmts))
	return b.String()
}

type WhileStmt struct {
	Cond    Node
	DoStmts []Node
}

func (w WhileStmt) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "while ")
	io.WriteString(&b, w.Cond.String())
	io.WriteString(&b, "; do ")
	io.WriteString(&b, stmtJoin(w.DoStmts))
	io.WriteString(&b, "; done")
	return b.String()
}

type ForStmt struct {
	Name     Node
	WordList []Node
	DoStmts  []Node
}

func (w ForStmt) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "for ")
	io.WriteString(&b, w.Name.String())
	io.WriteString(&b, " in ")
	io.WriteString(&b, nodeJoin(w.WordList, " "))
	io.WriteString(&b, "; do ")
	io.WriteString(&b, stmtJoin(w.DoStmts))
	io.WriteString(&b, "; done")
	return b.String()
}

type BinaryExpr struct {
	X, Y Node
	Op   Token
}

func (b BinaryExpr) String() string {
	return fmt.Sprintf("%s %s %s", b.X, b.Op, b.Y)
}

type Comment struct {
	Text string
}

func (c Comment) String() string {
	return "#" + c.Text
}

type FuncDecl struct {
	Name Lit
	Body Node
}

func (f FuncDecl) String() string {
	return fmt.Sprintf("%s() %s", f.Name, f.Body)
}

type Word struct {
	Parts []Node
}

func (w Word) String() string {
	return nodeJoin(w.Parts, "")
}

type Lit struct {
	Val string
}

func (l Lit) String() string {
	return l.Val
}
<commit_msg>Replace nodeJoin(x, " ") with wordJoin(x)<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

import (
	"bytes"
	"fmt"
	"io"
)

type Prog struct {
	Stmts []Node
}

func (p Prog) String() string {
	return nodeJoin(p.Stmts, "; ")
}

type Node interface {
	fmt.Stringer
}

func nodeJoin(ns []Node, sep string) string {
	var b bytes.Buffer
	for i, n := range ns {
		if i > 0 {
			io.WriteString(&b, sep)
		}
		io.WriteString(&b, n.String())
	}
	return b.String()
}

func stmtJoin(ns []Node) string {
	return nodeJoin(ns, "; ")
}

func wordJoin(ns []Node) string {
	return nodeJoin(ns, " ")
}

type Command struct {
	Args []Node

	Background bool
}

func (c Command) String() string {
	nodes := make([]Node, 0, len(c.Args))
	for _, l := range c.Args {
		nodes = append(nodes, l)
	}
	suffix := ""
	if c.Background {
		suffix += " &"
	}
	return wordJoin(nodes) + suffix
}

type Redirect struct {
	Op  Token
	Obj Node
}

func (r Redirect) String() string {
	return r.Op.String() + r.Obj.String()
}

type Subshell struct {
	Stmts []Node
}

func (s Subshell) String() string {
	return "( " + stmtJoin(s.Stmts) + "; )"
}

type Block struct {
	Stmts []Node
}

func (b Block) String() string {
	return "{ " + stmtJoin(b.Stmts) + "; }"
}

type IfStmt struct {
	Cond      Node
	ThenStmts []Node
	Elifs     []Node
	ElseStmts []Node
}

func (s IfStmt) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "if ")
	io.WriteString(&b, s.Cond.String())
	io.WriteString(&b, "; then ")
	io.WriteString(&b, stmtJoin(s.ThenStmts))
	for _, n := range s.Elifs {
		e := n.(Elif)
		io.WriteString(&b, "; ")
		io.WriteString(&b, e.String())
	}
	if len(s.ElseStmts) > 0 {
		io.WriteString(&b, "; else ")
		io.WriteString(&b, stmtJoin(s.ElseStmts))
	}
	io.WriteString(&b, "; fi")
	return b.String()
}

type Elif struct {
	Cond      Node
	ThenStmts []Node
}

func (e Elif) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "elif ")
	io.WriteString(&b, e.Cond.String())
	io.WriteString(&b, "; then ")
	io.WriteString(&b, stmtJoin(e.ThenStmts))
	return b.String()
}

type WhileStmt struct {
	Cond    Node
	DoStmts []Node
}

func (w WhileStmt) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "while ")
	io.WriteString(&b, w.Cond.String())
	io.WriteString(&b, "; do ")
	io.WriteString(&b, stmtJoin(w.DoStmts))
	io.WriteString(&b, "; done")
	return b.String()
}

type ForStmt struct {
	Name     Node
	WordList []Node
	DoStmts  []Node
}

func (w ForStmt) String() string {
	var b bytes.Buffer
	io.WriteString(&b, "for ")
	io.WriteString(&b, w.Name.String())
	io.WriteString(&b, " in ")
	io.WriteString(&b, wordJoin(w.WordList))
	io.WriteString(&b, "; do ")
	io.WriteString(&b, stmtJoin(w.DoStmts))
	io.WriteString(&b, "; done")
	return b.String()
}

type BinaryExpr struct {
	X, Y Node
	Op   Token
}

func (b BinaryExpr) String() string {
	return fmt.Sprintf("%s %s %s", b.X, b.Op, b.Y)
}

type Comment struct {
	Text string
}

func (c Comment) String() string {
	return "#" + c.Text
}

type FuncDecl struct {
	Name Lit
	Body Node
}

func (f FuncDecl) String() string {
	return fmt.Sprintf("%s() %s", f.Name, f.Body)
}

type Word struct {
	Parts []Node
}

func (w Word) String() string {
	return nodeJoin(w.Parts, "")
}

type Lit struct {
	Val string
}

func (l Lit) String() string {
	return l.Val
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/taskcluster/httpbackoff"
	"github.com/taskcluster/taskcluster-client-go/awsprovisioner"
)

func queryUserData() (*UserData, error) {
	// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-user-data-retrieval
	resp, _, err := httpbackoff.Get("http://169.254.169.254/latest/user-data")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	userData := new(UserData)
	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(userData)
	return userData, err
}

func queryMetaData(url string) (string, error) {
	// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-data-retrieval
	// call http://169.254.169.254/latest/meta-data/instance-id with httpbackoff
	resp, _, err := httpbackoff.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	content, err := ioutil.ReadAll(resp.Body)
	return string(content), err
}

type UserData struct {
	Data                interface{} `json:"data"`
	Capacity            int         `json:"capacity"`
	WorkerType          string      `json:"workerType"`
	ProvisionerId       string      `json:"provisionerId"`
	Region              string      `json:"region"`
	InstanceType        string      `json:"instanceType"`
	LaunchSpecGenerated time.Time   `json:"launchSpecGenerated"`
	WorkerModified      time.Time   `json:"workerModified"`
	ProvisionerBaseUrl  string      `json:"provisionerBaseUrl"`
	SecurityToken       string      `json:"securityToken"`
}

type Secrets struct {
	GenericWorker struct {
		Config json.RawMessage `json:"config"`
	} `json:"generic-worker"`
	Files []File `json:"files"`
}

type File struct {
	Description string `json:"description"`
	Path        string `json:"path"`
	Content     string `json:"content"`
	Encoding    string `json:"encoding"`
	Format      string `json:"format"`
}

func (f File) Extract() error {
	switch f.Format {
	case "file":
		return f.ExtractFile()
	case "zip":
		return f.ExtractZip()
	default:
		return errors.New("Unknown file format " + f.Format + " in worker type secret")
	}
}

func (f File) ExtractFile() error {
	switch f.Encoding {
	case "base64":
		data, err := base64.StdEncoding.DecodeString(f.Content)
		if err != nil {
			return err
		}
		return ioutil.WriteFile(f.Path, data, 0777)
	default:
		return errors.New("Unsupported encoding " + f.Encoding + " for file secret in worker type definition")
	}
}

func (f File) ExtractZip() error {
	switch f.Encoding {
	case "base64":
		data, err := base64.StdEncoding.DecodeString(f.Content)
		if err != nil {
			return err
		}
		return Unzip(data, f.Path)
	default:
		return errors.New("Unsupported encoding " + f.Encoding + " for zip secret in worker type definition")
	}
}

// This is a modified version of
// http://stackoverflow.com/questions/20357223/easy-way-to-unzip-file-with-golang
// to work with in memory zip, rather than a file
func Unzip(b []byte, dest string) error {
	br := bytes.NewReader(b)
	r, err := zip.NewReader(br, int64(len(b)))
	if err != nil {
		return err
	}

	os.MkdirAll(dest, 0755)

	// Closure to address file descriptors issue with all the deferred .Close() methods
	extractAndWriteFile := func(f *zip.File) error {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer func() {
			if err := rc.Close(); err != nil {
				panic(err)
			}
		}()

		path := filepath.Join(dest, f.Name)

		if f.FileInfo().IsDir() {
			os.MkdirAll(path, f.Mode())
		} else {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer func() {
				if err := f.Close(); err != nil {
					panic(err)
				}
			}()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
		return nil
	}

	for _, f := range r.File {
		err := extractAndWriteFile(f)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Config) updateConfigWithAmazonSettings() error {
	userData, err := queryUserData()
	if err != nil {
		return err
	}
	c.ProvisionerId = userData.ProvisionerId
	awsprov := awsprovisioner.AwsProvisioner{
		Authenticate: false,
		BaseURL:      userData.ProvisionerBaseUrl,
	}
	secToken, getErr := awsprov.GetSecret(userData.SecurityToken)
	// remove secrets even if we couldn't retrieve them!
	removeErr := awsprov.RemoveSecret(userData.SecurityToken)
	if getErr != nil {
		return err
	}
	if removeErr != nil {
		return removeErr
	}
	c.AccessToken = secToken.Credentials.AccessToken
	c.ClientId = secToken.Credentials.ClientID
	c.Certificate = secToken.Credentials.Certificate
	c.WorkerGroup = userData.Region
	c.WorkerType = userData.WorkerType

	awsMetadata := map[string]interface{}{}
	for _, url := range []string{
		"http://169.254.169.254/latest/meta-data/ami-id",
		"http://169.254.169.254/latest/meta-data/instance-id",
		"http://169.254.169.254/latest/meta-data/instsance-type",
		"http://169.254.169.254/latest/meta-data/public-ipv4",
		"http://169.254.169.254/latest/meta-data/placement/availability-zone",
	} {
		key := url[strings.LastIndex(url, "/")+1:]
		// if we get an error, be ok with it, it isn't sooooo important
		value, _ := queryMetaData(url)
		awsMetadata[key] = value
	}
	c.WorkerTypeMetadata["aws"] = awsMetadata
	c.WorkerId = awsMetadata["instance-id"].(string)
	c.PublicIP = net.ParseIP(awsMetadata["public-ipv4"].(string))
	secrets := new(Secrets)
	json.Unmarshal(secToken.Data, secrets)
	if err != nil {
		return err
	}

	// Now overlay existing config with values in secrets
	json.Unmarshal(secrets.GenericWorker.Config, c)
	if err != nil {
		return err
	}

	fmt.Printf("\n\nConfig\n\n%#v\n\n", c)

	// Now put secret files in place...
	for _, f := range secrets.Files {
		err := f.Extract()
		if err != nil {
			return err
		}
	}
	if c.IdleShutdownTimeoutSecs == 0 {
		c.IdleShutdownTimeoutSecs = 3600
	}
	return nil
}
<commit_msg>tyop :p<commit_after>package main

import (
	"archive/zip"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/taskcluster/httpbackoff"
	"github.com/taskcluster/taskcluster-client-go/awsprovisioner"
)

func queryUserData() (*UserData, error) {
	// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-user-data-retrieval
	resp, _, err := httpbackoff.Get("http://169.254.169.254/latest/user-data")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	userData := new(UserData)
	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(userData)
	return userData, err
}

func queryMetaData(url string) (string, error) {
	// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-data-retrieval
	// call http://169.254.169.254/latest/meta-data/instance-id with httpbackoff
	resp, _, err := httpbackoff.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	content, err := ioutil.ReadAll(resp.Body)
	return string(content), err
}

type UserData struct {
	Data                interface{} `json:"data"`
	Capacity            int         `json:"capacity"`
	WorkerType          string      `json:"workerType"`
	ProvisionerId       string      `json:"provisionerId"`
	Region              string      `json:"region"`
	InstanceType        string      `json:"instanceType"`
	LaunchSpecGenerated time.Time   `json:"launchSpecGenerated"`
	WorkerModified      time.Time   `json:"workerModified"`
	ProvisionerBaseUrl  string      `json:"provisionerBaseUrl"`
	SecurityToken       string      `json:"securityToken"`
}

type Secrets struct {
	GenericWorker struct {
		Config json.RawMessage `json:"config"`
	} `json:"generic-worker"`
	Files []File `json:"files"`
}

type File struct {
	Description string `json:"description"`
	Path        string `json:"path"`
	Content     string `json:"content"`
	Encoding    string `json:"encoding"`
	Format      string `json:"format"`
}

func (f File) Extract() error {
	switch f.Format {
	case "file":
		return f.ExtractFile()
	case "zip":
		return f.ExtractZip()
	default:
		return errors.New("Unknown file format " + f.Format + " in worker type secret")
	}
}

func (f File) ExtractFile() error {
	switch f.Encoding {
	case "base64":
		data, err := base64.StdEncoding.DecodeString(f.Content)
		if err != nil {
			return err
		}
		return ioutil.WriteFile(f.Path, data, 0777)
	default:
		return errors.New("Unsupported encoding " + f.Encoding + " for file secret in worker type definition")
	}
}

func (f File) ExtractZip() error {
	switch f.Encoding {
	case "base64":
		data, err := base64.StdEncoding.DecodeString(f.Content)
		if err != nil {
			return err
		}
		return Unzip(data, f.Path)
	default:
		return errors.New("Unsupported encoding " + f.Encoding + " for zip secret in worker type definition")
	}
}

// This is a modified version of
// http://stackoverflow.com/questions/20357223/easy-way-to-unzip-file-with-golang
// to work with in memory zip, rather than a file
func Unzip(b []byte, dest string) error {
	br := bytes.NewReader(b)
	r, err := zip.NewReader(br, int64(len(b)))
	if err != nil {
		return err
	}

	os.MkdirAll(dest, 0755)

	// Closure to address file descriptors issue with all the deferred .Close() methods
	extractAndWriteFile := func(f *zip.File) error {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer func() {
			if err := rc.Close(); err != nil {
				panic(err)
			}
		}()

		path := filepath.Join(dest, f.Name)

		if f.FileInfo().IsDir() {
			os.MkdirAll(path, f.Mode())
		} else {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer func() {
				if err := f.Close(); err != nil {
					panic(err)
				}
			}()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
		return nil
	}

	for _, f := range r.File {
		err := extractAndWriteFile(f)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Config) updateConfigWithAmazonSettings() error {
	userData, err := queryUserData()
	if err != nil {
		return err
	}
	c.ProvisionerId = userData.ProvisionerId
	awsprov := awsprovisioner.AwsProvisioner{
		Authenticate: false,
		BaseURL:      userData.ProvisionerBaseUrl,
	}
	secToken, getErr := awsprov.GetSecret(userData.SecurityToken)
	// remove secrets even if we couldn't retrieve them!
	removeErr := awsprov.RemoveSecret(userData.SecurityToken)
	if getErr != nil {
		return err
	}
	if removeErr != nil {
		return removeErr
	}
	c.AccessToken = secToken.Credentials.AccessToken
	c.ClientId = secToken.Credentials.ClientID
	c.Certificate = secToken.Credentials.Certificate
	c.WorkerGroup = userData.Region
	c.WorkerType = userData.WorkerType

	awsMetadata := map[string]interface{}{}
	for _, url := range []string{
		"http://169.254.169.254/latest/meta-data/ami-id",
		"http://169.254.169.254/latest/meta-data/instance-id",
		"http://169.254.169.254/latest/meta-data/instance-type",
		"http://169.254.169.254/latest/meta-data/public-ipv4",
		"http://169.254.169.254/latest/meta-data/placement/availability-zone",
	} {
		key := url[strings.LastIndex(url, "/")+1:]
		// if we get an error, be ok with it, it isn't sooooo important
		value, _ := queryMetaData(url)
		awsMetadata[key] = value
	}
	c.WorkerTypeMetadata["aws"] = awsMetadata
	c.WorkerId = awsMetadata["instance-id"].(string)
	c.PublicIP = net.ParseIP(awsMetadata["public-ipv4"].(string))
	secrets := new(Secrets)
	json.Unmarshal(secToken.Data, secrets)
	if err != nil {
		return err
	}

	// Now overlay existing config with values in secrets
	json.Unmarshal(secrets.GenericWorker.Config, c)
	if err != nil {
		return err
	}

	fmt.Printf("\n\nConfig\n\n%#v\n\n", c)

	// Now put secret files in place...
	for _, f := range secrets.Files {
		err := f.Extract()
		if err != nil {
			return err
		}
	}
	if c.IdleShutdownTimeoutSecs == 0 {
		c.IdleShutdownTimeoutSecs = 3600
	}
	return nil
}
<|endoftext|>


<commit_before>package bbs

import "fmt"
import "net/http"
import "log"
import "encoding/json"
import "io/ioutil"
import "time"
import "crypto/rand"

var name string
var version int = 0
var options []string
var description string
var server_version string

type Session struct {
	SessionID  string
	UserID     string
	BBS        BBS
	LastAction time.Time
}

type BBS interface {
	LogIn(m *LoginCommand) bool
	LogOut(m *LogoutCommand) *OKMessage
	IsLoggedIn() bool
	Get(m *GetCommand) (*ThreadMessage, *ErrorMessage)
	List(m *ListCommand) (*ListMessage, *ErrorMessage)
	Reply(m *ReplyCommand) (*OKMessage, *ErrorMessage)
	Post(m *PostCommand) (*OKMessage, *ErrorMessage)
}

var sessions = make(map[string]*Session)
var factory func() BBS
var addr string = ":8080"
var hello HelloMessage

func tryLogin(m *LoginCommand) *Session {
	//try to log in
	var board BBS
	board = factory()

	if board.LogIn(m) {
		//TODO: better session shit
		b := make([]byte, 16)
		_, err := rand.Read(b)
		if err != nil {
			return nil
		}
		id := fmt.Sprintf("%x", b)
		sesh := Session{id, m.Username, board, time.Now()}
		sessions[id] = &sesh

		return &sesh
	}

	return nil
}

func logout(session string) {
	delete(sessions, session)
}

func handle(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		//Display info
		index(w, r)
	case "POST":
		data, _ := ioutil.ReadAll(r.Body)
		incoming := BBSCommand{}
		err := json.Unmarshal(data, &incoming)
		if err != nil {
			fmt.Println("JSON Parsing Error!! " + string(data))
			return
		}
		switch incoming.Command {
		case "hello":
			w.Write(jsonify(&hello))
		case "login":
			m := LoginCommand{}
			json.Unmarshal(data, &m)
			sesh := tryLogin(&m)
			if sesh != nil {
				w.Write(jsonify(&WelcomeMessage{"welcome", sesh.UserID, sesh.SessionID}))
			} else {
				w.Write(jsonify(&ErrorMessage{"error", "login", "Can't log in!"}))
			}
		case "get":
			m := GetCommand{}
			json.Unmarshal(data, &m)
			sesh := getSession(m.Session)
			if sesh == nil {
				w.Write(jsonify(SessionErrorMessage))
				return
			}
			success, e := sesh.BBS.Get(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "list":
			m := ListCommand{}
			json.Unmarshal(data, &m)
			sesh := getSession(m.Session)
			if sesh == nil {
				w.Write(jsonify(SessionErrorMessage))
				return
			}
			success, e := sesh.BBS.List(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "reply":
			m := ReplyCommand{}
			json.Unmarshal(data, &m)
			sesh := getSession(m.Session)
			if sesh == nil {
				w.Write(jsonify(SessionErrorMessage))
				return
			}
			success, e := sesh.BBS.Reply(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "post":
			m := PostCommand{}
			json.Unmarshal(data, &m)
			sesh := getSession(m.Session)
			if sesh == nil {
				w.Write(jsonify(SessionErrorMessage))
				return
			}
			success, e := sesh.BBS.Post(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "logout":
			m := LogoutCommand{}
			json.Unmarshal(data, &m)
			logout(m.Session)
		default:
			w.Write(jsonify(&ErrorMessage{"error", incoming.Command, "Unknown command: " + incoming.Command}))
		}

	default:
		fmt.Println("Weird method used.")
	}
}

func getSession(sesh string) *Session {
	s, ok := sessions[sesh]
	if !ok {
		return nil
	}
	s.LastAction = time.Now()
	return s
}

func jsonify(j interface{}) []byte {
	b, err := json.Marshal(j)
	if err != nil {
		return []byte(`{"cmd": "error", "error": "server error"}`)
	}
	return b
}

func index(w http.ResponseWriter, r *http.Request) {
	f, err := ioutil.ReadFile("index.html")
	if err == nil {
		w.Write(f)
	} else {
		log.Fatal(err)
	}
}

func Serve(address string, path string, hm HelloMessage, fact func() BBS) {
	factory = fact
	addr = address
	hello = hm
	http.HandleFunc("/", index)
	http.HandleFunc(path, handle)
	fmt.Println("Starting server at " + addr)
	http.ListenAndServe(addr, nil)
}
<commit_msg>reorganized bbs.go, does session/login stuff for you now<commit_after>package bbs

import "fmt"
import "net/http"
import "log"
import "encoding/json"
import "io/ioutil"
import "time"
import "crypto/rand"

var name string
var version int = 0
var options []string
var description string
var server_version string

type Session struct {
	SessionID  string
	UserID     string
	BBS        BBS
	LastAction time.Time
}

type BBS interface {
	LogIn(m *LoginCommand) bool
	LogOut(m *LogoutCommand) *OKMessage
	IsLoggedIn() bool
	Get(m *GetCommand) (*ThreadMessage, *ErrorMessage)
	List(m *ListCommand) (*ListMessage, *ErrorMessage)
	Reply(m *ReplyCommand) (*OKMessage, *ErrorMessage)
	Post(m *PostCommand) (*OKMessage, *ErrorMessage)
}

var sessions = make(map[string]*Session)
var factory func() BBS
var addr string = ":8080"
var hello HelloMessage

var userCommands []string
var guestCommands []string
var defaultBBS BBS

func tryLogin(m *LoginCommand) *Session {
	//try to log in
	var board BBS
	board = factory()

	if board.LogIn(m) {
		//TODO: better session shit
		b := make([]byte, 16)
		_, err := rand.Read(b)
		if err != nil {
			return nil
		}
		id := fmt.Sprintf("%x", b)
		sesh := Session{id, m.Username, board, time.Now()}
		sessions[id] = &sesh

		return &sesh
	}

	return nil
}

func logout(session string) {
	delete(sessions, session)
}

func handle(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		//Display info
		index(w, r)
	case "POST":
		data, _ := ioutil.ReadAll(r.Body)
		incoming := UserCommand{}
		err := json.Unmarshal(data, &incoming)
		if err != nil {
			fmt.Println("JSON Parsing Error!! " + string(data))
			return
		}
		var bbs BBS
		var sesh *Session
		if incoming.Session != "" {
			sesh = getSession(incoming.Session)
			bbs = sesh.BBS
		} else {
			bbs = defaultBBS
		}
		if contains(userCommands, incoming.Command) {
			if sesh == nil {
				// a guest tried to use a user command
				w.Write(jsonify(SessionErrorMessage))
				return
			}
		}
		switch incoming.Command {
		case "hello":
			w.Write(jsonify(&hello))
		case "login":
			m := LoginCommand{}
			json.Unmarshal(data, &m)
			newsesh := tryLogin(&m)
			if newsesh != nil {
				w.Write(jsonify(&WelcomeMessage{"welcome", newsesh.UserID, newsesh.SessionID}))
			} else {
				w.Write(jsonify(&ErrorMessage{"error", "login", "Can't log in!"}))
			}
		case "get":
			m := GetCommand{}
			json.Unmarshal(data, &m)
			success, e := bbs.Get(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "list":
			m := ListCommand{}
			json.Unmarshal(data, &m)
			success, e := bbs.List(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "reply":
			m := ReplyCommand{}
			json.Unmarshal(data, &m)
			success, e := bbs.Reply(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "post":
			m := PostCommand{}
			json.Unmarshal(data, &m)
			success, e := bbs.Post(&m)
			if success != nil {
				w.Write(jsonify(success))
			} else {
				w.Write(jsonify(e))
			}
		case "logout":
			m := LogoutCommand{}
			json.Unmarshal(data, &m)
			logout(m.Session)
		default:
			w.Write(jsonify(&ErrorMessage{"error", incoming.Command, "Unknown command: " + incoming.Command}))
		}

	default:
		fmt.Println("Weird method used.")
	}
}

func contains(a []string, s string) bool {
	for _, c := range a {
		if c == s {
			return true
		}
	}
	return false
}

func getSession(sesh string) *Session {
	s, ok := sessions[sesh]
	if !ok {
		return nil
	}
	s.LastAction = time.Now()
	return s
}

func jsonify(j interface{}) []byte {
	b, err := json.Marshal(j)
	if err != nil {
		return []byte(`{"cmd": "error", "error": "server error"}`)
	}
	return b
}

func index(w http.ResponseWriter, r *http.Request) {
	f, err := ioutil.ReadFile("index.html")
	if err == nil {
		w.Write(f)
	} else {
		log.Fatal(err)
	}
}

func Serve(address string, path string, hm HelloMessage, fact func() BBS) {
	factory = fact
	addr = address
	hello = hm
	userCommands = hm.Access.UserCommands
	guestCommands = hm.Access.GuestCommands
	defaultBBS = fact()
	http.HandleFunc("/", index)
	http.HandleFunc(path, handle)
	fmt.Println("Starting server at " + addr)
	http.ListenAndServe(addr, nil)
}
<|endoftext|>


<commit_before>package stages

import (
	"fmt"
	"os"
	"reflect"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/vito/booklit"
	"github.com/vito/booklit/ast"
)

// Evaluate is an ast.Visitor that builds up the booklit.Content for a given
// section.
type Evaluate struct {
	// The section which acts as the evaluation context. The section's plugins
	// are used for evaluating Invoke nodes.
	Section *booklit.Section

	// Duration after which to log a warning for a slow \invoke.
	SlowInvokeThreshold time.Duration

	// The evaluated content after calling (ast.Node).Visit.
	Result booklit.Content
}

// VisitString appends the string's text to the result using booklit.Append.
func (eval *Evaluate) VisitString(str ast.String) error {
	eval.Result = booklit.Append(eval.Result, booklit.String(str))
	return nil
}

// VisitSequence visits each node within the sequence.
func (eval *Evaluate) VisitSequence(seq ast.Sequence) error {
	for _, node := range seq {
		err := node.Visit(eval)
		if err != nil {
			return err
		}
	}

	return nil
}

// VisitParagraph visits each line in the paragraph and builds up a
// booklit.Paragraph containing each evaluated line.
//
// Any lines which evaluate to a nil result are skipped, i.e. a Invoke which
// performed side effects and returned nothing. If the paragraph is empty as a
// result, the Result is unaffected.
//
// If the Result contains a single non-flow content, it is unwrapped and
// appended to the Result.
//
// Otherwise, i.e. a normal paragraph of flow content, the paragraph is
// appended to the Result.
func (eval *Evaluate) VisitParagraph(node ast.Paragraph) error {
	previous := eval.Result

	para := booklit.Paragraph{}
	for _, line := range node {
		eval.Result = nil

		err := line.Visit(eval)
		if err != nil {
			return err
		}

		if eval.Result != nil {
			para = append(para, eval.Result)
		}
	}

	eval.Result = nil

	if len(para) == 0 {
		// paragraph resulted in no content (e.g. an invoke with no return value)
		eval.Result = previous
		return nil
	}

	if len(para) == 1 && !para[0].IsFlow() {
		// paragraph resulted in block content (e.g. a section)
		eval.Result = booklit.Append(previous, para[0])
		return nil
	}

	eval.Result = booklit.Append(previous, para)

	return nil
}

// VisitPreformatted behaves similarly to VisitParagraph, but with no
// special-case for block content, and it appends a booklit.Preformatted
// instead.
func (eval *Evaluate) VisitPreformatted(node ast.Preformatted) error {
	previous := eval.Result

	pre := booklit.Preformatted{}
	for _, line := range node {
		eval.Result = nil

		err := line.Visit(eval)
		if err != nil {
			return err
		}

		if eval.Result != nil {
			pre = append(pre, eval.Result)
		}
	}

	eval.Result = booklit.Append(previous, pre)

	return nil
}

var complainL = new(sync.Mutex)

// VisitInvoke uses reflection to evaluate the corresponding method on the
// section's plugins, trying them in order.
//
// If no method is found, booklit.UndefinedFunctionError is returned.
//
// If the method's arity does not match the Invoke's arguments, an error is
// returned.
//
// The method must return either no value, a booklit.Content, an error, or
// (booklit.Content, error). Other return types will result in an error.
//
// If a PrettyError is returned, it is returned without wrapping.
//
// If an error is returned, it is wrapped in a booklit.FailedFunctionError.
//
// If a booklit.Content is returned, it will be appended to Result.
func (eval *Evaluate) VisitInvoke(invoke ast.Invoke) error {
	eval.Section.InvokeLocation = invoke.Location

	methodName := invoke.Method()

	var method reflect.Value
	for _, p := range eval.Section.Plugins {
		value := reflect.ValueOf(p)
		method = value.MethodByName(methodName)
		if method.IsValid() {
			break
		}
	}

	loc := booklit.ErrorLocation{
		FilePath:     eval.Section.FilePath(),
		NodeLocation: invoke.Location,
		Length:       len("\\" + invoke.Function),
	}

	if !method.IsValid() {
		return booklit.UndefinedFunctionError{
			Function:      invoke.Function,
			ErrorLocation: loc,
		}
	}

	start := time.Now()
	complain := time.AfterFunc(eval.SlowInvokeThreshold, func() {
		complainL.Lock()
		defer complainL.Unlock()
		logrus.WithField("elapsed", time.Since(start)).
			Warn(loc.Annotate("slow invoke: \\%s (still running)", invoke.Function))
		loc.AnnotateLocation(os.Stderr)
	})

	defer func() {
		complainL.Lock()
		defer complainL.Unlock()
		if complain.Stop() {
			logrus.WithField("duration", time.Since(start)).
				Debug(loc.Annotate("fast invoke: \\%s", invoke.Function))
		} else {
			logrus.WithField("duration", time.Since(start)).
				Info(loc.Annotate("slow invoke: \\%s (finished)", invoke.Function))
		}
	}()

	methodType := method.Type()

	rawArgs := invoke.Arguments

	argc := methodType.NumIn()
	if methodType.IsVariadic() {
		argc--

		if len(rawArgs) < argc {
			return fmt.Errorf("argument count mismatch for %s: given %d, need at least %d", invoke.Function, len(rawArgs), argc)
		}
	} else if len(rawArgs) != argc {
		return fmt.Errorf("argument count mismatch for %s: given %d, need %d", invoke.Function, len(rawArgs), argc)
	}

	argv := make([]reflect.Value, argc)
	for i := 0; i < argc; i++ {
		t := methodType.In(i)
		arg, err := eval.convert(t, rawArgs[i])
		if err != nil {
			return err
		}

		argv[i] = arg
	}

	if methodType.IsVariadic() {
		variadic := rawArgs[argc:]
		variadicType := methodType.In(argc)

		subType := variadicType.Elem()
		for _, varg := range variadic {
			arg, err := eval.convert(subType, varg)
			if err != nil {
				return err
			}

			argv = append(argv, arg)
		}
	}

	result := method.Call(argv)

	switch methodType.NumOut() {
	case 0:
		return nil
	case 1:
		val := result[0].Interface()
		valType := methodType.Out(0)

		switch reflect.New(valType).Interface().(type) {
		case *error:
			if val != nil {
				if pErr, ok := val.(booklit.PrettyError); ok {
					return pErr
				}

				return booklit.FailedFunctionError{
					Function:      invoke.Function,
					Err:           val.(error),
					ErrorLocation: loc,
				}
			}
		case *booklit.Content:
			eval.Result = booklit.Append(eval.Result, val.(booklit.Content))
		default:
			return fmt.Errorf("unknown return type: %s", valType)
		}
	case 2:
		second := result[1].Interface()
		secondType := methodType.Out(1)
		switch reflect.New(secondType).Interface().(type) {
		case *error:
			if second != nil {
				if pErr, ok := second.(booklit.PrettyError); ok {
					return pErr
				}

				return booklit.FailedFunctionError{
					Function:      invoke.Function,
					Err:           second.(error),
					ErrorLocation: loc,
				}
			}
		default:
			return fmt.Errorf("unknown second return type: %s", secondType)
		}

		first := result[0].Interface()
		firstType := methodType.Out(0)
		switch reflect.New(firstType).Interface().(type) {
		case *booklit.Content:
			eval.Result = booklit.Append(eval.Result, first.(booklit.Content))
		default:
			return fmt.Errorf("unknown first return type: %s", firstType)
		}
	default:
		return fmt.Errorf("expected 0-2 return values from %s, got %d", invoke.Function, len(result))
	}

	return nil
}

func (eval Evaluate) convert(to reflect.Type, node ast.Node) (reflect.Value, error) {
	switch reflect.New(to).Interface().(type) {
	case *string:
		content, err := eval.evalArg(node)
		if err != nil {
			return reflect.ValueOf(nil), err
		}

		return reflect.ValueOf(content.String()), nil
	case *booklit.Content:
		content, err := eval.evalArg(node)
		if err != nil {
			return reflect.ValueOf(nil), err
		}

		return reflect.ValueOf(content), nil
	case *ast.Node:
		return reflect.ValueOf(node), nil
	default:
		name := to.Name()
		if to.PkgPath() != "" {
			name = to.PkgPath() + "." + name
		}

		return reflect.ValueOf(nil), fmt.Errorf("unsupported argument type: %s", name)
	}
}

func (eval Evaluate) evalArg(node ast.Node) (booklit.Content, error) {
	subEval := &Evaluate{
		Section:             eval.Section,
		SlowInvokeThreshold: eval.SlowInvokeThreshold,
	}

	err := node.Visit(subEval)
	if err != nil {
		return nil, err
	}

	return subEval.Result, nil
}
<commit_msg>only log slow invokes if configured<commit_after>package stages

import (
	"fmt"
	"os"
	"reflect"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/vito/booklit"
	"github.com/vito/booklit/ast"
)

// Evaluate is an ast.Visitor that builds up the booklit.Content for a given
// section.
type Evaluate struct {
	// The section which acts as the evaluation context. The section's plugins
	// are used for evaluating Invoke nodes.
	Section *booklit.Section

	// Duration after which to log a warning for a slow \invoke.
	SlowInvokeThreshold time.Duration

	// The evaluated content after calling (ast.Node).Visit.
	Result booklit.Content
}

// VisitString appends the string's text to the result using booklit.Append.
func (eval *Evaluate) VisitString(str ast.String) error {
	eval.Result = booklit.Append(eval.Result, booklit.String(str))
	return nil
}

// VisitSequence visits each node within the sequence.
func (eval *Evaluate) VisitSequence(seq ast.Sequence) error {
	for _, node := range seq {
		err := node.Visit(eval)
		if err != nil {
			return err
		}
	}

	return nil
}

// VisitParagraph visits each line in the paragraph and builds up a
// booklit.Paragraph containing each evaluated line.
//
// Any lines which evaluate to a nil result are skipped, i.e. a Invoke which
// performed side effects and returned nothing. If the paragraph is empty as a
// result, the Result is unaffected.
//
// If the Result contains a single non-flow content, it is unwrapped and
// appended to the Result.
//
// Otherwise, i.e. a normal paragraph of flow content, the paragraph is
// appended to the Result.
func (eval *Evaluate) VisitParagraph(node ast.Paragraph) error {
	previous := eval.Result

	para := booklit.Paragraph{}
	for _, line := range node {
		eval.Result = nil

		err := line.Visit(eval)
		if err != nil {
			return err
		}

		if eval.Result != nil {
			para = append(para, eval.Result)
		}
	}

	eval.Result = nil

	if len(para) == 0 {
		// paragraph resulted in no content (e.g. an invoke with no return value)
		eval.Result = previous
		return nil
	}

	if len(para) == 1 && !para[0].IsFlow() {
		// paragraph resulted in block content (e.g. a section)
		eval.Result = booklit.Append(previous, para[0])
		return nil
	}

	eval.Result = booklit.Append(previous, para)

	return nil
}

// VisitPreformatted behaves similarly to VisitParagraph, but with no
// special-case for block content, and it appends a booklit.Preformatted
// instead.
func (eval *Evaluate) VisitPreformatted(node ast.Preformatted) error {
	previous := eval.Result

	pre := booklit.Preformatted{}
	for _, line := range node {
		eval.Result = nil

		err := line.Visit(eval)
		if err != nil {
			return err
		}

		if eval.Result != nil {
			pre = append(pre, eval.Result)
		}
	}

	eval.Result = booklit.Append(previous, pre)

	return nil
}

var complainL = new(sync.Mutex)

// VisitInvoke uses reflection to evaluate the corresponding method on the
// section's plugins, trying them in order.
//
// If no method is found, booklit.UndefinedFunctionError is returned.
//
// If the method's arity does not match the Invoke's arguments, an error is
// returned.
//
// The method must return either no value, a booklit.Content, an error, or
// (booklit.Content, error). Other return types will result in an error.
//
// If a PrettyError is returned, it is returned without wrapping.
//
// If an error is returned, it is wrapped in a booklit.FailedFunctionError.
//
// If a booklit.Content is returned, it will be appended to Result.
func (eval *Evaluate) VisitInvoke(invoke ast.Invoke) error {
	eval.Section.InvokeLocation = invoke.Location

	methodName := invoke.Method()

	var method reflect.Value
	for _, p := range eval.Section.Plugins {
		value := reflect.ValueOf(p)
		method = value.MethodByName(methodName)
		if method.IsValid() {
			break
		}
	}

	loc := booklit.ErrorLocation{
		FilePath:     eval.Section.FilePath(),
		NodeLocation: invoke.Location,
		Length:       len("\\" + invoke.Function),
	}

	if !method.IsValid() {
		return booklit.UndefinedFunctionError{
			Function:      invoke.Function,
			ErrorLocation: loc,
		}
	}

	if eval.SlowInvokeThreshold > 0 {
		start := time.Now()
		complain := time.AfterFunc(eval.SlowInvokeThreshold, func() {
			complainL.Lock()
			defer complainL.Unlock()
			logrus.WithField("elapsed", time.Since(start)).
				Warn(loc.Annotate("slow invoke: \\%s (still running)", invoke.Function))
			loc.AnnotateLocation(os.Stderr)
		})

		defer func() {
			complainL.Lock()
			defer complainL.Unlock()
			if complain.Stop() {
				logrus.WithField("duration", time.Since(start)).
					Debug(loc.Annotate("fast invoke: \\%s", invoke.Function))
			} else {
				logrus.WithField("duration", time.Since(start)).
					Info(loc.Annotate("slow invoke: \\%s (finished)", invoke.Function))
			}
		}()
	}

	methodType := method.Type()

	rawArgs := invoke.Arguments

	argc := methodType.NumIn()
	if methodType.IsVariadic() {
		argc--

		if len(rawArgs) < argc {
			return fmt.Errorf("argument count mismatch for %s: given %d, need at least %d", invoke.Function, len(rawArgs), argc)
		}
	} else if len(rawArgs) != argc {
		return fmt.Errorf("argument count mismatch for %s: given %d, need %d", invoke.Function, len(rawArgs), argc)
	}

	argv := make([]reflect.Value, argc)
	for i := 0; i < argc; i++ {
		t := methodType.In(i)
		arg, err := eval.convert(t, rawArgs[i])
		if err != nil {
			return err
		}

		argv[i] = arg
	}

	if methodType.IsVariadic() {
		variadic := rawArgs[argc:]
		variadicType := methodType.In(argc)

		subType := variadicType.Elem()
		for _, varg := range variadic {
			arg, err := eval.convert(subType, varg)
			if err != nil {
				return err
			}

			argv = append(argv, arg)
		}
	}

	result := method.Call(argv)

	switch methodType.NumOut() {
	case 0:
		return nil
	case 1:
		val := result[0].Interface()
		valType := methodType.Out(0)

		switch reflect.New(valType).Interface().(type) {
		case *error:
			if val != nil {
				if pErr, ok := val.(booklit.PrettyError); ok {
					return pErr
				}

				return booklit.FailedFunctionError{
					Function:      invoke.Function,
					Err:           val.(error),
					ErrorLocation: loc,
				}
			}
		case *booklit.Content:
			eval.Result = booklit.Append(eval.Result, val.(booklit.Content))
		default:
			return fmt.Errorf("unknown return type: %s", valType)
		}
	case 2:
		second := result[1].Interface()
		secondType := methodType.Out(1)
		switch reflect.New(secondType).Interface().(type) {
		case *error:
			if second != nil {
				if pErr, ok := second.(booklit.PrettyError); ok {
					return pErr
				}

				return booklit.FailedFunctionError{
					Function:      invoke.Function,
					Err:           second.(error),
					ErrorLocation: loc,
				}
			}
		default:
			return fmt.Errorf("unknown second return type: %s", secondType)
		}

		first := result[0].Interface()
		firstType := methodType.Out(0)
		switch reflect.New(firstType).Interface().(type) {
		case *booklit.Content:
			eval.Result = booklit.Append(eval.Result, first.(booklit.Content))
		default:
			return fmt.Errorf("unknown first return type: %s", firstType)
		}
	default:
		return fmt.Errorf("expected 0-2 return values from %s, got %d", invoke.Function, len(result))
	}

	return nil
}

func (eval Evaluate) convert(to reflect.Type, node ast.Node) (reflect.Value, error) {
	switch reflect.New(to).Interface().(type) {
	case *string:
		content, err := eval.evalArg(node)
		if err != nil {
			return reflect.ValueOf(nil), err
		}

		return reflect.ValueOf(content.String()), nil
	case *booklit.Content:
		content, err := eval.evalArg(node)
		if err != nil {
			return reflect.ValueOf(nil), err
		}

		return reflect.ValueOf(content), nil
	case *ast.Node:
		return reflect.ValueOf(node), nil
	default:
		name := to.Name()
		if to.PkgPath() != "" {
			name = to.PkgPath() + "." + name
		}

		return reflect.ValueOf(nil), fmt.Errorf("unsupported argument type: %s", name)
	}
}

func (eval Evaluate) evalArg(node ast.Node) (booklit.Content, error) {
	subEval := &Evaluate{
		Section:             eval.Section,
		SlowInvokeThreshold: eval.SlowInvokeThreshold,
	}

	err := node.Visit(subEval)
	if err != nil {
		return nil, err
	}

	return subEval.Result, nil
}
<|endoftext|>