<commit_before>package main

import (
    "encoding/json"
    "errors"
    "flag"
    "fmt"
    "log"
    "os"
    "os/signal"
    "sort"
    "strings"
    "syscall"
    "sync"

    gc "github.com/rthornton128/goncurses"
)

const _VERSION string = "0.2.0"
var _stdscr *gc.Window = nil

func sigHandler(ch *chan os.Signal) {
    sig := <-*ch
    gc.End()
    fmt.Println("Captured sig", sig)
    os.Exit(3)
}

func main() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs,
                  syscall.SIGHUP,
                  syscall.SIGINT,
                  syscall.SIGQUIT,
                  syscall.SIGABRT,
                  syscall.SIGKILL,
                  syscall.SIGSEGV,
                  syscall.SIGTERM,
                  syscall.SIGSTOP)
    go sigHandler(&sigs)

    initLog()
    initGui()
    order := loadOrder()

    arr, err := parseSituation(&order.Situation)
    if (err != nil ) {
        fmt.Println(err)
        os.Exit(1)
    }

    tasks, err2 := parseExecution(&order.Execution)
    if (err2 != nil ) {
        fmt.Println(err2)
        os.Exit(1)
    }

    targets := make([]target, len(arr))
    channels := make([]chan string, len(arr))
    var wg sync.WaitGroup
    for i := range arr {
        channels[i] = make(chan string, 10)
        if arr[i].Target.Prot == "SSH" {
            test := new(TargetSsh)
            target.New(test, arr[i], tasks)
            test.impl.ch = &channels[i]
            test.impl.wait = &wg
            targets[i] = test
        } else {
            test := new(TargetExec)
            target.New(test, arr[i], tasks)
            test.impl.ch = &channels[i]
            test.impl.wait = &wg
            targets[i] = test
        }
    }
    wg.Add(len(targets))
    for i := range targets {
        go target.Watch(targets[i])
    }
    ReportThread(targets)
    wg.Wait()
}

func initLog() {
    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

func initGui() {
    var err error
    _stdscr, err = gc.Init()
    if err != nil {
        gc.End()
        log.Fatal(err)
    }
    defer gc.End()

    gc.Echo(false)
    gc.CBreak(true)
    gc.Cursor(0)
    gc.StartColor()

    gc.InitPair(gc.C_WHITE, gc.C_WHITE, gc.C_BLACK)
    gc.InitPair(gc.C_YELLOW, gc.C_YELLOW, gc.C_BLACK)
    gc.InitPair(gc.C_RED, gc.C_RED, gc.C_BLACK)
    gc.InitPair(gc.C_CYAN, gc.C_CYAN, gc.C_BLACK)
}

func getPrettyJson(v interface{}) string {
    buffer, err := json.MarshalIndent(v, "", "    ")
    if (err != nil) {

    }
    return string(buffer)
}

func loadOrder() Order {
    option := flag.String("order", "order.json", "file containing scouting operations order")
    flag.Usage = func() {
        fmt.Fprintf(os.Stderr, "version %s\n", _VERSION)
        fmt.Fprintln(os.Stderr, "usage:")
        flag.PrintDefaults()
    }
    flag.Parse()

    file, _ := os.Open(*option)
    decoder := json.NewDecoder(file)
    order := Order{}
    err := decoder.Decode(&order)
    if err != nil {
        fmt.Println("error: ", err)
    } else {
        //log.Println(getPrettyJson(order))
    }
    //log.Println("Targets:", len(order.Situation.Targets))
    //log.Println("Tasks  :", len(order.Execution.Tasks))
    return order
}

func parseSituation(situation *Situation) (TargetArr, error) {
    size := 0
    ret := make(TargetArr, size)
    var err error = nil
    definitions := situation.Definitions
    credentials := situation.Credentials

    for _, id := range situation.Targets {
        var exists bool
        var group TargetGroup

        if group, exists = definitions[id]; exists {
            var cred Credentials
            var entry TargetEntry

            if cred, exists = credentials[group.Cred]; exists {
                entry.Credentials = cred
            } else {
                err = errors.New("Target '" + id + "' credentials '" + group.Cred + "' not found")
                break
            }

            // todo: check for duplicate addreses?
            for _, addr := range group.Addr {
                entry.Target.Name = group.Name
                entry.Target.Addr = addr
                entry.Target.Cred = group.Cred
                entry.Target.Prot = group.Prot
                entry.Target.Sys = group.Sys
                ret = append(ret, entry)
                size = size + 1
            }
        } else {
            err = errors.New("Target '" + id + "' is not found in definitions")
            break
        }
    }

    if size == 0 && err == nil {
        err = errors.New("No targets found")
    }

    return ret, err
}

func parseExecution(execution *Execution1) (TaskArr, error) {
    size := 0
    ret := make(TaskArr, 0)
    var err error = nil
    tasks := execution.Tasks
    definitions := execution.Definitions

    for _, task := range tasks {
        var def Task
        var exists bool
        if def, exists = definitions[task.Task]; exists {
            for j, vars := range task.Vars {
                if len(vars) == len(def.Vars) {
                    cmd := def.Task
                    for k, param := range vars {
                        cmd = strings.Replace(cmd, def.Vars[k], param, 1)
                    }
                    var entry TaskEntry
                    entry.Exec = task
                    entry.Cmd = cmd
                    entry.Desc = task.Desc[j]
                    entry.Ret = def.Type
                    entry.Scale = task.Scale
                    if len(task.Units) == len(task.Reports) {
                        entry.Units = task.Units
                    } else {
                        err = errors.New("Task '" + task.Task + "' reports and units lengths do not match")
                        break
                    }
                    ret = append(ret, entry)
                    size = size + 1
                } else {
                    err = errors.New("Task '" + task.Task + "' vars do not match definitions")
                    break
                }
            }
        } else {
            err = errors.New("Task '" + task.Task + "' is not found in definitions")
            break
        }
    }

    if size == 0 && err == nil {
        err = errors.New("No tasks found")
    } else {
        i := 0
        for _, task := range ret {
            if task.Exec.Active {
                ret[i] = task
                i++
            }
        }
        if i == 0 {
            err = errors.New("No active tasks found")
        } else {
            ret = ret[:i]
        }
    }

    sort.Sort(ret)

    return ret, err
}

func reportTargets(reports *[]database) {
    var maxTicks int = 20
    var yScale uint64 = 50
    var total uint64 = 0
    _stdscr.Move(0,0)

    for i := range *reports {
        x := 0
        _stdscr.MovePrintf(i, x, "%-15s", (*reports)[i].target)

        x += 15
        _stdscr.MovePrintln(i, x, "[")

        x += 1
        ticks := uint64((*reports)[i].rate) / yScale

        for j := 0; j < maxTicks; j++ {
            if (j * 100 / maxTicks >= 66) {
                _stdscr.ColorOn(gc.C_RED)
            } else if (j * 100 / maxTicks >= 33) {
                _stdscr.ColorOn(gc.C_YELLOW)
            } else {
                _stdscr.ColorOn(gc.C_CYAN)
            }

            if int(ticks) > j {
                _stdscr.MovePrintln(i, x, "|")
            } else {
                _stdscr.MovePrintln(i, x, " ")
            }

            x++
        }

        _stdscr.ColorOff(gc.C_RED)
        _stdscr.ColorOff(gc.C_YELLOW)
        _stdscr.ColorOff(gc.C_CYAN)
        _stdscr.MovePrintf(i, x, "%6d %s] %s\n", uint64((*reports)[i].rate), (*reports)[i].units, (*reports)[i].task)

        total += uint64((*reports)[i].rate)
    }

    _stdscr.MovePrintf(len(*reports), 0,  "%-15s", "Total")
    _stdscr.MovePrintf(len(*reports), 36, "%6d Mbps\n", total)
    _stdscr.Refresh()
}
<commit_msg>Added scouting report option<commit_after>package main

import (
    "encoding/json"
    "errors"
    "flag"
    "fmt"
    "log"
    "os"
    "os/signal"
    "sort"
    "strings"
    "syscall"
    "sync"

    gc "github.com/rthornton128/goncurses"
)

const _VERSION string = "0.3.0"
var _stdscr *gc.Window = nil

func sigHandler(ch *chan os.Signal) {
    sig := <-*ch
    gc.End()
    fmt.Println("Captured sig", sig)
    os.Exit(3)
}

func main() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs,
                  syscall.SIGHUP,
                  syscall.SIGINT,
                  syscall.SIGQUIT,
                  syscall.SIGABRT,
                  syscall.SIGKILL,
                  syscall.SIGSEGV,
                  syscall.SIGTERM,
                  syscall.SIGSTOP)
    go sigHandler(&sigs)

    initLog()
    initGui()

    orderFile := flag.String("order", "order.json", "file containing scouting operations order")
    /*reportFile := */flag.String("report", "report.csv", "file containing scouting report")
    flag.Usage = func() {
        fmt.Fprintf(os.Stderr, "version %s\n", _VERSION)
        fmt.Fprintln(os.Stderr, "usage:")
        flag.PrintDefaults()
    }
    flag.Parse()

    order := loadOrder(orderFile)

    arr, err := parseSituation(&order.Situation)
    if (err != nil ) {
        fmt.Println(err)
        os.Exit(1)
    }

    tasks, err2 := parseExecution(&order.Execution)
    if (err2 != nil ) {
        fmt.Println(err2)
        os.Exit(1)
    }

    targets := make([]target, len(arr))
    channels := make([]chan string, len(arr))
    var wg sync.WaitGroup
    for i := range arr {
        channels[i] = make(chan string, 10)
        if arr[i].Target.Prot == "SSH" {
            test := new(TargetSsh)
            target.New(test, arr[i], tasks)
            test.impl.ch = &channels[i]
            test.impl.wait = &wg
            targets[i] = test
        } else {
            test := new(TargetExec)
            target.New(test, arr[i], tasks)
            test.impl.ch = &channels[i]
            test.impl.wait = &wg
            targets[i] = test
        }
    }
    wg.Add(len(targets))
    for i := range targets {
        go target.Watch(targets[i])
    }
    ReportThread(targets)
    wg.Wait()
}

