<commit_before>package executors

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/akerl/speculate/creds"

	"github.com/aws/aws-sdk-go/service/sts"
)

const (
	mfaCodeRegexString   = `^\d{6}$`
	mfaArnRegexString    = `^arn:aws(?:-gov)?:iam::\d+:mfa/[\w+=,.@-]+$`
	iamEntityRegexString = `^[\w+=,.@-]+$`
	accountIDRegexString = `^\d{12}$`
)

var mfaCodeRegex = regexp.MustCompile(mfaCodeRegexString)
var mfaArnRegex = regexp.MustCompile(mfaArnRegexString)
var iamEntityRegex = regexp.MustCompile(iamEntityRegexString)
var accountIDRegex = regexp.MustCompile(accountIDRegexString)

// Executor defines the interface for requesting a new set of AWS creds
type Executor interface {
	Execute() (creds.Creds, error)
	ExecuteWithCreds(creds.Creds) (creds.Creds, error)
	SetAccountID(string) error
	SetRoleName(string) error
	SetSessionName(string) error
	SetPolicy(string) error
	SetLifetime(int64) error
	SetMfa(bool) error
	SetMfaSerial(string) error
	SetMfaCode(string) error
	SetMfaPrompt(mfaPromptFunc) error
	GetAccountID() (string, error)
	GetRoleName() (string, error)
	GetSessionName() (string, error)
	GetPolicy() (string, error)
	GetLifetime() (int64, error)
	GetMfa() (bool, error)
	GetMfaSerial() (string, error)
	GetMfaCode() (string, error)
	GetMfaPrompt() (mfaPromptFunc, error)
}

// Lifetime object encapsulates the setup of session duration
type Lifetime struct {
	lifetimeInt int64
}

// SetLifetime allows setting the credential lifespan
func (l *Lifetime) SetLifetime(val int64) error {
	if val != 0 && (val < 900 || val > 3600) {
		return fmt.Errorf("Lifetime must be between 900 and 3600: %d", val)
	}
	l.lifetimeInt = val
	return nil
}

// GetLifetime returns the lifetime of the executor
func (l *Lifetime) GetLifetime() (int64, error) {
	if l.lifetimeInt == 0 {
		l.lifetimeInt = 3600
	}
	return l.lifetimeInt, nil
}

// Mfa object encapsulates the setup of MFA for API calls
type Mfa struct {
	useMfa    bool
	mfaSerial string
	mfaCode   string
	mfaPrompt mfaPromptFunc
}

type mfaPromptFunc func() (string, error)

// SetMfa sets whether MFA is used
func (m *Mfa) SetMfa(val bool) error {
	m.useMfa = val
	return nil
}

// SetMfaSerial sets the ARN of the MFA device
func (m *Mfa) SetMfaSerial(val string) error {
	if val == "" || mfaArnRegex.MatchString(val) {
		m.mfaSerial = val
		return nil
	}
	return fmt.Errorf("MFA Serial is malformed: %s", val)
}

// SetMfaCode sets the OTP for MFA
func (m *Mfa) SetMfaCode(val string) error {
	if val == "" || mfaCodeRegex.MatchString(val) {
		m.mfaCode = val
		return nil
	}
	return fmt.Errorf("MFA Code is malformed: %s", val)
}

// SetMfaPrompt provides a custom method for loading the MFA code
func (m *Mfa) SetMfaPrompt(val mfaPromptFunc) error {
	m.mfaPrompt = val
	return nil
}

// GetMfa returns if MFA will be used
func (m *Mfa) GetMfa() (bool, error) {
	if !m.useMfa && m.mfaCode != "" {
		m.useMfa = true
	}
	return m.useMfa, nil
}

// GetMfaSerial returns the ARN of the MFA device
func (m *Mfa) GetMfaSerial() (string, error) {
	if m.mfaSerial == "" {
		c := creds.Creds{}
		var err error
		m.mfaSerial, err = c.MfaArn()
		if err != nil {
			return "", err
		}
	}
	return m.mfaSerial, nil
}

// GetMfaCode returns the OTP to use
func (m *Mfa) GetMfaCode() (string, error) {
	if m.mfaCode == "" {
		mfaPrompt, err := m.GetMfaPrompt()
		if err != nil {
			return "", err
		}
		mfa, err := mfaPrompt()
		if err != nil {
			return "", err
		}
		m.mfaCode = mfa
	}
	return m.mfaCode, nil
}

// GetMfaPrompt returns the function to use for asking the user for an MFA code
func (m *Mfa) GetMfaPrompt() (mfaPromptFunc, error) {
	if m.mfaPrompt == nil {
		m.mfaPrompt = defaultMfaPrompt
	}
	return m.mfaPrompt, nil
}

func defaultMfaPrompt() (string, error) {
	mfaReader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "MFA Code: ")
	mfa, err := mfaReader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(mfa), nil
}

func (m *Mfa) configureMfa(paramsIface interface{}) error {
	useMfa, err := m.GetMfa()
	if err != nil {
		return err
	}
	if !useMfa {
		return nil
	}

	mfaCode, err := m.GetMfaCode()
	if err != nil {
		return err
	}
	mfaSerial, err := m.GetMfaSerial()
	if err != nil {
		return err
	}

	switch params := paramsIface.(type) {
	case *sts.AssumeRoleInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	case *sts.GetSessionTokenInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	default:
		return fmt.Errorf("Expected AssumeRoleInput or GetSessionTokenInput, received %T", params)
	}
	return nil
}
<commit_msg>switch MfaPrompt to use an interface instead of a raw function<commit_after>package executors

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/akerl/speculate/creds"

	"github.com/aws/aws-sdk-go/service/sts"
)

const (
	mfaCodeRegexString   = `^\d{6}$`
	mfaArnRegexString    = `^arn:aws(?:-gov)?:iam::\d+:mfa/[\w+=,.@-]+$`
	iamEntityRegexString = `^[\w+=,.@-]+$`
	accountIDRegexString = `^\d{12}$`
)

var mfaCodeRegex = regexp.MustCompile(mfaCodeRegexString)
var mfaArnRegex = regexp.MustCompile(mfaArnRegexString)
var iamEntityRegex = regexp.MustCompile(iamEntityRegexString)
var accountIDRegex = regexp.MustCompile(accountIDRegexString)

// Executor defines the interface for requesting a new set of AWS creds
type Executor interface {
	Execute() (creds.Creds, error)
	ExecuteWithCreds(creds.Creds) (creds.Creds, error)
	SetAccountID(string) error
	SetRoleName(string) error
	SetSessionName(string) error
	SetPolicy(string) error
	SetLifetime(int64) error
	SetMfa(bool) error
	SetMfaSerial(string) error
	SetMfaCode(string) error
	SetMfaPrompt(MfaPrompt) error
	GetAccountID() (string, error)
	GetRoleName() (string, error)
	GetSessionName() (string, error)
	GetPolicy() (string, error)
	GetLifetime() (int64, error)
	GetMfa() (bool, error)
	GetMfaSerial() (string, error)
	GetMfaCode() (string, error)
	GetMfaPrompt() (MfaPrompt, error)
}

// Lifetime object encapsulates the setup of session duration
type Lifetime struct {
	lifetimeInt int64
}

// SetLifetime allows setting the credential lifespan
func (l *Lifetime) SetLifetime(val int64) error {
	if val != 0 && (val < 900 || val > 3600) {
		return fmt.Errorf("Lifetime must be between 900 and 3600: %d", val)
	}
	l.lifetimeInt = val
	return nil
}

// GetLifetime returns the lifetime of the executor
func (l *Lifetime) GetLifetime() (int64, error) {
	if l.lifetimeInt == 0 {
		l.lifetimeInt = 3600
	}
	return l.lifetimeInt, nil
}

// Mfa object encapsulates the setup of MFA for API calls
type Mfa struct {
	useMfa    bool
	mfaSerial string
	mfaCode   string
	mfaPrompt MfaPrompt
}

// MfaPrompt interface describes an object which can prompt the user for their MFA
type MfaPrompt interface {
	Prompt() (string, error)
}

// SetMfa sets whether MFA is used
func (m *Mfa) SetMfa(val bool) error {
	m.useMfa = val
	return nil
}

// SetMfaSerial sets the ARN of the MFA device
func (m *Mfa) SetMfaSerial(val string) error {
	if val == "" || mfaArnRegex.MatchString(val) {
		m.mfaSerial = val
		return nil
	}
	return fmt.Errorf("MFA Serial is malformed: %s", val)
}

// SetMfaCode sets the OTP for MFA
func (m *Mfa) SetMfaCode(val string) error {
	if val == "" || mfaCodeRegex.MatchString(val) {
		m.mfaCode = val
		return nil
	}
	return fmt.Errorf("MFA Code is malformed: %s", val)
}

// SetMfaPrompt provides a custom method for loading the MFA code
func (m *Mfa) SetMfaPrompt(val MfaPrompt) error {
	m.mfaPrompt = val
	return nil
}

// GetMfa returns if MFA will be used
func (m *Mfa) GetMfa() (bool, error) {
	if !m.useMfa && m.mfaCode != "" {
		m.useMfa = true
	}
	return m.useMfa, nil
}

// GetMfaSerial returns the ARN of the MFA device
func (m *Mfa) GetMfaSerial() (string, error) {
	if m.mfaSerial == "" {
		c := creds.Creds{}
		var err error
		m.mfaSerial, err = c.MfaArn()
		if err != nil {
			return "", err
		}
	}
	return m.mfaSerial, nil
}

// GetMfaCode returns the OTP to use
func (m *Mfa) GetMfaCode() (string, error) {
	if m.mfaCode == "" {
		mfaPrompt, err := m.GetMfaPrompt()
		if err != nil {
			return "", err
		}
		mfa, err := mfaPrompt.Prompt()
		if err != nil {
			return "", err
		}
		m.mfaCode = mfa
	}
	return m.mfaCode, nil
}

// GetMfaPrompt returns the function to use for asking the user for an MFA code
func (m *Mfa) GetMfaPrompt() (MfaPrompt, error) {
	if m.mfaPrompt == nil {
		m.mfaPrompt = &DefaultMfaPrompt{}
	}
	return m.mfaPrompt, nil
}

// DefaultMfaPrompt defines the standard CLI-based MFA prompt
type DefaultMfaPrompt struct{}

// Prompt asks the user for their MFA token
func (p *DefaultMfaPrompt) Prompt() (string, error) {
	mfaReader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "MFA Code: ")
	mfa, err := mfaReader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(mfa), nil
}

func (m *Mfa) configureMfa(paramsIface interface{}) error {
	useMfa, err := m.GetMfa()
	if err != nil {
		return err
	}
	if !useMfa {
		return nil
	}

	mfaCode, err := m.GetMfaCode()
	if err != nil {
		return err
	}
	mfaSerial, err := m.GetMfaSerial()
	if err != nil {
		return err
	}

	switch params := paramsIface.(type) {
	case *sts.AssumeRoleInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	case *sts.GetSessionTokenInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	default:
		return fmt.Errorf("Expected AssumeRoleInput or GetSessionTokenInput, received %T", params)
	}
	return nil
}
<|endoftext|>


<commit_before>package exif

//go:generate go run regen_regress.go -- regress_expected_test.go
//go:generate go fmt regress_expected_test.go

import (
	"flag"
	"fmt"
	"io"
	"math"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/xor-gate/goexif2/tiff"
)

var dataDir = flag.String("test_data_dir", ".", "Directory where the data files for testing are located")

