<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"context"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"
)

var (
	commonCmdCaptures = []CommandCapturer{
		{"/bin/date", nil},
		{"/bin/uname", []string{"-a"}},
		{"/bin/ps", []string{"uax"}},
		{"/bin/netstat", []string{"-tulpn"}},
		{"/sbin/iptables-save", nil},
		{"/sbin/ifconfig", nil},
		{"/sbin/route", nil},
		{"/usr/sbin/brctl", []string{"show"}},
		{"/bin/dmesg", nil},
		{"/usr/bin/docker", []string{"ps"}},
		{"/usr/bin/tail", []string{"-20000", "/var/log/docker.log"}},
		{"/usr/bin/tail", []string{"-20000", "/var/log/messages"}},
		{"/bin/mount", nil},
		{"/bin/df", []string{"-h"}},
		{"/bin/ls", []string{"-l", "/var"}},
		{"/bin/ls", []string{"-l", "/var/lib"}},
		{"/bin/ls", []string{"-l", "/var/lib/docker"}},
		{"/usr/bin/diagnostics", nil},
		{"/bin/ping", []string{"-w", "5", "8.8.8.8"}},
		{"/bin/cat", []string{"/etc/docker/daemon.json"}},
		{"/bin/cat", []string{"/etc/network/interfaces"}},
		{"/bin/cat", []string{"/etc/resolv.conf"}},
		{"/bin/cat", []string{"/etc/sysctl.conf"}},
		{"/usr/bin/dig", []string{"docker.com"}},
		{"/usr/bin/dig", []string{"@8.8.8.8", "docker.com"}},
		{"/usr/bin/wget", []string{"-O", "-", "http://www.docker.com/"}},
		{"/usr/bin/wget", []string{"-O", "-", "http://104.239.220.248/"}}, // a www.docker.com address
		{"/usr/bin/wget", []string{"-O", "-", "http://216.58.213.68/"}},   // a www.google.com address
		{"/usr/bin/wget", []string{"-O", "-", "http://91.198.174.192/"}},  // a www.wikipedia.com address
	}
	localCmdCaptures = []CommandCapturer{
		{"/usr/bin/tail", []string{"-100", "/var/log/proxy-vsockd.log"}},
		{"/usr/bin/tail", []string{"-100", "/var/log/vsudd.log"}},
	}
	localCaptures = []Capturer{NewDatabaseCapturer()}
)

func init() {
	for _, c := range commonCmdCaptures {
		localCaptures = append(localCaptures, c)
	}
	for _, c := range localCmdCaptures {
		localCaptures = append(localCaptures, c)
	}
}

// Capturer defines behavior for structs which will capture arbitrary
// diagnostic information and write it to a tar archive with a timeout.
type Capturer interface {
	Capture(time.Duration, *tar.Writer)
}

type CommandCapturer struct {
	command string
	args    []string
}

func (cc CommandCapturer) Capture(timeout time.Duration, w *tar.Writer) {
	stdout := &bytes.Buffer{}
	stderr := &bytes.Buffer{}
	done := make(chan struct{})

	name := strings.Join(append([]string{path.Base(cc.command)}, cc.args...), " ")
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	cmd := exec.CommandContext(ctx, cc.command, cc.args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr

	go runCmd(cmd, done)

	select {
	case <-ctx.Done():
		log.Println("ERROR:", ctx.Err())
	case <-done:
		tarWrite(w, stdout, name+".stdout")
		tarWrite(w, stderr, name+".stderr")
	}

	cancel()
}

// TODO(nathanleclaire): Is the user of log.Fatalln in this function really the
// right choice?  i.e., should the program really exit on failure here?
func tarWrite(w *tar.Writer, buf *bytes.Buffer, headerName string) {
	contents, err := ioutil.ReadAll(buf)
	if err != nil {
		log.Fatalln(err)
	}

	log.Println("HEADER:", headerName)
	log.Println("{")
	contentLines := strings.Split(string(contents), "\n")
	for _, line := range contentLines {
		log.Println(line)
	}
	log.Println("}")

	hdr := &tar.Header{
		Name: headerName,
		Mode: 0644,
		Size: int64(len(contents)),
	}
	if err := w.WriteHeader(hdr); err != nil {
		log.Fatalln(err)
	}
	if _, err := w.Write(contents); err != nil {
		log.Fatalln(err)
	}
}

func runCmd(cmd *exec.Cmd, done chan<- struct{}) {
	if err := cmd.Run(); err != nil {
		log.Println("ERROR:", err)
	}
	done <- struct{}{}
}

type DatabaseCapturer struct {
	*CommandCapturer
}

func NewDatabaseCapturer() DatabaseCapturer {
	return DatabaseCapturer{
		&CommandCapturer{
			command: "/bin/cat",
		},
	}
}

func (dc DatabaseCapturer) Capture(timeout time.Duration, w *tar.Writer) {
	// Dump the database
	dbBase := "/Database/branch/master/ro"
	filepath.Walk(dbBase, func(path string, f os.FileInfo, err error) error {
		if f.Mode().IsRegular() {
			dc.CommandCapturer.args = []string{path}
			dc.CommandCapturer.Capture(timeout, w)
		}
		return nil
	})
}

// Capture is the outer level wrapper function to trigger the capturing of
// information.  Clients are expected to call it with a slice of Capturers
// which define the information to be captured.  By using an interface we can
// flexibly define various capture actions for the various listeners.
//
// It is a passed a tar.Writer which the results of the capture will be written
// to.
func Capture(w *tar.Writer, captures []Capturer) {
	t := 2 * time.Second

	for _, c := range captures {
		c.Capture(t, w)
	}
}
<commit_msg>Use additional parent (global) context<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"context"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"
)

const (
	defaultCommandTimeout = 5 * time.Second

	// Might eventually have some pretty long (~30s) traces in here, so 35
	// seconds seems reasonable.
	allCaptureTimeout = 35 * time.Second
)

var (
	commonCmdCaptures = []CommandCapturer{
		{"/bin/date", nil, defaultCommandTimeout},
		{"/bin/uname", []string{"-a"}, defaultCommandTimeout},
		{"/bin/ps", []string{"uax"}, defaultCommandTimeout},
		{"/bin/netstat", []string{"-tulpn"}, defaultCommandTimeout},
		{"/sbin/iptables-save", nil, defaultCommandTimeout},
		{"/sbin/ifconfig", nil, defaultCommandTimeout},
		{"/sbin/route", nil, defaultCommandTimeout},
		{"/usr/sbin/brctl", []string{"show"}, defaultCommandTimeout},
		{"/bin/dmesg", nil, defaultCommandTimeout},
		{"/usr/bin/docker", []string{"ps"}, defaultCommandTimeout},
		{"/usr/bin/tail", []string{"-20000", "/var/log/docker.log"}, defaultCommandTimeout},
		{"/usr/bin/tail", []string{"-20000", "/var/log/messages"}, defaultCommandTimeout},
		{"/bin/mount", nil, defaultCommandTimeout},
		{"/bin/df", []string{"-h"}, defaultCommandTimeout},
		{"/bin/ls", []string{"-l", "/var"}, defaultCommandTimeout},
		{"/bin/ls", []string{"-l", "/var/lib"}, defaultCommandTimeout},
		{"/bin/ls", []string{"-l", "/var/lib/docker"}, defaultCommandTimeout},
		{"/usr/bin/diagnostics", nil, defaultCommandTimeout},
		{"/bin/ping", []string{"-w", "5", "8.8.8.8"}, 6 * time.Second},
		{"/bin/cat", []string{"/etc/docker/daemon.json"}, defaultCommandTimeout},
		{"/bin/cat", []string{"/etc/network/interfaces"}, defaultCommandTimeout},
		{"/bin/cat", []string{"/etc/resolv.conf"}, defaultCommandTimeout},
		{"/bin/cat", []string{"/etc/sysctl.conf"}, defaultCommandTimeout},
		{"/usr/bin/dig", []string{"docker.com"}, defaultCommandTimeout},
		{"/usr/bin/dig", []string{"@8.8.8.8", "docker.com"}, defaultCommandTimeout},
		{"/usr/bin/wget", []string{"-O", "-", "http://www.docker.com/"}, defaultCommandTimeout},
		{"/usr/bin/wget", []string{"-O", "-", "http://104.239.220.248/"}, defaultCommandTimeout}, // a www.docker.com address
		{"/usr/bin/wget", []string{"-O", "-", "http://216.58.213.68/"}, defaultCommandTimeout},   // a www.google.com address
		{"/usr/bin/wget", []string{"-O", "-", "http://91.198.174.192/"}, defaultCommandTimeout},  // a www.wikipedia.com address
	}
	localCmdCaptures = []CommandCapturer{
		{"/usr/bin/tail", []string{"-100", "/var/log/proxy-vsockd.log"}, defaultCommandTimeout},
		{"/usr/bin/tail", []string{"-100", "/var/log/vsudd.log"}, defaultCommandTimeout},
	}
	localCaptures = []Capturer{NewDatabaseCapturer()}
)

func init() {
	for _, c := range commonCmdCaptures {
		localCaptures = append(localCaptures, c)
	}
	for _, c := range localCmdCaptures {
		localCaptures = append(localCaptures, c)
	}
}

// Capturer defines behavior for structs which will capture arbitrary
// diagnostic information and write it to a tar archive with a timeout.
type Capturer interface {
	Capture(context.Context, *tar.Writer)
}

type CommandCapturer struct {
	command string
	args    []string
	timeout time.Duration
}

func (cc CommandCapturer) Capture(parentCtx context.Context, w *tar.Writer) {
	stdout := &bytes.Buffer{}
	stderr := &bytes.Buffer{}
	done := make(chan struct{})

	name := strings.Join(append([]string{path.Base(cc.command)}, cc.args...), " ")
	ctx, cancel := context.WithTimeout(parentCtx, cc.timeout)
	cmd := exec.CommandContext(ctx, cc.command, cc.args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr

	go runCmd(cmd, done)

	select {
	case <-ctx.Done():
		log.Println("ERROR:", ctx.Err())
	case <-done:
		tarWrite(w, stdout, name+".stdout")
		tarWrite(w, stderr, name+".stderr")
	}

	cancel()
}

// TODO(nathanleclaire): Is the user of log.Fatalln in this function really the
// right choice?  i.e., should the program really exit on failure here?
func tarWrite(w *tar.Writer, buf *bytes.Buffer, headerName string) {
	contents, err := ioutil.ReadAll(buf)
	if err != nil {
		log.Fatalln(err)
	}

	log.Println("HEADER:", headerName)
	log.Println("{")
	contentLines := strings.Split(string(contents), "\n")
	for _, line := range contentLines {
		log.Println(line)
	}
	log.Println("}")

	hdr := &tar.Header{
		Name: headerName,
		Mode: 0644,
		Size: int64(len(contents)),
	}
	if err := w.WriteHeader(hdr); err != nil {
		log.Fatalln(err)
	}
	if _, err := w.Write(contents); err != nil {
		log.Fatalln(err)
	}
}

func runCmd(cmd *exec.Cmd, done chan<- struct{}) {
	if err := cmd.Run(); err != nil {
		log.Println("ERROR:", err)
	}
	done <- struct{}{}
}

type DatabaseCapturer struct {
	*CommandCapturer
}

func NewDatabaseCapturer() DatabaseCapturer {
	return DatabaseCapturer{
		&CommandCapturer{
			command: "/bin/cat",
		},
	}
}

func (dc DatabaseCapturer) Capture(parentCtx context.Context, w *tar.Writer) {
	// Dump the database
	dbBase := "/Database/branch/master/ro"
	filepath.Walk(dbBase, func(path string, f os.FileInfo, err error) error {
		if f.Mode().IsRegular() {
			dc.CommandCapturer.args = []string{path}
			dc.CommandCapturer.Capture(parentCtx, w)
		}
		return nil
	})
}

// Capture is the outer level wrapper function to trigger the capturing of
// information.  Clients are expected to call it with a slice of Capturers
// which define the information to be captured.  By using an interface we can
// flexibly define various capture actions for the various listeners.
//
// It is a passed a tar.Writer which the results of the capture will be written
// to.
func Capture(w *tar.Writer, captures []Capturer) {
	allCaptureCtx, cancel := context.WithTimeout(context.Background(), allCaptureTimeout)
	done := make(chan struct{})

	go func(captures []Capturer, ctx context.Context, done chan<- struct{}) {
		for _, c := range captures {
			c.Capture(ctx, w)
		}
		done <- struct{}{}
	}(captures, allCaptureCtx, done)

	select {
	case <-allCaptureCtx.Done():
		log.Println("Global command context", allCaptureCtx.Err())
	case <-done:
		log.Println("Captures all finished")
	}

	cancel()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"github.com/bowery/prompt"
	"github.com/codegangsta/cli"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	app := cli.NewApp()
	app.Name = "greet"
	app.Usage = "fight the loneliness!"
	app.Action = func(c *cli.Context) {
		println("Hello friend!")
	}

	app.Run(os.Args)

	if len(os.Args) < 2 {
		log.Fatal("No file given.")
	}
	root := filepath.Clean(os.Args[1])

	hash := promptPassword("Password")
	if hash != promptPassword("Repeat") {
		log.Fatal("Passwords do not match.")
	}

	key := []byte(hash)

	for _, file := range listFilesToEncrypt(root) {
		log.Println("Encrypt", file)
		encryptFile(key, file)
	}

	for _, file := range listFilesToDecrypt(root) {
		log.Println("Decrypt", file)
		decryptFile(key, file)
	}
}

func promptPassword(message string) string {
	password, err := prompt.Password(message)
	if err != nil {
		panic(err)
	}
	hasher := sha256.New()
	hasher.Write([]byte(password))
	return string(hasher.Sum(nil))
}

func listFilesToEncrypt(root string) []string {
	files := []string{}
	if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if info.Name()[0:1] == "." {
			return nil
		}
		if filepath.Ext(path) == ".aes" {
			return nil
		}
		files = append(files, path)
		return nil
	}); err != nil {
		panic(err)
	}
	return files
}