func initLog() {
    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

func initGui() {
    var err error
    _stdscr, err = gc.Init()
    if err != nil {
        gc.End()
        log.Fatal(err)
    }
    defer gc.End()

    gc.Echo(false)
    gc.CBreak(true)
    gc.Cursor(0)
    gc.StartColor()

    gc.InitPair(gc.C_WHITE, gc.C_WHITE, gc.C_BLACK)
    gc.InitPair(gc.C_YELLOW, gc.C_YELLOW, gc.C_BLACK)
    gc.InitPair(gc.C_RED, gc.C_RED, gc.C_BLACK)
    gc.InitPair(gc.C_CYAN, gc.C_CYAN, gc.C_BLACK)
}

func getPrettyJson(v interface{}) string {
    buffer, err := json.MarshalIndent(v, "", "    ")
    if (err != nil) {

    }
    return string(buffer)
}

func loadOrder(fileName *string) Order {

    file, _ := os.Open(*fileName)
    decoder := json.NewDecoder(file)
    order := Order{}
    err := decoder.Decode(&order)
    if err != nil {
        fmt.Println("error: ", err)
    }

    return order
}

func parseSituation(situation *Situation) (TargetArr, error) {
    size := 0
    ret := make(TargetArr, size)
    var err error = nil
    definitions := situation.Definitions
    credentials := situation.Credentials

    for _, id := range situation.Targets {
        var exists bool
        var group TargetGroup

        if group, exists = definitions[id]; exists {
            var cred Credentials
            var entry TargetEntry

            if cred, exists = credentials[group.Cred]; exists {
                entry.Credentials = cred
            } else {
                err = errors.New("Target '" + id + "' credentials '" + group.Cred + "' not found")
                break
            }

            // todo: check for duplicate addreses?
            for _, addr := range group.Addr {
                entry.Target.Name = group.Name
                entry.Target.Addr = addr
                entry.Target.Cred = group.Cred
                entry.Target.Prot = group.Prot
                entry.Target.Sys = group.Sys
                ret = append(ret, entry)
                size = size + 1
            }
        } else {
            err = errors.New("Target '" + id + "' is not found in definitions")
            break
        }
    }

    if size == 0 && err == nil {
        err = errors.New("No targets found")
    }

    return ret, err
}

func parseExecution(execution *Execution1) (TaskArr, error) {
    size := 0
    ret := make(TaskArr, 0)
    var err error = nil
    tasks := execution.Tasks
    definitions := execution.Definitions

    for _, task := range tasks {
        var def Task
        var exists bool
        if def, exists = definitions[task.Task]; exists {
            for j, vars := range task.Vars {
                if len(vars) == len(def.Vars) {
                    cmd := def.Task
                    for k, param := range vars {
                        cmd = strings.Replace(cmd, def.Vars[k], param, 1)
                    }
                    var entry TaskEntry
                    entry.Exec = task
                    entry.Cmd = cmd
                    entry.Desc = task.Desc[j]
                    entry.Ret = def.Type
                    entry.Scale = task.Scale
                    if len(task.Units) == len(task.Reports) {
                        entry.Units = task.Units
                    } else {
                        err = errors.New("Task '" + task.Task + "' reports and units lengths do not match")
                        break
                    }
                    ret = append(ret, entry)
                    size = size + 1
                } else {
                    err = errors.New("Task '" + task.Task + "' vars do not match definitions")
                    break
                }
            }
        } else {
            err = errors.New("Task '" + task.Task + "' is not found in definitions")
            break
        }
    }

    if size == 0 && err == nil {
        err = errors.New("No tasks found")
    } else {
        i := 0
        for _, task := range ret {
            if task.Exec.Active {
                ret[i] = task
                i++
            }
        }
        if i == 0 {
            err = errors.New("No active tasks found")
        } else {
            ret = ret[:i]
        }
    }

    sort.Sort(ret)

    return ret, err
}

func reportTargets(reports *[]database) {
    var maxTicks int = 20
    var yScale uint64 = 50
    var total uint64 = 0
    _stdscr.Move(0,0)

    for i := range *reports {
        x := 0
        _stdscr.MovePrintf(i, x, "%-15s", (*reports)[i].target)

        x += 15
        _stdscr.MovePrintln(i, x, "[")

        x += 1
        ticks := uint64((*reports)[i].rate) / yScale

        for j := 0; j < maxTicks; j++ {
            if (j * 100 / maxTicks >= 66) {
                _stdscr.ColorOn(gc.C_RED)
            } else if (j * 100 / maxTicks >= 33) {
                _stdscr.ColorOn(gc.C_YELLOW)
            } else {
                _stdscr.ColorOn(gc.C_CYAN)
            }

            if int(ticks) > j {
                _stdscr.MovePrintln(i, x, "|")
            } else {
                _stdscr.MovePrintln(i, x, " ")
            }

            x++
        }

        _stdscr.ColorOff(gc.C_RED)
        _stdscr.ColorOff(gc.C_YELLOW)
        _stdscr.ColorOff(gc.C_CYAN)
        _stdscr.MovePrintf(i, x, "%6d %s] %s\n", uint64((*reports)[i].rate), (*reports)[i].units, (*reports)[i].task)

        total += uint64((*reports)[i].rate)
    }

    _stdscr.MovePrintf(len(*reports), 0,  "%-15s", "Total")
    _stdscr.MovePrintf(len(*reports), 36, "%6d Mbps\n", total)
    _stdscr.Refresh()
}
<|endoftext|>


<commit_before>package now

import (
    "github.com/hoisie/web.go"
)

func Serve(http string) {
    web.SetStaticDir(ResourceDir())
    web.Get("/now.json", jsonNext)
    web.Get("/now", htmlNext)
    web.Get("/later/", htmlLater)
    web.Get("/later", func (c *web.Context) { c.Redirect(301, "/later/") })
    web.Post("/done", jsonPop)
    web.Post("/now", jsonPushNext)
    web.Post("/later/", jsonLater)

    web.Run(http)
}

<commit_msg>Hey, the README says DELETE /now should do something.<commit_after>package now

import (
    "github.com/hoisie/web.go"
)

func Serve(http string) {
    web.SetStaticDir(ResourceDir())
    web.Get("/now.json", jsonNext)
    web.Get("/now", htmlNext)
    web.Get("/later/", htmlLater)
    web.Get("/later", func (c *web.Context) { c.Redirect(301, "/later/") })
    web.Post("/done", jsonPop)
    web.Post("/now", jsonPushNext)
    web.Post("/later/", jsonLater)
    web.Delete("/now", jsonPop)

    web.Run(http)
}

<|endoftext|>


<commit_before>package berlingo

import (
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func do(ai AI, r io.Reader) (response *Response, response_json []byte, err error) {

	game, err := NewGame(ai, r)
	if err != nil {
		return nil, nil, err
	}

	game.Do()

	response_json, err = game.Response.ToJson()
	if err != nil {
		return nil, nil, err
	}

	return response, response_json, nil
}

// Callback used to process an incoming HTTP request
func serveHttpRequest(ai AI, w http.ResponseWriter, r *http.Request) {

	log.Printf("HTTP: [%v] Processing %v %v", r.RemoteAddr, r.Method, r.RequestURI)
	w.Header().Set("Content-Type", "application/json")

	var input io.Reader
	content_type := r.Header.Get("Content-Type")
	switch {
	case r.Method == "POST" && content_type == "application/json":
		input = r.Body
	case r.Method == "POST" && content_type == "application/x-www-form-urlencoded":
		// Detect & work-around bug https://github.com/thirdside/berlin-ai/issues/4
		r.ParseForm()
		j := `{
				"action": "` + r.Form["action"][0] + `",
				"infos": ` + r.Form["infos"][0] + `,
				"map": ` + r.Form["map"][0] + `,
				"state": ` + r.Form["state"][0] + `
			}`
		input = strings.NewReader(j)
	default:
		log.Printf("HTTP: Replying with error")
		w.Write([]byte(`{"error": "Invalid request"}`))
		return
	}

	_, response_json, err := do(ai, input)
	if err != nil {
		log.Printf("HTTP: Responding with error: %+v\n", err)
		w.Write([]byte("Error"))
	} else {
		log.Printf("HTTP: Responding with moves\n")
		w.Write(response_json)
	}

}

func InitAppEngine(ai AI) {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		serveHttpRequest(ai, w, r)
	})
}

// ServeHttp serves the given AI over HTTP on the given port
func ServeHttp(ai AI, port string) {

	log.Println("Starting HTTP server on port", port)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		serveHttpRequest(ai, w, r)
	})

	err := http.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Println("HTTP Serving Error:", err)
	}

}

// ServeHttp serves the given AI a single time
// Request is read from the given filename
// filename may be supplied as "-" to indicate STDIN
func ServeFile(ai AI, filename string) {

	var fh *os.File
	var err error

	if filename == "-" {
		fh = os.Stdin
	} else {
		fh, err = os.Open(filename)
		if err != nil {
			log.Println("Error opening", filename, ": ", err)
			return
		}
		defer fh.Close()
	}

	_, response_json, err := do(ai, fh)
	if err != nil {
		log.Println("Error processing request:", err)
		return
	}
	os.Stdout.Write(response_json)
}

// Serve will inspect the CLI arguments and automatically call either ServeHttp or ServeFile
func Serve(ai AI) {

	port_or_filename := "-"
	if len(os.Args) >= 2 {
		port_or_filename = os.Args[1]
	}

	_, err := strconv.Atoi(port_or_filename)
	if err == nil {
		ServeHttp(ai, port_or_filename)
	} else {
		ServeFile(ai, port_or_filename)
	}
}
<commit_msg>serveHttp: More defensive request parsing and error messages<commit_after>package berlingo