func TestDecode(t *testing.T) {
	fpath := filepath.Join(*dataDir, "samples")
	f, err := os.Open(fpath)
	if err != nil {
		t.Fatalf("Could not open sample directory '%s': %v", fpath, err)
	}

	names, err := f.Readdirnames(0)
	if err != nil {
		t.Fatalf("Could not read sample directory '%s': %v", fpath, err)
	}

	cnt := 0
	for _, name := range names {
		if !strings.HasSuffix(name, ".jpg") {
			t.Logf("skipping non .jpg file %v", name)
			continue
		}
		t.Logf("testing file %v", name)
		f, err := os.Open(filepath.Join(fpath, name))
		if err != nil {
			t.Fatal(err)
		}

		x, err := Decode(f)
		if err != nil {
			t.Fatal(err)
		} else if x == nil {
			t.Fatalf("No error and yet %v was not decoded", name)
		}

		t.Logf("checking pic %v", name)
		x.Walk(&walker{name, t})
		cnt++
	}
	if cnt != len(regressExpected) {
		t.Errorf("Did not process enough samples, got %d, want %d", cnt, len(regressExpected))
	}
}

type walker struct {
	picName string
	t       *testing.T
}

func (w *walker) Walk(field FieldName, tag *tiff.Tag) error {
	// this needs to be commented out when regenerating regress expected vals
	pic := regressExpected[w.picName]
	if pic == nil {
		w.t.Errorf("   regression data not found")
		return nil
	}

	exp, ok := pic[field]
	if !ok {
		w.t.Errorf("   regression data does not have field %v", field)
		return nil
	}

	s := tag.String()
	if tag.Count == 1 && s != "\"\"" {
		s = fmt.Sprintf("[%s]", s)
	}
	got := tag.String()

	if exp != got {
		fmt.Println("s: ", s)
		fmt.Printf("len(s)=%v\n", len(s))
		w.t.Errorf("   field %v bad tag: expected '%s', got '%s'", field, exp, got)
	}
	return nil
}