func encryptFile(key []byte, clearfile string) {
	encryptedfile := strings.Join([]string{clearfile, "aes"}, ".")

	cleartext, err := ioutil.ReadFile(clearfile)
	if err != nil {
		log.Fatal(err)
	}

	encryptedtext, err := encryptText(key, cleartext)
	if err != nil {
		log.Fatal(err)
	}

	if err := ioutil.WriteFile(encryptedfile, encryptedtext, 0644); err != nil {
		panic(err)
	}
}

func encryptText(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	b := base64.StdEncoding.EncodeToString(text)
	encryptedtext := make([]byte, aes.BlockSize+len(b))
	iv := encryptedtext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(encryptedtext[aes.BlockSize:], []byte(b))
	return encryptedtext, nil
}

func listFilesToDecrypt(root string) []string {
	files := []string{}
	if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if info.Name()[0:1] == "." {
			return nil
		}
		if filepath.Ext(path) == ".aes" {
			files = append(files, path)
		}
		return nil
	}); err != nil {
		panic(err)
	}
	return files
}

func decryptFile(key []byte, encryptedfile string) {
	encryptedtext, err := ioutil.ReadFile(encryptedfile)
	if err != nil {
		log.Fatal(err)
	}

	cleartext, err := decryptText(key, encryptedtext)
	if err != nil {
		log.Fatal(err)
	}

	clearfile := strings.Split(encryptedfile, filepath.Ext(encryptedfile))[0]
	if err := ioutil.WriteFile(clearfile, cleartext, 0644); err != nil {
		panic(err)
	}
}

func decryptText(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	if len(text) < aes.BlockSize {
		return nil, errors.New("encryptedtext too short")
	}
	iv := text[:aes.BlockSize]
	text = text[aes.BlockSize:]
	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(text, text)
	data, err := base64.StdEncoding.DecodeString(string(text))
	if err != nil {
		return nil, err
	}
	return data, nil
}
<commit_msg>update<commit_after>package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"github.com/bowery/prompt"
	"github.com/codegangsta/cli"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	app := cli.NewApp()
	app.Name = "gosafe"
	app.Usage = "encrypt and decrypt files"

	app.Commands = []cli.Command{
		{
			Name:      "encrypt",
			ShortName: "e",
			Usage:     "encrypt the given file or all files inside the given directory",
			Action: func(c *cli.Context) {
				root := filepath.Clean(c.Args().First())
				hash := promptPassword("Password")
				if hash != promptPassword("Repeat") {
					log.Fatal("Passwords do not match.")
				}

				key := []byte(hash)

				for _, file := range listFilesToEncrypt(root) {
					log.Println("Encrypt", file)
					encryptFile(key, file)
				}
			},
		},
		{
			Name:      "decrypt",
			ShortName: "d",
			Usage:     "decrypt the given file or all files inside the given directory",
			Action: func(c *cli.Context) {
				root := filepath.Clean(c.Args().First())
				hash := promptPassword("Password")
				if hash != promptPassword("Repeat") {
					log.Fatal("Passwords do not match.")
				}

				key := []byte(hash)

				for _, file := range listFilesToDecrypt(root) {
					log.Println("Decrypt", file)
					decryptFile(key, file)
				}
			},
		},
	}

	app.Run(os.Args)
}

func promptPassword(message string) string {
	password, err := prompt.Password(message)
	if err != nil {
		panic(err)
	}
	hasher := sha256.New()
	hasher.Write([]byte(password))
	return string(hasher.Sum(nil))
}

func listFilesToEncrypt(root string) []string {
	files := []string{}
	if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if info.Name()[0:1] == "." {
			return nil
		}
		if filepath.Ext(path) == ".aes" {
			return nil
		}
		files = append(files, path)
		return nil
	}); err != nil {
		panic(err)
	}
	return files
}

func encryptFile(key []byte, clearfile string) {
	encryptedfile := strings.Join([]string{clearfile, "aes"}, ".")

	cleartext, err := ioutil.ReadFile(clearfile)
	if err != nil {
		log.Fatal(err)
	}

	encryptedtext, err := encryptText(key, cleartext)
	if err != nil {
		log.Fatal(err)
	}

	if err := ioutil.WriteFile(encryptedfile, encryptedtext, 0644); err != nil {
		panic(err)
	}
}

func encryptText(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	b := base64.StdEncoding.EncodeToString(text)
	encryptedtext := make([]byte, aes.BlockSize+len(b))
	iv := encryptedtext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(encryptedtext[aes.BlockSize:], []byte(b))
	return encryptedtext, nil
}

func listFilesToDecrypt(root string) []string {
	files := []string{}
	if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if info.Name()[0:1] == "." {
			return nil
		}
		if filepath.Ext(path) == ".aes" {
			files = append(files, path)
		}
		return nil
	}); err != nil {
		panic(err)
	}
	return files
}

func decryptFile(key []byte, encryptedfile string) {
	encryptedtext, err := ioutil.ReadFile(encryptedfile)
	if err != nil {
		log.Fatal(err)
	}

	cleartext, err := decryptText(key, encryptedtext)
	if err != nil {
		log.Fatal(err)
	}

	clearfile := strings.Split(encryptedfile, filepath.Ext(encryptedfile))[0]
	if err := ioutil.WriteFile(clearfile, cleartext, 0644); err != nil {
		panic(err)
	}
}

func decryptText(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	if len(text) < aes.BlockSize {
		return nil, errors.New("encryptedtext too short")
	}
	iv := text[:aes.BlockSize]
	text = text[aes.BlockSize:]
	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(text, text)
	data, err := base64.StdEncoding.DecodeString(string(text))
	if err != nil {
		return nil, err
	}
	return data, nil
}
<|endoftext|>


<commit_before>package zog

import (
	"fmt"
	"testing"
)

func TestEncodeBasic(t *testing.T) {
	testCases := []struct {
		buf      []byte
		expected string
	}{
		{[]byte{0x00}, "NOP"},
		{[]byte{0xf3}, "DI"},
		{[]byte{0x04}, "INC B"},
		{[]byte{0x0C}, "INC C"},
		{[]byte{0x34}, "INC (HL)"},
		{[]byte{0xdd, 0x34, 0x10}, "INC (IX+10h)"},
		{[]byte{0xfd, 0x34, 0x10}, "INC (IY+10h)"},
		//		{[]byte{0x77}, "LD (HL), A"},
		//		{[]byte{0xdd, 0x77, 0x10}, "LD (IX+10h), A"},
		//		{[]byte{0xfd, 0x77, 0x10}, "LD (IY+10h), A"},
	}

	for _, tc := range testCases {
		testEncodeOne(t, tc.buf, tc.expected)
	}
}

/*
func TestEncodeAll(t *testing.T) {
	testUtilRunAll(t, func(t *testing.T, byteForm []byte, stringForm string) {
		testEncodeOne(t, byteForm, stringForm)
	})
}
*/

func testEncodeOne(t *testing.T, byteForm []byte, stringForm string) {
	hexBuf := bufToHex(byteForm)

	fmt.Printf("== Encode buf [%s] -> string [%s]\n", hexBuf, stringForm)
	insts, err := Assemble(stringForm)
	if err != nil {
		t.Fatalf("Error for byte [%s]: %s (%s)", hexBuf, err, stringForm)
	}

	if len(insts) == 0 {
		t.Fatalf("No instructions for byte [%s] (%s)", hexBuf, stringForm)
	}
	if len(insts) != 1 {
		t.Fatalf("More than one instruction (%d) for byte [%s]: %v", len(insts), hexBuf, insts)
	}

	encodedBuf := insts[0].Encode()

	if bufToHex(encodedBuf) != bufToHex(byteForm) {
		t.Fatalf("Wrong encode for [%s] [%s] != [%s]", stringForm, bufToHex(encodedBuf), bufToHex(byteForm))
	}
	fmt.Printf("Encoded [%s] to [%s]\n", stringForm, bufToHex(encodedBuf))
}
<commit_msg>correct test forms for INC8<commit_after>package zog

import (
	"fmt"
	"testing"
)

func TestEncodeBasic(t *testing.T) {
	testCases := []struct {
		buf      []byte
		expected string
	}{
		{[]byte{0x00}, "NOP"},
		{[]byte{0xf3}, "DI"},
		{[]byte{0x04}, "INC B"},
		{[]byte{0x0C}, "INC C"},
		{[]byte{0x34}, "INC (HL)"},
		{[]byte{0xdd, 0x34, 0x10}, "INC (IX+0x10)"},
		{[]byte{0xfd, 0x34, 0x10}, "INC (IY+0x10)"},
		//		{[]byte{0x77}, "LD (HL), A"},
		//		{[]byte{0xdd, 0x77, 0x10}, "LD (IX+10h), A"},
		//		{[]byte{0xfd, 0x77, 0x10}, "LD (IY+10h), A"},
	}

	for _, tc := range testCases {
		testEncodeOne(t, tc.buf, tc.expected)
	}
}

/*
func TestEncodeAll(t *testing.T) {
	testUtilRunAll(t, func(t *testing.T, byteForm []byte, stringForm string) {
		testEncodeOne(t, byteForm, stringForm)
	})
}
*/