import (
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func do(ai AI, r io.Reader) (response *Response, response_json []byte, err error) {

	game, err := NewGame(ai, r)
	if err != nil {
		return nil, nil, err
	}

	game.Do()

	response_json, err = game.Response.ToJson()
	if err != nil {
		return nil, nil, err
	}

	return response, response_json, nil
}

// Callback used to process an incoming HTTP request
func serveHttpRequest(ai AI, w http.ResponseWriter, r *http.Request) {

	log.Printf("HTTP: [%v] Processing %v %v", r.RemoteAddr, r.Method, r.RequestURI)
	w.Header().Set("Content-Type", "application/json")

	var input io.Reader
	content_type := r.Header.Get("Content-Type")
	switch {
	case r.Method == "POST" && content_type == "application/json":
		input = r.Body
	case r.Method == "POST" && content_type == "application/x-www-form-urlencoded":
		// Detect & work-around bug https://github.com/thirdside/berlin-ai/issues/4
		r.ParseForm()
		j := `{
				"action": "` + r.Form.Get("action") + `",
				"infos": ` + r.Form.Get("infos") + `,
				"map": ` + r.Form.Get("map") + `,
				"state": ` + r.Form.Get("state") + `
			}`
		input = strings.NewReader(j)
	default:
		log.Printf("HTTP: Replying with error: Invalid request")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"error": "Invalid request"}`))
		return
	}

	_, response_json, err := do(ai, input)
	if err != nil {
		log.Printf("HTTP: Responding with error: %+v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(`{"error": "Internal server error"}`))
	} else {
		log.Printf("HTTP: Responding with moves\n")
		w.Write(response_json)
	}

}

func InitAppEngine(ai AI) {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		serveHttpRequest(ai, w, r)
	})
}

// ServeHttp serves the given AI over HTTP on the given port
func ServeHttp(ai AI, port string) {

	log.Println("Starting HTTP server on port", port)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		serveHttpRequest(ai, w, r)
	})

	err := http.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Println("HTTP Serving Error:", err)
	}

}

// ServeHttp serves the given AI a single time
// Request is read from the given filename
// filename may be supplied as "-" to indicate STDIN
func ServeFile(ai AI, filename string) {

	var fh *os.File
	var err error

	if filename == "-" {
		fh = os.Stdin
	} else {
		fh, err = os.Open(filename)
		if err != nil {
			log.Println("Error opening", filename, ": ", err)
			return
		}
		defer fh.Close()
	}

	_, response_json, err := do(ai, fh)
	if err != nil {
		log.Println("Error processing request:", err)
		return
	}
	os.Stdout.Write(response_json)
}

// Serve will inspect the CLI arguments and automatically call either ServeHttp or ServeFile
func Serve(ai AI) {

	port_or_filename := "-"
	if len(os.Args) >= 2 {
		port_or_filename = os.Args[1]
	}

	_, err := strconv.Atoi(port_or_filename)
	if err == nil {
		ServeHttp(ai, port_or_filename)
	} else {
		ServeFile(ai, port_or_filename)
	}
}
<|endoftext|>


<commit_before>package dynamixel

import (
	"errors"
	"fmt"
	"math"
)

const (

	// Control Table Addresses
	addrStatusReturnLevel byte = 0x10 // 1
	addrTorqueEnable      byte = 0x18 // 1
	addrLed               byte = 0x19 // 1
	addrGoalPosition      byte = 0x1E // 2
	addrMovingSpeed       byte = 0x20 // 2
	addrTorqueLimit       byte = 0x22 // 2

	// Read Only
	addrCurrentPosition byte = 0x24 // 2

	// Limits (from dxl_ax_actuator.htm)
	maxPos   uint16  = 1023
	maxSpeed uint16  = 1023
	maxAngle float64 = 300

	// Unit conversions
	positionToAngle float64 = maxAngle / float64(maxPos) // 0.293255132
	angleToPosition float64 = 1 / positionToAngle        // 3.41
)

type DynamixelServo struct {
	Network   *DynamixelNetwork
	Ident     uint8
	zeroAngle float64

	// Cache of control table values
	statusReturnLevel int
}

// http://support.robotis.com/en/product/dynamixel/ax_series/dxl_ax_actuator.htm
func NewServo(network *DynamixelNetwork, ident uint8) *DynamixelServo {
	s := &DynamixelServo{
		Network:           network,
		Ident:             ident,
		zeroAngle:         150,
		statusReturnLevel: 2,
	}

	return s
}

func (servo *DynamixelServo) Read(startAddress byte, length int) (uint16, error) {
	return servo.Network.ReadData(servo.Ident, startAddress, length)
}

// Ping sends the PING instruction to servo, and waits for the response. Returns
// nil if the ping succeeds, otherwise an error. It's optional, but a very good
// idea, to call this before sending any other instructions to the servo.
func (servo *DynamixelServo) Ping() error {
	return servo.Network.Ping(servo.Ident)
}

// Converts a bool to an int.
func btoi(b bool) uint8 {
	if b {
		return 1
	}
	return 0
}

func low(i int) byte {
	return byte(i & 0xFF)
}

func high(i int) byte {
	return low(i >> 8)
}

func (servo *DynamixelServo) readData(startAddress byte, length int) (uint16, error) {
	if servo.statusReturnLevel == 0 {
		return 0, errors.New("can't READ while Status Return Level is zero")
	}
	return servo.Network.ReadData(servo.Ident, startAddress, length)
}

func (servo *DynamixelServo) writeData(params ...byte) error {
	return servo.Network.WriteData(servo.Ident, (servo.statusReturnLevel == 2), params...)
}

func posDistance(a uint16, b uint16) uint16 {
	return uint16(math.Abs(float64(a) - float64(b)))
}

//
func normalizeAngle(d float64) float64 {
	if d > 180 {
		return normalizeAngle(d - 360)

	} else if d < -180 {
		return normalizeAngle(d + 360)

	} else {
		return d
	}
}

//
// -- High-level interface
//
//    These methods should provide as useful and friendly of an interface to the
//    servo as possible.

func (servo *DynamixelServo) posToAngle(pos uint16) float64 {
	return (positionToAngle * float64(pos)) - servo.zeroAngle
}

func (servo *DynamixelServo) angleToPos(angle float64) uint16 {
	pos := uint16((servo.zeroAngle + angle) * angleToPosition)
	return pos
}

// Sets the origin angle (in degrees).
func (servo *DynamixelServo) SetZero(offset float64) {
	servo.zeroAngle = offset
}

//
// Returns the current position of the servo, relative to the zero angle.
//
func (servo *DynamixelServo) Angle() (float64, error) {
	pos, err := servo.Position()

	if err != nil {
		return 0, err

	} else {
		return servo.posToAngle(pos), nil
	}
}

// MoveTo sets the goal position of the servo by angle (in degrees), where zero
// is the midpoint, 150 deg is max left (clockwise), and -150 deg is max right
// (counter-clockwise). This is generally preferable to calling SetGoalPosition,
// which uses the internal uint16 representation.
//
// If the angle is out of bounds
//
func (servo *DynamixelServo) MoveTo(angle float64) error {
	pos := int(servo.angleToPos(normalizeAngle(angle)))
	return servo.SetGoalPosition(pos)
}

//
// -- Low-level interface
//
//    These methods should follow the Dynamixel protocol docs as closely as
//    possible, with no fancy stuff.
//

// Enables or disables torque.
func (servo *DynamixelServo) SetTorqueEnable(state bool) error {
	return servo.writeData(addrTorqueEnable, btoi(state))
}

// Enables or disables the LED.
func (servo *DynamixelServo) SetLed(state bool) error {
	return servo.writeData(addrLed, btoi(state))
}

// Sets the goal position.
// See: http://support.robotis.com/en/product/dynamixel/ax_series/dxl_ax_actuator.htm#Actuator_Address_1E
func (servo *DynamixelServo) SetGoalPosition(pos int) error {
	if pos < 0 || pos > int(maxPos) {
		return errors.New("goal position out of range")
	}
	return servo.writeData(addrGoalPosition, low(pos), high(pos))
}

// Sets the moving speed.
func (servo *DynamixelServo) SetMovingSpeed(speed int) error {
	if speed < 0 || speed > int(maxSpeed) {
		return errors.New("moving speed out of range")
	}
	return servo.writeData(addrMovingSpeed, low(speed), high(speed))
}

// Sets the torque limit.
func (servo *DynamixelServo) SetTorqueLimit(limit int) error {
	if limit < 0 || limit > 1023 {
		return errors.New("torque limit out of range")
	}
	return servo.writeData(addrTorqueLimit, low(limit), high(limit))
}

// Sets the status return level. Possible values are:
//
// 0 = Only respond to PING commands
// 1 = Only respond to PING and READ commands
// 2 = Respond to all commands
//
// Servos default to 2, but retain the value so long as they're powered up. This
// makes it a very good idea to explicitly set the value after connecting, to
// avoid waiting for status packets which will never arrive.
//
// See: dxl_ax_actuator.htm#Actuator_Address_10
func (servo *DynamixelServo) SetStatusReturnLevel(value int) error {
	servo.Network.Log("SetStatusReturnLevel(%d, %d)", servo.Ident, value)

	if value < 0 || value > 2 {
		return fmt.Errorf("invalid Status Return Level value: %d", value)
	}

	err := servo.writeData(addrStatusReturnLevel, low(value))
	if err != nil {
		return err
	}

	servo.statusReturnLevel = value
	return nil
}

// Returns the current position.
func (servo *DynamixelServo) Position() (uint16, error) {
	return servo.readData(addrCurrentPosition, 2)
}
<commit_msg>Add servo.SetIdent method<commit_after>package dynamixel

import (
	"errors"
	"fmt"
	"math"
)

const (

	// Control Table Addresses (EEPROM)
	addrID                byte = 0x03 // 1
	addrStatusReturnLevel byte = 0x10 // 1
	addrTorqueEnable      byte = 0x18 // 1
	addrLed               byte = 0x19 // 1
	addrGoalPosition      byte = 0x1E // 2
	addrMovingSpeed       byte = 0x20 // 2
	addrTorqueLimit       byte = 0x22 // 2

	// Read Only
	addrCurrentPosition byte = 0x24 // 2

	// Limits (from dxl_ax_actuator.htm)
	maxPos   uint16  = 1023
	maxSpeed uint16  = 1023
	maxAngle float64 = 300

	// Unit conversions
	positionToAngle float64 = maxAngle / float64(maxPos) // 0.293255132
	angleToPosition float64 = 1 / positionToAngle        // 3.41
)

type DynamixelServo struct {
	Network   *DynamixelNetwork
	Ident     uint8
	zeroAngle float64

	// Cache of control table values
	statusReturnLevel int
}

// http://support.robotis.com/en/product/dynamixel/ax_series/dxl_ax_actuator.htm
func NewServo(network *DynamixelNetwork, ident uint8) *DynamixelServo {
	s := &DynamixelServo{
		Network:           network,
		Ident:             ident,
		zeroAngle:         150,
		statusReturnLevel: 2,
	}

	return s
}

// Ping sends the PING instruction to servo, and waits for the response. Returns
// nil if the ping succeeds, otherwise an error. It's optional, but a very good
// idea, to call this before sending any other instructions to the servo.
func (servo *DynamixelServo) Ping() error {
	return servo.Network.Ping(servo.Ident)
}

// Converts a bool to an int.
func btoi(b bool) uint8 {
	if b {
		return 1
	}
	return 0
}

func low(i int) byte {
	return byte(i & 0xFF)
}

func high(i int) byte {
	return low(i >> 8)
}

func (servo *DynamixelServo) readData(startAddress byte, length int) (uint16, error) {
	if servo.statusReturnLevel == 0 {
		return 0, errors.New("can't READ while Status Return Level is zero")
	}
	return servo.Network.ReadData(servo.Ident, startAddress, length)
}

func (servo *DynamixelServo) writeData(params ...byte) error {
	return servo.Network.WriteData(servo.Ident, (servo.statusReturnLevel == 2), params...)
}

func posDistance(a uint16, b uint16) uint16 {
	return uint16(math.Abs(float64(a) - float64(b)))
}

//
func normalizeAngle(d float64) float64 {
	if d > 180 {
		return normalizeAngle(d - 360)

	} else if d < -180 {
		return normalizeAngle(d + 360)

	} else {
		return d
	}
}

//
// -- High-level interface
//
//    These methods should provide as useful and friendly of an interface to the
//    servo as possible.

func (servo *DynamixelServo) posToAngle(pos uint16) float64 {
	return (positionToAngle * float64(pos)) - servo.zeroAngle
}

func (servo *DynamixelServo) angleToPos(angle float64) uint16 {
	pos := uint16((servo.zeroAngle + angle) * angleToPosition)
	return pos
}

// Sets the origin angle (in degrees).
func (servo *DynamixelServo) SetZero(offset float64) {
	servo.zeroAngle = offset
}

//
// Returns the current position of the servo, relative to the zero angle.
//
func (servo *DynamixelServo) Angle() (float64, error) {
	pos, err := servo.Position()

	if err != nil {
		return 0, err

	} else {
		return servo.posToAngle(pos), nil
	}
}

// MoveTo sets the goal position of the servo by angle (in degrees), where zero
// is the midpoint, 150 deg is max left (clockwise), and -150 deg is max right
// (counter-clockwise). This is generally preferable to calling SetGoalPosition,
// which uses the internal uint16 representation.
//
// If the angle is out of bounds
//
func (servo *DynamixelServo) MoveTo(angle float64) error {
	pos := int(servo.angleToPos(normalizeAngle(angle)))
	return servo.SetGoalPosition(pos)
}

//
// -- Low-level interface
//
//    These methods should follow the Dynamixel protocol docs as closely as
//    possible, with no fancy stuff.
//

// Enables or disables torque.
func (servo *DynamixelServo) SetTorqueEnable(state bool) error {
	return servo.writeData(addrTorqueEnable, btoi(state))
}

// Enables or disables the LED.
func (servo *DynamixelServo) SetLed(state bool) error {
	return servo.writeData(addrLed, btoi(state))
}

// Sets the goal position.
// See: http://support.robotis.com/en/product/dynamixel/ax_series/dxl_ax_actuator.htm#Actuator_Address_1E
func (servo *DynamixelServo) SetGoalPosition(pos int) error {
	if pos < 0 || pos > int(maxPos) {
		return errors.New("goal position out of range")
	}
	return servo.writeData(addrGoalPosition, low(pos), high(pos))
}

// Sets the moving speed.
func (servo *DynamixelServo) SetMovingSpeed(speed int) error {
	if speed < 0 || speed > int(maxSpeed) {
		return errors.New("moving speed out of range")
	}
	return servo.writeData(addrMovingSpeed, low(speed), high(speed))
}

// Sets the torque limit.
func (servo *DynamixelServo) SetTorqueLimit(limit int) error {
	if limit < 0 || limit > 1023 {
		return errors.New("torque limit out of range")
	}
	return servo.writeData(addrTorqueLimit, low(limit), high(limit))
}

// Sets the status return level. Possible values are:
//
// 0 = Only respond to PING commands
// 1 = Only respond to PING and READ commands
// 2 = Respond to all commands
//
// Servos default to 2, but retain the value so long as they're powered up. This
// makes it a very good idea to explicitly set the value after connecting, to
// avoid waiting for status packets which will never arrive.
//
// See: dxl_ax_actuator.htm#Actuator_Address_10
func (servo *DynamixelServo) SetStatusReturnLevel(value int) error {
	servo.Network.Log("SetStatusReturnLevel(%d, %d)", servo.Ident, value)

	if value < 0 || value > 2 {
		return fmt.Errorf("invalid Status Return Level value: %d", value)
	}

	err := servo.writeData(addrStatusReturnLevel, low(value))
	if err != nil {
		return err
	}

	servo.statusReturnLevel = value
	return nil
}

// Returns the current position.
func (servo *DynamixelServo) Position() (uint16, error) {
	return servo.readData(addrCurrentPosition, 2)
}

// Changes the identity of the servo.
// This is stored in EEPROM, so will persist between reboots.
func (servo *DynamixelServo) SetIdent(ident int) error {
	servo.LogMethod("SetIdent(%d, %d)", ident)
	i := low(ident)

	if i < 0 || i > 252 {
		return fmt.Errorf("invalid ID (must be 0-252): %d", i)
	}

	err := servo.writeData(addrID, i)
	if err != nil {
		return err
	}

	servo.Ident = i
	return nil
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// beehive's contains-filter.
package containsfilter

import (
	"github.com/muesli/beehive/filters"
	"strings"
)

type ContainsFilter struct {
}

func (filter *ContainsFilter) Name() string {
	return "contains"
}

func (filter *ContainsFilter) Description() string {
	return "This filter passes when a placeholder contains a specific thing"
}

func (filter *ContainsFilter) Passes(data interface{}, value interface{}) bool {
	switch v := data.(type) {
		case string:
			return strings.Contains(v, value.(string))
	}

	return false
}

func init() {
	f := ContainsFilter{}

	filters.RegisterFilter(&f)
}
<commit_msg>* Added FIXME.<commit_after>/*
 *    Copyright (C) 2014 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// beehive's contains-filter.
package containsfilter

import (
	"github.com/muesli/beehive/filters"
	"strings"
)

type ContainsFilter struct {
}

func (filter *ContainsFilter) Name() string {
	return "contains"
}

func (filter *ContainsFilter) Description() string {
	return "This filter passes when a placeholder contains a specific thing"
}

func (filter *ContainsFilter) Passes(data interface{}, value interface{}) bool {
	switch v := data.(type) {
		case string:
			return strings.Contains(v, value.(string))
		//FIXME: support maps
	}

	return false
}

func init() {
	f := ContainsFilter{}

	filters.RegisterFilter(&f)
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// beehive's template-filter.
package templatefilter

import (
	"bytes"
	"html/template"
	"strings"

	"github.com/muesli/beehive/filters"
)

type TemplateFilter struct {
}

func (filter *TemplateFilter) Name() string {
	return "template"
}

func (filter *TemplateFilter) Description() string {
	return "This filter passes when a template-if returns true"
}

func (filter *TemplateFilter) Passes(data interface{}, value interface{}) bool {
	switch v := value.(type) {
	case string:
		var res bytes.Buffer

		funcMap := template.FuncMap{
			"Left": func(values ...interface{}) string {
				return values[0].(string)[:values[1].(int)]
			},
			"Mid": func(values ...interface{}) string {
				if len(values) > 2 {
					return values[0].(string)[values[1].(int):values[2].(int)]
				} else {
					return values[0].(string)[values[1].(int):]
				}
			},
			"Right": func(values ...interface{}) string {
				return values[0].(string)[len(values[0].(string))-values[1].(int):]
			},
			"Split":     strings.Split,
			"HasPrefix": strings.HasPrefix,
			"Last": func(values ...interface{}) string {
				return values[0].([]string)[len(values[0].([]string))-1]
			},
		}

		if strings.Index(v, "{{test") >= 0 {
			v = strings.Replace(v, "{{test", "{{if", -1)
			v += "true{{end}}"
		}

		tmpl, err := template.New("_" + v).Funcs(funcMap).Parse(v)
		if err == nil {
			err = tmpl.Execute(&res, data)
		}
		if err != nil {
			panic(err)
		}

		return res.String() == "true"
	}

	return false
}

func init() {
	f := TemplateFilter{}

	filters.RegisterFilter(&f)
}
<commit_msg>Added strings.HasSuffix as a template function<commit_after>/*
 *    Copyright (C) 2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// beehive's template-filter.
package templatefilter

import (
	"bytes"
	"html/template"
	"strings"

	"github.com/muesli/beehive/filters"
)

type TemplateFilter struct {
}

func (filter *TemplateFilter) Name() string {
	return "template"
}

func (filter *TemplateFilter) Description() string {
	return "This filter passes when a template-if returns true"
}

func (filter *TemplateFilter) Passes(data interface{}, value interface{}) bool {
	switch v := value.(type) {
	case string:
		var res bytes.Buffer

		funcMap := template.FuncMap{
			"Left": func(values ...interface{}) string {
				return values[0].(string)[:values[1].(int)]
			},
			"Mid": func(values ...interface{}) string {
				if len(values) > 2 {
					return values[0].(string)[values[1].(int):values[2].(int)]
				} else {
					return values[0].(string)[values[1].(int):]
				}
			},
			"Right": func(values ...interface{}) string {
				return values[0].(string)[len(values[0].(string))-values[1].(int):]
			},
			"Split":     strings.Split,
			"HasPrefix": strings.HasPrefix,
			"HasSuffix": strings.HasSuffix,
			"Last": func(values ...interface{}) string {
				return values[0].([]string)[len(values[0].([]string))-1]
			},
		}

		if strings.Index(v, "{{test") >= 0 {
			v = strings.Replace(v, "{{test", "{{if", -1)
			v += "true{{end}}"
		}

		tmpl, err := template.New("_" + v).Funcs(funcMap).Parse(v)
		if err == nil {
			err = tmpl.Execute(&res, data)
		}
		if err != nil {
			panic(err)
		}

		return res.String() == "true"
	}

	return false
}

func init() {
	f := TemplateFilter{}

	filters.RegisterFilter(&f)
}
<|endoftext|>


<commit_before>package main

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

type SlackCommand struct {
	Token       string
	Command     string
	Text        string
	ResponseUrl string
	User        SlackUser
	Channel     SlackChannel
	Team        SlackTeam
}

type SlackTeam struct {
	Id     string
	Domain string
}

type SlackChannel struct {
	Team SlackTeam
	Id   string
	Name string
}

type SlackUser struct {
	Team SlackTeam
	Id   string
	Name string
}

func ParseCommand(values url.Values) (SlackCommand, error) {
	team := SlackTeam{
		Id:     values.Get("team_id"),
		Domain: values.Get("team_domain"),
	}
	channel := SlackChannel{
		Team: team,
		Id:   values.Get("channel_id"),
		Name: values.Get("channel_name"),
	}
	user := SlackUser{
		Team: team,
		Id:   values.Get("user_id"),
		Name: values.Get("user_name"),
	}
	command := SlackCommand{
		Token:       values.Get("token"),
		Command:     values.Get("command"),
		Text:        values.Get("text"),
		ResponseUrl: values.Get("response_url"),
		User:        user,
		Channel:     channel,
		Team:        team,
	}
	// validate
	return command, nil
}

type SlackResponse struct {
	Text         string `json:"text"`
	ResponseType string `json:"response_type,omitempty"`
}

func (cmd SlackCommand) Respond(message string, toChannel bool) error {
	response := SlackResponse{}
	response.Text = message
	if toChannel {
		response.ResponseType = "in_channel"
	}

	toSend, err := json.Marshal(response)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST",
		cmd.ResponseUrl,
		bytes.NewReader(toSend))
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "application/json")

	dbgReq(req)
	hc := http.Client{}
	resp, err := hc.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	dbgResp(resp)
	if resp.StatusCode != http.StatusOK {
		return errors.New(resp.Status)
	}

	return nil
}
<commit_msg>works<commit_after>package main

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

type SlackCommand struct {
	Token       string
	Command     string
	Text        string
	ResponseUrl string
	User        SlackUser
	Channel     SlackChannel
	Team        SlackTeam
}

type SlackTeam struct {
	Id     string
	Domain string
}

type SlackChannel struct {
	Team SlackTeam
	Id   string
	Name string
}

type SlackUser struct {
	Team SlackTeam
	Id   string
	Name string
}

func ParseCommand(values url.Values) (SlackCommand, error) {
	team := SlackTeam{
		Id:     values.Get("team_id"),
		Domain: values.Get("team_domain"),
	}
	channel := SlackChannel{
		Team: team,
		Id:   values.Get("channel_id"),
		Name: values.Get("channel_name"),
	}
	user := SlackUser{
		Team: team,
		Id:   values.Get("user_id"),
		Name: values.Get("user_name"),
	}
	command := SlackCommand{
		Token:       values.Get("token"),
		Command:     values.Get("command"),
		Text:        values.Get("text"),
		ResponseUrl: values.Get("response_url"),
		User:        user,
		Channel:     channel,
		Team:        team,
	}
	// validate
	return command, nil
}

type SlackResponse struct {
	Text         string `json:"text"`
	ResponseType string `json:"response_type,omitempty"`
}

func (cmd SlackCommand) Respond(message string, toChannel bool) error {
	response := SlackResponse{}
	response.Text = message
	if toChannel {
		response.ResponseType = "in_channel"
	}

	toSend, err := json.Marshal(response)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST",
		cmd.ResponseUrl,
		bytes.NewReader(toSend))
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "application/json")

	hc := http.Client{}
	resp, err := hc.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	dbgResp(resp)
	if resp.StatusCode != http.StatusOK {
		return errors.New(resp.Status)
	}

	return nil
}
<|endoftext|>


<commit_before>package slicer

import (
	"math"
	"runtime"
	"sort"
	"sync"

	"github.com/fogleman/fauxgl"
)

func SliceMesh(m *fauxgl.Mesh, step float64) []Layer {
	wn := runtime.NumCPU()
	minz := m.BoundingBox().Min.Z
	maxz := m.BoundingBox().Max.Z

	// copy triangles
	triangles := make([]*triangle, len(m.Triangles))
	var wg sync.WaitGroup
	for wi := 0; wi < wn; wi++ {
		wg.Add(1)
		go func(wi int) {
			for i := wi; i < len(m.Triangles); i += wn {
				triangles[i] = newTriangle(m.Triangles[i])
			}
			wg.Done()
		}(wi)
	}
	wg.Wait()

	// sort triangles
	sort.Slice(triangles, func(i, j int) bool {
		return triangles[i].MinZ < triangles[j].MinZ
	})

	// create jobs for workers
	n := int(math.Ceil((maxz - minz) / step))
	in := make(chan job, n)
	out := make(chan Layer, n)
	for wi := 0; wi < wn; wi++ {
		go worker(in, out)
	}
	index := 0
	var active []*triangle
	for i := 0; i < n; i++ {
		z := fauxgl.RoundPlaces(minz+step*float64(i), 8)
		// remove triangles below plane
		newActive := active[:0]
		for _, t := range active {
			if t.MaxZ >= z {
				newActive = append(newActive, t)
			}
		}
		active = newActive
		// add triangles above plane
		for index < len(triangles) && triangles[index].MinZ <= z {
			active = append(active, triangles[index])
			index++
		}
		// copy triangles for worker job
		activeCopy := make([]*triangle, len(active))
		copy(activeCopy, active)
		in <- job{z, activeCopy}
	}
	close(in)

	// read results from workers
	layers := make([]Layer, n)
	for i := 0; i < n; i++ {
		layers[i] = <-out
	}

	// sort layers
	sort.Slice(layers, func(i, j int) bool {
		return layers[i].Z < layers[j].Z
	})
	return layers
}

type job struct {
	Z         float64
	Triangles []*triangle
}

func worker(in chan job, out chan Layer) {
	var paths []Path
	for j := range in {
		paths = paths[:0]
		for _, t := range j.Triangles {
			if v1, v2, ok := intersectTriangle(j.Z, t); ok {
				paths = append(paths, Path{v1, v2})
			}
		}
		out <- Layer{j.Z, joinPaths(paths)}
	}
}

func intersectSegment(z float64, v0, v1 fauxgl.Vector) (fauxgl.Vector, bool) {
	if v0.Z == v1.Z {
		return fauxgl.Vector{}, false
	}
	t := (z - v0.Z) / (v1.Z - v0.Z)
	if t < 0 || t > 1 {
		return fauxgl.Vector{}, false
	}
	v := v0.Add(v1.Sub(v0).MulScalar(t))
	return v, true
}

func intersectTriangle(z float64, t *triangle) (fauxgl.Vector, fauxgl.Vector, bool) {
	v1, ok1 := intersectSegment(z, t.V1, t.V2)
	v2, ok2 := intersectSegment(z, t.V2, t.V3)
	v3, ok3 := intersectSegment(z, t.V3, t.V1)
	var p1, p2 fauxgl.Vector
	if ok1 && ok2 {
		p1, p2 = v1, v2
	} else if ok1 && ok3 {
		p1, p2 = v1, v3
	} else if ok2 && ok3 {
		p1, p2 = v2, v3
	} else {
		return fauxgl.Vector{}, fauxgl.Vector{}, false
	}
	p1 = p1.RoundPlaces(8)
	p2 = p2.RoundPlaces(8)
	if p1 == p2 {
		return fauxgl.Vector{}, fauxgl.Vector{}, false
	}
	n := fauxgl.Vector{p1.Y - p2.Y, p2.X - p1.X, 0}
	if n.Dot(t.N) < 0 {
		return p1, p2, true
	} else {
		return p2, p1, true
	}
}
<commit_msg>slice middle of layer; filter blanks<commit_after>package slicer

import (
	"math"
	"runtime"
	"sort"
	"sync"

	"github.com/fogleman/fauxgl"
)

func SliceMesh(m *fauxgl.Mesh, step float64) []Layer {
	wn := runtime.NumCPU()
	minz := m.BoundingBox().Min.Z
	maxz := m.BoundingBox().Max.Z

	// copy triangles
	triangles := make([]*triangle, len(m.Triangles))
	var wg sync.WaitGroup
	for wi := 0; wi < wn; wi++ {
		wg.Add(1)
		go func(wi int) {
			for i := wi; i < len(m.Triangles); i += wn {
				triangles[i] = newTriangle(m.Triangles[i])
			}
			wg.Done()
		}(wi)
	}
	wg.Wait()

	// sort triangles
	sort.Slice(triangles, func(i, j int) bool {
		return triangles[i].MinZ < triangles[j].MinZ
	})

	// create jobs for workers
	n := int(math.Ceil((maxz - minz) / step))
	in := make(chan job, n)
	out := make(chan Layer, n)
	for wi := 0; wi < wn; wi++ {
		go worker(in, out)
	}
	index := 0
	var active []*triangle
	for i := 0; i < n; i++ {
		z := fauxgl.RoundPlaces(minz+step*float64(i)+step/2, 8)
		// remove triangles below plane
		newActive := active[:0]
		for _, t := range active {
			if t.MaxZ >= z {
				newActive = append(newActive, t)
			}
		}
		active = newActive
		// add triangles above plane
		for index < len(triangles) && triangles[index].MinZ <= z {
			active = append(active, triangles[index])
			index++
		}
		// copy triangles for worker job
		activeCopy := make([]*triangle, len(active))
		copy(activeCopy, active)
		in <- job{z, activeCopy}
	}
	close(in)

	// read results from workers
	layers := make([]Layer, n)
	for i := 0; i < n; i++ {
		layers[i] = <-out
	}

	// sort layers
	sort.Slice(layers, func(i, j int) bool {
		return layers[i].Z < layers[j].Z
	})

	// filter out empty layers
	if len(layers[0].Paths) == 0 {
		layers = layers[1:]
	}
	if len(layers[len(layers)-1].Paths) == 0 {
		layers = layers[:len(layers)-1]
	}

	return layers
}

type job struct {
	Z         float64
	Triangles []*triangle
}

func worker(in chan job, out chan Layer) {
	var paths []Path
	for j := range in {
		paths = paths[:0]
		for _, t := range j.Triangles {
			if v1, v2, ok := intersectTriangle(j.Z, t); ok {
				paths = append(paths, Path{v1, v2})
			}
		}
		out <- Layer{j.Z, joinPaths(paths)}
	}
}

func intersectSegment(z float64, v0, v1 fauxgl.Vector) (fauxgl.Vector, bool) {
	if v0.Z == v1.Z {
		return fauxgl.Vector{}, false
	}
	t := (z - v0.Z) / (v1.Z - v0.Z)
	if t < 0 || t > 1 {
		return fauxgl.Vector{}, false
	}
	v := v0.Add(v1.Sub(v0).MulScalar(t))
	return v, true
}

func intersectTriangle(z float64, t *triangle) (fauxgl.Vector, fauxgl.Vector, bool) {
	v1, ok1 := intersectSegment(z, t.V1, t.V2)
	v2, ok2 := intersectSegment(z, t.V2, t.V3)
	v3, ok3 := intersectSegment(z, t.V3, t.V1)
	var p1, p2 fauxgl.Vector
	if ok1 && ok2 {
		p1, p2 = v1, v2
	} else if ok1 && ok3 {
		p1, p2 = v1, v3
	} else if ok2 && ok3 {
		p1, p2 = v2, v3
	} else {
		return fauxgl.Vector{}, fauxgl.Vector{}, false
	}
	p1 = p1.RoundPlaces(8)
	p2 = p2.RoundPlaces(8)
	if p1 == p2 {
		return fauxgl.Vector{}, fauxgl.Vector{}, false
	}
	n := fauxgl.Vector{p1.Y - p2.Y, p2.X - p1.X, 0}
	if n.Dot(t.N) < 0 {
		return p1, p2, true
	} else {
		return p2, p1, true
	}
}
<|endoftext|>


<commit_before>package cp

// #cgo CFLAGS: -DNDEBUG
// #include "chipmunk/chipmunk.h"
import "C"

type Space struct {
	ptr *C.cpSpace
}

func NewSpace() *Space {
	space := new(Space)
	space.ptr = C.cpSpaceNew()
	return space
}

func (s *Space) GetGravity() (float64, float64) {
	vect := C.cpSpaceGetGravity(s.ptr)
	return float64(vect.x), float64(vect.y)
}

func (s *Space) SetGravity(x float64, y float64) {
	C.cpSpaceSetGravity(s.ptr, C.cpVect{C.CGFloat(x), C.CGFloat(y)})
}
<commit_msg>don't use CGFloat anymore<commit_after>package cp

// #cgo CFLAGS: -DNDEBUG
// #define CP_USE_CGTYPES 0
// #include "chipmunk/chipmunk.h"
import "C"

type Space struct {
	ptr *C.cpSpace
}

func NewSpace() *Space {
	space := new(Space)
	space.ptr = C.cpSpaceNew()
	return space
}

func (s *Space) GetGravity() (float64, float64) {
	vect := C.cpSpaceGetGravity(s.ptr)
	return float64(vect.x), float64(vect.y)
}

func (s *Space) SetGravity(x float64, y float64) {
	C.cpSpaceSetGravity(s.ptr, C.cpVect{C.cpFloat(x), C.cpFloat(y)})
}
<|endoftext|>


<commit_before>// Package text reads any text/* content-type
package text

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/micro/go-micro/codec"
)

type Codec struct {
	Conn io.ReadWriteCloser
}

// Frame gives us the ability to define raw data to send over the pipes
type Frame struct {
	Data []byte
}

func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error {
	return nil
}

func (c *Codec) ReadBody(b interface{}) error {
	// read bytes
	buf, err := ioutil.ReadAll(c.Conn)
	if err != nil {
		return err
	}

	switch b.(type) {
	case *[]byte:
		v := b.(*[]byte)
		*v = buf
	case *Frame:
		v := b.(*Frame)
		v.Data = buf
	default:
		return fmt.Errorf("failed to read body: %v is not type of *[]byte", b)
	}

	return nil
}

func (c *Codec) Write(m *codec.Message, b interface{}) error {
	var v []byte
	switch b.(type) {
	case *Frame:
		v = b.(*Frame).Data
	case *[]byte:
		ve := b.(*[]byte)
		v = *ve
	case []byte:
		v = b.([]byte)
	default:
		return fmt.Errorf("failed to write: %v is not type of *[]byte or []byte", b)
	}
	_, err := c.Conn.Write(v)
	return err
}

func (c *Codec) Close() error {
	return c.Conn.Close()
}

func (c *Codec) String() string {
	return "bytes"
}

func NewCodec(c io.ReadWriteCloser) codec.Codec {
	return &Codec{
		Conn: c,
	}
}
<commit_msg>Fix text codec<commit_after>// Package text reads any text/* content-type
package text

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/micro/go-micro/codec"
)

type Codec struct {
	Conn io.ReadWriteCloser
}

// Frame gives us the ability to define raw data to send over the pipes
type Frame struct {
	Data []byte
}

func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error {
	return nil
}

func (c *Codec) ReadBody(b interface{}) error {
	// read bytes
	buf, err := ioutil.ReadAll(c.Conn)
	if err != nil {
		return err
	}

	switch b.(type) {
	case *string:
		v := b.(*string)
		*v = string(buf)
	case *[]byte:
		v := b.(*[]byte)
		*v = buf
	case *Frame:
		v := b.(*Frame)
		v.Data = buf
	default:
		return fmt.Errorf("failed to read body: %v is not type of *[]byte", b)
	}

	return nil
}

func (c *Codec) Write(m *codec.Message, b interface{}) error {
	var v []byte
	switch b.(type) {
	case *Frame:
		v = b.(*Frame).Data
	case *[]byte:
		ve := b.(*[]byte)
		v = *ve
	case *string:
		ve := b.(*string)
		v = []byte(*ve)
	case string:
		ve := b.(string)
		v = []byte(ve)
	case []byte:
		v = b.([]byte)
	default:
		return fmt.Errorf("failed to write: %v is not type of *[]byte or []byte", b)
	}
	_, err := c.Conn.Write(v)
	return err
}

func (c *Codec) Close() error {
	return c.Conn.Close()
}

func (c *Codec) String() string {
	return "text"
}

func NewCodec(c io.ReadWriteCloser) codec.Codec {
	return &Codec{
		Conn: c,
	}
}
<|endoftext|>


<commit_before>package comborpc

import (
	"io"
	"log"
	"mime"
	"net/http"

	"github.com/flynn/rpcplus"
	"github.com/flynn/rpcplus/jsonrpc"
)

type Server struct {
	s *rpcplus.Server
}

func New(s *rpcplus.Server) *Server {
	return &Server{s}
}

func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)
		w.Write([]byte("405 must CONNECT\n"))
		return
	}

	var serve func(conn io.ReadWriteCloser)
	accept, _, _ := mime.ParseMediaType(req.Header.Get("Accept"))
	switch accept {
	case "application/vnd.flynn.rpc-hijack+gob":
		serve = server.s.ServeConn
	case "application/vnd.flynn.rpc-hijack+json":
		serve = func(conn io.ReadWriteCloser) {
			codec := jsonrpc.NewServerCodec(conn)
			server.s.ServeCodec(codec)
		}
	default:
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(406)
		w.Write([]byte("Accept header must be application/vnd.flynn.rpc-hijack+gob or application/vnd.flynn.rpc-hijack+json\n"))
		return
	}

	conn, _, err := w.(http.Hijacker).Hijack()
	if err != nil {
		log.Print("rpc hijacking error:", req.RemoteAddr, ": ", err.Error())
		return
	}
	conn.Write([]byte("HTTP/1.0 200 Connected to Go RPC\n\n"))
	serve(conn)
}

func (server *Server) HandleHTTP(path string) {
	http.Handle(path, server)
}

func HandleHTTP() {
	New(rpcplus.DefaultServer).HandleHTTP(rpcplus.DefaultRPCPath)
}

func Register(rcvr interface{}) error {
	return rpcplus.Register(rcvr)
}
<commit_msg>comborpc: Default to gob<commit_after>package comborpc

import (
	"io"
	"log"
	"mime"
	"net/http"

	"github.com/flynn/rpcplus"
	"github.com/flynn/rpcplus/jsonrpc"
)

type Server struct {
	s *rpcplus.Server
}

func New(s *rpcplus.Server) *Server {
	return &Server{s}
}

func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)
		w.Write([]byte("405 must CONNECT\n"))
		return
	}

	var serve func(conn io.ReadWriteCloser)
	accept, _, _ := mime.ParseMediaType(req.Header.Get("Accept"))
	switch accept {
	case "application/vnd.flynn.rpc-hijack+json":
		serve = func(conn io.ReadWriteCloser) {
			codec := jsonrpc.NewServerCodec(conn)
			server.s.ServeCodec(codec)
		}
	default:
		serve = server.s.ServeConn
	}

	conn, _, err := w.(http.Hijacker).Hijack()
	if err != nil {
		log.Print("rpc hijacking error:", req.RemoteAddr, ": ", err.Error())
		return
	}
	conn.Write([]byte("HTTP/1.0 200 Connected to Go RPC\n\n"))
	serve(conn)
}

func (server *Server) HandleHTTP(path string) {
	http.Handle(path, server)
}

func HandleHTTP() {
	New(rpcplus.DefaultServer).HandleHTTP(rpcplus.DefaultRPCPath)
}

func Register(rcvr interface{}) error {
	return rpcplus.Register(rcvr)
}
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"fmt"
	"github.com/hashicorp/serf/command/agent"
	"github.com/mitchellh/cli"
	"net"
	"regexp"
	"strings"
)

// MembersCommand is a Command implementation that queries a running
// Serf agent what members are part of the cluster currently.
type MembersCommand struct {
	Ui cli.Ui
}

// A container of member details. Maintaining a command-specific struct here
// makes sense so that the agent.Member struct can evolve without changing the
// keys in the output interface.
type Member struct {
	detail bool
	Name   string            `json:"name"`
	Addr   string            `json:"addr"`
	Port   uint16            `json:"port"`
	Tags   map[string]string `json:"tags"`
	Status string            `json:"status"`
	Proto  map[string]uint8  `json:"protocol"`
}

type MemberContainer struct {
	Members []Member `json:"members"`
}

func (c MemberContainer) String() string {
	var result string
	for _, member := range c.Members {
		// Format the tags as tag1=v1,tag2=v2,...
		var tagPairs []string
		for name, value := range member.Tags {
			tagPairs = append(tagPairs, fmt.Sprintf("%s=%s", name, value))
		}
		tags := strings.Join(tagPairs, ",")

		result += fmt.Sprintf("%s     %s    %s    %s",
			member.Name, member.Addr, member.Status, tags)
		if member.detail {
			result += fmt.Sprintf(
				"    Protocol Version: %d    Available Protocol Range: [%d, %d]",
				member.Proto["version"], member.Proto["min"], member.Proto["max"])
		}
		result += "\n"
	}
	return result
}

func (c *MembersCommand) Help() string {
	helpText := `
Usage: serf members [options]

  Outputs the members of a running Serf agent.

Options:

  -detailed                 Additional information such as protocol verions
                            will be shown (only affects text output format).

  -format                   If provided, output is returned in the specified
                            format. Valid formats are 'json', and 'text' (default)

  -role=<regexp>            If provided, output is filtered to only nodes matching
                            the regular expression for role
                            '-role' is deprecated in favor of '-tag role=foo'.

  -rpc-addr=127.0.0.1:7373  RPC address of the Serf agent.

  -status=<regexp>			If provided, output is filtered to only nodes matching
                            the regular expression for status

  -tag <key>=<regexp>       If provided, output is filtered to only nodes with the
                            tag <key> with value matching the regular expression.
                            tag can be specified multiple times to filter on
                            multiple keys.
`
	return strings.TrimSpace(helpText)
}

func (c *MembersCommand) Run(args []string) int {
	var detailed bool
	var roleFilter, statusFilter, format string
	var tags []string
	var tagRes map[string](*regexp.Regexp)
	cmdFlags := flag.NewFlagSet("members", flag.ContinueOnError)
	cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
	cmdFlags.BoolVar(&detailed, "detailed", false, "detailed output")
	cmdFlags.StringVar(&roleFilter, "role", ".*", "role filter")
	cmdFlags.StringVar(&statusFilter, "status", ".*", "status filter")
	cmdFlags.StringVar(&format, "format", "text", "output format")
	cmdFlags.Var((*agent.AppendSliceValue)(&tags), "tag", "tag filter")
	rpcAddr := RPCAddrFlag(cmdFlags)
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

        // Deprecation warning for role
        if roleFilter != ".*" {
		c.Ui.Output("Deprecation warning: 'Role' has been replaced with 'Tags'")
        }

	// Compile the regexp
	roleRe, err := regexp.Compile(roleFilter)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to compile role regexp: %v", err))
		return 1
	}
	statusRe, err := regexp.Compile(statusFilter)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to compile status regexp: %v", err))
		return 1
	}
	tagRes = make(map[string](*regexp.Regexp))
	for _, tag := range tags {
		parts := strings.SplitN(tag, "=", 2)
		if len(parts) != 2 {
			c.Ui.Error(fmt.Sprintf("Invalid tag '%s' provided", tag))
			return 1
		}
		tagRe, err := regexp.Compile(parts[1])
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to compile status regexp: %v", err))
			return 1
		}
		tagRes[parts[0]] = tagRe
	}

	client, err := RPCClient(*rpcAddr)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error connecting to Serf agent: %s", err))
		return 1
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error retrieving members: %s", err))
		return 1
	}

	result := MemberContainer{}

	for _, member := range members {
		allTagsMatch := true
		for tag, re := range tagRes {
			value, ok := member.Tags[tag]
			if !ok || !re.MatchString(value) {
				allTagsMatch = false
			}
		}

		// Skip the non-matching members
		if !allTagsMatch || !roleRe.MatchString(member.Tags["role"]) || !statusRe.MatchString(member.Status) {
			continue
		}

		addr := net.TCPAddr{IP: member.Addr, Port: int(member.Port)}

		result.Members = append(result.Members, Member{
			detail: detailed,
			Name:   member.Name,
			Addr:   addr.String(),
			Port:   member.Port,
			Tags:   member.Tags,
			Status: member.Status,
			Proto: map[string]uint8{
				"min":     member.DelegateMin,
				"max":     member.DelegateMax,
				"version": member.DelegateCur,
			},
		})
	}

	output, err := formatOutput(result, format)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Encoding error: %s", err))
		return 1
	}

	c.Ui.Output(string(output))
	return 0
}

func (c *MembersCommand) Synopsis() string {
	return "Lists the members of a Serf cluster"
}
<commit_msg>formatting<commit_after>package command

import (
	"flag"
	"fmt"
	"github.com/hashicorp/serf/command/agent"
	"github.com/mitchellh/cli"
	"net"
	"regexp"
	"strings"
)

// MembersCommand is a Command implementation that queries a running
// Serf agent what members are part of the cluster currently.
type MembersCommand struct {
	Ui cli.Ui
}

// A container of member details. Maintaining a command-specific struct here
// makes sense so that the agent.Member struct can evolve without changing the
// keys in the output interface.
type Member struct {
	detail bool
	Name   string            `json:"name"`
	Addr   string            `json:"addr"`
	Port   uint16            `json:"port"`
	Tags   map[string]string `json:"tags"`
	Status string            `json:"status"`
	Proto  map[string]uint8  `json:"protocol"`
}

type MemberContainer struct {
	Members []Member `json:"members"`
}

func (c MemberContainer) String() string {
	var result string
	for _, member := range c.Members {
		// Format the tags as tag1=v1,tag2=v2,...
		var tagPairs []string
		for name, value := range member.Tags {
			tagPairs = append(tagPairs, fmt.Sprintf("%s=%s", name, value))
		}
		tags := strings.Join(tagPairs, ",")

		result += fmt.Sprintf("%s     %s    %s    %s",
			member.Name, member.Addr, member.Status, tags)
		if member.detail {
			result += fmt.Sprintf(
				"    Protocol Version: %d    Available Protocol Range: [%d, %d]",
				member.Proto["version"], member.Proto["min"], member.Proto["max"])
		}
		result += "\n"
	}
	return result
}

func (c *MembersCommand) Help() string {
	helpText := `
Usage: serf members [options]

  Outputs the members of a running Serf agent.

Options:

  -detailed                 Additional information such as protocol verions
                            will be shown (only affects text output format).

  -format                   If provided, output is returned in the specified
                            format. Valid formats are 'json', and 'text' (default)

  -role=<regexp>            If provided, output is filtered to only nodes matching
                            the regular expression for role
                            '-role' is deprecated in favor of '-tag role=foo'.

  -rpc-addr=127.0.0.1:7373  RPC address of the Serf agent.

  -status=<regexp>			If provided, output is filtered to only nodes matching
                            the regular expression for status

  -tag <key>=<regexp>       If provided, output is filtered to only nodes with the
                            tag <key> with value matching the regular expression.
                            tag can be specified multiple times to filter on
                            multiple keys.
`
	return strings.TrimSpace(helpText)
}

func (c *MembersCommand) Run(args []string) int {
	var detailed bool
	var roleFilter, statusFilter, format string
	var tags []string
	var tagRes map[string](*regexp.Regexp)
	cmdFlags := flag.NewFlagSet("members", flag.ContinueOnError)
	cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
	cmdFlags.BoolVar(&detailed, "detailed", false, "detailed output")
	cmdFlags.StringVar(&roleFilter, "role", ".*", "role filter")
	cmdFlags.StringVar(&statusFilter, "status", ".*", "status filter")
	cmdFlags.StringVar(&format, "format", "text", "output format")
	cmdFlags.Var((*agent.AppendSliceValue)(&tags), "tag", "tag filter")
	rpcAddr := RPCAddrFlag(cmdFlags)
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	// Deprecation warning for role
	if roleFilter != ".*" {
		c.Ui.Output("Deprecation warning: 'Role' has been replaced with 'Tags'")
	}

	// Compile the regexp
	roleRe, err := regexp.Compile(roleFilter)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to compile role regexp: %v", err))
		return 1
	}
	statusRe, err := regexp.Compile(statusFilter)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to compile status regexp: %v", err))
		return 1
	}
	tagRes = make(map[string](*regexp.Regexp))
	for _, tag := range tags {
		parts := strings.SplitN(tag, "=", 2)
		if len(parts) != 2 {
			c.Ui.Error(fmt.Sprintf("Invalid tag '%s' provided", tag))
			return 1
		}
		tagRe, err := regexp.Compile(parts[1])
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to compile status regexp: %v", err))
			return 1
		}
		tagRes[parts[0]] = tagRe
	}

	client, err := RPCClient(*rpcAddr)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error connecting to Serf agent: %s", err))
		return 1
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error retrieving members: %s", err))
		return 1
	}

	result := MemberContainer{}

	for _, member := range members {
		allTagsMatch := true
		for tag, re := range tagRes {
			value, ok := member.Tags[tag]
			if !ok || !re.MatchString(value) {
				allTagsMatch = false
			}
		}

		// Skip the non-matching members
		if !allTagsMatch || !roleRe.MatchString(member.Tags["role"]) || !statusRe.MatchString(member.Status) {
			continue
		}

		addr := net.TCPAddr{IP: member.Addr, Port: int(member.Port)}

		result.Members = append(result.Members, Member{
			detail: detailed,
			Name:   member.Name,
			Addr:   addr.String(),
			Port:   member.Port,
			Tags:   member.Tags,
			Status: member.Status,
			Proto: map[string]uint8{
				"min":     member.DelegateMin,
				"max":     member.DelegateMax,
				"version": member.DelegateCur,
			},
		})
	}

	output, err := formatOutput(result, format)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Encoding error: %s", err))
		return 1
	}

	c.Ui.Output(string(output))
	return 0
}

func (c *MembersCommand) Synopsis() string {
	return "Lists the members of a Serf cluster"
}
<|endoftext|>


<commit_before>package commands

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/EngineerBetter/concourse-up/terraform"

	"github.com/EngineerBetter/concourse-up/bosh"
	"github.com/EngineerBetter/concourse-up/certs"
	"github.com/EngineerBetter/concourse-up/commands/deploy"
	"github.com/EngineerBetter/concourse-up/concourse"
	"github.com/EngineerBetter/concourse-up/config"
	"github.com/EngineerBetter/concourse-up/fly"
	"github.com/EngineerBetter/concourse-up/iaas"
	"github.com/EngineerBetter/concourse-up/util"

	cli "gopkg.in/urfave/cli.v1"
)

const maxAllowedNameLength = 12

var initialDeployArgs deploy.Args

var deployFlags = []cli.Flag{
	cli.StringFlag{
		Name:        "region",
		Usage:       "(optional) AWS region",
		EnvVar:      "AWS_REGION",
		Destination: &initialDeployArgs.AWSRegion,
	},
	cli.StringFlag{
		Name:        "domain",
		Usage:       "(optional) Domain to use as endpoint for Concourse web interface (eg: ci.myproject.com)",
		EnvVar:      "DOMAIN",
		Destination: &initialDeployArgs.Domain,
	},
	cli.StringFlag{
		Name:        "tls-cert",
		Usage:       "(optional) TLS cert to use with Concourse endpoint",
		EnvVar:      "TLS_CERT",
		Destination: &initialDeployArgs.TLSCert,
	},
	cli.StringFlag{
		Name:        "tls-key",
		Usage:       "(optional) TLS private key to use with Concourse endpoint",
		EnvVar:      "TLS_KEY",
		Destination: &initialDeployArgs.TLSKey,
	},
	cli.IntFlag{
		Name:        "workers",
		Usage:       "(optional) Number of Concourse worker instances to deploy",
		EnvVar:      "WORKERS",
		Value:       1,
		Destination: &initialDeployArgs.WorkerCount,
	},
	cli.StringFlag{
		Name:        "worker-size",
		Usage:       "(optional) Size of Concourse workers. Can be medium, large, xlarge, 2xlarge, 4xlarge, 12xlarge or 24xlarge",
		EnvVar:      "WORKER_SIZE",
		Value:       "xlarge",
		Destination: &initialDeployArgs.WorkerSize,
	},
	cli.StringFlag{
		Name:        "worker-type",
		Usage:       "(optional) Specify a worker type for aws (m5 or m4)",
		EnvVar:      "WORKER_TYPE",
		Value:       "m4",
		Destination: &initialDeployArgs.WorkerType,
	},
	cli.StringFlag{
		Name:        "web-size",
		Usage:       "(optional) Size of Concourse web node. Can be small, medium, large, xlarge, 2xlarge",
		EnvVar:      "WEB_SIZE",
		Value:       "small",
		Destination: &initialDeployArgs.WebSize,
	},
	cli.BoolFlag{
		Name:        "self-update",
		Usage:       "(optional) Causes Concourse-up to exit as soon as the BOSH deployment starts. May only be used when upgrading an existing deployment",
		EnvVar:      "SELF_UPDATE",
		Hidden:      true,
		Destination: &initialDeployArgs.SelfUpdate,
	},
	cli.StringFlag{
		Name:        "db-size",
		Usage:       "(optional) Size of Concourse RDS instance. Can be small, medium, large, xlarge, 2xlarge, or 4xlarge",
		EnvVar:      "DB_SIZE",
		Value:       "small",
		Destination: &initialDeployArgs.DBSize,
	},
	cli.BoolTFlag{
		Name:        "spot",
		Usage:       "(optional) Use spot instances for workers. Can be true/false (default: true)",
		EnvVar:      "SPOT",
		Destination: &initialDeployArgs.Spot,
	},
	cli.BoolTFlag{
		Name:        "preemptible",
		Usage:       "(optional) Use preemptible instances for workers. Can be true/false (default: true)",
		EnvVar:      "PREEMPTIBLE",
		Destination: &initialDeployArgs.Preemptible,
	},
	cli.StringFlag{
		Name:        "allow-ips",
		Usage:       "(optional) Comma separated list of IP addresses or CIDR ranges to allow access to",
		EnvVar:      "ALLOW_IPS",
		Value:       "0.0.0.0/0",
		Destination: &initialDeployArgs.AllowIPs,
	},
	cli.StringFlag{
		Name:        "github-auth-client-id",
		Usage:       "(optional) Client ID for a github OAuth application - Used for Github Auth",
		EnvVar:      "GITHUB_AUTH_CLIENT_ID",
		Destination: &initialDeployArgs.GithubAuthClientID,
	},
	cli.StringFlag{
		Name:        "github-auth-client-secret",
		Usage:       "(optional) Client Secret for a github OAuth application - Used for Github Auth",
		EnvVar:      "GITHUB_AUTH_CLIENT_SECRET",
		Destination: &initialDeployArgs.GithubAuthClientSecret,
	},
	cli.StringSliceFlag{
		Name:  "add-tag",
		Usage: "(optional) Key=Value pair to tag EC2 instances with - Multiple tags can be applied with multiple uses of this flag",
		Value: &initialDeployArgs.Tags,
	},
	cli.StringFlag{
		Name:        "namespace",
		Usage:       "(optional) Specify a namespace for deployments in order to group them in a meaningful way",
		EnvVar:      "NAMESPACE",
		Destination: &initialDeployArgs.Namespace,
	},
	cli.StringFlag{
		Name:        "zone",
		Usage:       "(optional) Specify an availability zone",
		EnvVar:      "ZONE",
		Destination: &initialDeployArgs.Zone,
	},
}

func deployAction(c *cli.Context, deployArgs deploy.Args, chosenIaas string, iaasFactory iaas.Factory) error {
	name := c.Args().Get(0)
	if name == "" {
		return errors.New("Usage is `concourse-up deploy <name>`")
	}

	version := c.App.Version

	deployArgs, err := validateDeployArgs(c, deployArgs)
	if err != nil {
		return err
	}

	deployArgs, err = setZoneAndRegion(deployArgs, chosenIaas)
	if err != nil {
		return err
	}

	err = validateNameLength(name, deployArgs, chosenIaas)
	if err != nil {
		return err
	}

	client, err := buildClient(name, version, deployArgs, chosenIaas, iaasFactory)
	if err != nil {
		return err
	}

	return client.Deploy()
}

func validateDeployArgs(c *cli.Context, deployArgs deploy.Args) (deploy.Args, error) {
	err := deployArgs.MarkSetFlags(c)
	if err != nil {
		return deployArgs, err
	}

	if err = deployArgs.Validate(); err != nil {
		return deployArgs, err
	}

	return deployArgs, nil
}

func setZoneAndRegion(deployArgs deploy.Args, chosenIaas string) (deploy.Args, error) {
	if !deployArgs.AWSRegionIsSet {
		switch strings.ToUpper(chosenIaas) {
		case awsConst: //nolint
			deployArgs.AWSRegion = "eu-west-1" //nolint
		case gcpConst: //nolint
			deployArgs.AWSRegion = "europe-west1" //nolint
		}
	}

	if deployArgs.ZoneIsSet && deployArgs.AWSRegionIsSet {
		if err := zoneBelongsToRegion(deployArgs.Zone, deployArgs.AWSRegion); err != nil {
			return deployArgs, err
		}
	}

	if deployArgs.ZoneIsSet && !deployArgs.AWSRegionIsSet {
		region, message := regionFromZone(deployArgs.Zone)
		if region != "" {
			deployArgs.AWSRegion = region
			fmt.Print(message)
		}
	}

	return deployArgs, nil
}

func regionFromZone(zone string) (string, string) {
	re := regexp.MustCompile(`(?m)^\w+-\w+-\d`)
	regionFound := re.FindString(zone)
	if regionFound != "" {
		return regionFound, fmt.Sprintf("No region provided, please note that your zone will be paired with a matching region.\nThis region: %s is used for deployment.\n", regionFound)
	}
	return "", ""
}

func zoneBelongsToRegion(zone, region string) error {
	if !strings.Contains(zone, region) {
		return fmt.Errorf("The region and the zones provided do not match. Please note that the zone %s needs to be within a %s region", zone, region)
	}
	return nil
}

func validateNameLength(name string, args deploy.Args, chosenIaas string) error {
	if strings.ToUpper(chosenIaas) == "GCP" {
		if len(name) > maxAllowedNameLength {
			return fmt.Errorf("deployment name %s is too long. %d character limit", name, maxAllowedNameLength)
		}
	}

	return nil
}

func buildClient(name, version string, deployArgs deploy.Args, chosenIaas string, iaasFactory iaas.Factory) (*concourse.Client, error) {
	awsClient, err := iaasFactory(chosenIaas, deployArgs.AWSRegion)
	if err != nil {
		return nil, err
	}
	terraformClient, err := terraform.New(terraform.DownloadTerraform())
	if err != nil {
		return nil, err
	}

	maintainer, err := concourse.NewMaintainer(chosenIaas)
	if err != nil {
		return nil, err
	}

	client := concourse.NewClient(
		awsClient,
		terraformClient,
		bosh.New,
		fly.New,
		certs.Generate,
		config.New(awsClient, name, deployArgs.Namespace),
		&deployArgs,
		os.Stdout,
		os.Stderr,
		util.FindUserIP,
		certs.NewAcmeClient,
		version,
		maintainer,
	)

	return client, nil
}

var deployCmd = cli.Command{
	Name:      "deploy",
	Aliases:   []string{"d"},
	Usage:     "Deploys or updates a Concourse",
	ArgsUsage: "<name>",
	Flags:     deployFlags,
	Action: func(c *cli.Context) error {
		return deployAction(c, initialDeployArgs, chosenIaas, iaas.New)
	},
}
<commit_msg>pass provider to deploy command, not factory function<commit_after>package commands

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/EngineerBetter/concourse-up/terraform"

	"github.com/EngineerBetter/concourse-up/bosh"
	"github.com/EngineerBetter/concourse-up/certs"
	"github.com/EngineerBetter/concourse-up/commands/deploy"
	"github.com/EngineerBetter/concourse-up/concourse"
	"github.com/EngineerBetter/concourse-up/config"
	"github.com/EngineerBetter/concourse-up/fly"
	"github.com/EngineerBetter/concourse-up/iaas"
	"github.com/EngineerBetter/concourse-up/util"

	cli "gopkg.in/urfave/cli.v1"
)

const maxAllowedNameLength = 12

var initialDeployArgs deploy.Args

var deployFlags = []cli.Flag{
	cli.StringFlag{
		Name:        "region",
		Usage:       "(optional) AWS region",
		EnvVar:      "AWS_REGION",
		Destination: &initialDeployArgs.AWSRegion,
	},
	cli.StringFlag{
		Name:        "domain",
		Usage:       "(optional) Domain to use as endpoint for Concourse web interface (eg: ci.myproject.com)",
		EnvVar:      "DOMAIN",
		Destination: &initialDeployArgs.Domain,
	},
	cli.StringFlag{
		Name:        "tls-cert",
		Usage:       "(optional) TLS cert to use with Concourse endpoint",
		EnvVar:      "TLS_CERT",
		Destination: &initialDeployArgs.TLSCert,
	},
	cli.StringFlag{
		Name:        "tls-key",
		Usage:       "(optional) TLS private key to use with Concourse endpoint",
		EnvVar:      "TLS_KEY",
		Destination: &initialDeployArgs.TLSKey,
	},
	cli.IntFlag{
		Name:        "workers",
		Usage:       "(optional) Number of Concourse worker instances to deploy",
		EnvVar:      "WORKERS",
		Value:       1,
		Destination: &initialDeployArgs.WorkerCount,
	},
	cli.StringFlag{
		Name:        "worker-size",
		Usage:       "(optional) Size of Concourse workers. Can be medium, large, xlarge, 2xlarge, 4xlarge, 12xlarge or 24xlarge",
		EnvVar:      "WORKER_SIZE",
		Value:       "xlarge",
		Destination: &initialDeployArgs.WorkerSize,
	},
	cli.StringFlag{
		Name:        "worker-type",
		Usage:       "(optional) Specify a worker type for aws (m5 or m4)",
		EnvVar:      "WORKER_TYPE",
		Value:       "m4",
		Destination: &initialDeployArgs.WorkerType,
	},
	cli.StringFlag{
		Name:        "web-size",
		Usage:       "(optional) Size of Concourse web node. Can be small, medium, large, xlarge, 2xlarge",
		EnvVar:      "WEB_SIZE",
		Value:       "small",
		Destination: &initialDeployArgs.WebSize,
	},
	cli.BoolFlag{
		Name:        "self-update",
		Usage:       "(optional) Causes Concourse-up to exit as soon as the BOSH deployment starts. May only be used when upgrading an existing deployment",
		EnvVar:      "SELF_UPDATE",
		Hidden:      true,
		Destination: &initialDeployArgs.SelfUpdate,
	},
	cli.StringFlag{
		Name:        "db-size",
		Usage:       "(optional) Size of Concourse RDS instance. Can be small, medium, large, xlarge, 2xlarge, or 4xlarge",
		EnvVar:      "DB_SIZE",
		Value:       "small",
		Destination: &initialDeployArgs.DBSize,
	},
	cli.BoolTFlag{
		Name:        "spot",
		Usage:       "(optional) Use spot instances for workers. Can be true/false (default: true)",
		EnvVar:      "SPOT",
		Destination: &initialDeployArgs.Spot,
	},
	cli.BoolTFlag{
		Name:        "preemptible",
		Usage:       "(optional) Use preemptible instances for workers. Can be true/false (default: true)",
		EnvVar:      "PREEMPTIBLE",
		Destination: &initialDeployArgs.Preemptible,
	},
	cli.StringFlag{
		Name:        "allow-ips",
		Usage:       "(optional) Comma separated list of IP addresses or CIDR ranges to allow access to",
		EnvVar:      "ALLOW_IPS",
		Value:       "0.0.0.0/0",
		Destination: &initialDeployArgs.AllowIPs,
	},
	cli.StringFlag{
		Name:        "github-auth-client-id",
		Usage:       "(optional) Client ID for a github OAuth application - Used for Github Auth",
		EnvVar:      "GITHUB_AUTH_CLIENT_ID",
		Destination: &initialDeployArgs.GithubAuthClientID,
	},
	cli.StringFlag{
		Name:        "github-auth-client-secret",
		Usage:       "(optional) Client Secret for a github OAuth application - Used for Github Auth",
		EnvVar:      "GITHUB_AUTH_CLIENT_SECRET",
		Destination: &initialDeployArgs.GithubAuthClientSecret,
	},
	cli.StringSliceFlag{
		Name:  "add-tag",
		Usage: "(optional) Key=Value pair to tag EC2 instances with - Multiple tags can be applied with multiple uses of this flag",
		Value: &initialDeployArgs.Tags,
	},
	cli.StringFlag{
		Name:        "namespace",
		Usage:       "(optional) Specify a namespace for deployments in order to group them in a meaningful way",
		EnvVar:      "NAMESPACE",
		Destination: &initialDeployArgs.Namespace,
	},
	cli.StringFlag{
		Name:        "zone",
		Usage:       "(optional) Specify an availability zone",
		EnvVar:      "ZONE",
		Destination: &initialDeployArgs.Zone,
	},
}

func deployAction(c *cli.Context, deployArgs deploy.Args, provider iaas.Provider) error {
	name := c.Args().Get(0)
	if name == "" {
		return errors.New("Usage is `concourse-up deploy <name>`")
	}

	version := c.App.Version

	deployArgs, err := validateDeployArgs(c, deployArgs)
	if err != nil {
		return err
	}

	deployArgs, err = setZoneAndRegion(deployArgs, provider.IAAS())
	if err != nil {
		return err
	}

	err = validateNameLength(name, deployArgs, provider.IAAS())
	if err != nil {
		return err
	}

	client, err := buildClient(name, version, deployArgs, provider)
	if err != nil {
		return err
	}

	return client.Deploy()
}

func validateDeployArgs(c *cli.Context, deployArgs deploy.Args) (deploy.Args, error) {
	err := deployArgs.MarkSetFlags(c)
	if err != nil {
		return deployArgs, err
	}

	if err = deployArgs.Validate(); err != nil {
		return deployArgs, err
	}

	return deployArgs, nil
}

func setZoneAndRegion(deployArgs deploy.Args, chosenIaas string) (deploy.Args, error) {
	if !deployArgs.AWSRegionIsSet {
		switch strings.ToUpper(chosenIaas) {
		case awsConst: //nolint
			deployArgs.AWSRegion = "eu-west-1" //nolint
		case gcpConst: //nolint
			deployArgs.AWSRegion = "europe-west1" //nolint
		}
	}

	if deployArgs.ZoneIsSet && deployArgs.AWSRegionIsSet {
		if err := zoneBelongsToRegion(deployArgs.Zone, deployArgs.AWSRegion); err != nil {
			return deployArgs, err
		}
	}

	if deployArgs.ZoneIsSet && !deployArgs.AWSRegionIsSet {
		region, message := regionFromZone(deployArgs.Zone)
		if region != "" {
			deployArgs.AWSRegion = region
			fmt.Print(message)
		}
	}

	return deployArgs, nil
}

func regionFromZone(zone string) (string, string) {
	re := regexp.MustCompile(`(?m)^\w+-\w+-\d`)
	regionFound := re.FindString(zone)
	if regionFound != "" {
		return regionFound, fmt.Sprintf("No region provided, please note that your zone will be paired with a matching region.\nThis region: %s is used for deployment.\n", regionFound)
	}
	return "", ""
}

func zoneBelongsToRegion(zone, region string) error {
	if !strings.Contains(zone, region) {
		return fmt.Errorf("The region and the zones provided do not match. Please note that the zone %s needs to be within a %s region", zone, region)
	}
	return nil
}

func validateNameLength(name string, args deploy.Args, chosenIaas string) error {
	if strings.ToUpper(chosenIaas) == "GCP" {
		if len(name) > maxAllowedNameLength {
			return fmt.Errorf("deployment name %s is too long. %d character limit", name, maxAllowedNameLength)
		}
	}

	return nil
}

func buildClient(name, version string, deployArgs deploy.Args, provider iaas.Provider) (*concourse.Client, error) {
	terraformClient, err := terraform.New(terraform.DownloadTerraform())
	if err != nil {
		return nil, err
	}

	maintainer, err := concourse.NewMaintainer(provider.IAAS())
	if err != nil {
		return nil, err
	}

	client := concourse.NewClient(
		provider,
		terraformClient,
		bosh.New,
		fly.New,
		certs.Generate,
		config.New(awsClient, name, deployArgs.Namespace),
		&deployArgs,
		os.Stdout,
		os.Stderr,
		util.FindUserIP,
		certs.NewAcmeClient,
		version,
		maintainer,
	)

	return client, nil
}

var deployCmd = cli.Command{
	Name:      "deploy",
	Aliases:   []string{"d"},
	Usage:     "Deploys or updates a Concourse",
	ArgsUsage: "<name>",
	Flags:     deployFlags,
	Action: func(c *cli.Context) error {
		provider, err := iaas.New(chosenIaas, initialDeployArgs.AWSRegion)
		if err != nil {
			return fmt.Errorf("Error creating IAAS-specific provider before deploy action: [%v]", err)
		}
		return deployAction(c, initialDeployArgs, provider)
	},
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"github.com/jingweno/gh/git"
	"os"
)

type Runner struct {
	Args []string
}

func (r *Runner) Execute() error {
	args := NewArgs(os.Args[1:])
	if args.Command == "" {
		usage()
	}

	expandAlias(args)

	for _, cmd := range All() {
		if cmd.Name() == args.Command && cmd.Runnable() {
			if !cmd.GitExtension {
				cmd.Flag.Usage = func() {
					cmd.PrintUsage()
				}
				if err := cmd.Flag.Parse(args.Params); err != nil {
					return err
				}

				args.Params = cmd.Flag.Args()
			}

			cmd.Run(cmd, args)

			cmds := args.Commands()
			length := len(cmds)
			for i, c := range cmds {
				var err error
				if i == (length - 1) {
					err = c.SysExec()
				} else {
					err = c.Exec()
				}

				if err != nil {
					return err
				}
			}

			return nil
		}
	}

	return git.SysExec(args.Command, args.Params...)
}

func expandAlias(args *Args) {
	cmd := args.Command
	expandedCmd, err := git.Config(fmt.Sprintf("alias.%s", cmd))
	if err == nil && expandedCmd != "" {
		args.Command = expandedCmd
	}
}
<commit_msg>Use passin args<commit_after>package commands

import (
	"fmt"
	"github.com/jingweno/gh/git"
)

type Runner struct {
	Args []string
}

func (r *Runner) Execute() error {
	args := NewArgs(r.Args)
	if args.Command == "" {
		usage()
	}

	expandAlias(args)

	for _, cmd := range All() {
		if cmd.Name() == args.Command && cmd.Runnable() {
			if !cmd.GitExtension {
				cmd.Flag.Usage = func() {
					cmd.PrintUsage()
				}
				if err := cmd.Flag.Parse(args.Params); err != nil {
					return err
				}

				args.Params = cmd.Flag.Args()
			}

			cmd.Run(cmd, args)

			cmds := args.Commands()
			length := len(cmds)
			for i, c := range cmds {
				var err error
				if i == (length - 1) {
					err = c.SysExec()
				} else {
					err = c.Exec()
				}

				if err != nil {
					return err
				}
			}

			return nil
		}
	}

	return git.SysExec(args.Command, args.Params...)
}

func expandAlias(args *Args) {
	cmd := args.Command
	expandedCmd, err := git.Config(fmt.Sprintf("alias.%s", cmd))
	if err == nil && expandedCmd != "" {
		args.Command = expandedCmd
	}
}
<|endoftext|>


<commit_before>package common

import (
	log "github.com/Sirupsen/logrus"
)

type Executor interface {
	Prepare(config *RunnerConfig, build *Build) error
	Start() error
	Wait() error
	Finish(err error)
	Cleanup()
}

var executors map[string]func() Executor

func RegisterExecutor(executor string, closure func() Executor) {
	log.Debugln("Registering", executor, "executor...")

	if executors == nil {
		executors = make(map[string]func() Executor)
	}
	if executors[executor] != nil {
		panic("Executor already exist: " + executor)
	}
	executors[executor] = closure
}

func GetExecutor(executor string) Executor {
	if executors == nil {
		return nil
	}

	closure := executors[executor]
	if closure == nil {
		return nil
	}

	return closure()
}
<commit_msg>Allow to fetch list of executor names<commit_after>package common

import (
	log "github.com/Sirupsen/logrus"
)

type Executor interface {
	Prepare(config *RunnerConfig, build *Build) error
	Start() error
	Wait() error
	Finish(err error)
	Cleanup()
}

var executors map[string]func() Executor

func RegisterExecutor(executor string, closure func() Executor) {
	log.Debugln("Registering", executor, "executor...")

	if executors == nil {
		executors = make(map[string]func() Executor)
	}
	if executors[executor] != nil {
		panic("Executor already exist: " + executor)
	}
	executors[executor] = closure
}

func GetExecutor(executor string) Executor {
	if executors == nil {
		return nil
	}

	closure := executors[executor]
	if closure == nil {
		return nil
	}

	return closure()
}

func GetExecutors() []string {
	names := []string{}
	if executors != nil {
		for name, _ := range executors {
			names = append(names, name)
		}
	}
	return names
}
<|endoftext|>


<commit_before>package sqalx

import (
	"database/sql"
	"errors"

	"github.com/jmoiron/sqlx"
	uuid "github.com/satori/go.uuid"
)

var (
	// ErrNotInTransaction is returned when using Commit
	// outside of a transaction.
	ErrNotInTransaction = errors.New("not in transaction")

	// ErrIncompatibleOption is returned when using an option incompatible
	// with the selected driver.
	ErrIncompatibleOption = errors.New("incompatible option")
)

// A Node is a database driver that can manage nested transactions.
type Node interface {
	Driver

	// Close the underlying sqlx connection.
	Close() error
	// Begin a new transaction.
	Beginx() (Node, error)
	// Rollback the associated transaction.
	Rollback() error
	// Commit the assiociated transaction.
	Commit() error
}

// A Driver can query the database. It can either be a *sqlx.DB or a *sqlx.Tx
// and therefore is limited to the methods they have in common.
type Driver interface {
	sqlx.Execer
	sqlx.Queryer
	sqlx.Preparer
	BindNamed(query string, arg interface{}) (string, []interface{}, error)
	DriverName() string
	Get(dest interface{}, query string, args ...interface{}) error
	MustExec(query string, args ...interface{}) sql.Result
	NamedExec(query string, arg interface{}) (sql.Result, error)
	NamedQuery(query string, arg interface{}) (*sqlx.Rows, error)
	PrepareNamed(query string) (*sqlx.NamedStmt, error)
	Preparex(query string) (*sqlx.Stmt, error)
	Rebind(query string) string
	Select(dest interface{}, query string, args ...interface{}) error
}

// New creates a new Node with the given DB.
func New(db *sqlx.DB, options ...Option) (Node, error) {
	n := node{
		db:     db,
		Driver: db,
	}

	for _, opt := range options {
		err := opt(&n)
		if err != nil {
			return nil, err
		}
	}

	return &n, nil
}

// Connect to a database.
func Connect(driverName, dataSourceName string, options ...Option) (Node, error) {
	db, err := sqlx.Connect(driverName, dataSourceName)
	if err != nil {
		return nil, err
	}

	node, err := New(db, options...)
	if err != nil {
		// the connection has been opened within this function, we must close it
		// on error.
		db.Close()
		return nil, err
	}

	return node, nil
}

type node struct {
	Driver
	db               *sqlx.DB
	tx               *sqlx.Tx
	savePointID      string
	savePointEnabled bool
	nested           bool
}

func (n *node) Close() error {
	return n.db.Close()
}

func (n node) Beginx() (Node, error) {
	var err error

	switch {
	case n.tx == nil:
		// new actual transaction
		n.tx, err = n.db.Beginx()
		n.Driver = n.tx
	case n.savePointEnabled:
		// already in a transaction: using savepoints
		n.nested = true
		n.savePointID = uuid.NewV1().String()
		_, err = n.tx.Exec("SAVEPOINT $1", n.savePointID)
	default:
		// already in a transaction: reusing current transaction
		n.nested = true
	}

	if err != nil {
		return nil, err
	}

	return &n, nil
}

func (n *node) Rollback() error {
	if n.tx == nil {
		return nil
	}

	var err error

	if n.savePointEnabled && n.savePointID != "" {
		_, err = n.tx.Exec("ROLLBACK TO SAVEPOINT $1", n.savePointID)
	} else if !n.nested {
		err = n.tx.Rollback()
	}

	if err != nil {
		return err
	}

	n.tx = nil
	n.Driver = nil

	return nil
}

func (n *node) Commit() error {
	if n.tx == nil {
		return ErrNotInTransaction
	}

	var err error

	if n.savePointID != "" {
		_, err = n.tx.Exec("RELEASE TO SAVEPOINT $1", n.savePointID)
	} else if !n.nested {
		err = n.tx.Commit()
	}

	if err != nil {
		return err
	}

	n.tx = nil
	n.Driver = nil

	return nil
}

// Option to configure sqalx
type Option func(*node) error

// SavePoint option enables PostgreSQL Savepoints for nested transactions.
func SavePoint(enabled bool) Option {
	return func(n *node) error {
		if enabled && n.db.DriverName() != "postgres" {
			return ErrIncompatibleOption
		}
		n.savePointEnabled = enabled
		return nil
	}
}
<commit_msg>fix(Savepoint): Fix multiple SQL syntax errors<commit_after>package sqalx

import (
	"database/sql"
	"errors"
	"strings"

	"github.com/jmoiron/sqlx"
	uuid "github.com/satori/go.uuid"
)

var (
	// ErrNotInTransaction is returned when using Commit
	// outside of a transaction.
	ErrNotInTransaction = errors.New("not in transaction")

	// ErrIncompatibleOption is returned when using an option incompatible
	// with the selected driver.
	ErrIncompatibleOption = errors.New("incompatible option")
)

// A Node is a database driver that can manage nested transactions.
type Node interface {
	Driver

	// Close the underlying sqlx connection.
	Close() error
	// Begin a new transaction.
	Beginx() (Node, error)
	// Rollback the associated transaction.
	Rollback() error
	// Commit the assiociated transaction.
	Commit() error
}

// A Driver can query the database. It can either be a *sqlx.DB or a *sqlx.Tx
// and therefore is limited to the methods they have in common.
type Driver interface {
	sqlx.Execer
	sqlx.Queryer
	sqlx.Preparer
	BindNamed(query string, arg interface{}) (string, []interface{}, error)
	DriverName() string
	Get(dest interface{}, query string, args ...interface{}) error
	MustExec(query string, args ...interface{}) sql.Result
	NamedExec(query string, arg interface{}) (sql.Result, error)
	NamedQuery(query string, arg interface{}) (*sqlx.Rows, error)
	PrepareNamed(query string) (*sqlx.NamedStmt, error)
	Preparex(query string) (*sqlx.Stmt, error)
	Rebind(query string) string
	Select(dest interface{}, query string, args ...interface{}) error
}

// New creates a new Node with the given DB.
func New(db *sqlx.DB, options ...Option) (Node, error) {
	n := node{
		db:     db,
		Driver: db,
	}

	for _, opt := range options {
		err := opt(&n)
		if err != nil {
			return nil, err
		}
	}

	return &n, nil
}

// Connect to a database.
func Connect(driverName, dataSourceName string, options ...Option) (Node, error) {
	db, err := sqlx.Connect(driverName, dataSourceName)
	if err != nil {
		return nil, err
	}

	node, err := New(db, options...)
	if err != nil {
		// the connection has been opened within this function, we must close it
		// on error.
		db.Close()
		return nil, err
	}

	return node, nil
}

type node struct {
	Driver
	db               *sqlx.DB
	tx               *sqlx.Tx
	savePointID      string
	savePointEnabled bool
	nested           bool
}

func (n *node) Close() error {
	return n.db.Close()
}

func (n node) Beginx() (Node, error) {
	var err error

	switch {
	case n.tx == nil:
		// new actual transaction
		n.tx, err = n.db.Beginx()
		n.Driver = n.tx
	case n.savePointEnabled:
		// already in a transaction: using savepoints
		n.nested = true
		// savepoints name must start with a char and cannot contain dash (-)
		n.savePointID = "sp_" + strings.Replace(uuid.NewV1().String(), "-", "_", -1)
		_, err = n.tx.Exec("SAVEPOINT " + n.savePointID)
	default:
		// already in a transaction: reusing current transaction
		n.nested = true
	}

	if err != nil {
		return nil, err
	}

	return &n, nil
}

func (n *node) Rollback() error {
	if n.tx == nil {
		return nil
	}

	var err error

	if n.savePointEnabled && n.savePointID != "" {
		_, err = n.tx.Exec("ROLLBACK TO SAVEPOINT " + n.savePointID)
	} else if !n.nested {
		err = n.tx.Rollback()
	}

	if err != nil {
		return err
	}

	n.tx = nil
	n.Driver = nil

	return nil
}

func (n *node) Commit() error {
	if n.tx == nil {
		return ErrNotInTransaction
	}

	var err error

	if n.savePointID != "" {
		_, err = n.tx.Exec("RELEASE SAVEPOINT " + n.savePointID)
	} else if !n.nested {
		err = n.tx.Commit()
	}

	if err != nil {
		return err
	}

	n.tx = nil
	n.Driver = nil

	return nil
}

// Option to configure sqalx
type Option func(*node) error

// SavePoint option enables PostgreSQL Savepoints for nested transactions.
func SavePoint(enabled bool) Option {
	return func(n *node) error {
		if enabled && n.db.DriverName() != "postgres" {
			return ErrIncompatibleOption
		}
		n.savePointEnabled = enabled
		return nil
	}
}
<|endoftext|>