func TestMarshal(t *testing.T) {
	name := filepath.Join(*dataDir, "sample1.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	x, err := Decode(f)
	if err != nil {
		t.Fatal(err)
	}
	if x == nil {
		t.Fatal("bad err")
	}

	b, err := x.MarshalJSON()
	if err != nil {
		t.Fatal(err)
	}

	t.Logf("%s", b)
}

func testSingleParseDegreesString(t *testing.T, s string, w float64) {
	g, err := parseTagDegreesString(s)
	if err != nil {
		t.Fatal(err)
	}
	if math.Abs(w-g) > 1e-10 {
		t.Errorf("Wrong parsing result %s: Want %.12f, got %.12f", s, w, g)
	}
}

func TestParseTagDegreesString(t *testing.T) {
	// semicolon as decimal mark
	testSingleParseDegreesString(t, "52,00000,50,00000,34,01180", 52.842781055556) // comma as separator
	testSingleParseDegreesString(t, "52,00000;50,00000;34,01180", 52.842781055556) // semicolon as separator

	// point as decimal mark
	testSingleParseDegreesString(t, "14.00000,44.00000,34.01180", 14.742781055556) // comma as separator
	testSingleParseDegreesString(t, "14.00000;44.00000;34.01180", 14.742781055556) // semicolon as separator
	testSingleParseDegreesString(t, "14.00000;44.00000,34.01180", 14.742781055556) // mixed separators

	testSingleParseDegreesString(t, "-008.0,30.0,03.6", -8.501) // leading zeros

	// no decimal places
	testSingleParseDegreesString(t, "-10,15,54", -10.265)
	testSingleParseDegreesString(t, "-10;15;54", -10.265)

	// incorrect mix of comma and point as decimal mark
	s := "-17,00000,15.00000,04.80000"
	if _, err := parseTagDegreesString(s); err == nil {
		t.Error("parseTagDegreesString: false positive for " + s)
	}
}

// Make sure we error out early when a tag had a count of MaxUint32
func TestMaxUint32CountError(t *testing.T) {
	name := filepath.Join(*dataDir, "corrupt/max_uint32_exif.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(f)
	if err == nil {
		t.Fatal("no error on bad exif data")
	}
	if !strings.Contains(err.Error(), "invalid Count offset") {
		t.Fatal("wrong error:", err.Error())
	}
}

// Make sure we error out early with tag data sizes larger than the image file
func TestHugeTagError(t *testing.T) {
	name := filepath.Join(*dataDir, "corrupt/huge_tag_exif.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(f)
	if err == nil {
		t.Fatal("no error on bad exif data")
	}
	if !strings.Contains(err.Error(), "short read") {
		t.Fatal("wrong error:", err.Error())
	}
}

// Even though the image contains a 0-length tag value, we continue and get some data
func TestZeroLengthTagError(t *testing.T) {
	name := filepath.Join(*dataDir, "corrupt/infinite_loop_exif.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(f)
	if err == nil {
		t.Fatal("no error on bad exif data")
	}
	if !strings.Contains(err.Error(), "exif: decode failed (tiff: recursive IFD)") {
		t.Fatal("wrong error:", err.Error())
	}
}

// stutteredReader makes sure that any call to Read only returns N number of
// bytes at most.
type stutteredReader struct {
	R io.Reader
	N int64
}

func (r stutteredReader) Read(b []byte) (int, error) {
	lr := &io.LimitedReader{r.R, r.N}
	return lr.Read(b)
}

func TestShortRead(t *testing.T) {
	name := filepath.Join(*dataDir, "sample1.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(stutteredReader{f, 1})
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>exif: Fix vet io.LimitedReader composite literal uses unkeyed fields<commit_after>package exif

//go:generate go run regen_regress.go -- regress_expected_test.go
//go:generate go fmt regress_expected_test.go

import (
	"flag"
	"fmt"
	"io"
	"math"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/xor-gate/goexif2/tiff"
)

var dataDir = flag.String("test_data_dir", ".", "Directory where the data files for testing are located")

func TestDecode(t *testing.T) {
	fpath := filepath.Join(*dataDir, "samples")
	f, err := os.Open(fpath)
	if err != nil {
		t.Fatalf("Could not open sample directory '%s': %v", fpath, err)
	}

	names, err := f.Readdirnames(0)
	if err != nil {
		t.Fatalf("Could not read sample directory '%s': %v", fpath, err)
	}

	cnt := 0
	for _, name := range names {
		if !strings.HasSuffix(name, ".jpg") {
			t.Logf("skipping non .jpg file %v", name)
			continue
		}
		t.Logf("testing file %v", name)
		f, err := os.Open(filepath.Join(fpath, name))
		if err != nil {
			t.Fatal(err)
		}

		x, err := Decode(f)
		if err != nil {
			t.Fatal(err)
		} else if x == nil {
			t.Fatalf("No error and yet %v was not decoded", name)
		}

		t.Logf("checking pic %v", name)
		x.Walk(&walker{name, t})
		cnt++
	}
	if cnt != len(regressExpected) {
		t.Errorf("Did not process enough samples, got %d, want %d", cnt, len(regressExpected))
	}
}

type walker struct {
	picName string
	t       *testing.T
}

func (w *walker) Walk(field FieldName, tag *tiff.Tag) error {
	// this needs to be commented out when regenerating regress expected vals
	pic := regressExpected[w.picName]
	if pic == nil {
		w.t.Errorf("   regression data not found")
		return nil
	}

	exp, ok := pic[field]
	if !ok {
		w.t.Errorf("   regression data does not have field %v", field)
		return nil
	}

	s := tag.String()
	if tag.Count == 1 && s != "\"\"" {
		s = fmt.Sprintf("[%s]", s)
	}
	got := tag.String()

	if exp != got {
		fmt.Println("s: ", s)
		fmt.Printf("len(s)=%v\n", len(s))
		w.t.Errorf("   field %v bad tag: expected '%s', got '%s'", field, exp, got)
	}
	return nil
}

func TestMarshal(t *testing.T) {
	name := filepath.Join(*dataDir, "sample1.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	x, err := Decode(f)
	if err != nil {
		t.Fatal(err)
	}
	if x == nil {
		t.Fatal("bad err")
	}

	b, err := x.MarshalJSON()
	if err != nil {
		t.Fatal(err)
	}

	t.Logf("%s", b)
}

func testSingleParseDegreesString(t *testing.T, s string, w float64) {
	g, err := parseTagDegreesString(s)
	if err != nil {
		t.Fatal(err)
	}
	if math.Abs(w-g) > 1e-10 {
		t.Errorf("Wrong parsing result %s: Want %.12f, got %.12f", s, w, g)
	}
}

func TestParseTagDegreesString(t *testing.T) {
	// semicolon as decimal mark
	testSingleParseDegreesString(t, "52,00000,50,00000,34,01180", 52.842781055556) // comma as separator
	testSingleParseDegreesString(t, "52,00000;50,00000;34,01180", 52.842781055556) // semicolon as separator

	// point as decimal mark
	testSingleParseDegreesString(t, "14.00000,44.00000,34.01180", 14.742781055556) // comma as separator
	testSingleParseDegreesString(t, "14.00000;44.00000;34.01180", 14.742781055556) // semicolon as separator
	testSingleParseDegreesString(t, "14.00000;44.00000,34.01180", 14.742781055556) // mixed separators

	testSingleParseDegreesString(t, "-008.0,30.0,03.6", -8.501) // leading zeros

	// no decimal places
	testSingleParseDegreesString(t, "-10,15,54", -10.265)
	testSingleParseDegreesString(t, "-10;15;54", -10.265)

	// incorrect mix of comma and point as decimal mark
	s := "-17,00000,15.00000,04.80000"
	if _, err := parseTagDegreesString(s); err == nil {
		t.Error("parseTagDegreesString: false positive for " + s)
	}
}

// Make sure we error out early when a tag had a count of MaxUint32
func TestMaxUint32CountError(t *testing.T) {
	name := filepath.Join(*dataDir, "corrupt/max_uint32_exif.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(f)
	if err == nil {
		t.Fatal("no error on bad exif data")
	}
	if !strings.Contains(err.Error(), "invalid Count offset") {
		t.Fatal("wrong error:", err.Error())
	}
}

// Make sure we error out early with tag data sizes larger than the image file
func TestHugeTagError(t *testing.T) {
	name := filepath.Join(*dataDir, "corrupt/huge_tag_exif.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(f)
	if err == nil {
		t.Fatal("no error on bad exif data")
	}
	if !strings.Contains(err.Error(), "short read") {
		t.Fatal("wrong error:", err.Error())
	}
}

// Even though the image contains a 0-length tag value, we continue and get some data
func TestZeroLengthTagError(t *testing.T) {
	name := filepath.Join(*dataDir, "corrupt/infinite_loop_exif.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(f)
	if err == nil {
		t.Fatal("no error on bad exif data")
	}
	if !strings.Contains(err.Error(), "exif: decode failed (tiff: recursive IFD)") {
		t.Fatal("wrong error:", err.Error())
	}
}

// stutteredReader makes sure that any call to Read only returns N number of
// bytes at most.
type stutteredReader struct {
	R io.Reader
	N int64
}

func (r stutteredReader) Read(b []byte) (int, error) {
	lr := &io.LimitedReader{R: r.R, N: r.N}
	return lr.Read(b)
}

func TestShortRead(t *testing.T) {
	name := filepath.Join(*dataDir, "sample1.jpg")
	f, err := os.Open(name)
	if err != nil {
		t.Fatalf("%v\n", err)
	}
	defer f.Close()

	_, err = Decode(stutteredReader{f, 1})
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package handlers

import (
	"code.google.com/p/go-uuid/uuid"
	"github.com/Clever/leakybucket"
	"github.com/Clever/sphinx"
	"github.com/Clever/sphinx/common"
	"log"
	"net/http"
	"strconv"
	"strings"
)

func stringifyHeaders(headers http.Header) string {
	out := ""
	for header, values := range headers {
		out += header + "=" + strings.Join(values, ",") + " "
	}
	return out
}
func stringifyRequest(req common.Request) string {
	out := "path=" + req["path"].(string) + " "
	out += "remoteaddr=" + req["remoteaddr"].(string) + " "
	out += stringifyHeaders(req["headers"].(http.Header))
	return out
}

type httpRateLimiter struct {
	rateLimiter sphinx.RateLimiter
	proxy       http.Handler
}

func (hrl httpRateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	guid := uuid.New()
	request := common.HTTPToSphinxRequest(r)
	log.Printf("[%s] REQUEST: %s", guid, stringifyRequest(request))
	matches, err := hrl.rateLimiter.Add(request)
	if err != nil && err != leakybucket.ErrorFull {
		log.Printf("[%s] ERROR: %s", guid, err)
		w.WriteHeader(500)
		return
	}
	addRateLimitHeaders(w, matches)
	if err == leakybucket.ErrorFull {
		w.WriteHeader(429)
		return
	}
	hrl.proxy.ServeHTTP(w, r)
}

type httpRateLogger httpRateLimiter

func (hrl httpRateLogger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	guid := uuid.New()
	request := common.HTTPToSphinxRequest(r)
	log.Printf("[%s] REQUEST: %s", guid, stringifyRequest(request))
	matches, err := hrl.rateLimiter.Add(request)
	if err != nil && err != leakybucket.ErrorFull {
		log.Printf("[%s] ERROR: %s", guid, err)
		hrl.proxy.ServeHTTP(w, r)
		return
	}
	log.Printf("[%s] RATE LIMIT HEADERS: %s", guid, stringifyHeaders(getRateLimitHeaders(matches)))
	if err == leakybucket.ErrorFull {
		log.Printf("[%s] BUCKET FULL", guid)
	}
	hrl.proxy.ServeHTTP(w, r)
}

func uintToString(num uint) string {
	return strconv.Itoa(int(num))
}

func int64ToString(num int64) string {
	return strconv.Itoa(int(num))
}

func initHeaders() map[string][]string {
	headers := map[string][]string{}
	for _, header := range []string{"Limit", "Reset", "Remaining", "Bucket"} {
		headerName := "X-Ratelimit-" + header
		if headers[headerName] == nil {
			headers[headerName] = []string{}
		}
	}
	return headers
}

func getRateLimitHeaders(statuses []sphinx.Status) map[string][]string {
	if len(statuses) == 0 {
		return map[string][]string{}
	}
	headers := initHeaders()
	for _, status := range statuses {
		headers["X-Ratelimit-Limit"] = append(headers["X-Ratelimit-Limit"], uintToString(status.Capacity))
		headers["X-Ratelimit-Reset"] = append(headers["X-Ratelimit-Reset"], int64ToString(status.Reset.Unix()))
		headers["X-Ratelimit-Remaining"] = append(headers["X-Ratelimit-Remaining"], uintToString(status.Remaining))
		headers["X-Ratelimit-Bucket"] = append(headers["X-Ratelimit-Bucket"], status.Name)
	}
	return headers
}

func addRateLimitHeaders(w http.ResponseWriter, statuses []sphinx.Status) {
	for header, values := range getRateLimitHeaders(statuses) {
		for _, value := range values {
			w.Header().Add(header, value)
		}
	}
}

// NewHTTPLimiter returns an http.Handler that rate limits and proxies requests.
func NewHTTPLimiter(rateLimiter sphinx.RateLimiter, proxy http.Handler) http.Handler {
	return httpRateLimiter{rateLimiter: rateLimiter, proxy: proxy}
}

// NewHTTPLogger returns an http.Handler that logs the results of rate limiting requests, but
// actually proxies everything.
func NewHTTPLogger(rateLimiter sphinx.RateLimiter, proxy http.Handler) http.Handler {
	return httpRateLogger{rateLimiter: rateLimiter, proxy: proxy}
}
<commit_msg>handlers: concat buffers instead of bytes<commit_after>package handlers

import (
	"bytes"
	"code.google.com/p/go-uuid/uuid"
	"github.com/Clever/leakybucket"
	"github.com/Clever/sphinx"
	"github.com/Clever/sphinx/common"
	"log"
	"net/http"
	"strconv"
	"strings"
)

func stringifyHeaders(headers http.Header) *bytes.Buffer {
	buf := &bytes.Buffer{}
	for header, values := range headers {
		buf.WriteString(header)
		buf.WriteString("=")
		buf.WriteString(strings.Join(values, ","))
		buf.WriteString(" ")
	}
	return buf
}
func stringifyRequest(req common.Request) *bytes.Buffer {
	buf := &bytes.Buffer{}
	for _, field := range []string{"path", "remoteaddr"} {
		buf.WriteString(field)
		buf.WriteString("=")
		buf.WriteString(req[field].(string))
		buf.WriteString(" ")
	}
	buf.Write(stringifyHeaders(req["headers"].(http.Header)).Bytes())
	return buf
}

type httpRateLimiter struct {
	rateLimiter sphinx.RateLimiter
	proxy       http.Handler
}

func (hrl httpRateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	guid := uuid.New()
	request := common.HTTPToSphinxRequest(r)
	log.Printf("[%s] REQUEST: %s", guid, stringifyRequest(request).String())
	matches, err := hrl.rateLimiter.Add(request)
	if err != nil && err != leakybucket.ErrorFull {
		log.Printf("[%s] ERROR: %s", guid, err)
		w.WriteHeader(500)
		return
	}
	addRateLimitHeaders(w, matches)
	if err == leakybucket.ErrorFull {
		w.WriteHeader(429)
		return
	}
	hrl.proxy.ServeHTTP(w, r)
}

type httpRateLogger httpRateLimiter

func (hrl httpRateLogger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	guid := uuid.New()
	request := common.HTTPToSphinxRequest(r)
	log.Printf("[%s] REQUEST: %s", guid, stringifyRequest(request).String())
	matches, err := hrl.rateLimiter.Add(request)
	if err != nil && err != leakybucket.ErrorFull {
		log.Printf("[%s] ERROR: %s", guid, err)
		hrl.proxy.ServeHTTP(w, r)
		return
	}
	log.Printf("[%s] RATE LIMIT HEADERS: %s", guid, stringifyHeaders(getRateLimitHeaders(matches)).String())
	if err == leakybucket.ErrorFull {
		log.Printf("[%s] BUCKET FULL", guid)
	}
	hrl.proxy.ServeHTTP(w, r)
}

func uintToString(num uint) string {
	return strconv.Itoa(int(num))
}

func int64ToString(num int64) string {
	return strconv.Itoa(int(num))
}

func initHeaders() map[string][]string {
	headers := map[string][]string{}
	for _, header := range []string{"Limit", "Reset", "Remaining", "Bucket"} {
		headerName := "X-Ratelimit-" + header
		if headers[headerName] == nil {
			headers[headerName] = []string{}
		}
	}
	return headers
}

func getRateLimitHeaders(statuses []sphinx.Status) map[string][]string {
	if len(statuses) == 0 {
		return map[string][]string{}
	}
	headers := initHeaders()
	for _, status := range statuses {
		headers["X-Ratelimit-Limit"] = append(headers["X-Ratelimit-Limit"], uintToString(status.Capacity))
		headers["X-Ratelimit-Reset"] = append(headers["X-Ratelimit-Reset"], int64ToString(status.Reset.Unix()))
		headers["X-Ratelimit-Remaining"] = append(headers["X-Ratelimit-Remaining"], uintToString(status.Remaining))
		headers["X-Ratelimit-Bucket"] = append(headers["X-Ratelimit-Bucket"], status.Name)
	}
	return headers
}

func addRateLimitHeaders(w http.ResponseWriter, statuses []sphinx.Status) {
	for header, values := range getRateLimitHeaders(statuses) {
		for _, value := range values {
			w.Header().Add(header, value)
		}
	}
}

// NewHTTPLimiter returns an http.Handler that rate limits and proxies requests.
func NewHTTPLimiter(rateLimiter sphinx.RateLimiter, proxy http.Handler) http.Handler {
	return httpRateLimiter{rateLimiter: rateLimiter, proxy: proxy}
}

// NewHTTPLogger returns an http.Handler that logs the results of rate limiting requests, but
// actually proxies everything.
func NewHTTPLogger(rateLimiter sphinx.RateLimiter, proxy http.Handler) http.Handler {
	return httpRateLogger{rateLimiter: rateLimiter, proxy: proxy}
}
<|endoftext|>


<commit_before>package main

func init() {
	h := NewHandler()
	h.CommandName = "version"
	h.CommandPattern = "(version)(( )(.*))"
	h.HandlerFunc = func(cmd *Command) string {
		return `
	elRepl version 0.1
	`
	}
	HandlerRegistry[h.CommandName] = h
}
<commit_msg>Changed to show version of es, not repl.<commit_after>package main

import (
	"fmt"
)

func init() {
	h := NewHandler()
	h.CommandName = "version"
	h.CommandPattern = "(version)(( )(.*))"
	h.HandlerFunc = func(cmd *Command) string {
		url := fmt.Sprintf("http://%s:%s", server.host, server.port)
		fmt.Println("Request:", url)
		res, err := getHttpResource(url)
		if err != nil {
			return err.Error()
		}
		return res
	}
	HandlerRegistry[h.CommandName] = h
}
<|endoftext|>


<commit_before>package esatompub

import (
	"errors"
	"github.com/stretchr/testify/assert"
	"github.com/xtracdev/goes"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"os"
	"testing"
)

func TestSetThresholdFromEnv(t *testing.T) {
	assert.Equal(t, defaultFeedThreshold, FeedThreshold)
	os.Setenv("FEED_THRESHOLD", "2")
	ReadFeedThresholdFromEnv()
	assert.Equal(t, 2, FeedThreshold)
}

func TestSetThresholdToDefaultOnBadEnvSpec(t *testing.T) {
	os.Setenv("FEED_THRESHOLD", "two")
	ReadFeedThresholdFromEnv()
	assert.Equal(t, defaultFeedThreshold, FeedThreshold)
	os.Setenv("FEED_THRESHOLD", "2")
}

func TestReadPreviousFeedId(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	rows := sqlmock.NewRows([]string{"feedid"}).
		AddRow("foo")

	mock.ExpectBegin()
	mock.ExpectQuery(`select feedid from feed where id = \(select max\(id\) from feed\)`).WillReturnRows(rows)

	tx, _ := db.Begin()
	feedid, err := readPreviousFeedId(tx)
	if assert.Nil(t, err) {
		assert.Equal(t, "foo", feedid.String)
		err = mock.ExpectationsWereMet()
		assert.Nil(t, err)
	}
}

func TestReadPreviousFeedIdQueryError(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	queryErr := errors.New("query error")
	mock.ExpectBegin()
	mock.ExpectQuery(`select feedid from feed where id = \(select max\(id\) from feed\)`).WillReturnError(queryErr)

	tx, _ := db.Begin()
	_, err = readPreviousFeedId(tx)
	if assert.NotNil(t, err) {
		assert.Equal(t, queryErr, err)
	}
}

func TestReadPreviousFeedIdScanError(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	foo := struct {
		foo string
		bar string
	}{
		"foo", "bar",
	}
	rows := sqlmock.NewRows([]string{"feedid"}).AddRow(foo)

	mock.ExpectBegin()
	mock.ExpectQuery(`select feedid from feed where id = \(select max\(id\) from feed\)`).WillReturnRows(rows)

	tx, _ := db.Begin()
	_, err = readPreviousFeedId(tx)
	if assert.NotNil(t, err) {
		err = mock.ExpectationsWereMet()
		assert.Nil(t, err)
	}
}

func TestWriteEvent(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	eventPtr := &goes.Event{
		Source:   "agg1",
		Version:  1,
		TypeCode: "foo",
		Payload:  []byte("ok"),
	}

	mock.ExpectBegin()
	mock.ExpectExec("insert into atom_event")

	tx, _ := db.Begin()
	err = writeEventToAtomEventTable(tx, eventPtr)
	assert.Nil(t, nil)
	err = mock.ExpectationsWereMet()
	assert.Nil(t, err)
}

func TestGetRecentFeedCount(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	rows := sqlmock.NewRows([]string{"count(*)"}).AddRow(23)

	mock.ExpectBegin()
	mock.ExpectQuery(`select count\(\*\) from atom_event where feedid is null`).WillReturnRows(rows)
	tx, _ := db.Begin()
	count, err := getRecentFeedCount(tx)
	if assert.Nil(t, err) {
		assert.Equal(t, count, 23)
	}

}
<commit_msg>Unit test of process events<commit_after>package esatompub

import (
	"errors"
	"github.com/stretchr/testify/assert"
	"github.com/xtracdev/goes"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"os"
	"testing"
)

func TestSetThresholdFromEnv(t *testing.T) {
	assert.Equal(t, defaultFeedThreshold, FeedThreshold)
	os.Setenv("FEED_THRESHOLD", "2")
	ReadFeedThresholdFromEnv()
	assert.Equal(t, 2, FeedThreshold)
}

func TestSetThresholdToDefaultOnBadEnvSpec(t *testing.T) {
	os.Setenv("FEED_THRESHOLD", "two")
	ReadFeedThresholdFromEnv()
	assert.Equal(t, defaultFeedThreshold, FeedThreshold)
	os.Setenv("FEED_THRESHOLD", "2")
}

func TestReadPreviousFeedId(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	rows := sqlmock.NewRows([]string{"feedid"}).
		AddRow("foo")

	mock.ExpectBegin()
	mock.ExpectQuery(`select feedid from feed where id = \(select max\(id\) from feed\)`).WillReturnRows(rows)

	tx, _ := db.Begin()
	feedid, err := readPreviousFeedId(tx)
	if assert.Nil(t, err) {
		assert.Equal(t, "foo", feedid.String)
		err = mock.ExpectationsWereMet()
		assert.Nil(t, err)
	}
}

func TestReadPreviousFeedIdQueryError(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	queryErr := errors.New("query error")
	mock.ExpectBegin()
	mock.ExpectQuery(`select feedid from feed where id = \(select max\(id\) from feed\)`).WillReturnError(queryErr)

	tx, _ := db.Begin()
	_, err = readPreviousFeedId(tx)
	if assert.NotNil(t, err) {
		assert.Equal(t, queryErr, err)
	}
}

func TestReadPreviousFeedIdScanError(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	foo := struct {
		foo string
		bar string
	}{
		"foo", "bar",
	}
	rows := sqlmock.NewRows([]string{"feedid"}).AddRow(foo)

	mock.ExpectBegin()
	mock.ExpectQuery(`select feedid from feed where id = \(select max\(id\) from feed\)`).WillReturnRows(rows)

	tx, _ := db.Begin()
	_, err = readPreviousFeedId(tx)
	if assert.NotNil(t, err) {
		err = mock.ExpectationsWereMet()
		assert.Nil(t, err)
	}
}

func TestWriteEvent(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	eventPtr := &goes.Event{
		Source:   "agg1",
		Version:  1,
		TypeCode: "foo",
		Payload:  []byte("ok"),
	}

	mock.ExpectBegin()
	mock.ExpectExec("insert into atom_event")

	tx, _ := db.Begin()
	err = writeEventToAtomEventTable(tx, eventPtr)
	assert.Nil(t, nil)
	err = mock.ExpectationsWereMet()
	assert.Nil(t, err)
}

func TestGetRecentFeedCount(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	rows := sqlmock.NewRows([]string{"count(*)"}).AddRow(23)

	mock.ExpectBegin()
	mock.ExpectQuery(`select count\(\*\) from atom_event where feedid is null`).WillReturnRows(rows)
	tx, _ := db.Begin()
	count, err := getRecentFeedCount(tx)
	if assert.Nil(t, err) {
		assert.Equal(t, count, 23)
	}

}

func TestProcessEvents(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	eventPtr := &goes.Event{
		Source:   "agg1",
		Version:  1,
		TypeCode: "foo",
		Payload:  []byte("ok"),
	}

	//processEvents starts a transaction
	mock.ExpectBegin()

	//table lock is acquired in the happy path
	execOkResult := sqlmock.NewResult(1,1)
	mock.ExpectExec("lock table feed").WillReturnResult(execOkResult)

	//feed id is selected
	rows := sqlmock.NewRows([]string{"feedid"}).
		AddRow("XXX")
	mock.ExpectQuery("select feedid from feed").WillReturnRows(rows)

	//event is inserted into the atom_event table
	mock.ExpectExec("insert into atom_event").WithArgs(
		eventPtr.Source, eventPtr.Version, eventPtr.TypeCode, eventPtr.Payload,
	).WillReturnResult(execOkResult)

	//return the count of threshold to trigger new feed creation
	rows = sqlmock.NewRows([]string{"count(*)"}).
		AddRow(FeedThreshold)
	mock.ExpectQuery(`select count`).WillReturnRows(rows)

	//atom_event is updated with the feed id
	mock.ExpectExec("update atom_event set feedid").WillReturnResult(execOkResult)

	//insert the new feed into the feed table
	mock.ExpectExec("insert into feed").WillReturnResult(execOkResult).WithArgs(sqlmock.AnyArg(),"XXX")

	//expect a commit at the end
	mock.ExpectCommit()

	err = processEvent(db, eventPtr)
	assert.Nil(t, err)

	err = mock.ExpectationsWereMet()
	assert.Nil(t, err)
}
<|endoftext|>


<commit_before>/*
Copyright 2013, 2015, 2017 Andrew Medworth

This file is part of Gopoker, a set of miscellaneous poker-related functions
written in the Go programming language (http://golang.org).

Gopoker 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.

Gopoker 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 Gopoker.  If not, see <http://www.gnu.org/licenses/>.
*/
package holdem

import (
	"fmt"
	"github.com/amdw/gopoker/poker"
	"math/rand"
	"sort"
)

func Classify(holeCards, tableCards []poker.Card) (poker.HandLevel, []poker.Card) {
	allCards := make([]poker.Card, 7)
	copy(allCards, holeCards)
	copy(allCards[2:], tableCards)

	// Construct all possible hands and find the best one
	allPossibleHands := poker.AllCardCombinations(allCards, 5)

	bestHand := allPossibleHands[0]
	bestRank := poker.ClassifyHand(bestHand)

	for i := 1; i < len(allPossibleHands); i++ {
		hand := allPossibleHands[i]
		rank := poker.ClassifyHand(hand)
		if poker.Beats(rank, bestRank) {
			bestHand = hand
			bestRank = rank
		}
	}

	return bestRank, bestHand
}

type PlayerOutcome struct {
	Player int
	Level  poker.HandLevel
	Cards  []poker.Card
}

func sortOutcomes(outcomes []PlayerOutcome) {
	sort.Slice(outcomes, func(i, j int) bool {
		iBeatsJ := poker.Beats(outcomes[i].Level, outcomes[j].Level)
		jBeatsI := poker.Beats(outcomes[j].Level, outcomes[i].Level)
		if iBeatsJ && !jBeatsI {
			return true
		}
		if jBeatsI && !iBeatsJ {
			return false
		}
		return outcomes[i].Player < outcomes[j].Player
	})
}

// Shuffle the pack, but fix certain cards in place. For use in simulations.
// It is assumed that there are no duplicate cards in (tableCards+yourCards).
func shuffleFixing(p *poker.Pack, tableCards, yourCards []poker.Card, randGen *rand.Rand) {
	if len(tableCards) > 5 || len(yourCards) > 2 {
		panic(fmt.Sprintf("Maximum of 5 table cards and 2 hole cards supported, found %v and %v", len(tableCards), len(yourCards)))
	}

	indexOf := func(cards [52]poker.Card, card poker.Card) int {
		result := -1
		for i, c := range cards {
			if c == card {
				result = i
				break
			}
		}
		return result
	}

	// Just shuffle the pack and then swap the fixed cards into place from wherever they are in the deck
	p.Shuffle(randGen)
	for i := 0; i < len(tableCards); i++ {
		swapIdx := indexOf(p.Cards, tableCards[i])
		p.Cards[i], p.Cards[swapIdx] = p.Cards[swapIdx], p.Cards[i]
	}
	for i := 0; i < len(yourCards); i++ {
		swapIdx := indexOf(p.Cards, yourCards[i])
		targetIdx := i + 5
		p.Cards[targetIdx], p.Cards[swapIdx] = p.Cards[swapIdx], p.Cards[targetIdx]
	}
}

func Deal(p *poker.Pack, players int) (onTable []poker.Card, playerCards [][]poker.Card) {
	if players < 1 {
		panic(fmt.Sprintf("At least one player required, found %v", players))
	}

	onTable = p.Cards[0:5]

	playerCards = make([][]poker.Card, players)
	for player := 0; player < players; player++ {
		playerCards[player] = p.Cards[5+2*player : 7+2*player]
	}

	return onTable, playerCards
}

// Assess the hand each player holds and return a sorted list of outcomes
// by hand strength (descending) then player number (ascending).
// Player numbers are in ascending order of playerCards entries, starting with 1.
func DealOutcomes(onTable []poker.Card, playerCards [][]poker.Card) []PlayerOutcome {
	outcomes := make([]PlayerOutcome, len(playerCards))
	for playerIdx, hand := range playerCards {
		level, cards := Classify(hand, onTable)
		outcomes[playerIdx] = PlayerOutcome{playerIdx + 1, level, cards}
	}
	sortOutcomes(outcomes)
	return outcomes
}

type HandOutcome struct {
	Won, OpponentWon, RandomOpponentWon                      bool
	PotFractionWon                                           float64
	BestOpponentPotFractionWon, RandomOpponentPotFractionWon float64
	OurLevel, BestOpponentLevel, RandomOpponentLevel         poker.HandLevel
}

func calcPotFraction(won bool, potSplit int) float64 {
	if won {
		return 1.0 / float64(potSplit)
	} else {
		return 0
	}
}

func calcHandOutcome(outcomes []PlayerOutcome, randGen *rand.Rand) *HandOutcome {
	// This works even if player 1 was equal first, since equal hands are sorted by player
	won := outcomes[0].Player == 1

	var ourOutcome PlayerOutcome
	opponentOutcomes := make([]PlayerOutcome, len(outcomes)-1)
	potSplit := 0
	i := 0
	for _, o := range outcomes {
		if o.Player == 1 {
			ourOutcome = o
		} else {
			opponentOutcomes[i] = o
			i++
		}
		if !poker.Beats(outcomes[0].Level, o.Level) {
			// The best hand doesn't beat this hand so it must be a winner
			potSplit++
		}
	}

	bestOpponentWon := !poker.Beats(ourOutcome.Level, opponentOutcomes[0].Level)

	randomOpponentIdx := randGen.Intn(len(opponentOutcomes))
	randomOpponentLevel := opponentOutcomes[randomOpponentIdx].Level
	randomOpponentWon := !poker.Beats(outcomes[0].Level, randomOpponentLevel)

	potFractionWon := calcPotFraction(won, potSplit)
	bestOpponentPotFraction := calcPotFraction(bestOpponentWon, potSplit)
	randomOpponentPotFraction := calcPotFraction(randomOpponentWon, potSplit)

	return &HandOutcome{won, bestOpponentWon, randomOpponentWon,
		potFractionWon, bestOpponentPotFraction, randomOpponentPotFraction,
		ourOutcome.Level, opponentOutcomes[0].Level, randomOpponentLevel}
}

// Play out one hand of Texas Hold'em and return whether or not player 1 won,
// plus player 1's hand level, plus the best hand level of any of player 1's opponents.
func SimulateOneHoldemHand(p *poker.Pack, players int, randGen *rand.Rand) *HandOutcome {
	onTable, playerCards := Deal(p, players)
	outcomes := DealOutcomes(onTable, playerCards)
	return calcHandOutcome(outcomes, randGen)
}
<commit_msg>Consistently put table cards before hole cards in function parameters<commit_after>/*
Copyright 2013, 2015, 2017 Andrew Medworth

This file is part of Gopoker, a set of miscellaneous poker-related functions
written in the Go programming language (http://golang.org).

Gopoker 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.

Gopoker 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 Gopoker.  If not, see <http://www.gnu.org/licenses/>.
*/
package holdem

import (
	"fmt"
	"github.com/amdw/gopoker/poker"
	"math/rand"
	"sort"
)

func classify(tableCards, holeCards []poker.Card) (poker.HandLevel, []poker.Card) {
	allCards := make([]poker.Card, 7)
	copy(allCards, holeCards)
	copy(allCards[2:], tableCards)

	// Construct all possible hands and find the best one
	allPossibleHands := poker.AllCardCombinations(allCards, 5)

	bestHand := allPossibleHands[0]
	bestRank := poker.ClassifyHand(bestHand)

	for i := 1; i < len(allPossibleHands); i++ {
		hand := allPossibleHands[i]
		rank := poker.ClassifyHand(hand)
		if poker.Beats(rank, bestRank) {
			bestHand = hand
			bestRank = rank
		}
	}

	return bestRank, bestHand
}

type PlayerOutcome struct {
	Player int
	Level  poker.HandLevel
	Cards  []poker.Card
}

func sortOutcomes(outcomes []PlayerOutcome) {
	sort.Slice(outcomes, func(i, j int) bool {
		iBeatsJ := poker.Beats(outcomes[i].Level, outcomes[j].Level)
		jBeatsI := poker.Beats(outcomes[j].Level, outcomes[i].Level)
		if iBeatsJ && !jBeatsI {
			return true
		}
		if jBeatsI && !iBeatsJ {
			return false
		}
		return outcomes[i].Player < outcomes[j].Player
	})
}

// Shuffle the pack, but fix certain cards in place. For use in simulations.
// It is assumed that there are no duplicate cards in (tableCards+yourCards).
func shuffleFixing(p *poker.Pack, tableCards, yourCards []poker.Card, randGen *rand.Rand) {
	if len(tableCards) > 5 || len(yourCards) > 2 {
		panic(fmt.Sprintf("Maximum of 5 table cards and 2 hole cards supported, found %v and %v", len(tableCards), len(yourCards)))
	}

	indexOf := func(cards [52]poker.Card, card poker.Card) int {
		result := -1
		for i, c := range cards {
			if c == card {
				result = i
				break
			}
		}
		return result
	}

	// Just shuffle the pack and then swap the fixed cards into place from wherever they are in the deck
	p.Shuffle(randGen)
	for i := 0; i < len(tableCards); i++ {
		swapIdx := indexOf(p.Cards, tableCards[i])
		p.Cards[i], p.Cards[swapIdx] = p.Cards[swapIdx], p.Cards[i]
	}
	for i := 0; i < len(yourCards); i++ {
		swapIdx := indexOf(p.Cards, yourCards[i])
		targetIdx := i + 5
		p.Cards[targetIdx], p.Cards[swapIdx] = p.Cards[swapIdx], p.Cards[targetIdx]
	}
}

func Deal(p *poker.Pack, players int) (onTable []poker.Card, playerCards [][]poker.Card) {
	if players < 1 {
		panic(fmt.Sprintf("At least one player required, found %v", players))
	}

	onTable = p.Cards[0:5]

	playerCards = make([][]poker.Card, players)
	for player := 0; player < players; player++ {
		playerCards[player] = p.Cards[5+2*player : 7+2*player]
	}

	return onTable, playerCards
}

// Assess the hand each player holds and return a sorted list of outcomes
// by hand strength (descending) then player number (ascending).
// Player numbers are in ascending order of playerCards entries, starting with 1.
func DealOutcomes(onTable []poker.Card, playerCards [][]poker.Card) []PlayerOutcome {
	outcomes := make([]PlayerOutcome, len(playerCards))
	for playerIdx, hand := range playerCards {
		level, cards := classify(onTable, hand)
		outcomes[playerIdx] = PlayerOutcome{playerIdx + 1, level, cards}
	}
	sortOutcomes(outcomes)
	return outcomes
}

type HandOutcome struct {
	Won, OpponentWon, RandomOpponentWon                      bool
	PotFractionWon                                           float64
	BestOpponentPotFractionWon, RandomOpponentPotFractionWon float64
	OurLevel, BestOpponentLevel, RandomOpponentLevel         poker.HandLevel
}

func calcPotFraction(won bool, potSplit int) float64 {
	if won {
		return 1.0 / float64(potSplit)
	} else {
		return 0
	}
}

func calcHandOutcome(outcomes []PlayerOutcome, randGen *rand.Rand) *HandOutcome {
	// This works even if player 1 was equal first, since equal hands are sorted by player
	won := outcomes[0].Player == 1

	var ourOutcome PlayerOutcome
	opponentOutcomes := make([]PlayerOutcome, len(outcomes)-1)
	potSplit := 0
	i := 0
	for _, o := range outcomes {
		if o.Player == 1 {
			ourOutcome = o
		} else {
			opponentOutcomes[i] = o
			i++
		}
		if !poker.Beats(outcomes[0].Level, o.Level) {
			// The best hand doesn't beat this hand so it must be a winner
			potSplit++
		}
	}

	bestOpponentWon := !poker.Beats(ourOutcome.Level, opponentOutcomes[0].Level)

	randomOpponentIdx := randGen.Intn(len(opponentOutcomes))
	randomOpponentLevel := opponentOutcomes[randomOpponentIdx].Level
	randomOpponentWon := !poker.Beats(outcomes[0].Level, randomOpponentLevel)

	potFractionWon := calcPotFraction(won, potSplit)
	bestOpponentPotFraction := calcPotFraction(bestOpponentWon, potSplit)
	randomOpponentPotFraction := calcPotFraction(randomOpponentWon, potSplit)

	return &HandOutcome{won, bestOpponentWon, randomOpponentWon,
		potFractionWon, bestOpponentPotFraction, randomOpponentPotFraction,
		ourOutcome.Level, opponentOutcomes[0].Level, randomOpponentLevel}
}

// Play out one hand of Texas Hold'em and return whether or not player 1 won,
// plus player 1's hand level, plus the best hand level of any of player 1's opponents.
func SimulateOneHoldemHand(p *poker.Pack, players int, randGen *rand.Rand) *HandOutcome {
	onTable, playerCards := Deal(p, players)
	outcomes := DealOutcomes(onTable, playerCards)
	return calcHandOutcome(outcomes, randGen)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"os"
	"strings"
	"syscall"

	"github.com/miekg/dns"
)

type resolver struct {
	spec, addr  string
	defaultport bool
}

func (r resolver) String() string {
	resolved := ""
	host, port, err := net.SplitHostPort(r.addr)
	if err != nil {
		resolved = "???"
	} else if r.spec != host {
		if r.defaultport {
			resolved = host
		} else {
			resolved = net.JoinHostPort(host, port)
		}
	}
	if resolved == r.spec {
		resolved = ""
	}
	if resolved != "" {
		resolved = fmt.Sprintf("=(%s)", resolved)
	}
	return r.spec + resolved
}

func newResolver(server string) (resolver, error) {
	r := resolver{spec: server}
	host, port, err := net.SplitHostPort(server)
	if err != nil {
		host = server
		port = "53"
		r.defaultport = true
	}
	if port == "domain" {
		r.defaultport = true
	}
	if net.ParseIP(host) == nil {
		ips, err := net.LookupIP(host)
		if err != nil {
			return r, err
		}
		host = ips[0].String()
	}
	r.addr = net.JoinHostPort(host, port)
	_, _, err = net.SplitHostPort(r.addr)
	return r, err
}

func query(host string, server resolver) ([]net.IP, error) {
	fqhost := dns.Fqdn(host)
	client := dns.Client{}
	m := dns.Msg{}
	m.SetQuestion(fqhost, dns.TypeA)
	res, _, err := client.Exchange(&m, server.addr)
	if err == nil && (res == nil || res.Answer == nil) {
		err = fmt.Errorf("No results for [%s] from [%s]", fqhost, server)
	}
	if err != nil {
		return nil, err
	}
	var addrs []net.IP
	for _, answer := range res.Answer {
		if record, valid := answer.(*dns.A); valid {
			addrs = append(addrs, record.A)
		}
	}
	return addrs, nil
}

func lookupIPs(host string, servers []resolver) ([]net.IP, error) {
	if servers == nil {
		return net.LookupIP(host)
	}
	var addrs []net.IP
	var failures []error
	failed := func(err error) bool {
		failed := err != nil
		if failed {
			failures = append(failures, err)
		}
		return failed
	}
	for _, server := range servers {
		ips, err := query(host, server)
		if !failed(err) {
			addrs = append(addrs, ips...)
		}
	}
	if addrs == nil && failures == nil {
		failed(fmt.Errorf("No results for [%s] from [%v]", host, servers))
	}
	var err error
	if failures != nil {
		var lines []string
		for _, failure := range failures {
			lines = append(lines, fmt.Sprintf("%s", failure))
		}
		err = fmt.Errorf("%s", strings.Join(lines, "\n"))
	}
	return addrs, err
}

func main() {
	var short bool
	var hosts []string
	var servers []resolver
	for _, arg := range os.Args[1:] {
		switch arg {
		case "+short":
			short = true
		default:
			if strings.HasPrefix(arg, "@") {
				server, err := newResolver(arg[1:])
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error resolving server: %s\n", err)
					goto failed
				}
				servers = append(servers, server)
			} else {
				hosts = append(hosts, arg)
			}
		}
	}
	for _, host := range hosts {
		ips, err := lookupIPs(host, servers)
		if err != nil {
			if !short {
				fmt.Fprintln(os.Stderr, err)
			}
			continue
		}
		fmt.Println(ips[0].String())
		syscall.Exit(0)
	}
failed:
	syscall.Exit(1)
}
<commit_msg>Add some comments to `dig.go`<commit_after>package main

import (
	"fmt"
	"net"
	"os"
	"strings"
	"syscall"

	"github.com/miekg/dns"
)

// A resolver consists of a "spec" (as the server was specified) and an "addr"
// to which the server was resolved.  defaultport is only used for printing the
// resolver back out (port is omitted if it was defaulted).
type resolver struct {
	spec, addr  string
	defaultport bool
}

// String prints the resolver's specification, along with what it resolved to,
// if it differs from the spec.
func (r resolver) String() string {
	resolved := ""
	host, port, err := net.SplitHostPort(r.addr)
	if err != nil {
		resolved = "???"
	} else if r.spec != host {
		if r.defaultport {
			resolved = host
		} else {
			resolved = net.JoinHostPort(host, port)
		}
	}
	if resolved == r.spec {
		resolved = ""
	}
	if resolved != "" {
		resolved = fmt.Sprintf("=(%s)", resolved)
	}
	return r.spec + resolved
}

// newResolver returns a server spec and its locally-resolved address.
func newResolver(server string) (resolver, error) {
	r := resolver{spec: server}
	host, port, err := net.SplitHostPort(server)
	if err != nil {
		host = server
		port = "53"
		r.defaultport = true
	}
	if port == "domain" {
		r.defaultport = true
	}
	if net.ParseIP(host) == nil {
		ips, err := net.LookupIP(host)
		if err != nil {
			return r, err
		}
		host = ips[0].String()
	}
	r.addr = net.JoinHostPort(host, port)
	_, _, err = net.SplitHostPort(r.addr)
	return r, err
}

// resolve a host via the given server
func query(host string, server resolver) ([]net.IP, error) {
	fqhost := dns.Fqdn(host)
	client := dns.Client{}
	m := dns.Msg{}
	m.SetQuestion(fqhost, dns.TypeA)
	res, _, err := client.Exchange(&m, server.addr)
	if err == nil && (res == nil || res.Answer == nil) {
		err = fmt.Errorf("No results for [%s] from [%s]", fqhost, server)
	}
	if err != nil {
		return nil, err
	}
	var addrs []net.IP
	for _, answer := range res.Answer {
		if record, valid := answer.(*dns.A); valid {
			addrs = append(addrs, record.A)
		}
	}
	return addrs, nil
}

// Fetch IPs for the given host. If servers is empty, resolve it locally.
func lookupIPs(host string, servers []resolver) ([]net.IP, error) {
	if servers == nil {
		return net.LookupIP(host)
	}
	var addrs []net.IP
	var failures []error
	failed := func(err error) bool {
		failed := err != nil
		if failed {
			failures = append(failures, err)
		}
		return failed
	}
	for _, server := range servers {
		ips, err := query(host, server)
		if !failed(err) {
			addrs = append(addrs, ips...)
		}
	}
	if addrs == nil && failures == nil {
		failed(fmt.Errorf("No results for [%s] from [%v]", host, servers))
	}
	var err error
	if failures != nil {
		var lines []string
		for _, failure := range failures {
			lines = append(lines, fmt.Sprintf("%s", failure))
		}
		err = fmt.Errorf("%s", strings.Join(lines, "\n"))
	}
	return addrs, err
}

func main() {
	var short bool
	var hosts []string
	var servers []resolver
	for _, arg := range os.Args[1:] {
		switch arg {
		case "+short":
			short = true
		default:
			if strings.HasPrefix(arg, "@") {
				server, err := newResolver(arg[1:])
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error resolving server: %s\n", err)
					goto failed
				}
				servers = append(servers, server)
			} else {
				hosts = append(hosts, arg)
			}
		}
	}
	for _, host := range hosts {
		ips, err := lookupIPs(host, servers)
		if err != nil {
			if !short {
				fmt.Fprintln(os.Stderr, err)
			}
			continue
		}
		fmt.Println(ips[0].String())
		syscall.Exit(0)
	}
failed:
	syscall.Exit(1)
}
<|endoftext|>


<commit_before>package gorobdd

import (
	"testing"
	"github.com/callpraths/gorobdd/internal/tag"
)

func TestBinaryOpsCheckVocabulary(t *testing.T) {
	var tests = []struct {
		lhs *ROBDD
		rhs *ROBDD
	}{
		{True([]string{"a"}), True([]string{"a", "b"})},
		{True([]string{"a", "b"}), True([]string{"a"})},
		{True([]string{"a", "b"}), True([]string{})},
		{True([]string{"a", "b"}), True([]string{"b", "a"})},
		{True([]string{"a", "b"}), True([]string{"a", "a"})},
	}
	for _, tt := range tests {
		if _, e := Equal(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from Equal(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := And(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from And(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := Or(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from Or(%v, %v)", tt.lhs, tt.rhs)
		}
	}
}

func fromTuplesNoError(t *testing.T, v []string, tu [][]bool) *ROBDD {
	b, e := FromTuples(v, tu)
	if e != nil {
		t.Fatalf("FromTuples(%v, %v) returned error: %v", v, tu, e)
	}
	return b
}

func TestBDDEqual(t *testing.T) {
	type testCase struct {
		lhs *ROBDD
		rhs *ROBDD
		eq  bool
		g_eq bool
	}
	tcs := []testCase {
		{True([]string{}), True([]string{}), true, true},
		{False([]string{}), False([]string{}), true, true},
		{True([]string{}), False([]string{}), false, false},
		{False([]string{}), True([]string{}), false, false},
		{True([]string{"a"}), True([]string{"a"}), true, true},
		{False([]string{"a"}), False([]string{"a"}), true, true},
		{True([]string{"a"}), False([]string{"a"}), false, false},
		{False([]string{"a"}), True([]string{"a"}), false, false},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			true,
			true,
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{false, false}}),
			false,
			false,
		},
	}

	tfunc := func (tt testCase) {
		eq, e := Equal(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Equal(%v, %v) failed: %v", tt.lhs, tt.rhs, e)
		}
		if eq != tt.eq {
			t.Errorf("Equal(%v, %v) = %v, want %v", tt.lhs, tt.rhs, eq, tt.eq)
		}
		g_eq, e2 := GraphEqual(tt.lhs, tt.rhs)
		if e2 != nil {
			t.Errorf("GraphEqual(%v, %v) failed: %v", tt.lhs, tt.rhs, e2)
		}
		if g_eq != tt.g_eq {
			t.Errorf("GraphEqual(%v, %v) = %v, want %v", tt.lhs, tt.rhs, g_eq, tt.g_eq)
		}
	}

	s := tag.NewSeenContext()
	for _, tt := range tcs {
		tfunc(tt)
		// Equal operations should completely ignore tags.
		s.MarkSeen(tt.lhs.Node)
		tfunc(tt)
	}
}

func TestBDDBooleanOps(t *testing.T) {
	var tests = []struct {
		lhs *ROBDD
		rhs *ROBDD
		and *ROBDD
		or  *ROBDD
	}{
		{True([]string{}), True([]string{}), True([]string{}), True([]string{})},
		{True([]string{}), False([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), True([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), False([]string{}), False([]string{}), False([]string{})},
		{True([]string{"a"}), True([]string{"a"}), True([]string{"a"}), True([]string{"a"})},
		{True([]string{"a"}), False([]string{"a"}), False([]string{"a"}), True([]string{"a"})},
		{False([]string{"a"}), True([]string{"a"}), False([]string{"a"}), True([]string{"a"})},
		{False([]string{"a"}), False([]string{"a"}), False([]string{"a"}), False([]string{"a"})},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}, {false, true}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {true, false}, {false, true}, {false, false}}),
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {true, false}, {false, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {true, false}, {false, true}, {false, false}}),
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
		},
	}
	for _, tt := range tests {
		var and, or *ROBDD
		var eq bool
		var e error
		and, e = And(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(and, tt.and)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("And(%v, %v) = %v, want %v", tt.lhs, tt.rhs, and, tt.and)
		}
		or, e = Or(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Or(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(or, tt.or)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("Or(%v, %v) = %v, want %v", tt.lhs, tt.rhs, or, tt.or)
		}
	}
}

func TestTrivialBDDNot(t *testing.T) {
	var tests = []struct {
		in  *ROBDD
		ans *ROBDD
	}{
		{True([]string{}), False([]string{})},
		{False([]string{}), True([]string{})},
	}
	for _, tt := range tests {
		ans, e1 := Not(tt.in)
		if e1 != nil {
			t.Errorf("Not(%v) returned error %v", tt.in, e1)
		}
		eq, e2 := Equal(ans, tt.ans)
		if e2 != nil {
			t.Errorf("Equal(%v, %v) returned error %v", ans, tt.ans, e2)
		}
		if !eq {
			t.Errorf("Not(%v) = %v, want %v", tt.in, ans, tt.ans)
		}
	}
}
<commit_msg>BROKEN: Add broken test for Equal.<commit_after>package gorobdd

import (
	"testing"
	"github.com/callpraths/gorobdd/internal/node"
	"github.com/callpraths/gorobdd/internal/tag"
)

func TestBinaryOpsCheckVocabulary(t *testing.T) {
	var tests = []struct {
		lhs *ROBDD
		rhs *ROBDD
	}{
		{True([]string{"a"}), True([]string{"a", "b"})},
		{True([]string{"a", "b"}), True([]string{"a"})},
		{True([]string{"a", "b"}), True([]string{})},
		{True([]string{"a", "b"}), True([]string{"b", "a"})},
		{True([]string{"a", "b"}), True([]string{"a", "a"})},
	}
	for _, tt := range tests {
		if _, e := Equal(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from Equal(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := And(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from And(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := Or(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from Or(%v, %v)", tt.lhs, tt.rhs)
		}
	}
}

func fromTuplesNoError(t *testing.T, v []string, tu [][]bool) *ROBDD {
	b, e := FromTuples(v, tu)
	if e != nil {
		t.Fatalf("FromTuples(%v, %v) returned error: %v", v, tu, e)
	}
	return b
}

func TestBDDEqual(t *testing.T) {
	type testCase struct {
		lhs *ROBDD
		rhs *ROBDD
		eq  bool
		g_eq bool
	}
	tcs := []testCase {
		{True([]string{}), True([]string{}), true, true},
		{False([]string{}), False([]string{}), true, true},
		{True([]string{}), False([]string{}), false, false},
		{False([]string{}), True([]string{}), false, false},
		{True([]string{"a"}), True([]string{"a"}), true, true},
		{False([]string{"a"}), False([]string{"a"}), true, true},
		{True([]string{"a"}), False([]string{"a"}), false, false},
		{False([]string{"a"}), True([]string{"a"}), false, false},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			true,
			true,
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{false, false}}),
			false,
			false,
		},
	}

	tfunc := func (tt testCase) {
		eq, e := Equal(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Equal(%v, %v) failed: %v", tt.lhs, tt.rhs, e)
		}
		if eq != tt.eq {
			t.Errorf("Equal(%v, %v) = %v, want %v", tt.lhs, tt.rhs, eq, tt.eq)
		}
		g_eq, e2 := GraphEqual(tt.lhs, tt.rhs)
		if e2 != nil {
			t.Errorf("GraphEqual(%v, %v) failed: %v", tt.lhs, tt.rhs, e2)
		}
		if g_eq != tt.g_eq {
			t.Errorf("GraphEqual(%v, %v) = %v, want %v", tt.lhs, tt.rhs, g_eq, tt.g_eq)
		}
	}

	s := tag.NewSeenContext()
	for _, tt := range tcs {
		tfunc(tt)
		// Equal operations should completely ignore tags.
		s.MarkSeen(tt.lhs.Node)
		tfunc(tt)
	}
}

func TestBDDEqualLogicallyNotEqualStructurally(t *testing.T) {
	a1 := &ROBDD{
		[]string{"a", "b"},
		&node.Node{
			Type: node.InternalType,
			Internal: node.Internal{
				Ply: 0,
				True: &node.Node{
					Type: node.LeafType,
					Leaf: node.Leaf{false},
				},
				False: &node.Node{
					Type: node.InternalType,
					Internal: node.Internal{
						Ply: 1,
						True: &node.Node{
							Type: node.LeafType,
							Leaf: node.Leaf{false},
						},
						False: &node.Node{
							Type: node.LeafType,
							Leaf: node.Leaf{true},
						},
					},
				},
			},
		},
	}
	tn := &node.Node {
		Type: node.LeafType,
		Leaf: node.Leaf{true},
	}
	fn := &node.Node {
		Type: node.LeafType,
		Leaf: node.Leaf{false},
	}
	bt := &node.Node {
		Type: node.InternalType,
		Internal: node.Internal{True:fn, False:fn},
	}
	bf := &node.Node {
		Type: node.InternalType,
		Internal: node.Internal{True:fn, False:tn},
	}
	a2 := &ROBDD{
		[]string{"a", "b"},
	        &node.Node {
			Type: node.InternalType,
			Internal: node.Internal{True:bt, False:bf},
		},
	}

	eq, e := Equal(a1, a2)
	if e != nil {
		t.Errorf("Equal(%v, %v) failed: %v", a1, a2, e)
	}
	if !eq {
		t.Errorf("Equal(%v, %v) = false, want true", a1, a2)
	}
	g_eq, e2 := GraphEqual(a1, a2)
	if e2 != nil {
		t.Errorf("Equal(%v, %v) failed: %v", a1, a2, e2)
	}
	if g_eq {
		t.Errorf("GraphEqual(%v, %v) = true, want false", a1, a2)
	}
}

func TestBDDBooleanOps(t *testing.T) {
	var tests = []struct {
		lhs *ROBDD
		rhs *ROBDD
		and *ROBDD
		or  *ROBDD
	}{
		{True([]string{}), True([]string{}), True([]string{}), True([]string{})},
		{True([]string{}), False([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), True([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), False([]string{}), False([]string{}), False([]string{})},
		{True([]string{"a"}), True([]string{"a"}), True([]string{"a"}), True([]string{"a"})},
		{True([]string{"a"}), False([]string{"a"}), False([]string{"a"}), True([]string{"a"})},
		{False([]string{"a"}), True([]string{"a"}), False([]string{"a"}), True([]string{"a"})},
		{False([]string{"a"}), False([]string{"a"}), False([]string{"a"}), False([]string{"a"})},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}, {false, true}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {true, false}, {false, true}, {false, false}}),
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {true, false}, {false, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {true, false}, {false, true}, {false, false}}),
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, true}, {false, false}}),
		},
	}
	for _, tt := range tests {
		var and, or *ROBDD
		var eq bool
		var e error
		and, e = And(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(and, tt.and)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("And(%v, %v) = %v, want %v", tt.lhs, tt.rhs, and, tt.and)
		}
		or, e = Or(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Or(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(or, tt.or)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("Or(%v, %v) = %v, want %v", tt.lhs, tt.rhs, or, tt.or)
		}
	}
}

func TestTrivialBDDNot(t *testing.T) {
	var tests = []struct {
		in  *ROBDD
		ans *ROBDD
	}{
		{True([]string{}), False([]string{})},
		{False([]string{}), True([]string{})},
	}
	for _, tt := range tests {
		ans, e1 := Not(tt.in)
		if e1 != nil {
			t.Errorf("Not(%v) returned error %v", tt.in, e1)
		}
		eq, e2 := Equal(ans, tt.ans)
		if e2 != nil {
			t.Errorf("Equal(%v, %v) returned error %v", ans, tt.ans, e2)
		}
		if !eq {
			t.Errorf("Not(%v) = %v, want %v", tt.in, ans, tt.ans)
		}
	}
}
<|endoftext|>


<commit_before>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

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

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

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

   @author: Juliano Martinez
*/

package main

import (
	"fmt"
	docopt "github.com/docopt/docopt.go"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"strconv"
	"strings"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func main() {
	usage := `Hot Potato Router Control

Usage:
  hprctl add <vhost> <backend_ip:port> [--weight=<n>]
  hprctl del <vhost> <backend_ip:port> [--weight=<n>]
  hprctl show <vhost>
  hprctl list

Args:
  add           add a new vhost and backend
  dell          del a vhost and a backend
  show          show all backends from a given vhost
  list          list all vhosts

Options:
  -h --help     Show this screen.
  --version     Show version.`

	/*  --weight=<n>  Weight in wrr [default: 1].
	`*/

	arguments, _ := docopt.Parse(usage, nil, true, "Hot Potato Router 0.3.0", false)
	if arguments["add"] == true {
		// _, err := rc.ZAdd(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		_, err := rc.ZAdd(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), 1, arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	}

	if arguments["del"] == true {
		// _, err := rc.ZRem(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		_, err := rc.ZRem(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), 1, arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	}

	if arguments["show"] == true {
		bes, err := rc.ZRange(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), 0, -1, true)
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		fmt.Printf(":: vhost [ %s ]\n", arguments["<vhost>"])
		var url string
		for _, be := range bes {
			count, err := strconv.Atoi(be)
			if err != nil {
				url = be
				continue
			}
			fmt.Printf("-- backend %s weight=%d\n", url, count)
		}
		return
	}

	if arguments["list"] == true {
		keys, err := rc.Keys("hpr-backends::*")
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		for _, k := range keys {
			fmt.Printf(":: vhost [ %s ]\n", strings.TrimLeft(k, "hpr-backends::"))
		}
		return
	}
}
<commit_msg>put the wrr back<commit_after>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

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

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

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

   @author: Juliano Martinez
*/

package main

import (
	"fmt"
	docopt "github.com/docopt/docopt.go"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"strconv"
	"strings"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func main() {
	usage := `Hot Potato Router Control

Usage:
  hprctl add <vhost> <backend_ip:port> [--weight=<n>]
  hprctl del <vhost> <backend_ip:port> [--weight=<n>]
  hprctl show <vhost>
  hprctl list

Args:
  add           add a new vhost and backend
  dell          del a vhost and a backend
  show          show all backends from a given vhost
  list          list all vhosts

Options:
  -h --help     Show this screen.
  --version     Show version.
  --weight=<n>  Weight in wrr [default: 1].
`

	arguments, _ := docopt.Parse(usage, nil, true, "Hot Potato Router 0.3.0", false)
	if arguments["add"] == true {
		_, err := rc.ZAdd(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	}

	if arguments["del"] == true {
		_, err := rc.ZRem(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	}

	if arguments["show"] == true {
		bes, err := rc.ZRange(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), 0, -1, true)
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		fmt.Printf(":: vhost [ %s ]\n", arguments["<vhost>"])
		var url string
		for _, be := range bes {
			count, err := strconv.Atoi(be)
			if err != nil {
				url = be
				continue
			}
			fmt.Printf("-- backend %s weight=%d\n", url, count)
		}
		return
	}

	if arguments["list"] == true {
		keys, err := rc.Keys("hpr-backends::*")
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		for _, k := range keys {
			fmt.Printf(":: vhost [ %s ]\n", strings.TrimLeft(k, "hpr-backends::"))
		}
		return
	}
}
<|endoftext|>


<commit_before>package html

//#include "helper.h"
import "C"
import (
	"unsafe"
	"os"
	"bytes"
	"gokogiri/xml"
)

var fragmentWrapperStart = []byte("<html><body>")
var bodySigBytes = []byte("<body")

var ErrFailParseFragment = os.NewError("failed to parse html fragment")
var ErrEmptyFragment = os.NewError("empty html fragment")

const initChildrenNumber = 4

func parsefragment(document xml.Document, content, encoding, url []byte, options int) (fragment *xml.DocumentFragment, err os.Error) {
	//deal with trivial cases
	if len(content) == 0 {
		err = ErrEmptyFragment
		return
	}

	containBody := (bytes.Index(content, bodySigBytes) >= 0)

	//wrap the content
	content = append(fragmentWrapperStart, content...)

	//set up pointers before calling the C function
	var contentPtr, urlPtr unsafe.Pointer
	contentPtr   = unsafe.Pointer(&content[0])
	contentLen   := len(content)
	if len(url) > 0  { urlPtr = unsafe.Pointer(&url[0]) }

	htmlPtr := C.htmlParseFragment(document.DocPtr(), contentPtr, C.int(contentLen), urlPtr, C.int(options), nil, 0)

	//Note we've parsed the fragment within the given document
	//the root is not the root of the document; rather it's the root of the subtree from the fragment
	html := xml.NewNode(unsafe.Pointer(htmlPtr), document)

	if html == nil {
		err = ErrFailParseFragment
		return
	}
	root := html
	if ! containBody {
		root = html.FirstChild()
		html.Remove() //remove html otherwise it's leaked
	}

	fragment = &xml.DocumentFragment{}
	fragment.Node = root

	nodes := make([]xml.Node, 0, initChildrenNumber)
	child := root.FirstChild()
	for ; child != nil; child = child.NextSibling() {
		nodes = append(nodes, child)
	}
	fragment.Children = xml.NewNodeSet(document, nodes)
	document.BookkeepFragment(fragment)
	return
}

func ParseFragment(content, inEncoding, url []byte, options int, outEncoding, outBuffer []byte) (fragment *xml.DocumentFragment, err os.Error) {
	if len(content) == 0 {
		err = ErrEmptyFragment
		return
	}

	document := CreateEmptyDocument(inEncoding, outEncoding, outBuffer)
	fragment, err = parsefragment(document, content, inEncoding, url, options)
	return
}
<commit_msg>sublime reformats it<commit_after>package html

//#include "helper.h"
import "C"
import (
	"unsafe"
	"os"
	"bytes"
	"gokogiri/xml"
)

var fragmentWrapperStart = []byte("<html><body>")
var bodySigBytes = []byte("<body")

var ErrFailParseFragment = os.NewError("failed to parse html fragment")
var ErrEmptyFragment = os.NewError("empty html fragment")

const initChildrenNumber = 4

func parsefragment(document xml.Document, content, encoding, url []byte, options int) (fragment *xml.DocumentFragment, err os.Error) {
	//deal with trivial cases
	if len(content) == 0 {
		err = ErrEmptyFragment
		return
	}

	containBody := (bytes.Index(content, bodySigBytes) >= 0)

	//wrap the content
	content = append(fragmentWrapperStart, content...)

	//set up pointers before calling the C function
	var contentPtr, urlPtr unsafe.Pointer
	contentPtr   = unsafe.Pointer(&content[0])
	contentLen   := len(content)
	if len(url) > 0  { urlPtr = unsafe.Pointer(&url[0]) }

	htmlPtr := C.htmlParseFragment(document.DocPtr(), contentPtr, C.int(contentLen), urlPtr, C.int(options), nil, 0)

	//Note we've parsed the fragment within the given document
	//the root is not the root of the document; rather it's the root of the subtree from the fragment
	html := xml.NewNode(unsafe.Pointer(htmlPtr), document)

	if html == nil {
		err = ErrFailParseFragment
		return
	}
	root := html
	if !containBody {
		root = html.FirstChild()
		html.Remove() //remove html otherwise it's leaked
	}

	fragment = &xml.DocumentFragment{}
	fragment.Node = root

	nodes := make([]xml.Node, 0, initChildrenNumber)
	child := root.FirstChild()
	for ; child != nil; child = child.NextSibling() {
		nodes = append(nodes, child)
	}
	fragment.Children = xml.NewNodeSet(document, nodes)
	document.BookkeepFragment(fragment)
	return
}

func ParseFragment(content, inEncoding, url []byte, options int, outEncoding, outBuffer []byte) (fragment *xml.DocumentFragment, err os.Error) {
	if len(content) == 0 {
		err = ErrEmptyFragment
		return
	}

	document := CreateEmptyDocument(inEncoding, outEncoding, outBuffer)
	fragment, err = parsefragment(document, content, inEncoding, url, options)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"net/http"
	"log"
	"io"
	"path"
)

func main() {
	path := "."

	if len(os.Args) > 1 {
		path = os.Args[1]
	}

	log.Printf("Sharing directory '%v'.\n", path)

	http.HandleFunc("/", handleRequest)
	log.Fatal(http.ListenAndServe(":8000", nil))
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	// FIXME
	path := fmt.Sprintf("%v%v", ".", path.Clean(r.URL.Path))
	f, err := os.Open(path)
	if err != nil {
		fmt.Fprintf(w, "Error: %v.", err)
		return
	}
	defer f.Close()

	log.Printf("Serving file '%v'.\n", path)
	io.Copy(w, f)
}

<commit_msg>httpfileshare.go: add ui; add ability to upload files<commit_after>package main

import (
	"fmt"
	"os"
	"net/http"
	"log"
	"io"
	"io/ioutil"
	"path"
	"html/template"
)

const HTML_TEMPLATE = `<!doctype html>

		<meta charset="utf-8">
		<title>File Share</title>

			<form method="post" action="/" enctype="multipart/form-data">
				<input type="file" name="fileName" accept="*"/>
				<input type="submit"/>
			</form>

			{{range .}}

					{{.Name}}{{if .IsDir}}/{{end}}

			{{end}}

`

var htmlTemplate *template.Template

func main() {
	var err error

	path := "."

	if len(os.Args) > 1 {
		path = os.Args[1]
	}

	htmlTemplate, err = template.New("htmlTemplate").Parse(HTML_TEMPLATE)
	if err != nil {
		log.Fatalf("Failed to parse the HTML template: %v", err)
	}

	log.Printf("Sharing directory '%v'.\n", path)

	http.HandleFunc("/", handleRequest)
	log.Fatal(http.ListenAndServe(":8800", nil))
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet: handleGETRequest(w, r)
	case http.MethodPost: handlePOSTRequest(w, r)
	default: http.Error(w, "Method unsupported", http.StatusMethodNotAllowed)
	}
}

func handleGETRequest(w http.ResponseWriter, r *http.Request) {
	path := fmt.Sprintf("%v%v", ".", path.Clean(r.URL.Path))

	fi, err := os.Stat(path)
	if err != nil {
		http.Error(w, fmt.Sprintf("%s", err), http.StatusInternalServerError)
		return
	}

	if fi.IsDir() {
		listDirectory(w, r, path)
	} else {
		http.ServeFile(w, r, path)
	}
}

func listDirectory(w http.ResponseWriter, r *http.Request, path string) {
	fileInfos, err := ioutil.ReadDir(path)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to list directory %v: %v", path, err), http.StatusInternalServerError)
		return
	}

	err = htmlTemplate.Execute(w, fileInfos)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to execute HTML template: %v", err), http.StatusInternalServerError)
	}
}

func handlePOSTRequest(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(128 * 1024 * 1024)

	for _, val := range r.MultipartForm.File {
		fileHeader := val[0]

		fileName := fileHeader.Filename
		if fileName == "" {
			http.Error(w, "Invalid file name", http.StatusBadRequest)
			return
		}
		path := fmt.Sprintf("%v%v", "./", path.Clean(fileName))

		uploadedFile, err := fileHeader.Open()
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to open uploaded file: %v", err), http.StatusInternalServerError)
			return
		}
		defer uploadedFile.Close()

		f, err := os.Create(path)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to create file: %v", err), http.StatusInternalServerError)
			return
		}
		defer f.Close()

		io.Copy(f, uploadedFile)
	}

	handleGETRequest(w, r)
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "time"
    "github.com/boombuler/led"
    "image/color"
    "math/rand"
    "os"
    "sort"
    "strings"
    "regexp"
    "encoding/hex"
    "gopkg.in/alecthomas/kingpin.v1"
)

var (
    VERSION = "0.0.1"
    flagSetColor = kingpin.Flag("set-color", "Set color for device. The format must be \"#rrggbb\", \"random\", \"off\" or an CSS3 color keyword, e.g. \"green\"").String()
    flagListColors = kingpin.Flag("list-colors", "List all available CSS3 color keywords, as defined in http://www.w3.org/TR/css3-color/").Bool()
    flagListDevices = kingpin.Flag("list-devices", "List all connected devices").Short('l').Bool()
    flagNumber = kingpin.Flag("number", "Select device by number, starts with 0, default: action is applied to all").Short('n').Int()
)

func printListColorNames() {
    var colorNames []string
    for k := range colors {
        colorNames = append(colorNames, k)
    }
    sort.Strings(colorNames)
    for k := range colorNames {
        if (k > 0) {
            fmt.Print(",")
        }
        fmt.Print(colorNames[k])
    }
}

func printListDevices() {
    var i int = 0
    fmt.Printf("%s\t%s\t%s\n", "Number", "Type", "Path")
    for devInfo := range led.Devices() {
        fmt.Printf("%d\t%s\t%s\n", i, devInfo.GetType(), devInfo.GetPath())
        i++
    }
}

func getFlagColor() color.Color {
    col := strings.ToLower(*flagSetColor)
    if (col == "random") {
        rand.Seed(time.Now().UnixNano())
        return color.RGBA{uint8(rand.Int()), uint8(rand.Int()), uint8(rand.Int()), 0xFF}
    }
    if (col == "off") {
        return color.Black
    }
    if (colors[col] != nil) {
        return colors[col]
    }
    validHexCode := regexp.MustCompile(`^#?([a-f0-9]{6})$`)
    if (validHexCode.MatchString(col)) {
        hexStr := validHexCode.FindStringSubmatch(col)
        bytes, err := hex.DecodeString(hexStr[1])
        if (err != nil) {
            fmt.Printf("invalid color code '%s'. use '#rrggbb' instead", hexStr[1])
            return nil
        }
        return color.RGBA{uint8(bytes[0]), uint8(bytes[1]), uint8(bytes[2]), 0xFF}
    }
    return nil
}

func main() {

    kingpin.Version(VERSION)
    kingpin.Parse()

    if (len(os.Args) <= 1) {
        kingpin.Usage()
        os.Exit(0)
    }

    if (flagListColors != nil && *flagListColors) {
        printListColorNames()
        os.Exit(0)
    }

    if (flagListDevices != nil && *flagListDevices) {
        printListDevices()
        os.Exit(0)
    }

    if (flagSetColor == nil) {
        os.Exit(0)
    }

    var number int = 0
    for devInfo := range led.Devices() {
        if (flagNumber == nil || *flagNumber == number) {
            col := getFlagColor()
            if (col != nil) {
                dev, err := devInfo.Open()
                dev.SetKeepActive(true)
                if err != nil {
                    fmt.Println(err)
                    continue
                }
                dev.SetColor(col)
                defer func() {
                    dev.Close()
                }()
            }
        }
        number++;
    }

}
<commit_msg>fixed support for multiple LEDs<commit_after>package main

import (
    "fmt"
    "strconv"
    "time"
    "github.com/boombuler/led"
    "image/color"
    "math/rand"
    "os"
    "sort"
    "strings"
    "regexp"
    "encoding/hex"
    "gopkg.in/alecthomas/kingpin.v1"
)

var (
    VERSION = "0.0.1"
    DEFAULT_NO_NUMBER = -1
    flagSetColor = kingpin.Flag("set-color", "Set color for device. The format must be \"#rrggbb\", \"random\", \"off\" or an CSS3 color keyword, e.g. \"green\"").String()
    flagListColors = kingpin.Flag("list-colors", "List all available CSS3 color keywords, as defined in http://www.w3.org/TR/css3-color/").Bool()
    flagListDevices = kingpin.Flag("list-devices", "List all connected devices").Short('l').Bool()
    flagNumber = kingpin.Flag("number", "Select device by number, starts with 0, default: action is applied to all").Short('n').Default(strconv.Itoa(DEFAULT_NO_NUMBER)).Int()
)

func printListColorNames() {
    var colorNames []string
    for k := range colors {
        colorNames = append(colorNames, k)
    }
    sort.Strings(colorNames)
    for k := range colorNames {
        if (k > 0) {
            fmt.Print(",")
        }
        fmt.Print(colorNames[k])
    }
}

func printListDevices() {
    var i int = 0
    fmt.Printf("%s\t%s\t%s\n", "Number", "Type", "Path")
    for devInfo := range led.Devices() {
        fmt.Printf("%d\t%s\t%s\n", i, devInfo.GetType(), devInfo.GetPath())
        i++
    }
}

func getFlagColor() color.Color {
    col := strings.ToLower(*flagSetColor)
    if (col == "random") {
        rand.Seed(time.Now().UnixNano())
        return color.RGBA{uint8(rand.Int()), uint8(rand.Int()), uint8(rand.Int()), 0xFF}
    }
    if (col == "off") {
        return color.Black
    }
    if (colors[col] != nil) {
        return colors[col]
    }
    validHexCode := regexp.MustCompile(`^#?([a-f0-9]{6})$`)
    if (validHexCode.MatchString(col)) {
        hexStr := validHexCode.FindStringSubmatch(col)
        bytes, err := hex.DecodeString(hexStr[1])
        if (err != nil) {
            fmt.Printf("invalid color code '%s'. use '#rrggbb' instead", hexStr[1])
            return nil
        }
        return color.RGBA{uint8(bytes[0]), uint8(bytes[1]), uint8(bytes[2]), 0xFF}
    }
    return nil
}

func main() {

    kingpin.Version(VERSION)
    kingpin.Parse()

    if (len(os.Args) <= 1) {
        kingpin.Usage()
        os.Exit(0)
    }

    if (flagListColors != nil && *flagListColors) {
        printListColorNames()
        os.Exit(0)
    }

    if (flagListDevices != nil && *flagListDevices) {
        printListDevices()
        os.Exit(0)
    }

    if (flagSetColor == nil) {
        os.Exit(0)
    }

    var number int = 0
    for devInfo := range led.Devices() {
        if (DEFAULT_NO_NUMBER == *flagNumber || *flagNumber == number) {
            col := getFlagColor()
            if (col != nil) {
                dev, err := devInfo.Open()
                if err != nil {
                    fmt.Println(err)
                    continue
                }
                dev.SetKeepActive(true)
                dev.SetColor(col)
                defer func() {
                    dev.Close()
                }()
            }
        }
        number++;
    }

}
<|endoftext|>


<commit_before>package blocks

import (
	"container/heap"
	"log"
	"strings"
	"time"
)

func Sync(b *Block) {
	pq := &PriorityQueue{}
	heap.Init(pq)

	type syncRule struct {
		Path string
		Lag  int
	}

	rule := &syncRule{}

	unmarshal(<-b.Routes["set_rule"], &rule)

	lagTime := time.Duration(time.Duration(rule.Lag) * time.Second)

	emitTick := time.NewTimer(500 * time.Millisecond)

	for {
		select {
		case m := <-b.Routes["set_rule"]:
			unmarshal(m, &rule)
			lagTime = time.Duration(time.Duration(rule.Lag) * time.Second)
		case m := <-b.Routes["get_rule"]:
			marshal(m, rule)
		case msg := <-b.AddChan:
			updateOutChans(msg, b)
		case <-b.QuitChan:
			quit(b)
			return
		case <-emitTick.C:
		case msg := <-b.InChan:
			keys := strings.Split(rule.Path, ".")
			msgTime, err := Get(msg, keys...)
			if err != nil {
				log.Println(err.Error())
			}
			msgTimeI, ok := msgTime.(int64)
			if !ok {
				log.Println("could not cast time key to int")
			}

			// assuming the value is in MS
			// TODO: make this more explicit and/or flexible
			ms := time.Unix(0, int64(time.Duration(msgTimeI)*time.Millisecond))

			queueMessage := &PQMessage{
				val:  msg,
				t:    ms,
			}

			heap.Push(pq, queueMessage)
		}
		now := time.Now()
		for {
			item, diff := pq.PeekAndShift(now, lagTime)
			if item == nil {
				// then the queue is empty. Pause for 5 seconds before checking again
				diff = time.Duration(500) * time.Millisecond

				emitTick.Reset(diff)
				break
			}
			broadcast(b.OutChans, &item.(*PQMessage).val)
		}
	}

}
<commit_msg>no longer blocking<commit_after>package blocks

import (
	"container/heap"
	"log"
	"strings"
	"time"
)

func Sync(b *Block) {
	pq := &PriorityQueue{}
	heap.Init(pq)

	type syncRule struct {
		Path string
		Lag  int
	}

	var rule *syncRule
	lagTime := time.Duration(0)
	emitTick := time.NewTimer(500 * time.Millisecond)

	for {
		select {
		case m := <-b.Routes["set_rule"]:
			if rule  == nil {
				rule = &syncRule{}
			}
			unmarshal(m, rule)
			lagTime = time.Duration(time.Duration(rule.Lag) * time.Second)
		case m := <-b.Routes["get_rule"]:
			if rule == nil {
				marshal(m, &syncRule{})
			} else {
				marshal(m, rule)
			}
		case msg := <-b.AddChan:
			updateOutChans(msg, b)
		case <-b.QuitChan:
			quit(b)
			return
		case <-emitTick.C:
		case msg := <-b.InChan:
			if rule == nil {
				break
			}

			keys := strings.Split(rule.Path, ".")
			msgTime, err := Get(msg, keys...)
			if err != nil {
				log.Println(err.Error())
			}
			msgTimeI, ok := msgTime.(int64)
			if !ok {
				log.Println("could not cast time key to int")
			}

			// assuming the value is in MS
			// TODO: make this more explicit and/or flexible
			ms := time.Unix(0, int64(time.Duration(msgTimeI)*time.Millisecond))

			queueMessage := &PQMessage{
				val:  msg,
				t:    ms,
			}

			heap.Push(pq, queueMessage)
		}
		now := time.Now()
		for {
			item, diff := pq.PeekAndShift(now, lagTime)
			if item == nil {
				// then the queue is empty. Pause for 5 seconds before checking again
				diff = time.Duration(500) * time.Millisecond

				emitTick.Reset(diff)
				break
			}
			broadcast(b.OutChans, &item.(*PQMessage).val)
		}
	}

}
<|endoftext|>