func testEncodeOne(t *testing.T, byteForm []byte, stringForm string) {
	hexBuf := bufToHex(byteForm)

	fmt.Printf("== Encode buf [%s] -> string [%s]\n", hexBuf, stringForm)
	insts, err := Assemble(stringForm)
	if err != nil {
		t.Fatalf("Error for byte [%s]: %s (%s)", hexBuf, err, stringForm)
	}

	if len(insts) == 0 {
		t.Fatalf("No instructions for byte [%s] (%s)", hexBuf, stringForm)
	}
	if len(insts) != 1 {
		t.Fatalf("More than one instruction (%d) for byte [%s]: %v", len(insts), hexBuf, insts)
	}

	encodedBuf := insts[0].Encode()

	if bufToHex(encodedBuf) != bufToHex(byteForm) {
		t.Fatalf("Wrong encode for [%s] [%s] != [%s]", stringForm, bufToHex(encodedBuf), bufToHex(byteForm))
	}
	fmt.Printf("Encoded [%s] to [%s]\n", stringForm, bufToHex(encodedBuf))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

type Builtin struct {
	Run func(args []string)
}

var BUILTINS = map[string]*Builtin{
	"cd": &Builtin{func(args []string) {
		os.Chdir(args[0])
	}},
	"exit": &Builtin{func(args []string) {
		var code int
		if len(args) == 1 {
			code, _ = strconv.Atoi(args[0])
		}
		os.Exit(code)
	}},
	"exec": &Builtin{func(args []string) {
		cmd := exec.Command(args[0], args[1:]...)
		spawnPrograms(cmd)
	}},
	"set": &Builtin{func(args []string) {
		for _, arg := range args {
			keyValuePair := strings.Split(arg, "=")
			if len(keyValuePair) == 2 {
				os.Setenv(keyValuePair[0], keyValuePair[1])
			}
		}
	}},
}

func init() {
	os.Setenv("PROMPT", "->")
}

func main() {
	prompt()

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		commands := splitOnPipes(scanner.Text())

		var cmds []*exec.Cmd
		for _, command := range commands {
			name, args := parseCommand(command)
			if name == "" {
				continue
			}

			if isBuiltin(name) {
				callBuiltin(name, args)
			} else {
				cmd := exec.Command(name, args...)
				cmds = append(cmds, cmd)
			}
		}

		spawnPrograms(cmds...)
		prompt()
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "Reading standard input:", err)
	}
}

func prompt() {
	fmt.Fprintf(os.Stdout, "%s ", os.Getenv("PROMPT"))
}

func splitOnPipes(line string) (commands []string) {
	commands = strings.Split(line, "|")

	for i, command := range commands {
		commands[i] = strings.TrimSpace(command)
	}

	return
}

func parseCommand(line string) (name string, args []string) {
	regexpBySpace := regexp.MustCompile("\\s+")
	cmd := regexpBySpace.Split(line, -1)

	name = cmd[0]
	// expand environment variables
	// somehow os/exec.Command.Run() doesn't expand automatically
	envVarRegexp := regexp.MustCompile("^\\$(.+)$")
	for _, arg := range cmd[1:] {
		if envVarRegexp.MatchString(arg) {
			match := envVarRegexp.FindStringSubmatch(arg)
			arg = os.Getenv(match[1])
		}

		args = append(args, arg)
	}

	return
}

func isBuiltin(name string) bool {
	_, ok := BUILTINS[name]

	return ok
}

func callBuiltin(name string, args []string) {
	builtin, _ := BUILTINS[name]
	builtin.Run(args)
}

func spawnProgram(name string, args []string, placeHolderOut io.WriteCloser, placeHolderIn io.ReadCloser) {
	cmdFullPath, err := exec.LookPath(name)
	if err != nil {
		fmt.Fprintf(os.Stderr, "osh: command not found: %s\n", name)
		return
	}

	c := exec.Command(cmdFullPath, args...)
	c.Env = os.Environ()
	c.Stdin = placeHolderIn
	c.Stdout = placeHolderOut
	c.Stderr = c.Stdout

	if err = c.Run(); err != nil {
		panic(err)
	}
}

func spawnPrograms(cmds ...*exec.Cmd) {
	stdout, stderr, err := pipeline(cmds)
	if err != nil {
		fmt.Printf("%s\n", err)
	}

	if len(stdout) > 0 {
		fmt.Printf("%s", stdout)
	}

	if len(stderr) > 0 {
		fmt.Printf("%s", stderr)
	}
}

func pipeline(cmds []*exec.Cmd) (pipeLineOutput, collectedStandardError []byte, pipeLineError error) {
	if len(cmds) < 1 {
		return nil, nil, nil
	}

	// Collect the output from the command(s)
	var output bytes.Buffer
	var stderr bytes.Buffer

	last := len(cmds) - 1
	for i, cmd := range cmds[:last] {
		var err error
		// Connect each command's stdin to the previous command's stdout
		if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
			return nil, nil, err
		}
		// Connect each command's stderr to a buffer
		cmd.Stderr = &stderr
	}

	// Connect the output and error for the last command
	cmds[last].Stdout, cmds[last].Stderr = &output, &stderr

	// Start each command
	for _, cmd := range cmds {
		if err := cmd.Start(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Wait for each command to complete
	for _, cmd := range cmds {
		if err := cmd.Wait(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Return the pipeline output and the collected standard error
	return output.Bytes(), stderr.Bytes(), nil
}
<commit_msg>Use better regexp<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

type Builtin struct {
	Run func(args []string)
}

var BUILTINS = map[string]*Builtin{
	"cd": &Builtin{func(args []string) {
		os.Chdir(args[0])
	}},
	"exit": &Builtin{func(args []string) {
		var code int
		if len(args) == 1 {
			code, _ = strconv.Atoi(args[0])
		}
		os.Exit(code)
	}},
	"exec": &Builtin{func(args []string) {
		cmd := exec.Command(args[0], args[1:]...)
		spawnPrograms(cmd)
	}},
	"set": &Builtin{func(args []string) {
		for _, arg := range args {
			keyValuePair := strings.Split(arg, "=")
			if len(keyValuePair) == 2 {
				os.Setenv(keyValuePair[0], keyValuePair[1])
			}
		}
	}},
}

func init() {
	os.Setenv("PROMPT", "->")
}

func main() {
	prompt()

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		commands := splitOnPipes(scanner.Text())

		var cmds []*exec.Cmd
		for _, command := range commands {
			name, args := parseCommand(command)
			if name == "" {
				continue
			}

			if isBuiltin(name) {
				callBuiltin(name, args)
			} else {
				cmd := exec.Command(name, args...)
				cmds = append(cmds, cmd)
			}
		}

		if len(cmds) > 0 {
			spawnPrograms(cmds...)
		}

		prompt()
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "Reading standard input:", err)
	}
}

func prompt() {
	fmt.Fprintf(os.Stdout, "%s ", os.Getenv("PROMPT"))
}

func splitOnPipes(line string) (commands []string) {
	pipeRegexp := regexp.MustCompile("([^\"'|]+)|[\"']([^\"']+)[\"']")
	if pipeRegexp.MatchString(line) {
		commands = pipeRegexp.FindAllString(line, -1)
	} else {
		commands = append(commands, line)
	}

	for i, command := range commands {
		commands[i] = strings.TrimSpace(command)
	}

	return
}

func parseCommand(line string) (name string, args []string) {
	regexpBySpace := regexp.MustCompile("\\s+")
	cmd := regexpBySpace.Split(line, -1)

	name = cmd[0]
	// expand environment variables
	// somehow os/exec.Command.Run() doesn't expand automatically
	envVarRegexp := regexp.MustCompile("^\\$(.+)$")
	for _, arg := range cmd[1:] {
		if envVarRegexp.MatchString(arg) {
			match := envVarRegexp.FindStringSubmatch(arg)
			arg = os.Getenv(match[1])
		}

		args = append(args, arg)
	}

	return
}

func isBuiltin(name string) bool {
	_, ok := BUILTINS[name]

	return ok
}

func callBuiltin(name string, args []string) {
	builtin, _ := BUILTINS[name]
	builtin.Run(args)
}

func spawnProgram(name string, args []string, placeHolderOut io.WriteCloser, placeHolderIn io.ReadCloser) {
	cmdFullPath, err := exec.LookPath(name)
	if err != nil {
		fmt.Fprintf(os.Stderr, "osh: command not found: %s\n", name)
		return
	}

	c := exec.Command(cmdFullPath, args...)
	c.Env = os.Environ()
	c.Stdin = placeHolderIn
	c.Stdout = placeHolderOut
	c.Stderr = c.Stdout

	if err = c.Run(); err != nil {
		panic(err)
	}
}

func spawnPrograms(cmds ...*exec.Cmd) {
	stdout, stderr, err := pipeline(cmds)
	if err != nil {
		fmt.Printf("%s\n", err)
	}

	if len(stdout) > 0 {
		fmt.Printf("%s", stdout)
	}

	if len(stderr) > 0 {
		fmt.Printf("%s", stderr)
	}
}

func pipeline(cmds []*exec.Cmd) (pipeLineOutput, collectedStandardError []byte, pipeLineError error) {
	// Collect the output from the command(s)
	var output bytes.Buffer
	var stderr bytes.Buffer

	last := len(cmds) - 1
	for i, cmd := range cmds[:last] {
		var err error
		// Connect each command's stdin to the previous command's stdout
		if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
			return nil, nil, err
		}
		// Connect each command's stderr to a buffer
		cmd.Stderr = &stderr
	}

	// Connect the output and error for the last command
	cmds[last].Stdout, cmds[last].Stderr = &output, &stderr

	// Start each command
	for _, cmd := range cmds {
		if err := cmd.Start(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Wait for each command to complete
	for _, cmd := range cmds {
		if err := cmd.Wait(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Return the pipeline output and the collected standard error
	return output.Bytes(), stderr.Bytes(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jessevdk/go-flags"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"log"
	"os"
	"reflect"
	"strings"
)

const (
	SQL_TABLES       = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name;"
	SQL_TABLE_SCHEMA = "SELECT column_name, data_type, is_nullable, character_maximum_length, character_set_catalog, column_default FROM information_schema.columns where table_name = '%s';"
)

type Client struct {
	db *sqlx.DB
}

type Result struct {
	Columns []string        `json:"columns"`
	Rows    [][]interface{} `json:"rows"`
}

type Error struct {
	Message string `json:"error"`
}

var dbClient *Client
var history []string

var options struct {
	Url    string `long:"url" description:"Database connection string"`
	Host   string `short:"h" long:"host" description:"Server hostname or IP" default:"localhost"`
	Port   int    `short:"p" long:"port" description:"Server port" default:"5432"`
	User   string `short:"u" long:"user" description:"Database user" default:"postgres"`
	DbName string `short:"d" long:"db" description:"Database name" default:"postgres"`
	Ssl    string `long:"ssl" description:"SSL option" default:"disable"`
	Static string `short:"s" description:"Path to static assets" default:"./static"`
}

func getConnectionString() string {
	if options.Url != "" {
		return options.Url
	}

	return fmt.Sprintf(
		"host=%s port=%d user=%s dbname=%s sslmode=disable",
		options.Host, options.Port,
		options.User, options.DbName,
	)
}

func NewClient() (*Client, error) {
	db, err := sqlx.Open("postgres", getConnectionString())

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

func NewError(err error) Error {
	return Error{err.Error()}
}

func (client *Client) Tables() ([]string, error) {
	res, err := client.Query(SQL_TABLES)

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

func (client *Client) Query(query string) (*Result, error) {
	rows, err := client.db.Queryx(query)

	if err != nil {
		return nil, err
	}

	defer rows.Close()

	cols, err := rows.Columns()

	if err != nil {
		return nil, err
	}

	result := Result{
		Columns: cols,
	}

	for rows.Next() {
		obj, err := rows.SliceScan()

		for i, item := range obj {
			if item == nil {
				obj[i] = nil
			} else {
				t := reflect.TypeOf(item).Kind().String()

				if t == "slice" {
					obj[i] = string(item.([]byte))
				}
			}
		}

		if err == nil {
			result.Rows = append(result.Rows, obj)
		}
	}

	return &result, nil
}

func API_RunQuery(c *gin.Context) {
	query := strings.TrimSpace(c.Request.FormValue("query"))

	if query == "" {
		c.JSON(400, errors.New("Query parameter is missing"))
		return
	}

	history = append(history, query)
	API_HandleQuery(query, c)
}

func API_GetTables(c *gin.Context) {
	names, err := dbClient.Tables()

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, names)
}

func API_GetTable(c *gin.Context) {
	var columns []map[string]interface{}

	res, err := dbClient.Query(fmt.Sprintf(SQL_TABLE_SCHEMA, "users"))

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	for _, row := range res.Rows {
		item := make(map[string]interface{})

		for i, c := range res.Columns {
			item[c] = row[i]
		}

		columns = append(columns, item)
	}

	c.JSON(200, columns)
}

func API_History(c *gin.Context) {
	c.JSON(200, history)
}

func API_HandleQuery(query string, c *gin.Context) {
	result, err := dbClient.Query(query)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	buff, err := json.Marshal(result)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.String(200, string(buff))
}

func initClient() {
	client, err := NewClient()

	if err != nil {
		log.Fatal(err)
	}

	dbClient = client
}

func initOptions() {
	_, err := flags.ParseArgs(&options, os.Args)

	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	initOptions()
	initClient()
	defer dbClient.db.Close()

	router := gin.Default()

	router.GET("/tables", API_GetTables)
	router.GET("/tables/:name", API_GetTable)
	router.GET("/select", API_RunQuery)
	router.POST("/select", API_RunQuery)
	router.GET("/history", API_History)

	router.Static("/app", options.Static)

	fmt.Println("Starting server at 0.0.0.0:8080")
	router.Run(":8080")
}
<commit_msg>Remove unused code<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jessevdk/go-flags"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"log"
	"os"
	"reflect"
	"strings"
)

const (
	SQL_TABLES       = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name;"
	SQL_TABLE_SCHEMA = "SELECT column_name, data_type, is_nullable, character_maximum_length, character_set_catalog, column_default FROM information_schema.columns where table_name = '%s';"
)

type Client struct {
	db *sqlx.DB
}

type Result struct {
	Columns []string        `json:"columns"`
	Rows    [][]interface{} `json:"rows"`
}

type Error struct {
	Message string `json:"error"`
}

var dbClient *Client
var history []string

var options struct {
	Url    string `long:"url" description:"Database connection string"`
	Host   string `short:"h" long:"host" description:"Server hostname or IP" default:"localhost"`
	Port   int    `short:"p" long:"port" description:"Server port" default:"5432"`
	User   string `short:"u" long:"user" description:"Database user" default:"postgres"`
	DbName string `short:"d" long:"db" description:"Database name" default:"postgres"`
	Ssl    string `long:"ssl" description:"SSL option" default:"disable"`
	Static string `short:"s" description:"Path to static assets" default:"./static"`
}

func getConnectionString() string {
	if options.Url != "" {
		return options.Url
	}

	return fmt.Sprintf(
		"host=%s port=%d user=%s dbname=%s sslmode=disable",
		options.Host, options.Port,
		options.User, options.DbName,
	)
}

func NewClient() (*Client, error) {
	db, err := sqlx.Open("postgres", getConnectionString())

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

func NewError(err error) Error {
	return Error{err.Error()}
}

func (client *Client) Tables() ([]string, error) {
	res, err := client.Query(SQL_TABLES)

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

func (client *Client) Query(query string) (*Result, error) {
	rows, err := client.db.Queryx(query)

	if err != nil {
		return nil, err
	}

	defer rows.Close()

	cols, err := rows.Columns()

	if err != nil {
		return nil, err
	}

	result := Result{
		Columns: cols,
	}

	for rows.Next() {
		obj, err := rows.SliceScan()

		for i, item := range obj {
			if item == nil {
				obj[i] = nil
			} else {
				t := reflect.TypeOf(item).Kind().String()

				if t == "slice" {
					obj[i] = string(item.([]byte))
				}
			}
		}

		if err == nil {
			result.Rows = append(result.Rows, obj)
		}
	}

	return &result, nil
}

func API_RunQuery(c *gin.Context) {
	query := strings.TrimSpace(c.Request.FormValue("query"))

	if query == "" {
		c.JSON(400, errors.New("Query parameter is missing"))
		return
	}

	history = append(history, query)
	API_HandleQuery(query, c)
}

func API_GetTables(c *gin.Context) {
	names, err := dbClient.Tables()

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, names)
}

func API_GetTable(c *gin.Context) {
	var columns []map[string]interface{}

	res, err := dbClient.Query(fmt.Sprintf(SQL_TABLE_SCHEMA, "users"))

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	for _, row := range res.Rows {
		item := make(map[string]interface{})

		for i, c := range res.Columns {
			item[c] = row[i]
		}

		columns = append(columns, item)
	}

	c.JSON(200, columns)
}

func API_History(c *gin.Context) {
	c.JSON(200, history)
}

func API_HandleQuery(query string, c *gin.Context) {
	result, err := dbClient.Query(query)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, result)
}

func initClient() {
	client, err := NewClient()

	if err != nil {
		log.Fatal(err)
	}

	dbClient = client
}

func initOptions() {
	_, err := flags.ParseArgs(&options, os.Args)

	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	initOptions()
	initClient()
	defer dbClient.db.Close()

	router := gin.Default()

	router.GET("/tables", API_GetTables)
	router.GET("/tables/:name", API_GetTable)
	router.GET("/select", API_RunQuery)
	router.POST("/select", API_RunQuery)
	router.GET("/history", API_History)

	router.Static("/app", options.Static)

	fmt.Println("Starting server at 0.0.0.0:8080")
	router.Run(":8080")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/citruspi/Iago/configuration"
	"github.com/citruspi/Iago/host"
	"github.com/citruspi/Iago/travis"
	"github.com/gin-gonic/gin"
)

type Status struct {
	Hosts  []host.Host `json:"hosts"`
	Uptime float64     `json:"uptime"`
}

var (
	hosts []host.Host
	boot  time.Time
	conf  configuration.Configuration
)

func cleanup() {
	for {
		for i, h := range hosts {
			if time.Now().UTC().After(h.Expiration) {
				diff := hosts
				diff = append(diff[:i], diff[i+1:]...)
				hosts = diff
			}
		}
		time.Sleep(time.Duration(conf.Host.TTL) * time.Second)
	}
}

func announce(c *gin.Context) {
	var notification travis.Notification

	c.Bind(&notification)

	payload, _ := json.Marshal(notification.Payload)
	body := bytes.NewBuffer(payload)

	for _, host := range hosts {
		urlStr := host.URL()

		req, err := http.NewRequest("POST", urlStr, body)
		req.Header.Set("Content-Type", "application/json")

		client := &http.Client{}
		resp, err := client.Do(req)

		if err != nil {
			log.Fatal(err)
		}

		defer resp.Body.Close()
	}

	c.JSON(200, "")
}

func checkin(c *gin.Context) {
	var newHost host.Host

	c.Bind(&newHost)

	if newHost.Hostname != "" {
		for i, h := range hosts {
			if h.Hostname == newHost.Hostname {
				diff := hosts
				diff = append(diff[:i], diff[i+1:]...)
				hosts = diff
			}
		}

		newHost = newHost.Process()

		hosts = append(hosts, newHost)

		c.JSON(200, "")
	} else {
		var response struct {
			Message string `json:"message"`
		}
		response.Message = "Invalid hostname."
		c.JSON(400, response)
	}
}

func status(c *gin.Context) {
	status := Status{}
	status.Hosts = hosts
	status.Uptime = time.Now().Sub(boot).Seconds()

	c.JSON(200, status)
}

func main() {
	boot = time.Now()

	configuration.Process()
	conf = configuration.Conf

	hosts = host.List

	go cleanup()

	router := gin.Default()

	router.POST("/checkin/", checkin)
	router.POST("/announce/", announce)

	if conf.Web.Status {
		router.GET("/status/", status)
	}

	router.Run(conf.Web.Address)
}
<commit_msg>Used the host.List instance instead of creating a new copy<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/citruspi/Iago/configuration"
	"github.com/citruspi/Iago/host"
	"github.com/citruspi/Iago/travis"
	"github.com/gin-gonic/gin"
)

type Status struct {
	Hosts  []host.Host `json:"hosts"`
	Uptime float64     `json:"uptime"`
}

var (
	hosts []host.Host
	boot  time.Time
	conf  configuration.Configuration
)

func cleanup() {
	for {
		for i, h := range host.List {
			if time.Now().UTC().After(h.Expiration) {
				diff := host.List
				diff = append(diff[:i], diff[i+1:]...)
				host.List = diff
			}
		}
		time.Sleep(time.Duration(conf.Host.TTL) * time.Second)
	}
}

func announce(c *gin.Context) {
	var notification travis.Notification

	c.Bind(&notification)

	payload, _ := json.Marshal(notification.Payload)
	body := bytes.NewBuffer(payload)

	for _, host := range hosts {
		urlStr := host.URL()

		req, err := http.NewRequest("POST", urlStr, body)
		req.Header.Set("Content-Type", "application/json")

		client := &http.Client{}
		resp, err := client.Do(req)

		if err != nil {
			log.Fatal(err)
		}

		defer resp.Body.Close()
	}

	c.JSON(200, "")
}

func checkin(c *gin.Context) {
	var newHost host.Host

	c.Bind(&newHost)

	if newHost.Hostname != "" {
		for i, h := range host.List {
			if h.Hostname == newHost.Hostname {
				diff := host.List
				diff = append(diff[:i], diff[i+1:]...)
				host.List = diff
			}
		}

		newHost = newHost.Process()

		host.List = append(host.List, newHost)

		c.JSON(200, "")
	} else {
		var response struct {
			Message string `json:"message"`
		}
		response.Message = "Invalid hostname."
		c.JSON(400, response)
	}
}

func status(c *gin.Context) {
	status := Status{}
	status.Hosts = host.List
	status.Uptime = time.Now().Sub(boot).Seconds()

	c.JSON(200, status)
}

func main() {
	boot = time.Now()

	configuration.Process()
	conf = configuration.Conf

	go cleanup()

	router := gin.Default()

	router.POST("/checkin/", checkin)
	router.POST("/announce/", announce)

	if conf.Web.Status {
		router.GET("/status/", status)
	}

	router.Run(conf.Web.Address)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"gopkg.in/sorcix/irc.v2"
	"io"
	"log"
	"os"
	"os/user"
	"strings"
)

var target string

func printmsg(msg *irc.Message) {
	switch msg.Command {
	case "JOIN":
		fmt.Printf("%s has joined %s\n", msg.Prefix.Name, msg.Params[0])
	case "PRIVMSG":
		fmt.Printf("%s/%s: %s\n", msg.Prefix.Name, msg.Params[0], msg.Params[1])
	case "MODE":
		fmt.Printf("%s sets mode %s\n", msg.Prefix.Name, strings.Join(msg.Params[0:], " "))
	case "NOTICE":
		fmt.Printf("Notice from %s to %s: %s\n", msg.Prefix.Name, msg.Params[0], msg.Params[1])
	case "001":
		fallthrough
	case "002":
		fallthrough
	case "003":
		fallthrough
	case "372":
		fallthrough
	case "375":
		fallthrough
	case "376":
		fmt.Println(msg.Params[1])
	case "QUIT":
		fmt.Printf("%s has quit (%s)\n", msg.Prefix.Name, msg.Params[0])
	default:
		fmt.Println("RAW:", msg.String())
	}
}

func Parse(text string) (string, bool) {
	if text[0] == '/' {
		words := strings.Split(text, " ")
		if words[0] == "/q" {
			if len(words) > 1 {
				return fmt.Sprintf("QUIT :%s", strings.Join(words[1:], " ")), true
			} else {
				return "QUIT :Bunnyirc", true
			}
		}
		if words[0] == "/t" && len(words) > 1 {
			target = words[1]
			return "", false
		}
		if words[0] == "/r" && len(words) > 1 {
			return strings.Join(words[1:], " "), true
		}
		if words[0] == "/j" && len(words) > 1 {
			return fmt.Sprintf("JOIN %s", words[1]), true
		}
		if words[0] == "/m" && len(words) > 2 {
			return fmt.Sprintf("PRIVMSG %s :%s", words[1], strings.Join(words[2:], " ")), true
		}
		if words[0] == "/N" && len(words) > 2 {
			return fmt.Sprintf("NOTICE %s :%s", words[1], strings.Join(words[2:], " ")), true
		}
		if words[0] == "/n" && len(words) > 1 {
			return fmt.Sprintf("NICK %s", words[1]), true
		}
	}
	return fmt.Sprintf("PRIVMSG %s :%s", target, text), target != ""
}

func Command(client *Client, text string) bool {
	send, dosend := Parse(strings.Replace(text, "\n", "", -1))
	if dosend {
		msg := irc.ParseMessage(send)
		if msg != nil {
			client.Send(msg)
			return msg.Command == "QUIT"
		}
	}
	return false
}

func readloop(client *Client) {
	reader := bufio.NewReader(os.Stdin)
	for {
		text, err := reader.ReadString('\n')
		if err == io.EOF {
			return
		}
		if Command(client, text) {
			return
		}
	}
}

func printloop(client *Client) {
	for {
		msg, err := client.Receive()
		if err != nil {
			fmt.Println("Output loop closing:", err)
			return
		}
		printmsg(msg)
		if msg.Command == "ERROR" {
			return
		}
	}
}

func main() {
	current, _ := user.Current()
	nick := flag.String("n", current.Username, "Nickname")
	user := flag.String("u", current.Username, "Username")
	server := flag.String("s", "chat.freenode.net", "Server to connect to")
	port := flag.Int("p", 6667, "Port to use")
	usetls := flag.Bool("z", false, "Use TLS")
	flag.Parse()
	client, err := New(*usetls, fmt.Sprint(*server, ":", *port), *nick, *user)
	if err != nil {
		log.Fatalln("Could not connect to IRC server; ", err.Error())
	}
	client.Auth()
	go printloop(client)
	readloop(client)
}
<commit_msg>else if instead of subsequent ifs<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"gopkg.in/sorcix/irc.v2"
	"io"
	"log"
	"os"
	"os/user"
	"strings"
)

var target string

func printmsg(msg *irc.Message) {
	switch msg.Command {
	case "JOIN":
		fmt.Printf("%s has joined %s\n", msg.Prefix.Name, msg.Params[0])
	case "PRIVMSG":
		fmt.Printf("%s/%s: %s\n", msg.Prefix.Name, msg.Params[0], msg.Params[1])
	case "MODE":
		fmt.Printf("%s sets mode %s\n", msg.Prefix.Name, strings.Join(msg.Params[0:], " "))
	case "NOTICE":
		fmt.Printf("Notice from %s to %s: %s\n", msg.Prefix.Name, msg.Params[0], msg.Params[1])
	case "001":
		fallthrough
	case "002":
		fallthrough
	case "003":
		fallthrough
	case "372":
		fallthrough
	case "375":
		fallthrough
	case "376":
		fmt.Println(msg.Params[1])
	case "QUIT":
		fmt.Printf("%s has quit (%s)\n", msg.Prefix.Name, msg.Params[0])
	default:
		fmt.Println("RAW:", msg.String())
	}
}

func Parse(text string) (string, bool) {
	if text[0] == '/' {
		words := strings.Split(text, " ")
		if words[0] == "/q" {
			if len(words) > 1 {
				return fmt.Sprintf("QUIT :%s", strings.Join(words[1:], " ")), true
			} else {
				return "QUIT :Bunnyirc", true
			}
		} else if words[0] == "/t" && len(words) > 1 {
			target = words[1]
			return "", false
		} else if words[0] == "/r" && len(words) > 1 {
			return strings.Join(words[1:], " "), true
		} else if words[0] == "/j" && len(words) > 1 {
			return fmt.Sprintf("JOIN %s", words[1]), true
		} else if words[0] == "/m" && len(words) > 2 {
			return fmt.Sprintf("PRIVMSG %s :%s", words[1], strings.Join(words[2:], " ")), true
		} else if words[0] == "/N" && len(words) > 2 {
			return fmt.Sprintf("NOTICE %s :%s", words[1], strings.Join(words[2:], " ")), true
		} else if words[0] == "/n" && len(words) > 1 {
			return fmt.Sprintf("NICK %s", words[1]), true
		}
	}
	return fmt.Sprintf("PRIVMSG %s :%s", target, text), target != ""
}

func Command(client *Client, text string) bool {
	send, dosend := Parse(strings.Replace(text, "\n", "", -1))
	if dosend {
		msg := irc.ParseMessage(send)
		if msg != nil {
			client.Send(msg)
			return msg.Command == "QUIT"
		}
	}
	return false
}

func readloop(client *Client) {
	reader := bufio.NewReader(os.Stdin)
	for {
		text, err := reader.ReadString('\n')
		if err == io.EOF {
			return
		}
		if Command(client, text) {
			return
		}
	}
}

func printloop(client *Client) {
	for {
		msg, err := client.Receive()
		if err != nil {
			fmt.Println("Output loop closing:", err)
			return
		}
		printmsg(msg)
		if msg.Command == "ERROR" {
			return
		}
	}
}

func main() {
	current, _ := user.Current()
	nick := flag.String("n", current.Username, "Nickname")
	user := flag.String("u", current.Username, "Username")
	server := flag.String("s", "chat.freenode.net", "Server to connect to")
	port := flag.Int("p", 6667, "Port to use")
	usetls := flag.Bool("z", false, "Use TLS")
	flag.Parse()
	client, err := New(*usetls, fmt.Sprint(*server, ":", *port), *nick, *user)
	if err != nil {
		log.Fatalln("Could not connect to IRC server; ", err.Error())
	}
	client.Auth()
	go printloop(client)
	readloop(client)
}
<|endoftext|>


<commit_before>// Copyright 2017 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/signal"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
	lSyslog "github.com/sirupsen/logrus/hooks/syslog"
)

const (
	shimName    = "kata-shim"
	exitFailure = 1
)

// version is the shim version. This variable is populated at build time.
var version = "unknown"

var shimLog = logrus.New()

func logger() *logrus.Entry {
	return shimLog.WithFields(logrus.Fields{
		"name": shimName,
		"pid":  os.Getpid(),
	})
}

func initLogger(logLevel string) error {
	shimLog.Formatter = &logrus.TextFormatter{TimestampFormat: time.RFC3339Nano}

	level, err := logrus.ParseLevel(logLevel)
	if err != nil {
		return err
	}

	shimLog.SetLevel(level)

	// Make sure all output going to stdout/stderr is actually discarded.
	shimLog.Out = ioutil.Discard

	hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, shimName)
	if err == nil {
		shimLog.AddHook(hook)
	}

	logger().WithField("version", version).Info()

	return nil
}

func main() {
	var (
		logLevel      string
		agentAddr     string
		container     string
		execID        string
		terminal      bool
		proxyExitCode bool
		showVersion   bool
	)

	flag.BoolVar(&showVersion, "version", false, "display program version and exit")
	flag.StringVar(&logLevel, "log", "warn", "set shim log level: debug, info, warn, error, fatal or panic")
	flag.StringVar(&agentAddr, "agent", "", "agent gRPC socket endpoint")

	flag.StringVar(&container, "container", "", "container id for the shim")
	flag.StringVar(&execID, "exec-id", "", "process id for the shim")
	flag.BoolVar(&terminal, "terminal", false, "specify if a terminal is setup")
	flag.BoolVar(&proxyExitCode, "proxy-exit-code", true, "proxy exit code of the process")

	flag.Parse()

	if showVersion {
		fmt.Printf("%v version %v\n", shimName, version)
		os.Exit(0)
	}

	if agentAddr == "" || container == "" || execID == "" {
		logger().WithField("agentAddr", agentAddr).WithField("container", container).WithField("exec-id", execID).Error("container ID, exec ID and agent socket endpoint must be set")
		os.Exit(exitFailure)
	}

	err := initLogger(logLevel)
	if err != nil {
		logger().WithError(err).WithField("loglevel", logLevel).Error("invalid log level")
		os.Exit(exitFailure)
	}

	shim, err := newShim(agentAddr, container, execID)
	if err != nil {
		logger().WithError(err).Error("failed to create new shim")
		os.Exit(exitFailure)
	}

	// winsize
	if terminal {
		termios, err := setupTerminal(int(os.Stdin.Fd()))
		if err != nil {
			logger().WithError(err).Error("failed to set raw terminal")
			os.Exit(exitFailure)
		}
		defer restoreTerminal(int(os.Stdin.Fd()), termios)
	}
	shim.monitorTtySize(os.Stdin)

	// signals
	sigc := shim.forwardAllSignals()
	defer signal.Stop(sigc)

	// This wait call cannot be deferred and has to wait for every
	// input/output to return before the code tries to go further
	// and wait for the process. Indeed, after the process has been
	// waited for, we cannot expect to do any more calls related to
	// this process since it is going to be removed from the agent.
	wg := &sync.WaitGroup{}
	shim.proxyStdio(wg, terminal)
	wg.Wait()

	// wait until exit
	exitcode, err := shim.wait()
	if err != nil {
		logger().WithError(err).WithField("exec-id", execID).Error("failed waiting for process")
		os.Exit(exitFailure)
	} else if proxyExitCode {
		logger().WithField("exitcode", exitcode).Info("using shim to proxy exit code")
		if exitcode != 0 {
			os.Exit(int(exitcode))
		}
	}
}
<commit_msg>logging: Add source log field<commit_after>// Copyright 2017 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/signal"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
	lSyslog "github.com/sirupsen/logrus/hooks/syslog"
)

const (
	shimName    = "kata-shim"
	exitFailure = 1
)

// version is the shim version. This variable is populated at build time.
var version = "unknown"

var shimLog = logrus.New()

func logger() *logrus.Entry {
	return shimLog.WithFields(logrus.Fields{
		"name":   shimName,
		"pid":    os.Getpid(),
		"source": "shim",
	})
}

func initLogger(logLevel string) error {
	shimLog.Formatter = &logrus.TextFormatter{TimestampFormat: time.RFC3339Nano}

	level, err := logrus.ParseLevel(logLevel)
	if err != nil {
		return err
	}

	shimLog.SetLevel(level)

	// Make sure all output going to stdout/stderr is actually discarded.
	shimLog.Out = ioutil.Discard

	hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, shimName)
	if err == nil {
		shimLog.AddHook(hook)
	}

	logger().WithField("version", version).Info()

	return nil
}

func main() {
	var (
		logLevel      string
		agentAddr     string
		container     string
		execID        string
		terminal      bool
		proxyExitCode bool
		showVersion   bool
	)

	flag.BoolVar(&showVersion, "version", false, "display program version and exit")
	flag.StringVar(&logLevel, "log", "warn", "set shim log level: debug, info, warn, error, fatal or panic")
	flag.StringVar(&agentAddr, "agent", "", "agent gRPC socket endpoint")

	flag.StringVar(&container, "container", "", "container id for the shim")
	flag.StringVar(&execID, "exec-id", "", "process id for the shim")
	flag.BoolVar(&terminal, "terminal", false, "specify if a terminal is setup")
	flag.BoolVar(&proxyExitCode, "proxy-exit-code", true, "proxy exit code of the process")

	flag.Parse()

	if showVersion {
		fmt.Printf("%v version %v\n", shimName, version)
		os.Exit(0)
	}

	if agentAddr == "" || container == "" || execID == "" {
		logger().WithField("agentAddr", agentAddr).WithField("container", container).WithField("exec-id", execID).Error("container ID, exec ID and agent socket endpoint must be set")
		os.Exit(exitFailure)
	}

	err := initLogger(logLevel)
	if err != nil {
		logger().WithError(err).WithField("loglevel", logLevel).Error("invalid log level")
		os.Exit(exitFailure)
	}

	shim, err := newShim(agentAddr, container, execID)
	if err != nil {
		logger().WithError(err).Error("failed to create new shim")
		os.Exit(exitFailure)
	}

	// winsize
	if terminal {
		termios, err := setupTerminal(int(os.Stdin.Fd()))
		if err != nil {
			logger().WithError(err).Error("failed to set raw terminal")
			os.Exit(exitFailure)
		}
		defer restoreTerminal(int(os.Stdin.Fd()), termios)
	}
	shim.monitorTtySize(os.Stdin)

	// signals
	sigc := shim.forwardAllSignals()
	defer signal.Stop(sigc)

	// This wait call cannot be deferred and has to wait for every
	// input/output to return before the code tries to go further
	// and wait for the process. Indeed, after the process has been
	// waited for, we cannot expect to do any more calls related to
	// this process since it is going to be removed from the agent.
	wg := &sync.WaitGroup{}
	shim.proxyStdio(wg, terminal)
	wg.Wait()

	// wait until exit
	exitcode, err := shim.wait()
	if err != nil {
		logger().WithError(err).WithField("exec-id", execID).Error("failed waiting for process")
		os.Exit(exitFailure)
	} else if proxyExitCode {
		logger().WithField("exitcode", exitcode).Info("using shim to proxy exit code")
		if exitcode != 0 {
			os.Exit(int(exitcode))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/christophwitzko/github-release-download/release"
	"github.com/julienschmidt/httprouter"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

var bindAddress string = ":5000"
var client *release.GithubClient

func init() {
	if ba := os.Getenv("BIND_ADDRESS"); ba != "" {
		bindAddress = ba
	}
	client = release.NewClient(os.Getenv("GITHUB_TOKEN"))
}

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

func doRedirect(w http.ResponseWriter, r *http.Request, url string, err error) {
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	if url == "" {
		http.NotFound(w, r)
		return
	}
	w.Header().Set("Cache-Control", "public, max-age=300")
	http.Redirect(w, r, url, 302)
}

func getLatestDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if len(ps) == 3 {
		url, err := client.GetLatestDownloadUrl(ctx, "go-" + ps[0].Value, ps[0].Value, ps[1].Value, ps[2].Value)
		doRedirect(w, r, url, err)
		return
	}
	url, err := client.GetLatestDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value)
	doRedirect(w, r, url, err)
}

func getMatchingDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	url, err := client.GetMatchingDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value, ps[4].Value)
	doRedirect(w, r, url, err)
}

func getVersions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if ps[0].Value == "_" && ps[1].Value == "go" {
		versions, err := client.GetGoVersions(ctx)
		if err != nil {
			log.Println(err)
			http.Error(w, "server error", http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(versions)
		return
	}
	http.NotFound(w, r)
}

func usage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if ps[0].Value != "_usage" {
		http.NotFound(w, r)
		return
	}
	rl, _, err := client.Client.RateLimits(r.Context())
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(rl.Core)
}

func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintln(w, "https://get-release.xyz/:owner/:repo/:os/:arch{/:constraint}")
}

func main() {
	router := httprouter.New()
	router.GET("/", index)
	router.GET("/:owner", usage)
	router.GET("/:owner/:repo", getVersions)
	router.GET("/:owner/:repo/:os", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch/:constraint", getMatchingDownload)
	server := http.Server{
		Addr:    bindAddress,
		Handler: logger(router),
	}
	go func() {
		log.Printf("starting server on port %s...", bindAddress)
		if err := server.ListenAndServe(); err != nil {
			log.Fatal(err)
		}
	}()
	defer server.Shutdown(nil)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
	log.Println("server stopped")
}
<commit_msg>fix: increase cache time to 2 hours<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/christophwitzko/github-release-download/release"
	"github.com/julienschmidt/httprouter"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

var bindAddress string = ":5000"
var client *release.GithubClient

func init() {
	if ba := os.Getenv("BIND_ADDRESS"); ba != "" {
		bindAddress = ba
	}
	client = release.NewClient(os.Getenv("GITHUB_TOKEN"))
}

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

func doRedirect(w http.ResponseWriter, r *http.Request, url string, err error) {
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	if url == "" {
		http.NotFound(w, r)
		return
	}
	w.Header().Set("Cache-Control", "public, max-age=7200")
	http.Redirect(w, r, url, 302)
}

func getLatestDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if len(ps) == 3 {
		url, err := client.GetLatestDownloadUrl(ctx, "go-" + ps[0].Value, ps[0].Value, ps[1].Value, ps[2].Value)
		doRedirect(w, r, url, err)
		return
	}
	url, err := client.GetLatestDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value)
	doRedirect(w, r, url, err)
}

func getMatchingDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	url, err := client.GetMatchingDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value, ps[4].Value)
	doRedirect(w, r, url, err)
}

func getVersions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if ps[0].Value == "_" && ps[1].Value == "go" {
		versions, err := client.GetGoVersions(ctx)
		if err != nil {
			log.Println(err)
			http.Error(w, "server error", http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(versions)
		return
	}
	http.NotFound(w, r)
}

func usage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if ps[0].Value != "_usage" {
		http.NotFound(w, r)
		return
	}
	rl, _, err := client.Client.RateLimits(r.Context())
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(rl.Core)
}

func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintln(w, "https://get-release.xyz/:owner/:repo/:os/:arch{/:constraint}")
}

func main() {
	router := httprouter.New()
	router.GET("/", index)
	router.GET("/:owner", usage)
	router.GET("/:owner/:repo", getVersions)
	router.GET("/:owner/:repo/:os", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch/:constraint", getMatchingDownload)
	server := http.Server{
		Addr:    bindAddress,
		Handler: logger(router),
	}
	go func() {
		log.Printf("starting server on port %s...", bindAddress)
		if err := server.ListenAndServe(); err != nil {
			log.Fatal(err)
		}
	}()
	defer server.Shutdown(nil)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
	log.Println("server stopped")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"math/rand"
	"fmt"
	"github.com/hoisie/web"
	"io"
	"os"
    "os/signal"
    "syscall"
	"time"
	"strings"
	"path/filepath"
)

func TempFileName(prefix, suffix string) string {
    s := rand.NewSource(time.Now().UTC().UnixNano())
    r := rand.New(s)
    alphabet := "abcdefghijklmnopqrstuvwxyz0123456789"
    name := ""
    for i := 0; i < 5; i++ {
        idx := r.Intn(len(alphabet))
        name += string(alphabet[idx])
    }
	return filepath.Join(name + suffix)
}

func Md5(r io.Reader) string {
	hash := md5.New()
	io.Copy(hash, r)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func hello(ctx *web.Context, val string) string {
	ctx.SetHeader("X-Powered-By", "web.go", true)
	ctx.SetHeader("X-Frame-Options", "DENY", true)
	ctx.SetHeader("X-Frame-Options", "DENY", true)
	ctx.SetHeader("Location", "/grill.png", true)
	ctx.SetHeader("Connection", "close", true)
	return "hello " + val
}

func handlePost(ctx *web.Context, val string, updateURL chan<-string) string {
	ctx.Request.ParseMultipartForm(10 * 1024 * 1024)
	form := ctx.Request.MultipartForm
	var output bytes.Buffer

	fileHeader := form.File["file"][0]
	filename := fileHeader.Filename
	file, err := fileHeader.Open()
	if err != nil {
		return err.Error()
	}
    hash := Md5(file)
    //TODO: Parse file properly and get the ext
    name := TempFileName(filename, ".tmp")
    //output.WriteString("orig name: " + filename + " new name: " + TempFileName(filename, ".tmp", Md5(file)) + " hash: " + Md5(file) + "\n")
    output.WriteString("
file: " + name + " " + hash + "
")
    //Send the URL for updating
    updateURL<-name + ":" + hash
	return output.String()
}

func handleGet(ctx *web.Context, val string, getURL chan<-string, sendURL<-chan string) string {
    getURL<-val
    res := <-sendURL
    if res == "" {
        return "File not found"
    }else{
        return "File at: " + res
    }
}

func urlHandler(getURL<-chan string, sendURL chan<-string, updateURL<-chan string){
    //Read in the CSV, then wait for updates
    urls := make(map[string]string)
    f, err := os.OpenFile("files.csv", os.O_APPEND|os.O_WRONLY, 0660)
    if err != nil {
        fmt.Println("Warning, file could not be opened.")
    }

    defer f.Close()
    for {
        select {
            case read := <-getURL:
                if val, ok := urls[read]; ok {
                    sendURL<-val
                }else{
                    sendURL<-""
                }
            case update := <-updateURL:
                s := strings.Split(update, ":")
                urls[s[0]] = s[1]
                fmt.Println("Updated URLs")
                //Write changes to file
                t := time.Now().UTC()
                nl := s[0] + "," + s[1] + "," + t.Format("2006-01-02 15:04:05") + "\n"
                if _, err := f.WriteString(nl); err != nil {
                    fmt.Println("Warning, file could not be written to.")
                    fmt.Println(err.Error())
                }
        }
    }
}

func main() {
    getURL := make(chan string)
    sendURL := make(chan string)
    updateURL := make(chan string)

    go urlHandler(getURL, sendURL, updateURL)

    //Le clever. Get around their interface only allowing specific values
    //to be passed by wrapping in a function and sending stuff from there
	web.Post("(/api/upload)", func(ctx *web.Context, val string) string{
        return handlePost(ctx, val, updateURL)
    })
    web.Get("/(.*)", func(ctx *web.Context, val string) string{
        return handleGet(ctx, val, getURL, sendURL)
    })
	web.Run("0.0.0.0:9999")
}
<commit_msg>Formatted stuff<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"fmt"
	"github.com/hoisie/web"
	"io"
	"math/rand"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

func TempFileName(prefix, suffix string) string {
	s := rand.NewSource(time.Now().UTC().UnixNano())
	r := rand.New(s)
	alphabet := "abcdefghijklmnopqrstuvwxyz0123456789"
	name := ""
	for i := 0; i < 5; i++ {
		idx := r.Intn(len(alphabet))
		name += string(alphabet[idx])
	}
	return filepath.Join(name + suffix)
}

func Md5(r io.Reader) string {
	hash := md5.New()
	io.Copy(hash, r)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func hello(ctx *web.Context, val string) string {
	ctx.SetHeader("X-Powered-By", "web.go", true)
	ctx.SetHeader("X-Frame-Options", "DENY", true)
	ctx.SetHeader("X-Frame-Options", "DENY", true)
	ctx.SetHeader("Location", "/grill.png", true)
	ctx.SetHeader("Connection", "close", true)
	return "hello " + val
}

func handlePost(ctx *web.Context, val string, updateURL chan<- string) string {
	ctx.Request.ParseMultipartForm(10 * 1024 * 1024)
	form := ctx.Request.MultipartForm
	var output bytes.Buffer

	fileHeader := form.File["file"][0]
	filename := fileHeader.Filename
	file, err := fileHeader.Open()
	if err != nil {
		return err.Error()
	}
	hash := Md5(file)
	//TODO: Parse file properly and get the ext
	name := TempFileName(filename, ".tmp")
	//output.WriteString("orig name: " + filename + " new name: " + TempFileName(filename, ".tmp", Md5(file)) + " hash: " + Md5(file) + "\n")
	output.WriteString("
file: " + name + " " + hash + "
")
	//Send the URL for updating
	updateURL <- name + ":" + hash
	return output.String()
}

func handleGet(ctx *web.Context, val string, getURL chan<- string, sendURL <-chan string) string {
	getURL <- val
	res := <-sendURL
	if res == "" {
		return "File not found"
	} else {
		return "File at: " + res
	}
}

func urlHandler(getURL <-chan string, sendURL chan<- string, updateURL <-chan string) {
	//Read in the CSV, then wait for updates
	urls := make(map[string]string)
	f, err := os.OpenFile("files.csv", os.O_APPEND|os.O_WRONLY, 0660)
	if err != nil {
		fmt.Println("Warning, file could not be opened.")
	}

	defer f.Close()
	for {
		select {
		case read := <-getURL:
			if val, ok := urls[read]; ok {
				sendURL <- val
			} else {
				sendURL <- ""
			}
		case update := <-updateURL:
			s := strings.Split(update, ":")
			urls[s[0]] = s[1]
			fmt.Println("Updated URLs")
			//Write changes to file
			t := time.Now().UTC()
			nl := s[0] + "," + s[1] + "," + t.Format("2006-01-02 15:04:05") + "\n"
			if _, err := f.WriteString(nl); err != nil {
				fmt.Println("Warning, file could not be written to.")
				fmt.Println(err.Error())
			}
		}
	}
}

func main() {
	getURL := make(chan string)
	sendURL := make(chan string)
	updateURL := make(chan string)

	go urlHandler(getURL, sendURL, updateURL)

	//Le clever. Get around their interface only allowing specific values
	//to be passed by wrapping in a function and sending stuff from there
	web.Post("(/api/upload)", func(ctx *web.Context, val string) string {
		return handlePost(ctx, val, updateURL)
	})
	web.Get("/(.*)", func(ctx *web.Context, val string) string {
		return handleGet(ctx, val, getURL, sendURL)
	})
	web.Run("0.0.0.0:9999")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	_ "github.com/joho/godotenv/autoload"
	"github.com/urfave/cli"
)

var version string // build number set at compile-time

func main() {
	app := cli.NewApp()
	app.Name = "Drone downstream plugin"
	app.Usage = "drone downstream plugin"
	app.Action = run
	app.Version = version
	app.Flags = []cli.Flag{

		cli.StringSliceFlag{
			Name:   "repositories",
			Usage:  "List of repositories to trigger",
			EnvVar: "PLUGIN_REPOSITORIES",
		},
		cli.StringFlag{
			Name:   "server",
			Usage:  "Trigger a drone build on a custom server",
			EnvVar: "PLUGIN_SERVER",
		},
		cli.StringFlag{
			Name:   "token",
			Usage:  "Drone API token from your user settings",
			EnvVar: "DOWNSTREAM_TOKEN,PLUGIN_TOKEN",
		},
		cli.BoolFlag{
			Name:   "fork",
			Usage:  "Trigger a new build for a repository",
			EnvVar: "PLUGIN_FORK",
		},
	}

	app.Run(os.Args)
}

func run(c *cli.Context) error {

	plugin := Plugin{
		Repos:  c.StringSlice("repositories"),
		Server: c.String("server"),
		Token:  c.String("token"),
		Fork:   c.Bool("fork"),
	}

	if err := plugin.Exec(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	return nil
}
<commit_msg>Added env-file flag, moved error logging more general, added logrus<commit_after>package main

import (
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/urfave/cli"
	"github.com/joho/godotenv"
)

var version string // build number set at compile-time

func main() {
	app := cli.NewApp()
	app.Name = "downstream plugin"
	app.Usage = "downstream plugin"
	app.Action = run
	app.Version = version
	app.Flags = []cli.Flag{
		cli.StringSliceFlag{
			Name:   "repositories",
			Usage:  "List of repositories to trigger",
			EnvVar: "PLUGIN_REPOSITORIES",
		},
		cli.StringFlag{
			Name:   "server",
			Usage:  "Trigger a drone build on a custom server",
			EnvVar: "PLUGIN_SERVER",
		},
		cli.StringFlag{
			Name:   "token",
			Usage:  "Drone API token from your user settings",
			EnvVar: "DOWNSTREAM_TOKEN,PLUGIN_TOKEN",
		},
		cli.BoolFlag{
			Name:   "fork",
			Usage:  "Trigger a new build for a repository",
			EnvVar: "PLUGIN_FORK",
		},
		cli.StringFlag{
			Name:  "env-file",
			Usage: "source env file",
		},
	}

	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}

	plugin := Plugin{
		Repos:  c.StringSlice("repositories"),
		Server: c.String("server"),
		Token:  c.String("token"),
		Fork:   c.Bool("fork"),
	}

	return plugin.Exec()
}
<|endoftext|>


<commit_before>//go:generate stringer -type=Token
package main

import (
	"io/ioutil"
	"os"

	"gopkg.in/logex.v1"

	"github.com/danwakefield/gosh/T"
	"github.com/danwakefield/gosh/variables"
)

func init() {
	logex.DebugLevel = 0
}

func main() {
	fileContents, _ := ioutil.ReadFile(os.Args[1]) // Ignore error
	p := NewParser(string(fileContents))
	scp := variables.NewScope()
	scp.SetPositionalArgs(os.Args[1:])
	ex := T.ExitSuccess

	stdIO := &T.IOContainer{In: os.Stdin, Out: os.Stdout, Err: os.Stderr}

	for {
		n := p.Parse()
		if n == nil {
			//Newline
			continue
		}
		logex.Pretty(n)
		if _, isEOF := n.(NodeEOF); isEOF {
			os.Exit(int(ex))
		}

		ex = n.Eval(scp, stdIO)
	}
}
<commit_msg>Add check to stop index error when passed no file<commit_after>//go:generate stringer -type=Token
package main

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

	"gopkg.in/logex.v1"

	"github.com/danwakefield/gosh/T"
	"github.com/danwakefield/gosh/variables"
)

func init() {
	logex.DebugLevel = 0
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Please pass a file to run")
		os.Exit(1)
	}
	fileContents, err := ioutil.ReadFile(os.Args[1]) // Ignore error
	if err != nil {
		fmt.Println(err.Error())
	}
	p := NewParser(string(fileContents))
	scp := variables.NewScope()
	scp.SetPositionalArgs(os.Args[1:])
	ex := T.ExitSuccess

	stdIO := &T.IOContainer{In: os.Stdin, Out: os.Stdout, Err: os.Stderr}

	for {
		n := p.Parse()
		if n == nil {
			//Newline
			continue
		}
		logex.Pretty(n)
		if _, isEOF := n.(NodeEOF); isEOF {
			os.Exit(int(ex))
		}

		ex = n.Eval(scp, stdIO)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hashicorp/serf/cli"
	"os"
)

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPreRelease = "dev"

func main() {
	os.Exit(realMain())
}

func realMain() int {
	cli := &cli.CLI{
		Args:     os.Args[1:],
		Commands: make(map[string]cli.CommandFactory),
		Ui:       &cli.BasicUi{Writer: os.Stdout},
	}

	exitCode, err := cli.Run()
	if err != nil {
		// TODO(mitchellh): too harsh
		panic(err)
	}

	return exitCode
}
<commit_msg>main: Can set the log with SERF_LOG=1<commit_after>package main

import (
	"github.com/hashicorp/serf/cli"
	"io/ioutil"
	"log"
	"os"
)

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPreRelease = "dev"

func main() {
	os.Exit(realMain())
}

func realMain() int {
	log.SetOutput(ioutil.Discard)
	if os.Getenv("SERF_LOG") != "" {
		log.SetOutput(os.Stderr)
	}

	cli := &cli.CLI{
		Args:     os.Args[1:],
		Commands: make(map[string]cli.CommandFactory),
		Ui:       &cli.BasicUi{Writer: os.Stdout},
	}

	exitCode, err := cli.Run()
	if err != nil {
		// TODO(mitchellh): too harsh
		panic(err)
	}

	return exitCode
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/andlabs/ui"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

type ItemData []struct {
	Name             string `json:"name"`
	Shown            bool   `json:"shown,omitempty"`
	Tears            string `json:"tears,omitempty"`
	Delay            string `json:"delay,omitempty"`
	DelayMultiplier  string `json:"delayx,omitempty"`
	Text             string `json:"text,omitempty"`
	Range            string `json:"range,omitempty"`
	Height           string `json:"height,omitempty"`
	Damage           string `json:"damage,omitempty"`
	DamageMultiplier string `json:"damagex,omitempty"`
	Speed            string `json:"speed,omitempty"`
	Health           string `json:"health,omitempty"`
	Space            bool   `json:"space,omitempty"`
	SoulHearts       string `json:"soulhearts,omitempty"`
	ID               string `json:"id"`
}

type RunData struct {
	Seed             string
	Tears            float64
	Delay            float64
	DelayMultiplier  float64
	Range            float64
	Height           float64
	Damage           float64
	DamageMultiplier float64
	Speed            float64
	ItemIDs          []string
}

type LastItemStat struct {
	Name             string
	Tears            float64
	Delay            float64
	DelayMultiplier  float64
	Range            float64
	Height           float64
	Damage           float64
	DamageMultiplier float64
	Speed            float64
	Description      string
}

var SeedLabel, TearsLabel, DelayLabel, DelayMultLabel, RangeLabel, DamageLabel, DamageMultLabel, SpeedLabel, LastItemLabel ui.Label
var Data ItemData
var Run RunData
var LastItem LastItemStat
var Window ui.Window

func main() {

	go ui.Do(gui)

	go processData()
	err := ui.Go()
	if err != nil {
		log.Fatal(err)
	}

}

func addToRunData(id string) {
	for _, element := range Data {
		if element.ID == id {
			LastItem.resetLastItem()
			if element.Tears != "" {
				tears, err := strconv.ParseFloat(element.Tears, 64)
				LastItem.Tears = tears
				if err != nil {
					log.Fatal(err)
				}
				Run.Tears += tears
			}
			if element.Delay != "" {
				delay, err := strconv.ParseFloat(element.Delay, 64)
				LastItem.Delay = delay
				if err != nil {
					log.Fatal(err)
				}
				Run.Delay += delay
			}
			if element.DelayMultiplier != "" {
				delayMultiplier, err := strconv.ParseFloat(element.DelayMultiplier, 64)
				LastItem.DelayMultiplier = delayMultiplier
				if err != nil {
					log.Fatal(err)
				}
				Run.DelayMultiplier += delayMultiplier
			}
			if element.Range != "" {
				rangey, err := strconv.ParseFloat(element.Range, 64)
				LastItem.Range = rangey
				if err != nil {
					log.Fatal(err)
				}
				Run.Range += rangey
			}
			if element.Height != "" {
				height, err := strconv.ParseFloat(element.Height, 64)
				LastItem.Height = height
				if err != nil {
					log.Fatal(err)
				}
				Run.Height += height
			}
			if element.Damage != "" {
				damage, err := strconv.ParseFloat(element.Damage, 64)
				LastItem.Damage = damage
				if err != nil {
					log.Fatal(err)
				}
				Run.Damage += damage
			}
			if element.DamageMultiplier != "" {
				damageMultiplier, err := strconv.ParseFloat(element.DamageMultiplier, 64)
				LastItem.DamageMultiplier = damageMultiplier
				if err != nil {
					log.Fatal(err)
				}
				Run.DamageMultiplier += damageMultiplier
			}
			if element.Speed != "" {
				speed, err := strconv.ParseFloat(element.Speed, 64)
				LastItem.Speed = speed
				if err != nil {
					log.Fatal(err)
				}
				Run.Speed += speed
			}
			LastItem.Name = element.Name
			break
		}
	}
}

func gui() {
	SeedLabel = ui.NewLabel("Seed")
	TearsLabel = ui.NewLabel("Tears")
	DelayLabel = ui.NewLabel("Delay")
	DelayMultLabel = ui.NewLabel("Delay Multiplier")
	RangeLabel = ui.NewLabel("Range")
	DamageLabel = ui.NewLabel("Damage")
	DamageMultLabel = ui.NewLabel("Damage Multiplier")
	SpeedLabel = ui.NewLabel("Speed")
	LastItemLabel = ui.NewLabel("Last Item Info")

	stack := ui.NewVerticalStack(
		SeedLabel,
		TearsLabel,
		DelayLabel,
		DelayMultLabel,
		RangeLabel,
		DamageLabel,
		DamageMultLabel,
		SpeedLabel,
		LastItemLabel)

	Window = ui.NewWindow("Binding of Isaac Item Tracker", 1200, 175, stack)

	Window.OnClosing(func() bool {
		ui.Stop()
		return true
	})

	Window.Show()
}

func processData() {
	ItemsJson, err := ioutil.ReadFile("items.json")
	if err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(ItemsJson, &Data); err != nil {
		log.Fatal(err)
	}
	ticker := time.NewTicker(time.Millisecond * 500)
	go func() {
		for _ = range ticker.C {
			lines, err := readLines()
			if err != nil {
				log.Fatal(err)
			}
			for _, element := range lines {
				processLine(element)
			}
			ui.Do(fixGui)
		}
	}()

}

func readLines() ([]string, error) {
	file, err := os.Open("log.txt")
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

func fixGui() {
	SeedLabel.SetText(fmt.Sprintf("Seed: %s", Run.Seed))
	TearsLabel.SetText(fmt.Sprintf("Tear Rate: %.2f", Run.Tears))
	DelayLabel.SetText(fmt.Sprintf("Tear Delay: %.2f", Run.Delay))
	DelayMultLabel.SetText(fmt.Sprintf("Tear Delay Multiplier: %.2f", Run.DelayMultiplier))
	RangeLabel.SetText(fmt.Sprintf("Range: %.2f", Run.Range))
	DamageLabel.SetText(fmt.Sprintf("Damage: %.2f", Run.Damage))
	DamageMultLabel.SetText(fmt.Sprintf("Damage Multiplier: %.2f", Run.DamageMultiplier))
	SpeedLabel.SetText(fmt.Sprintf("Speed: %.2f", Run.Speed))
	LastItemLabel.SetText(fmt.Sprintf("Last Item was %s and gave you: %.2f Tear Rate, %.2f Tear Delay, %.2f Tear Delay Multiplier, %.2f Range,%.2f Height, %.2f Damage, %.2f Damage Multiplier, %.2f Speed",
		LastItem.Name,
		LastItem.Tears,
		LastItem.Delay,
		LastItem.DelayMultiplier,
		LastItem.Range,
		LastItem.Height,
		LastItem.Damage,
		LastItem.DamageMultiplier,
		LastItem.Speed),
	)
}

func (lastItem LastItemStat) resetLastItem() {
	lastItem.Tears = 0
	lastItem.Delay = 0
	lastItem.DelayMultiplier = 0
	lastItem.Range = 0
	lastItem.Height = 0
	lastItem.Damage = 0
	lastItem.DamageMultiplier = 0
	lastItem.Speed = 0
	lastItem.Description = ""
	lastItem.Name = ""
}

func processLine(line string) {
	if strings.HasPrefix(line, "RNG Start Seed") {
		splitSeed := strings.Split(line, " ")
		Run.Seed = strings.Join(splitSeed[3:5], " ")
		Run.Tears = 0
		Run.Delay = 0
		Run.DelayMultiplier = 0
		Run.Range = 0
		Run.Height = 0
		Run.Damage = 0
		Run.DamageMultiplier = 0
		Run.Speed = 0
		Run.ItemIDs = make([]string, 0)
	}

	if strings.HasPrefix(line, "Adding collectible") {
		collectibleSplit := strings.Split(line, " ")
		collectibleID := collectibleSplit[2]
		Run.ItemIDs = append(Run.ItemIDs, collectibleID)
		addToRunData(collectibleID)
	}
}
<commit_msg>This is easier<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/andlabs/ui"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

type ItemData []struct {
	Name             string `json:"name"`
	Shown            bool   `json:"shown,omitempty"`
	Tears            string `json:"tears,omitempty"`
	Delay            string `json:"delay,omitempty"`
	DelayMultiplier  string `json:"delayx,omitempty"`
	Text             string `json:"text,omitempty"`
	Range            string `json:"range,omitempty"`
	Height           string `json:"height,omitempty"`
	Damage           string `json:"damage,omitempty"`
	DamageMultiplier string `json:"damagex,omitempty"`
	Speed            string `json:"speed,omitempty"`
	Health           string `json:"health,omitempty"`
	Space            bool   `json:"space,omitempty"`
	SoulHearts       string `json:"soulhearts,omitempty"`
	ID               string `json:"id"`
}

type RunData struct {
	Seed             string
	Tears            float64
	Delay            float64
	DelayMultiplier  float64
	Range            float64
	Height           float64
	Damage           float64
	DamageMultiplier float64
	Speed            float64
	ItemIDs          []string
}

type LastItemStat struct {
	Name             string
	Tears            float64
	Delay            float64
	DelayMultiplier  float64
	Range            float64
	Height           float64
	Damage           float64
	DamageMultiplier float64
	Speed            float64
	Description      string
}

var SeedLabel, TearsLabel, DelayLabel, DelayMultLabel, RangeLabel, DamageLabel, DamageMultLabel, SpeedLabel, LastItemLabel ui.Label
var Data ItemData
var Run RunData
var LastItem LastItemStat
var Window ui.Window

func main() {

	go ui.Do(gui)

	go processData()
	err := ui.Go()
	if err != nil {
		log.Fatal(err)
	}

}

func addToRunData(id string) {
	for _, element := range Data {
		if element.ID == id {
			LastItem = LastItemStat{}
			if element.Tears != "" {
				tears, err := strconv.ParseFloat(element.Tears, 64)
				LastItem.Tears = tears
				if err != nil {
					log.Fatal(err)
				}
				Run.Tears += tears
			}
			if element.Delay != "" {
				delay, err := strconv.ParseFloat(element.Delay, 64)
				LastItem.Delay = delay
				if err != nil {
					log.Fatal(err)
				}
				Run.Delay += delay
			}
			if element.DelayMultiplier != "" {
				delayMultiplier, err := strconv.ParseFloat(element.DelayMultiplier, 64)
				LastItem.DelayMultiplier = delayMultiplier
				if err != nil {
					log.Fatal(err)
				}
				Run.DelayMultiplier += delayMultiplier
			}
			if element.Range != "" {
				rangey, err := strconv.ParseFloat(element.Range, 64)
				LastItem.Range = rangey
				if err != nil {
					log.Fatal(err)
				}
				Run.Range += rangey
			}
			if element.Height != "" {
				height, err := strconv.ParseFloat(element.Height, 64)
				LastItem.Height = height
				if err != nil {
					log.Fatal(err)
				}
				Run.Height += height
			}
			if element.Damage != "" {
				damage, err := strconv.ParseFloat(element.Damage, 64)
				LastItem.Damage = damage
				if err != nil {
					log.Fatal(err)
				}
				Run.Damage += damage
			}
			if element.DamageMultiplier != "" {
				damageMultiplier, err := strconv.ParseFloat(element.DamageMultiplier, 64)
				LastItem.DamageMultiplier = damageMultiplier
				if err != nil {
					log.Fatal(err)
				}
				Run.DamageMultiplier += damageMultiplier
			}
			if element.Speed != "" {
				speed, err := strconv.ParseFloat(element.Speed, 64)
				LastItem.Speed = speed
				if err != nil {
					log.Fatal(err)
				}
				Run.Speed += speed
			}
			LastItem.Name = element.Name
			break
		}
	}
}

func gui() {
	SeedLabel = ui.NewLabel("Seed")
	TearsLabel = ui.NewLabel("Tears")
	DelayLabel = ui.NewLabel("Delay")
	DelayMultLabel = ui.NewLabel("Delay Multiplier")
	RangeLabel = ui.NewLabel("Range")
	DamageLabel = ui.NewLabel("Damage")
	DamageMultLabel = ui.NewLabel("Damage Multiplier")
	SpeedLabel = ui.NewLabel("Speed")
	LastItemLabel = ui.NewLabel("Last Item Info")

	stack := ui.NewVerticalStack(
		SeedLabel,
		TearsLabel,
		DelayLabel,
		DelayMultLabel,
		RangeLabel,
		DamageLabel,
		DamageMultLabel,
		SpeedLabel,
		LastItemLabel)

	Window = ui.NewWindow("Binding of Isaac Item Tracker", 1200, 175, stack)

	Window.OnClosing(func() bool {
		ui.Stop()
		return true
	})

	Window.Show()
}

func processData() {
	ItemsJson, err := ioutil.ReadFile("items.json")
	if err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(ItemsJson, &Data); err != nil {
		log.Fatal(err)
	}
	ticker := time.NewTicker(time.Millisecond * 500)
	go func() {
		for _ = range ticker.C {
			lines, err := readLines()
			if err != nil {
				log.Fatal(err)
			}
			for _, element := range lines {
				processLine(element)
			}
			ui.Do(fixGui)
		}
	}()

}

func readLines() ([]string, error) {
	file, err := os.Open("log.txt")
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

func fixGui() {
	SeedLabel.SetText(fmt.Sprintf("Seed: %s", Run.Seed))
	TearsLabel.SetText(fmt.Sprintf("Tear Rate: %.2f", Run.Tears))
	DelayLabel.SetText(fmt.Sprintf("Tear Delay: %.2f", Run.Delay))
	DelayMultLabel.SetText(fmt.Sprintf("Tear Delay Multiplier: %.2f", Run.DelayMultiplier))
	RangeLabel.SetText(fmt.Sprintf("Range: %.2f", Run.Range))
	DamageLabel.SetText(fmt.Sprintf("Damage: %.2f", Run.Damage))
	DamageMultLabel.SetText(fmt.Sprintf("Damage Multiplier: %.2f", Run.DamageMultiplier))
	SpeedLabel.SetText(fmt.Sprintf("Speed: %.2f", Run.Speed))
	LastItemLabel.SetText(fmt.Sprintf("Last Item was %s and gave you: %.2f Tear Rate, %.2f Tear Delay, %.2f Tear Delay Multiplier, %.2f Range,%.2f Height, %.2f Damage, %.2f Damage Multiplier, %.2f Speed",
		LastItem.Name,
		LastItem.Tears,
		LastItem.Delay,
		LastItem.DelayMultiplier,
		LastItem.Range,
		LastItem.Height,
		LastItem.Damage,
		LastItem.DamageMultiplier,
		LastItem.Speed),
	)
}

func processLine(line string) {
	if strings.HasPrefix(line, "RNG Start Seed") {
		splitSeed := strings.Split(line, " ")
		Run.Seed = strings.Join(splitSeed[3:5], " ")
		Run.Tears = 0
		Run.Delay = 0
		Run.DelayMultiplier = 0
		Run.Range = 0
		Run.Height = 0
		Run.Damage = 0
		Run.DamageMultiplier = 0
		Run.Speed = 0
		Run.ItemIDs = make([]string, 0)
		LastItem = LastItemStat{}
	}

	if strings.HasPrefix(line, "Adding collectible") {
		LastItem = LastItemStat{}
		collectibleSplit := strings.Split(line, " ")
		collectibleID := collectibleSplit[2]
		Run.ItemIDs = append(Run.ItemIDs, collectibleID)
		addToRunData(collectibleID)
	}
}
<|endoftext|>