<commit_before>// Copyright (c) 2017 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package workload

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"strings"
	"sync"

	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/types"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/felix/fv/containers"
	"github.com/projectcalico/felix/fv/utils"
	api "github.com/projectcalico/libcalico-go/lib/apis/v2"
	client "github.com/projectcalico/libcalico-go/lib/clientv2"
)

type Workload struct {
	C                *containers.Container
	Name             string
	InterfaceName    string
	IP               string
	Ports            string
	DefaultPort      string
	runCmd           *exec.Cmd
	outPipe          io.ReadCloser
	errPipe          io.ReadCloser
	namespacePath    string
	WorkloadEndpoint *api.WorkloadEndpoint
	Protocol         string // "tcp" or "udp"
}

var workloadIdx = 0

func (w *Workload) Stop() {
	if w == nil {
		log.Info("Stop no-op because nil workload")
	} else {
		log.WithField("workload", w).Info("Stop")
		outputBytes, err := utils.Command("docker", "exec", w.C.Name,
			"cat", fmt.Sprintf("/tmp/%v", w.Name)).CombinedOutput()
		Expect(err).NotTo(HaveOccurred())
		pid := strings.TrimSpace(string(outputBytes))
		err = utils.Command("docker", "exec", w.C.Name, "kill", pid).Run()
		Expect(err).NotTo(HaveOccurred())
		w.runCmd.Process.Wait()
		log.WithField("workload", w).Info("Workload now stopped")
	}
}

func Run(c *containers.Container, name, interfaceName, ip, ports string, protocol string) (w *Workload) {

	// Build unique workload name and struct.
	workloadIdx++
	w = &Workload{
		C:             c,
		Name:          fmt.Sprintf("%s-idx%v", name, workloadIdx),
		InterfaceName: interfaceName,
		IP:            ip,
		Ports:         ports,
		Protocol:      protocol,
	}

	// Ensure that the host has the 'test-workload' binary.
	w.C.EnsureBinary("test-workload")

	// Start the workload.
	log.WithField("workload", w).Info("About to run workload")
	var udpArg string
	if protocol == "udp" {
		udpArg = "--udp"
	}
	w.runCmd = utils.Command("docker", "exec", w.C.Name,
		"sh", "-c",
		fmt.Sprintf("echo $$ > /tmp/%v; exec /test-workload %v %v %v %v",
			w.Name,
			udpArg,
			w.InterfaceName,
			w.IP,
			w.Ports))
	var err error
	w.outPipe, err = w.runCmd.StdoutPipe()
	Expect(err).NotTo(HaveOccurred())
	w.errPipe, err = w.runCmd.StderrPipe()
	Expect(err).NotTo(HaveOccurred())
	err = w.runCmd.Start()
	Expect(err).NotTo(HaveOccurred())

	// Read the workload's namespace path, which it writes to its standard output.
	stdoutReader := bufio.NewReader(w.outPipe)
	stderrReader := bufio.NewReader(w.errPipe)
	namespacePath, err := stdoutReader.ReadString('\n')
	Expect(err).NotTo(HaveOccurred())
	w.namespacePath = strings.TrimSpace(namespacePath)

	go func() {
		for {
			line, err := stderrReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Info("End of workload stderr")
				return
			}
			log.Infof("Workload %s stderr: %s", name, strings.TrimSpace(string(line)))
		}
	}()
	go func() {
		for {
			line, err := stdoutReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Info("End of workload stdout")
				return
			}
			log.Infof("Workload %s stdout: %s", name, strings.TrimSpace(string(line)))
		}
	}()

	log.WithField("workload", w).Info("Workload now running")

	wep := api.NewWorkloadEndpoint()
	wep.Labels = map[string]string{"name": w.Name}
	wep.Spec.Node = w.C.Hostname
	wep.Spec.Orchestrator = "felixfv"
	wep.Spec.Workload = w.Name
	wep.Spec.Endpoint = w.Name
	wep.Spec.IPNetworks = []string{w.IP + "/32"}
	wep.Spec.InterfaceName = w.InterfaceName
	wep.Spec.Profiles = []string{"default"}
	w.WorkloadEndpoint = wep

	return
}

func (w *Workload) IPNet() string {
	return w.IP + "/32"
}

func (w *Workload) Configure(client client.Interface) {
	wep := w.WorkloadEndpoint
	wep.Namespace = "fv"
	_, err := client.WorkloadEndpoints().Create(utils.Ctx, w.WorkloadEndpoint, utils.NoOptions)
	Expect(err).NotTo(HaveOccurred())
}

func (w *Workload) NameSelector() string {
	return "name=='" + w.Name + "'"
}

func (w *Workload) SourceName() string {
	return w.Name
}

func (w *Workload) CanConnectTo(ip, port, protocol string) bool {
	anyPort := Port{
		Workload: w,
	}
	return anyPort.CanConnectTo(ip, port, protocol)
}

func (w *Workload) Port(port uint16) *Port {
	return &Port{
		Workload: w,
		Port:     port,
	}
}

type Port struct {
	*Workload
	Port uint16
}

func (w *Port) SourceName() string {
	if w.Port == 0 {
		return w.Name
	}
	return fmt.Sprintf("%s:%d", w.Name, w.Port)
}

func (p *Port) CanConnectTo(ip, port, protocol string) bool {

	// Ensure that the host has the 'test-connection' binary.
	p.C.EnsureBinary("test-connection")

	if protocol == "udp" {
		// If this is a retry then we may have stale conntrack entries and we don't want those
		// to influence the connectivity check.  Only an issue for UDP due to the lack of a
		// sequence number.
		p.C.ExecMayFail("conntrack", "-D", "-p", "udp", "-s", p.Workload.IP, "-d", ip)
	}

	// Run 'test-connection' to the target.
	args := []string{
		"exec", p.C.Name, "/test-connection", p.namespacePath, ip, port, "--protocol=" + protocol,
	}
	if p.Port != 0 {
		// If we are using a particular source port, fill it in.
		args = append(args, fmt.Sprintf("--source-port=%d", p.Port))
	}
	connectionCmd := utils.Command("docker", args...)
	outPipe, err := connectionCmd.StdoutPipe()
	Expect(err).NotTo(HaveOccurred())
	errPipe, err := connectionCmd.StderrPipe()
	Expect(err).NotTo(HaveOccurred())
	err = connectionCmd.Start()
	Expect(err).NotTo(HaveOccurred())

	wOut, err := ioutil.ReadAll(outPipe)
	Expect(err).NotTo(HaveOccurred())
	wErr, err := ioutil.ReadAll(errPipe)
	Expect(err).NotTo(HaveOccurred())
	err = connectionCmd.Wait()

	log.WithFields(log.Fields{
		"stdout": string(wOut),
		"stderr": string(wErr)}).WithError(err).Info("Connection test")

	return err == nil
}

// ToMatcher implements the connectionTarget interface, allowing this port to be used as
// target.
func (p *Port) ToMatcher(explicitPort ...uint16) *connectivityMatcher {
	if p.Port == 0 {
		return p.Workload.ToMatcher(explicitPort...)
	}
	return &connectivityMatcher{
		ip:         p.Workload.IP,
		port:       fmt.Sprint(p.Port),
		targetName: fmt.Sprintf("%s on port %d", p.Workload.Name, p.Port),
	}
}

type connectionTarget interface {
	ToMatcher(explicitPort ...uint16) *connectivityMatcher
}

type IP string // Just so we can define methods on it...

func (s IP) ToMatcher(explicitPort ...uint16) *connectivityMatcher {
	if len(explicitPort) != 1 {
		panic("Explicit port needed with IP as a connectivity target")
	}
	port := fmt.Sprintf("%d", explicitPort[0])
	return &connectivityMatcher{
		ip:         string(s),
		port:       port,
		targetName: string(s) + ":" + port,
		protocol:   "tcp",
	}
}

func (w *Workload) ToMatcher(explicitPort ...uint16) *connectivityMatcher {
	var port string
	if len(explicitPort) == 1 {
		port = fmt.Sprintf("%d", explicitPort[0])
	} else if w.DefaultPort != "" {
		port = w.DefaultPort
	} else if !strings.Contains(w.Ports, ",") {
		port = w.Ports
	} else {
		panic("Explicit port needed for workload with multiple ports")
	}
	return &connectivityMatcher{
		ip:         w.IP,
		port:       port,
		targetName: fmt.Sprintf("%s on port %s", w.Name, port),
		protocol:   "tcp",
	}
}

func HaveConnectivityTo(target connectionTarget, explicitPort ...uint16) types.GomegaMatcher {
	return target.ToMatcher(explicitPort...)
}

type connectivityMatcher struct {
	ip, port, targetName, protocol string
}

type connectionSource interface {
	CanConnectTo(ip, port, protocol string) bool
	SourceName() string
}

func (m *connectivityMatcher) Match(actual interface{}) (success bool, err error) {
	success = actual.(connectionSource).CanConnectTo(m.ip, m.port, m.protocol)
	return
}

func (m *connectivityMatcher) FailureMessage(actual interface{}) (message string) {
	src := actual.(connectionSource)
	message = fmt.Sprintf("Expected %v\n\t%+v\nto have connectivity to %v\n\t%v:%v\nbut it does not", src.SourceName(), src, m.targetName, m.ip, m.port)
	return
}

func (m *connectivityMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	src := actual.(connectionSource)
	message = fmt.Sprintf("Expected %v\n\t%+v\nnot to have connectivity to %v\n\t%v:%v\nbut it does", src.SourceName(), src, m.targetName, m.ip, m.port)
	return
}

type expectation struct {
	from     connectionSource     // Workload or Container
	to       *connectivityMatcher // Workload or IP, + port
	expected bool
}

// ConnectivityChecker records a set of connectivity expectations and supports calculating the
// actual state of the connectivity between the given workloads.  It is expected to be used like so:
//
//     var cc = &workload.ConnectivityChecker{}
//     cc.ExpectNone(w[2], w[0], 1234)
//     cc.ExpectSome(w[1], w[0], 5678)
//     Eventually(cc.ActualConnectivity, "10s", "100ms").Should(Equal(cc.ExpectedConnectivity()))
//
// Note that the ActualConnectivity method is passed to Eventually as a function pointer to allow
// Ginkgo to re-evaluate the result as needed.
type ConnectivityChecker struct {
	ReverseDirection bool
	Protocol         string // "tcp" or "udp"
	expectations     []expectation
}

func (c *ConnectivityChecker) ExpectSome(from connectionSource, to connectionTarget, explicitPort ...uint16) {
	if c.ReverseDirection {
		from, to = to.(connectionSource), from.(connectionTarget)
	}
	c.expectations = append(c.expectations, expectation{from, to.ToMatcher(explicitPort...), true})
}

func (c *ConnectivityChecker) ExpectNone(from connectionSource, to connectionTarget, explicitPort ...uint16) {
	if c.ReverseDirection {
		from, to = to.(connectionSource), from.(connectionTarget)
	}
	c.expectations = append(c.expectations, expectation{from, to.ToMatcher(explicitPort...), false})
}

func (c *ConnectivityChecker) ResetExpectations() {
	c.expectations = nil
}

// ActualConnectivity calculates the current connectivity for all the expected paths.  One string is
// returned for each expectation, in the order they were recorded.  The strings are intended to be
// human readable, and they are in the same order and format as those returned by
// ExpectedConnectivity().
func (c *ConnectivityChecker) ActualConnectivity() []string {
	var wg sync.WaitGroup
	result := make([]string, len(c.expectations))
	for i, exp := range c.expectations {
		wg.Add(1)
		go func(i int, exp expectation) {
			defer wg.Done()
			p := "tcp"
			if c.Protocol != "" {
				p = c.Protocol
			}
			hasConnectivity := exp.from.CanConnectTo(exp.to.ip, exp.to.port, p)
			result[i] = fmt.Sprintf("%s -> %s = %v", exp.from.SourceName(), exp.to.targetName, hasConnectivity)
		}(i, exp)
	}
	wg.Wait()
	log.Debug("Connectivity", result)
	return result
}

// ExpectedConnectivity returns one string per recorded expection in order, encoding the expected
// connectivity in the same format used by ActualConnectivity().
func (c *ConnectivityChecker) ExpectedConnectivity() []string {
	result := make([]string, len(c.expectations))
	for i, exp := range c.expectations {
		result[i] = fmt.Sprintf("%s -> %s = %v", exp.from.SourceName(), exp.to.targetName, exp.expected)
	}
	return result
}
<commit_msg>Wait for stderr after a workload failure.<commit_after>// Copyright (c) 2017 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package workload

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"strings"
	"sync"

	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/types"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/felix/fv/containers"
	"github.com/projectcalico/felix/fv/utils"
	api "github.com/projectcalico/libcalico-go/lib/apis/v2"
	client "github.com/projectcalico/libcalico-go/lib/clientv2"
)

type Workload struct {
	C                *containers.Container
	Name             string
	InterfaceName    string
	IP               string
	Ports            string
	DefaultPort      string
	runCmd           *exec.Cmd
	outPipe          io.ReadCloser
	errPipe          io.ReadCloser
	namespacePath    string
	WorkloadEndpoint *api.WorkloadEndpoint
	Protocol         string // "tcp" or "udp"
}

var workloadIdx = 0

func (w *Workload) Stop() {
	if w == nil {
		log.Info("Stop no-op because nil workload")
	} else {
		log.WithField("workload", w).Info("Stop")
		outputBytes, err := utils.Command("docker", "exec", w.C.Name,
			"cat", fmt.Sprintf("/tmp/%v", w.Name)).CombinedOutput()
		Expect(err).NotTo(HaveOccurred())
		pid := strings.TrimSpace(string(outputBytes))
		err = utils.Command("docker", "exec", w.C.Name, "kill", pid).Run()
		Expect(err).NotTo(HaveOccurred())
		w.runCmd.Process.Wait()
		log.WithField("workload", w).Info("Workload now stopped")
	}
}

func Run(c *containers.Container, name, interfaceName, ip, ports string, protocol string) (w *Workload) {

	// Build unique workload name and struct.
	workloadIdx++
	w = &Workload{
		C:             c,
		Name:          fmt.Sprintf("%s-idx%v", name, workloadIdx),
		InterfaceName: interfaceName,
		IP:            ip,
		Ports:         ports,
		Protocol:      protocol,
	}

	// Ensure that the host has the 'test-workload' binary.
	w.C.EnsureBinary("test-workload")

	// Start the workload.
	log.WithField("workload", w).Info("About to run workload")
	var udpArg string
	if protocol == "udp" {
		udpArg = "--udp"
	}
	w.runCmd = utils.Command("docker", "exec", w.C.Name,
		"sh", "-c",
		fmt.Sprintf("echo $$ > /tmp/%v; exec /test-workload %v %v %v %v",
			w.Name,
			udpArg,
			w.InterfaceName,
			w.IP,
			w.Ports))
	var err error
	w.outPipe, err = w.runCmd.StdoutPipe()
	Expect(err).NotTo(HaveOccurred())
	w.errPipe, err = w.runCmd.StderrPipe()
	Expect(err).NotTo(HaveOccurred())
	err = w.runCmd.Start()
	Expect(err).NotTo(HaveOccurred())

	// Read the workload's namespace path, which it writes to its standard output.
	stdoutReader := bufio.NewReader(w.outPipe)
	stderrReader := bufio.NewReader(w.errPipe)

	var errDone sync.WaitGroup
	errDone.Add(1)
	go func() {
		defer errDone.Done()
		for {
			line, err := stderrReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Info("End of workload stderr")
				return
			}
			log.Infof("Workload %s stderr: %s", name, strings.TrimSpace(string(line)))
		}
	}()

	namespacePath, err := stdoutReader.ReadString('\n')
	if err != nil {
		// (Only) if we fail here, wait for the stderr to be output before returning.
		defer errDone.Wait()
		Expect(err).NotTo(HaveOccurred())
	}

	w.namespacePath = strings.TrimSpace(namespacePath)

	go func() {
		for {
			line, err := stdoutReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Info("End of workload stdout")
				return
			}
			log.Infof("Workload %s stdout: %s", name, strings.TrimSpace(string(line)))
		}
	}()

	log.WithField("workload", w).Info("Workload now running")

	wep := api.NewWorkloadEndpoint()
	wep.Labels = map[string]string{"name": w.Name}
	wep.Spec.Node = w.C.Hostname
	wep.Spec.Orchestrator = "felixfv"
	wep.Spec.Workload = w.Name
	wep.Spec.Endpoint = w.Name
	wep.Spec.IPNetworks = []string{w.IP + "/32"}
	wep.Spec.InterfaceName = w.InterfaceName
	wep.Spec.Profiles = []string{"default"}
	w.WorkloadEndpoint = wep

	return
}

func (w *Workload) IPNet() string {
	return w.IP + "/32"
}

func (w *Workload) Configure(client client.Interface) {
	wep := w.WorkloadEndpoint
	wep.Namespace = "fv"
	_, err := client.WorkloadEndpoints().Create(utils.Ctx, w.WorkloadEndpoint, utils.NoOptions)
	Expect(err).NotTo(HaveOccurred())
}

func (w *Workload) NameSelector() string {
	return "name=='" + w.Name + "'"
}

func (w *Workload) SourceName() string {
	return w.Name
}

func (w *Workload) CanConnectTo(ip, port, protocol string) bool {
	anyPort := Port{
		Workload: w,
	}
	return anyPort.CanConnectTo(ip, port, protocol)
}

func (w *Workload) Port(port uint16) *Port {
	return &Port{
		Workload: w,
		Port:     port,
	}
}

type Port struct {
	*Workload
	Port uint16
}

func (w *Port) SourceName() string {
	if w.Port == 0 {
		return w.Name
	}
	return fmt.Sprintf("%s:%d", w.Name, w.Port)
}

func (p *Port) CanConnectTo(ip, port, protocol string) bool {

	// Ensure that the host has the 'test-connection' binary.
	p.C.EnsureBinary("test-connection")

	if protocol == "udp" {
		// If this is a retry then we may have stale conntrack entries and we don't want those
		// to influence the connectivity check.  Only an issue for UDP due to the lack of a
		// sequence number.
		p.C.ExecMayFail("conntrack", "-D", "-p", "udp", "-s", p.Workload.IP, "-d", ip)
	}

	// Run 'test-connection' to the target.
	args := []string{
		"exec", p.C.Name, "/test-connection", p.namespacePath, ip, port, "--protocol=" + protocol,
	}
	if p.Port != 0 {
		// If we are using a particular source port, fill it in.
		args = append(args, fmt.Sprintf("--source-port=%d", p.Port))
	}
	connectionCmd := utils.Command("docker", args...)
	outPipe, err := connectionCmd.StdoutPipe()
	Expect(err).NotTo(HaveOccurred())
	errPipe, err := connectionCmd.StderrPipe()
	Expect(err).NotTo(HaveOccurred())
	err = connectionCmd.Start()
	Expect(err).NotTo(HaveOccurred())

	wOut, err := ioutil.ReadAll(outPipe)
	Expect(err).NotTo(HaveOccurred())
	wErr, err := ioutil.ReadAll(errPipe)
	Expect(err).NotTo(HaveOccurred())
	err = connectionCmd.Wait()

	log.WithFields(log.Fields{
		"stdout": string(wOut),
		"stderr": string(wErr)}).WithError(err).Info("Connection test")

	return err == nil
}

// ToMatcher implements the connectionTarget interface, allowing this port to be used as
// target.
func (p *Port) ToMatcher(explicitPort ...uint16) *connectivityMatcher {
	if p.Port == 0 {
		return p.Workload.ToMatcher(explicitPort...)
	}
	return &connectivityMatcher{
		ip:         p.Workload.IP,
		port:       fmt.Sprint(p.Port),
		targetName: fmt.Sprintf("%s on port %d", p.Workload.Name, p.Port),
	}
}

type connectionTarget interface {
	ToMatcher(explicitPort ...uint16) *connectivityMatcher
}

type IP string // Just so we can define methods on it...

func (s IP) ToMatcher(explicitPort ...uint16) *connectivityMatcher {
	if len(explicitPort) != 1 {
		panic("Explicit port needed with IP as a connectivity target")
	}
	port := fmt.Sprintf("%d", explicitPort[0])
	return &connectivityMatcher{
		ip:         string(s),
		port:       port,
		targetName: string(s) + ":" + port,
		protocol:   "tcp",
	}
}

func (w *Workload) ToMatcher(explicitPort ...uint16) *connectivityMatcher {
	var port string
	if len(explicitPort) == 1 {
		port = fmt.Sprintf("%d", explicitPort[0])
	} else if w.DefaultPort != "" {
		port = w.DefaultPort
	} else if !strings.Contains(w.Ports, ",") {
		port = w.Ports
	} else {
		panic("Explicit port needed for workload with multiple ports")
	}
	return &connectivityMatcher{
		ip:         w.IP,
		port:       port,
		targetName: fmt.Sprintf("%s on port %s", w.Name, port),
		protocol:   "tcp",
	}
}

func HaveConnectivityTo(target connectionTarget, explicitPort ...uint16) types.GomegaMatcher {
	return target.ToMatcher(explicitPort...)
}

type connectivityMatcher struct {
	ip, port, targetName, protocol string
}

type connectionSource interface {
	CanConnectTo(ip, port, protocol string) bool
	SourceName() string
}

func (m *connectivityMatcher) Match(actual interface{}) (success bool, err error) {
	success = actual.(connectionSource).CanConnectTo(m.ip, m.port, m.protocol)
	return
}

func (m *connectivityMatcher) FailureMessage(actual interface{}) (message string) {
	src := actual.(connectionSource)
	message = fmt.Sprintf("Expected %v\n\t%+v\nto have connectivity to %v\n\t%v:%v\nbut it does not", src.SourceName(), src, m.targetName, m.ip, m.port)
	return
}

func (m *connectivityMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	src := actual.(connectionSource)
	message = fmt.Sprintf("Expected %v\n\t%+v\nnot to have connectivity to %v\n\t%v:%v\nbut it does", src.SourceName(), src, m.targetName, m.ip, m.port)
	return
}

type expectation struct {
	from     connectionSource     // Workload or Container
	to       *connectivityMatcher // Workload or IP, + port
	expected bool
}

// ConnectivityChecker records a set of connectivity expectations and supports calculating the
// actual state of the connectivity between the given workloads.  It is expected to be used like so:
//
//     var cc = &workload.ConnectivityChecker{}
//     cc.ExpectNone(w[2], w[0], 1234)
//     cc.ExpectSome(w[1], w[0], 5678)
//     Eventually(cc.ActualConnectivity, "10s", "100ms").Should(Equal(cc.ExpectedConnectivity()))
//
// Note that the ActualConnectivity method is passed to Eventually as a function pointer to allow
// Ginkgo to re-evaluate the result as needed.
type ConnectivityChecker struct {
	ReverseDirection bool
	Protocol         string // "tcp" or "udp"
	expectations     []expectation
}

func (c *ConnectivityChecker) ExpectSome(from connectionSource, to connectionTarget, explicitPort ...uint16) {
	if c.ReverseDirection {
		from, to = to.(connectionSource), from.(connectionTarget)
	}
	c.expectations = append(c.expectations, expectation{from, to.ToMatcher(explicitPort...), true})
}

func (c *ConnectivityChecker) ExpectNone(from connectionSource, to connectionTarget, explicitPort ...uint16) {
	if c.ReverseDirection {
		from, to = to.(connectionSource), from.(connectionTarget)
	}
	c.expectations = append(c.expectations, expectation{from, to.ToMatcher(explicitPort...), false})
}

func (c *ConnectivityChecker) ResetExpectations() {
	c.expectations = nil
}

// ActualConnectivity calculates the current connectivity for all the expected paths.  One string is
// returned for each expectation, in the order they were recorded.  The strings are intended to be
// human readable, and they are in the same order and format as those returned by
// ExpectedConnectivity().
func (c *ConnectivityChecker) ActualConnectivity() []string {
	var wg sync.WaitGroup
	result := make([]string, len(c.expectations))
	for i, exp := range c.expectations {
		wg.Add(1)
		go func(i int, exp expectation) {
			defer wg.Done()
			p := "tcp"
			if c.Protocol != "" {
				p = c.Protocol
			}
			hasConnectivity := exp.from.CanConnectTo(exp.to.ip, exp.to.port, p)
			result[i] = fmt.Sprintf("%s -> %s = %v", exp.from.SourceName(), exp.to.targetName, hasConnectivity)
		}(i, exp)
	}
	wg.Wait()
	log.Debug("Connectivity", result)
	return result
}

// ExpectedConnectivity returns one string per recorded expection in order, encoding the expected
// connectivity in the same format used by ActualConnectivity().
func (c *ConnectivityChecker) ExpectedConnectivity() []string {
	result := make([]string, len(c.expectations))
	for i, exp := range c.expectations {
		result[i] = fmt.Sprintf("%s -> %s = %v", exp.from.SourceName(), exp.to.targetName, exp.expected)
	}
	return result
}
<|endoftext|>


<commit_before>package atomas
import (
	"container/list"
)

const (
	PLUS_SIGN  int = 0
)

func EvaluateBoard(arrayBoard []int) (int, []int) {
	score, multiplier, board := lookForPossibleCombinations(toList(arrayBoard), 0, 0)
	return score * multiplier, toArray(board)
}

func lookForPossibleCombinations(board *list.List, multiplier int, score int) (int, int, *list.List) {
	mergablePlusSign := findMergablePlusSign(board)
	if (mergablePlusSign == nil) {
		return score, multiplier, board
	}else {
		return applyPlusSign(board, mergablePlusSign, multiplier + 1, score)
	}
}

func applyPlusSign(board *list.List, element *list.Element, multiplier int, score int) (int, int, *list.List) {
	score, board = mergeElementsAround(board, element, score)
	if (shouldMergeElements(board, element)) {
		return applyPlusSign(board, element, multiplier + 1, score)
	}else {
		return lookForPossibleCombinations(board, multiplier, score)
	}
}

func mergeElementsAround(board *list.List, element *list.Element, score int) (int, *list.List) {
	next := nextWithLoop(board, element)
	prev := prevWithLoop(board, element)
	surroundingValue := next.Value.(int)
	element.Value = Max(surroundingValue, element.Value.(int)) + 1
	board.Remove(prev)
	board.Remove(next)
	return score + surroundingValue * 2, board
}

func shouldMergeElements(board *list.List, element *list.Element) bool {
	return (board.Len() > 2 && isSurroundingSame(board, element) && theyAreProperElement(board, element))
}

func findMergablePlusSign(board *list.List) *list.Element {
	for e := board.Front(); e != nil; e = e.Next() {
		if e.Value == PLUS_SIGN && shouldMergeElements(board, e) {
			return e
		}
	}
	return nil
}

func theyAreProperElement(board *list.List, element *list.Element) bool {
	return nextWithLoop(board, element).Value.(int) > 0
}

func nextWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Next() != nil ) {
		return element.Next()
	}else {
		return board.Front()
	}
}

func prevWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Prev() != nil ) {
		return element.Prev()
	}else {
		return board.Back()
	}
}

func isSurroundingSame(board *list.List, element *list.Element) bool {
	return nextWithLoop(board, element).Value == prevWithLoop(board, element).Value
}

func toList(board []int) *list.List {
	result := list.New()
	for _, element := range board {
		result.PushBack(int(element))
	}
	return result
}

func toArray(board *list.List) []int {
	array := make([]int, board.Len())
	i := 0
	for e := board.Front(); e != nil; e = e.Next() {
		array[i] = e.Value.(int)
		i += 1
	}
	return array
}
<commit_msg>final refactor<commit_after>package atomas
import (
	"container/list"
)

const (
	PLUS_SIGN  int = 0
)

func EvaluateBoard(arrayBoard []int) (int, []int) {
	score, multiplier, board := lookForPossibleCombinations(toList(arrayBoard), 0, 0)
	return score * multiplier, toArray(board)
}

func lookForPossibleCombinations(board *list.List, multiplier int, score int) (int, int, *list.List) {
	mergablePlusSign := findMergablePlusSign(board)
	if (mergablePlusSign == nil) {
		return score, multiplier, board
	}else {
		return applyPlusSign(board, mergablePlusSign, multiplier + 1, score)
	}
}

func applyPlusSign(board *list.List, element *list.Element, multiplier int, score int) (int, int, *list.List) {
	score, board = mergeElementsAround(board, element, score)
	if (shouldMergeElements(board, element)) {
		return applyPlusSign(board, element, multiplier + 1, score)
	}else {
		return lookForPossibleCombinations(board, multiplier, score)
	}
}

func mergeElementsAround(board *list.List, element *list.Element, score int) (int, *list.List) {
	next := nextWithLoop(board, element)
	prev := prevWithLoop(board, element)
	surroundingValue := next.Value.(int)
	element.Value = Max(surroundingValue, element.Value.(int)) + 1
	board.Remove(prev)
	board.Remove(next)
	return score + surroundingValue * 2, board
}

func nextWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Next() != nil ) {
		return element.Next()
	}else {
		return board.Front()
	}
}

func findMergablePlusSign(board *list.List) *list.Element {
	for e := board.Front(); e != nil; e = e.Next() {
		if isMergablePlusSign(board, e) {
			return e
		}
	}
	return nil
}

func isMergablePlusSign(board *list.List, e *list.Element) bool {
	return e.Value == PLUS_SIGN && shouldMergeElements(board, e)
}

func shouldMergeElements(board *list.List, element *list.Element) bool {
	if (board.Len() < 3) {
		return false
	}
	next := nextWithLoop(board, element).Value
	prev := prevWithLoop(board, element).Value
	return areSameAndValid(next, prev)
}

func areSameAndValid(next interface{}, prev interface{}) bool {
	return next == prev && next.(int) > 0
}

func prevWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Prev() != nil ) {
		return element.Prev()
	}else {
		return board.Back()
	}
}

func toList(board []int) *list.List {
	result := list.New()
	for _, element := range board {
		result.PushBack(int(element))
	}
	return result
}

func toArray(board *list.List) []int {
	array := make([]int, board.Len())
	i := 0
	for e := board.Front(); e != nil; e = e.Next() {
		array[i] = e.Value.(int)
		i += 1
	}
	return array
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"
	"testing"

	"github.com/docker/docker/api"
	"github.com/docker/docker/api/types"
	"golang.org/x/net/context"
)

func TestNewEnvClient(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("skipping unix only test for windows")
	}
	cases := []struct {
		envs            map[string]string
		expectedError   string
		expectedVersion string
	}{
		{
			envs:            map[string]string{},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH": "invalid/path",
			},
			expectedError: "Could not load X509 key pair: open invalid/path/cert.pem: no such file or directory. Make sure the key is not encrypted",
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH": "testdata/",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH":  "testdata/",
				"DOCKER_TLS_VERIFY": "1",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH": "testdata/",
				"DOCKER_HOST":      "https://notaunixsocket",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_HOST": "host",
			},
			expectedError: "unable to parse docker host `host`",
		},
		{
			envs: map[string]string{
				"DOCKER_HOST": "invalid://url",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_API_VERSION": "anything",
			},
			expectedVersion: "anything",
		},
		{
			envs: map[string]string{
				"DOCKER_API_VERSION": "1.22",
			},
			expectedVersion: "1.22",
		},
	}
	for _, c := range cases {
		recoverEnvs := setupEnvs(t, c.envs)
		apiclient, err := NewEnvClient()
		if c.expectedError != "" {
			if err == nil {
				t.Errorf("expected an error for %v", c)
			} else if err.Error() != c.expectedError {
				t.Errorf("expected an error %s, got %s, for %v", c.expectedError, err.Error(), c)
			}
		} else {
			if err != nil {
				t.Error(err)
			}
			version := apiclient.ClientVersion()
			if version != c.expectedVersion {
				t.Errorf("expected %s, got %s, for %v", c.expectedVersion, version, c)
			}
		}

		if c.envs["DOCKER_TLS_VERIFY"] != "" {
			// pedantic checking that this is handled correctly
			tr := apiclient.client.Transport.(*http.Transport)
			if tr.TLSClientConfig == nil {
				t.Error("no TLS config found when DOCKER_TLS_VERIFY enabled")
			}

			if tr.TLSClientConfig.InsecureSkipVerify {
				t.Error("TLS verification should be enabled")
			}
		}

		recoverEnvs(t)
	}
}

func setupEnvs(t *testing.T, envs map[string]string) func(*testing.T) {
	oldEnvs := map[string]string{}
	for key, value := range envs {
		oldEnv := os.Getenv(key)
		oldEnvs[key] = oldEnv
		err := os.Setenv(key, value)
		if err != nil {
			t.Error(err)
		}
	}
	return func(t *testing.T) {
		for key, value := range oldEnvs {
			err := os.Setenv(key, value)
			if err != nil {
				t.Error(err)
			}
		}
	}
}

func TestGetAPIPath(t *testing.T) {
	cases := []struct {
		v string
		p string
		q url.Values
		e string
	}{
		{"", "/containers/json", nil, "/containers/json"},
		{"", "/containers/json", url.Values{}, "/containers/json"},
		{"", "/containers/json", url.Values{"s": []string{"c"}}, "/containers/json?s=c"},
		{"1.22", "/containers/json", nil, "/v1.22/containers/json"},
		{"1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"},
		{"1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"},
		{"v1.22", "/containers/json", nil, "/v1.22/containers/json"},
		{"v1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"},
		{"v1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"},
		{"v1.22", "/networks/kiwl$%^", nil, "/v1.22/networks/kiwl$%25%5E"},
	}

	for _, cs := range cases {
		c, err := NewClient("unix:///var/run/docker.sock", cs.v, nil, nil)
		if err != nil {
			t.Fatal(err)
		}
		g := c.getAPIPath(cs.p, cs.q)
		if g != cs.e {
			t.Fatalf("Expected %s, got %s", cs.e, g)
		}

		err = c.Close()
		if nil != err {
			t.Fatalf("close client failed, error message: %s", err)
		}
	}
}

func TestParseHost(t *testing.T) {
	cases := []struct {
		host  string
		proto string
		addr  string
		base  string
		err   bool
	}{
		{"", "", "", "", true},
		{"foobar", "", "", "", true},
		{"foo://bar", "foo", "bar", "", false},
		{"tcp://localhost:2476", "tcp", "localhost:2476", "", false},
		{"tcp://localhost:2476/path", "tcp", "localhost:2476", "/path", false},
	}

	for _, cs := range cases {
		p, a, b, e := ParseHost(cs.host)
		if cs.err && e == nil {
			t.Fatalf("expected error, got nil")
		}
		if !cs.err && e != nil {
			t.Fatal(e)
		}
		if cs.proto != p {
			t.Fatalf("expected proto %s, got %s", cs.proto, p)
		}
		if cs.addr != a {
			t.Fatalf("expected addr %s, got %s", cs.addr, a)
		}
		if cs.base != b {
			t.Fatalf("expected base %s, got %s", cs.base, b)
		}
	}
}

func TestUpdateClientVersion(t *testing.T) {
	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			splitQuery := strings.Split(req.URL.Path, "/")
			queryVersion := splitQuery[1]
			b, err := json.Marshal(types.Version{
				APIVersion: queryVersion,
			})
			if err != nil {
				return nil, err
			}
			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader(b)),
			}, nil
		}),
	}

	cases := []struct {
		v string
	}{
		{"1.20"},
		{"v1.21"},
		{"1.22"},
		{"v1.22"},
	}

	for _, cs := range cases {
		client.UpdateClientVersion(cs.v)
		r, err := client.ServerVersion(context.Background())
		if err != nil {
			t.Fatal(err)
		}
		if strings.TrimPrefix(r.APIVersion, "v") != strings.TrimPrefix(cs.v, "v") {
			t.Fatalf("Expected %s, got %s", cs.v, r.APIVersion)
		}
	}
}

func TestNewEnvClientSetsDefaultVersion(t *testing.T) {
	// Unset environment variables
	envVarKeys := []string{
		"DOCKER_HOST",
		"DOCKER_API_VERSION",
		"DOCKER_TLS_VERIFY",
		"DOCKER_CERT_PATH",
	}
	envVarValues := make(map[string]string)
	for _, key := range envVarKeys {
		envVarValues[key] = os.Getenv(key)
		os.Setenv(key, "")
	}

	client, err := NewEnvClient()
	if err != nil {
		t.Fatal(err)
	}
	if client.version != api.DefaultVersion {
		t.Fatalf("Expected %s, got %s", api.DefaultVersion, client.version)
	}

	expected := "1.22"
	os.Setenv("DOCKER_API_VERSION", expected)
	client, err = NewEnvClient()
	if err != nil {
		t.Fatal(err)
	}
	if client.version != expected {
		t.Fatalf("Expected %s, got %s", expected, client.version)
	}

	// Restore environment variables
	for _, key := range envVarKeys {
		os.Setenv(key, envVarValues[key])
	}
}
<commit_msg>use an encrypted client certificate to connect to a docker daemon<commit_after>package client

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"
	"testing"

	"github.com/docker/docker/api"
	"github.com/docker/docker/api/types"
	"golang.org/x/net/context"
)

func TestNewEnvClient(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("skipping unix only test for windows")
	}
	cases := []struct {
		envs            map[string]string
		expectedError   string
		expectedVersion string
	}{
		{
			envs:            map[string]string{},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH": "invalid/path",
			},
			expectedError: "Could not load X509 key pair: open invalid/path/cert.pem: no such file or directory",
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH": "testdata/",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH":  "testdata/",
				"DOCKER_TLS_VERIFY": "1",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_CERT_PATH": "testdata/",
				"DOCKER_HOST":      "https://notaunixsocket",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_HOST": "host",
			},
			expectedError: "unable to parse docker host `host`",
		},
		{
			envs: map[string]string{
				"DOCKER_HOST": "invalid://url",
			},
			expectedVersion: api.DefaultVersion,
		},
		{
			envs: map[string]string{
				"DOCKER_API_VERSION": "anything",
			},
			expectedVersion: "anything",
		},
		{
			envs: map[string]string{
				"DOCKER_API_VERSION": "1.22",
			},
			expectedVersion: "1.22",
		},
	}
	for _, c := range cases {
		recoverEnvs := setupEnvs(t, c.envs)
		apiclient, err := NewEnvClient()
		if c.expectedError != "" {
			if err == nil {
				t.Errorf("expected an error for %v", c)
			} else if err.Error() != c.expectedError {
				t.Errorf("expected an error %s, got %s, for %v", c.expectedError, err.Error(), c)
			}
		} else {
			if err != nil {
				t.Error(err)
			}
			version := apiclient.ClientVersion()
			if version != c.expectedVersion {
				t.Errorf("expected %s, got %s, for %v", c.expectedVersion, version, c)
			}
		}

		if c.envs["DOCKER_TLS_VERIFY"] != "" {
			// pedantic checking that this is handled correctly
			tr := apiclient.client.Transport.(*http.Transport)
			if tr.TLSClientConfig == nil {
				t.Error("no TLS config found when DOCKER_TLS_VERIFY enabled")
			}

			if tr.TLSClientConfig.InsecureSkipVerify {
				t.Error("TLS verification should be enabled")
			}
		}

		recoverEnvs(t)
	}
}

func setupEnvs(t *testing.T, envs map[string]string) func(*testing.T) {
	oldEnvs := map[string]string{}
	for key, value := range envs {
		oldEnv := os.Getenv(key)
		oldEnvs[key] = oldEnv
		err := os.Setenv(key, value)
		if err != nil {
			t.Error(err)
		}
	}
	return func(t *testing.T) {
		for key, value := range oldEnvs {
			err := os.Setenv(key, value)
			if err != nil {
				t.Error(err)
			}
		}
	}
}

func TestGetAPIPath(t *testing.T) {
	cases := []struct {
		v string
		p string
		q url.Values
		e string
	}{
		{"", "/containers/json", nil, "/containers/json"},
		{"", "/containers/json", url.Values{}, "/containers/json"},
		{"", "/containers/json", url.Values{"s": []string{"c"}}, "/containers/json?s=c"},
		{"1.22", "/containers/json", nil, "/v1.22/containers/json"},
		{"1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"},
		{"1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"},
		{"v1.22", "/containers/json", nil, "/v1.22/containers/json"},
		{"v1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"},
		{"v1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"},
		{"v1.22", "/networks/kiwl$%^", nil, "/v1.22/networks/kiwl$%25%5E"},
	}

	for _, cs := range cases {
		c, err := NewClient("unix:///var/run/docker.sock", cs.v, nil, nil)
		if err != nil {
			t.Fatal(err)
		}
		g := c.getAPIPath(cs.p, cs.q)
		if g != cs.e {
			t.Fatalf("Expected %s, got %s", cs.e, g)
		}

		err = c.Close()
		if nil != err {
			t.Fatalf("close client failed, error message: %s", err)
		}
	}
}

func TestParseHost(t *testing.T) {
	cases := []struct {
		host  string
		proto string
		addr  string
		base  string
		err   bool
	}{
		{"", "", "", "", true},
		{"foobar", "", "", "", true},
		{"foo://bar", "foo", "bar", "", false},
		{"tcp://localhost:2476", "tcp", "localhost:2476", "", false},
		{"tcp://localhost:2476/path", "tcp", "localhost:2476", "/path", false},
	}

	for _, cs := range cases {
		p, a, b, e := ParseHost(cs.host)
		if cs.err && e == nil {
			t.Fatalf("expected error, got nil")
		}
		if !cs.err && e != nil {
			t.Fatal(e)
		}
		if cs.proto != p {
			t.Fatalf("expected proto %s, got %s", cs.proto, p)
		}
		if cs.addr != a {
			t.Fatalf("expected addr %s, got %s", cs.addr, a)
		}
		if cs.base != b {
			t.Fatalf("expected base %s, got %s", cs.base, b)
		}
	}
}

func TestUpdateClientVersion(t *testing.T) {
	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			splitQuery := strings.Split(req.URL.Path, "/")
			queryVersion := splitQuery[1]
			b, err := json.Marshal(types.Version{
				APIVersion: queryVersion,
			})
			if err != nil {
				return nil, err
			}
			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader(b)),
			}, nil
		}),
	}

	cases := []struct {
		v string
	}{
		{"1.20"},
		{"v1.21"},
		{"1.22"},
		{"v1.22"},
	}

	for _, cs := range cases {
		client.UpdateClientVersion(cs.v)
		r, err := client.ServerVersion(context.Background())
		if err != nil {
			t.Fatal(err)
		}
		if strings.TrimPrefix(r.APIVersion, "v") != strings.TrimPrefix(cs.v, "v") {
			t.Fatalf("Expected %s, got %s", cs.v, r.APIVersion)
		}
	}
}

func TestNewEnvClientSetsDefaultVersion(t *testing.T) {
	// Unset environment variables
	envVarKeys := []string{
		"DOCKER_HOST",
		"DOCKER_API_VERSION",
		"DOCKER_TLS_VERIFY",
		"DOCKER_CERT_PATH",
	}
	envVarValues := make(map[string]string)
	for _, key := range envVarKeys {
		envVarValues[key] = os.Getenv(key)
		os.Setenv(key, "")
	}

	client, err := NewEnvClient()
	if err != nil {
		t.Fatal(err)
	}
	if client.version != api.DefaultVersion {
		t.Fatalf("Expected %s, got %s", api.DefaultVersion, client.version)
	}

	expected := "1.22"
	os.Setenv("DOCKER_API_VERSION", expected)
	client, err = NewEnvClient()
	if err != nil {
		t.Fatal(err)
	}
	if client.version != expected {
		t.Fatalf("Expected %s, got %s", expected, client.version)
	}

	// Restore environment variables
	for _, key := range envVarKeys {
		os.Setenv(key, envVarValues[key])
	}
}
<|endoftext|>


<commit_before>package ftp

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"net/textproto"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

const (
	testData = "Just some text"
	testDir  = "mydir"
)

func TestConnPASV(t *testing.T) {
	testConn(t, true)
}

func TestConnEPSV(t *testing.T) {
	testConn(t, false)
}

func testConn(t *testing.T, disableEPSV bool) {

	mock, c := openConn(t, "127.0.0.1", DialWithTimeout(5*time.Second), DialWithDisabledEPSV(disableEPSV))

	err := c.Login("anonymous", "anonymous")
	if err != nil {
		t.Fatal(err)
	}

	err = c.NoOp()
	if err != nil {
		t.Error(err)
	}

	err = c.ChangeDir("incoming")
	if err != nil {
		t.Error(err)
	}

	dir, err := c.CurrentDir()
	if err != nil {
		t.Error(err)
	} else {
		if dir != "/incoming" {
			t.Error("Wrong dir: " + dir)
		}
	}

	data := bytes.NewBufferString(testData)
	err = c.Stor("test", data)
	if err != nil {
		t.Error(err)
	}

	_, err = c.List(".")
	if err != nil {
		t.Error(err)
	}

	err = c.Rename("test", "tset")
	if err != nil {
		t.Error(err)
	}

	// Read without deadline
	r, err := c.Retr("tset")
	if err != nil {
		t.Error(err)
	} else {
		buf, errRead := ioutil.ReadAll(r)
		if err != nil {
			t.Error(errRead)
		}
		if string(buf) != testData {
			t.Errorf("'%s'", buf)
		}
		r.Close()
		r.Close() // test we can close two times
	}

	// Read with deadline
	r, err = c.Retr("tset")
	if err != nil {
		t.Error(err)
	} else {
		if err := r.SetDeadline(time.Now()); err != nil {
			t.Fatal(err)
		}
		_, err = ioutil.ReadAll(r)
		if err == nil {
			t.Error("deadline should have caused error")
		} else if !strings.HasSuffix(err.Error(), "i/o timeout") {
			t.Error(err)
		}
		r.Close()
	}

	// Read with offset
	r, err = c.RetrFrom("tset", 5)
	if err != nil {
		t.Error(err)
	} else {
		buf, errRead := ioutil.ReadAll(r)
		if errRead != nil {
			t.Error(errRead)
		}
		expected := testData[5:]
		if string(buf) != expected {
			t.Errorf("read %q, expected %q", buf, expected)
		}
		r.Close()
	}

	data2 := bytes.NewBufferString(testData)
	err = c.Append("tset", data2)
	if err != nil {
		t.Error(err)
	}

	// Read without deadline, after append
	r, err = c.Retr("tset")
	if err != nil {
		t.Error(err)
	} else {
		buf, errRead := ioutil.ReadAll(r)
		if err != nil {
			t.Error(errRead)
		}
		if string(buf) != testData+testData {
			t.Errorf("'%s'", buf)
		}
		r.Close()
	}

	fileSize, err := c.FileSize("magic-file")
	if err != nil {
		t.Error(err)
	}
	if fileSize != 42 {
		t.Errorf("file size %q, expected %q", fileSize, 42)
	}

	_, err = c.FileSize("not-found")
	if err == nil {
		t.Fatal("expected error, got nil")
	}

	err = c.Delete("tset")
	if err != nil {
		t.Error(err)
	}

	err = c.MakeDir(testDir)
	if err != nil {
		t.Error(err)
	}

	err = c.ChangeDir(testDir)
	if err != nil {
		t.Error(err)
	}

	err = c.ChangeDirToParent()
	if err != nil {
		t.Error(err)
	}

	entries, err := c.NameList("/")
	if err != nil {
		t.Error(err)
	}
	if len(entries) != 1 || entries[0] != "/incoming" {
		t.Errorf("Unexpected entries: %v", entries)
	}

	err = c.RemoveDir(testDir)
	if err != nil {
		t.Error(err)
	}

	err = c.Logout()
	if err != nil {
		if protoErr := err.(*textproto.Error); protoErr != nil {
			if protoErr.Code != StatusNotImplemented {
				t.Error(err)
			}
		} else {
			t.Error(err)
		}
	}

	if err = c.Quit(); err != nil {
		t.Fatal(err)
	}

	// Wait for the connection to close
	mock.Wait()

	err = c.NoOp()
	if err == nil {
		t.Error("Expected error")
	}
}

// TestConnect tests the legacy Connect function
func TestConnect(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, err := Connect(mock.Addr())
	if err != nil {
		t.Fatal(err)
	}

	if err := c.Quit(); err != nil {
		t.Fatal(err)
	}
	mock.Wait()
}

func TestTimeout(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	if c, err := DialTimeout("localhost:2121", 1*time.Second); err == nil {
		_ = c.Quit()
		t.Fatal("expected timeout, got nil error")
	}
}

func TestWrongLogin(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, err := DialTimeout(mock.Addr(), 5*time.Second)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := c.Quit(); err != nil {
			t.Errorf("can not quit: %s", err)
		}
	}()

	err = c.Login("zoo2Shia", "fei5Yix9")
	if err == nil {
		t.Fatal("expected error, got nil")
	}
}

func TestDeleteDirRecur(t *testing.T) {
	mock, c := openConn(t, "127.0.0.1")

	err := c.RemoveDirRecur("testDir")
	if err != nil {
		t.Error(err)
	}

	if err := c.Quit(); err != nil {
		t.Fatal(err)
	}

	// Wait for the connection to close
	mock.Wait()
}

// func TestFileDeleteDirRecur(t *testing.T) {
// 	mock, c := openConn(t, "127.0.0.1")

// 	err := c.RemoveDirRecur("testFile")
// 	if err == nil {
// 		t.Fatal("expected error got nil")
// 	}

// 	if err := c.Quit(); err != nil {
// 		t.Fatal(err)
// 	}

// 	// Wait for the connection to close
// 	mock.Wait()
// }

func TestMissingFolderDeleteDirRecur(t *testing.T) {
	mock, c := openConn(t, "127.0.0.1")

	err := c.RemoveDirRecur("missing-dir")
	if err == nil {
		t.Fatal("expected error got nil")
	}

	if err := c.Quit(); err != nil {
		t.Fatal(err)
	}

	// Wait for the connection to close
	mock.Wait()
}

func TestListCurrentDir(t *testing.T) {
	mock, c := openConn(t, "127.0.0.1")

	_, err := c.List("")
	assert.NoError(t, err)
	assert.Equal(t, "LIST", mock.lastFull, "LIST must not have a trailing whitespace")

	_, err = c.NameList("")
	assert.NoError(t, err)
	assert.Equal(t, "NLST", mock.lastFull, "NLST must not have a trailing whitespace")

	err = c.Quit()
	assert.NoError(t, err)

	mock.Wait()
}

func TestTimeUnsupported(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "no-time")

	assert.False(t, c.mdtmSupported, "MDTM must NOT be supported")
	assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")

	assert.False(t, c.IsGetTimeSupported(), "GetTime must NOT be supported")
	assert.False(t, c.IsSetTimeSupported(), "SetTime must NOT be supported")

	_, err := c.GetTime("file1")
	assert.NotNil(t, err)

	err = c.SetTime("file1", time.Now())
	assert.NotNil(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestTimeStandard(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "std-time")

	assert.True(t, c.mdtmSupported, "MDTM must be supported")
	assert.True(t, c.mfmtSupported, "MFMT must be supported")

	assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
	assert.True(t, c.IsSetTimeSupported(), "SetTime must be supported")

	tm, err := c.GetTime("file1")
	assert.NoError(t, err)
	assert.False(t, tm.IsZero(), "GetTime must return valid time")

	err = c.SetTime("file1", time.Now())
	assert.NoError(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestTimeVsftpdPartial(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "vsftpd")

	assert.True(t, c.mdtmSupported, "MDTM must be supported")
	assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")

	assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
	assert.False(t, c.IsSetTimeSupported(), "SetTime must NOT be supported")

	tm, err := c.GetTime("file1")
	assert.NoError(t, err)
	assert.False(t, tm.IsZero(), "GetTime must return valid time")

	err = c.SetTime("file1", time.Now())
	assert.NotNil(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestTimeVsftpdFull(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "vsftpd", DialWithWritingMDTM(true))

	assert.True(t, c.mdtmSupported, "MDTM must be supported")
	assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")

	assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
	assert.True(t, c.IsSetTimeSupported(), "SetTime must be supported")

	tm, err := c.GetTime("file1")
	assert.NoError(t, err)
	assert.False(t, tm.IsZero(), "GetTime must return valid time")

	err = c.SetTime("file1", time.Now())
	assert.NoError(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestDialWithDialFunc(t *testing.T) {
	dialErr := fmt.Errorf("this is proof that dial function was called")

	f := func(network, address string) (net.Conn, error) {
		return nil, dialErr
	}

	_, err := Dial("bogus-address", DialWithDialFunc(f))
	assert.Equal(t, dialErr, err)
}
<commit_msg>Add test for DialWithDialer<commit_after>package ftp

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"net/textproto"
	"strings"
	"syscall"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

const (
	testData = "Just some text"
	testDir  = "mydir"
)

func TestConnPASV(t *testing.T) {
	testConn(t, true)
}

func TestConnEPSV(t *testing.T) {
	testConn(t, false)
}

func testConn(t *testing.T, disableEPSV bool) {
	mock, c := openConn(t, "127.0.0.1", DialWithTimeout(5*time.Second), DialWithDisabledEPSV(disableEPSV))

	err := c.Login("anonymous", "anonymous")
	if err != nil {
		t.Fatal(err)
	}

	err = c.NoOp()
	if err != nil {
		t.Error(err)
	}

	err = c.ChangeDir("incoming")
	if err != nil {
		t.Error(err)
	}

	dir, err := c.CurrentDir()
	if err != nil {
		t.Error(err)
	} else {
		if dir != "/incoming" {
			t.Error("Wrong dir: " + dir)
		}
	}

	data := bytes.NewBufferString(testData)
	err = c.Stor("test", data)
	if err != nil {
		t.Error(err)
	}

	_, err = c.List(".")
	if err != nil {
		t.Error(err)
	}

	err = c.Rename("test", "tset")
	if err != nil {
		t.Error(err)
	}

	// Read without deadline
	r, err := c.Retr("tset")
	if err != nil {
		t.Error(err)
	} else {
		buf, errRead := ioutil.ReadAll(r)
		if err != nil {
			t.Error(errRead)
		}
		if string(buf) != testData {
			t.Errorf("'%s'", buf)
		}
		r.Close()
		r.Close() // test we can close two times
	}

	// Read with deadline
	r, err = c.Retr("tset")
	if err != nil {
		t.Error(err)
	} else {
		if err := r.SetDeadline(time.Now()); err != nil {
			t.Fatal(err)
		}
		_, err = ioutil.ReadAll(r)
		if err == nil {
			t.Error("deadline should have caused error")
		} else if !strings.HasSuffix(err.Error(), "i/o timeout") {
			t.Error(err)
		}
		r.Close()
	}

	// Read with offset
	r, err = c.RetrFrom("tset", 5)
	if err != nil {
		t.Error(err)
	} else {
		buf, errRead := ioutil.ReadAll(r)
		if errRead != nil {
			t.Error(errRead)
		}
		expected := testData[5:]
		if string(buf) != expected {
			t.Errorf("read %q, expected %q", buf, expected)
		}
		r.Close()
	}

	data2 := bytes.NewBufferString(testData)
	err = c.Append("tset", data2)
	if err != nil {
		t.Error(err)
	}

	// Read without deadline, after append
	r, err = c.Retr("tset")
	if err != nil {
		t.Error(err)
	} else {
		buf, errRead := ioutil.ReadAll(r)
		if err != nil {
			t.Error(errRead)
		}
		if string(buf) != testData+testData {
			t.Errorf("'%s'", buf)
		}
		r.Close()
	}

	fileSize, err := c.FileSize("magic-file")
	if err != nil {
		t.Error(err)
	}
	if fileSize != 42 {
		t.Errorf("file size %q, expected %q", fileSize, 42)
	}

	_, err = c.FileSize("not-found")
	if err == nil {
		t.Fatal("expected error, got nil")
	}

	err = c.Delete("tset")
	if err != nil {
		t.Error(err)
	}

	err = c.MakeDir(testDir)
	if err != nil {
		t.Error(err)
	}

	err = c.ChangeDir(testDir)
	if err != nil {
		t.Error(err)
	}

	err = c.ChangeDirToParent()
	if err != nil {
		t.Error(err)
	}

	entries, err := c.NameList("/")
	if err != nil {
		t.Error(err)
	}
	if len(entries) != 1 || entries[0] != "/incoming" {
		t.Errorf("Unexpected entries: %v", entries)
	}

	err = c.RemoveDir(testDir)
	if err != nil {
		t.Error(err)
	}

	err = c.Logout()
	if err != nil {
		if protoErr := err.(*textproto.Error); protoErr != nil {
			if protoErr.Code != StatusNotImplemented {
				t.Error(err)
			}
		} else {
			t.Error(err)
		}
	}

	if err = c.Quit(); err != nil {
		t.Fatal(err)
	}

	// Wait for the connection to close
	mock.Wait()

	err = c.NoOp()
	if err == nil {
		t.Error("Expected error")
	}
}

// TestConnect tests the legacy Connect function
func TestConnect(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, err := Connect(mock.Addr())
	if err != nil {
		t.Fatal(err)
	}

	if err := c.Quit(); err != nil {
		t.Fatal(err)
	}
	mock.Wait()
}

func TestTimeout(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	if c, err := DialTimeout("localhost:2121", 1*time.Second); err == nil {
		_ = c.Quit()
		t.Fatal("expected timeout, got nil error")
	}
}

func TestWrongLogin(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, err := DialTimeout(mock.Addr(), 5*time.Second)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := c.Quit(); err != nil {
			t.Errorf("can not quit: %s", err)
		}
	}()

	err = c.Login("zoo2Shia", "fei5Yix9")
	if err == nil {
		t.Fatal("expected error, got nil")
	}
}

func TestDeleteDirRecur(t *testing.T) {
	mock, c := openConn(t, "127.0.0.1")

	err := c.RemoveDirRecur("testDir")
	if err != nil {
		t.Error(err)
	}

	if err := c.Quit(); err != nil {
		t.Fatal(err)
	}

	// Wait for the connection to close
	mock.Wait()
}

// func TestFileDeleteDirRecur(t *testing.T) {
// 	mock, c := openConn(t, "127.0.0.1")

// 	err := c.RemoveDirRecur("testFile")
// 	if err == nil {
// 		t.Fatal("expected error got nil")
// 	}

// 	if err := c.Quit(); err != nil {
// 		t.Fatal(err)
// 	}

// 	// Wait for the connection to close
// 	mock.Wait()
// }

func TestMissingFolderDeleteDirRecur(t *testing.T) {
	mock, c := openConn(t, "127.0.0.1")

	err := c.RemoveDirRecur("missing-dir")
	if err == nil {
		t.Fatal("expected error got nil")
	}

	if err := c.Quit(); err != nil {
		t.Fatal(err)
	}

	// Wait for the connection to close
	mock.Wait()
}

func TestListCurrentDir(t *testing.T) {
	mock, c := openConn(t, "127.0.0.1")

	_, err := c.List("")
	assert.NoError(t, err)
	assert.Equal(t, "LIST", mock.lastFull, "LIST must not have a trailing whitespace")

	_, err = c.NameList("")
	assert.NoError(t, err)
	assert.Equal(t, "NLST", mock.lastFull, "NLST must not have a trailing whitespace")

	err = c.Quit()
	assert.NoError(t, err)

	mock.Wait()
}

func TestTimeUnsupported(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "no-time")

	assert.False(t, c.mdtmSupported, "MDTM must NOT be supported")
	assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")

	assert.False(t, c.IsGetTimeSupported(), "GetTime must NOT be supported")
	assert.False(t, c.IsSetTimeSupported(), "SetTime must NOT be supported")

	_, err := c.GetTime("file1")
	assert.NotNil(t, err)

	err = c.SetTime("file1", time.Now())
	assert.NotNil(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestTimeStandard(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "std-time")

	assert.True(t, c.mdtmSupported, "MDTM must be supported")
	assert.True(t, c.mfmtSupported, "MFMT must be supported")

	assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
	assert.True(t, c.IsSetTimeSupported(), "SetTime must be supported")

	tm, err := c.GetTime("file1")
	assert.NoError(t, err)
	assert.False(t, tm.IsZero(), "GetTime must return valid time")

	err = c.SetTime("file1", time.Now())
	assert.NoError(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestTimeVsftpdPartial(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "vsftpd")

	assert.True(t, c.mdtmSupported, "MDTM must be supported")
	assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")

	assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
	assert.False(t, c.IsSetTimeSupported(), "SetTime must NOT be supported")

	tm, err := c.GetTime("file1")
	assert.NoError(t, err)
	assert.False(t, tm.IsZero(), "GetTime must return valid time")

	err = c.SetTime("file1", time.Now())
	assert.NotNil(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestTimeVsftpdFull(t *testing.T) {
	mock, c := openConnExt(t, "127.0.0.1", "vsftpd", DialWithWritingMDTM(true))

	assert.True(t, c.mdtmSupported, "MDTM must be supported")
	assert.False(t, c.mfmtSupported, "MFMT must NOT be supported")

	assert.True(t, c.IsGetTimeSupported(), "GetTime must be supported")
	assert.True(t, c.IsSetTimeSupported(), "SetTime must be supported")

	tm, err := c.GetTime("file1")
	assert.NoError(t, err)
	assert.False(t, tm.IsZero(), "GetTime must return valid time")

	err = c.SetTime("file1", time.Now())
	assert.NoError(t, err)

	assert.NoError(t, c.Quit())
	mock.Wait()
}

func TestDialWithDialFunc(t *testing.T) {
	dialErr := fmt.Errorf("this is proof that dial function was called")

	f := func(network, address string) (net.Conn, error) {
		return nil, dialErr
	}

	_, err := Dial("bogus-address", DialWithDialFunc(f))
	assert.Equal(t, dialErr, err)
}

func TestDialWithDialer(t *testing.T) {
	dialerCalled := false
	dialer := net.Dialer{
		Control: func(network, address string, c syscall.RawConn) error {
			dialerCalled = true
			return nil
		},
	}

	mock, err := newFtpMock(t, "127.0.0.1")
	assert.NoError(t, err)

	c, err := Dial(mock.Addr(), DialWithDialer(dialer))
	assert.NoError(t, err)
	assert.NoError(t, c.Quit())

	assert.Equal(t, true, dialerCalled)
}
<|endoftext|>


<commit_before>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.15.0")
	},
}
<commit_msg>Revert "Bump version - v"0.15.0""<commit_after>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.14.5")
	},
}
<|endoftext|>


<commit_before>package common

import (
	"compress/gzip"
	"crypto/md5"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
)

type Ring interface {
	GetNodes(partition uint64) (response []*Device)
	GetJobNodes(partition uint64, localDevice int) (response []*Device, handoff bool)
	GetPartition(account string, container string, object string) uint64
	LocalDevices(localPort int) (devs []*Device)
	GetMoreNodes(partition uint64) MoreNodes
}

type MoreNodes interface {
	Next() *Device
}

type Device struct {
	Id              int     `json:"id"`
	Device          string  `json:"device"`
	Ip              string  `json:"ip"`
	Meta            string  `json:"meta"`
	Port            int     `json:"port"`
	Region          int     `json:"region"`
	ReplicationIp   string  `json:"replication_ip"`
	ReplicationPort int     `json:"replication_port"`
	Weight          float64 `json:"weight"`
	Zone            int     `json:"zone"`
}

type hashRing struct {
	Devs                                []Device `json:"devs"`
	ReplicaCount                        int      `json:"replica_count"`
	PartShift                           uint64   `json:"part_shift"`
	replica2part2devId                  [][]uint16
	prefix                              string
	suffix                              string
	regionCount, zoneCount, ipPortCount int
}

type regionZone struct {
	region, zone int
}

type ipPort struct {
	region, zone, port int
	ip                 string
}

type hashMoreNodes struct {
	r                 *hashRing
	used, sameRegions map[int]bool
	sameZones         map[regionZone]bool
	sameIpPorts       map[ipPort]bool
	parts, start, inc int
	partition         uint64
}

func (d *Device) String() string {
	return fmt.Sprintf("Device{Id: %d, Device: %s, Ip: %s, Port: %d}", d.Id, d.Device, d.Ip, d.Port)
}

func (r *hashRing) GetNodes(partition uint64) (response []*Device) {
	for i := 0; i < r.ReplicaCount; i++ {
		response = append(response, &r.Devs[r.replica2part2devId[i][partition]])
	}
	return response
}

func (r *hashRing) GetJobNodes(partition uint64, localDevice int) (response []*Device, handoff bool) {
	handoff = true
	for i := 0; i < r.ReplicaCount; i++ {
		dev := &r.Devs[r.replica2part2devId[i][partition]]
		if dev.Id == localDevice {
			handoff = false
		} else {
			response = append(response, dev)
		}
	}
	return response, handoff
}

func (r *hashRing) GetPartition(account string, container string, object string) uint64 {
	hash := md5.New()
	hash.Write([]byte(r.prefix + "/" + account + "/"))
	if container != "" {
		hash.Write([]byte(container + "/"))
		if object != "" {
			hash.Write([]byte(object + "/"))
		}
	}
	// treat as big endian unsigned int
	hash.Write([]byte(r.suffix))
	digest := hash.Sum(nil)
	val := uint64(digest[0])<<24 | uint64(digest[1])<<16 | uint64(digest[2])<<8 | uint64(digest[3])
	return val >> r.PartShift
}

func (r *hashRing) LocalDevices(localPort int) (devs []*Device) {
	var localIPs = make(map[string]bool)

	localAddrs, _ := net.InterfaceAddrs()
	for _, addr := range localAddrs {
		localIPs[strings.Split(addr.String(), "/")[0]] = true
	}

	for _, dev := range r.Devs {
		if localIPs[dev.ReplicationIp] && dev.ReplicationPort == localPort {
			devs = append(devs, &dev)
		}
	}
	return devs
}

func (r *hashRing) GetMoreNodes(partition uint64) MoreNodes {
	return &hashMoreNodes{r: r, partition: partition, used: nil}
}

func (m *hashMoreNodes) addDevice(d *Device) {
	m.used[d.Id] = true
	m.sameRegions[d.Region] = true
	m.sameZones[regionZone{d.Region, d.Zone}] = true
	m.sameIpPorts[ipPort{d.Region, d.Zone, d.Port, d.Ip}] = true
}

func (m *hashMoreNodes) initialize() {
	m.parts = len(m.r.replica2part2devId[0])
	m.used = make(map[int]bool)
	m.sameRegions = make(map[int]bool)
	m.sameZones = make(map[regionZone]bool)
	m.sameIpPorts = make(map[ipPort]bool)
	for _, mp := range m.r.replica2part2devId {
		m.addDevice(&m.r.Devs[mp[m.partition]])
	}
	hash := md5.New()
	hash.Write([]byte(strconv.FormatUint(m.partition, 10)))
	digest := hash.Sum(nil)
	m.start = int((uint64(digest[0])<<24 | uint64(digest[1])<<16 | uint64(digest[2])<<8 | uint64(digest[3])) >> m.r.PartShift)
	m.inc = m.parts / 65536
	if m.inc == 0 {
		m.inc = 1
	}
}

func (m *hashMoreNodes) Next() *Device {
	if m.used == nil {
		m.initialize()
	}
	var check func(d *Device) bool
	if len(m.sameRegions) < m.r.regionCount {
		check = func(d *Device) bool { return !m.sameRegions[d.Region] }
	} else if len(m.sameZones) < m.r.zoneCount {
		check = func(d *Device) bool { return !m.sameZones[regionZone{d.Region, d.Zone}] }
	} else if len(m.sameIpPorts) < m.r.ipPortCount {
		check = func(d *Device) bool { return !m.sameIpPorts[ipPort{d.Region, d.Zone, d.Port, d.Ip}] }
	} else {
		check = func(d *Device) bool { return !m.used[d.Id] }
	}
	for i := 0; i < m.parts; i += m.inc {
		handoffPart := (i + m.start) % m.parts
		for _, part2devId := range m.r.replica2part2devId {
			if handoffPart < len(part2devId) {
				if check(&m.r.Devs[part2devId[handoffPart]]) {
					m.addDevice(&m.r.Devs[part2devId[handoffPart]])
					return &m.r.Devs[part2devId[handoffPart]]
				}
			}
		}
	}
	return nil
}

func LoadRing(path string, prefix string, suffix string) (Ring, error) {
	fp, err := os.Open(path)
	if err != nil {
		if os.IsNotExist(err) {
			errMsg := fmt.Sprintf("File at %s doesn't exists", path)
			return nil, errors.New(errMsg)
		} else {
			return nil, err
		}
	}
	gz, _ := gzip.NewReader(fp)
	magicBuf := make([]byte, 4)
	io.ReadFull(gz, magicBuf)
	if string(magicBuf) != "R1NG" {
		return nil, errors.New("Bad magic string")
	}
	var ringVersion uint16
	binary.Read(gz, binary.BigEndian, &ringVersion)
	if ringVersion != 1 {
		return nil, errors.New(fmt.Sprintf("Unknown ring version %d", ringVersion))
	}
	// TODO: assert ringVersion == 1
	var json_len uint32
	binary.Read(gz, binary.BigEndian, &json_len)
	jsonBuf := make([]byte, json_len)
	io.ReadFull(gz, jsonBuf)
	var ring hashRing
	json.Unmarshal(jsonBuf, &ring)
	ring.prefix = prefix
	ring.suffix = suffix
	partitionCount := 1 << (32 - ring.PartShift)
	for i := 0; i < ring.ReplicaCount; i++ {
		part2dev := make([]uint16, partitionCount)
		binary.Read(gz, binary.LittleEndian, &part2dev)
		ring.replica2part2devId = append(ring.replica2part2devId, part2dev)
	}
	regionCount := make(map[int]bool)
	zoneCount := make(map[regionZone]bool)
	ipPortCount := make(map[ipPort]bool)
	for _, d := range ring.Devs {
		regionCount[d.Region] = true
		zoneCount[regionZone{d.Region, d.Zone}] = true
		ipPortCount[ipPort{d.Region, d.Zone, d.Port, d.Ip}] = true
	}
	ring.regionCount = len(regionCount)
	ring.zoneCount = len(zoneCount)
	ring.ipPortCount = len(ipPortCount)
	return &ring, nil
}

// GetRing returns the current ring given the ring_type ("account", "container", "object"),
// hash path prefix, and hash path suffix. An error is raised if the requested ring does
// not exist.
func GetRing(ring_type, prefix, suffix string) (*Ring, error) {
	var ring *Ring
	var err error
	if ring, err = LoadRing(fmt.Sprintf("/etc/hummingbird/%s.ring.gz", ring_type), prefix, suffix); err != nil {
		if ring, err = LoadRing(fmt.Sprintf("/etc/swift/%s.ring.gz", ring_type), prefix, suffix); err != nil {
			return nil, errors.New(fmt.Sprintf("Error loading %s ring", ring_type))
		}
	}
	return ring, nil
}
<commit_msg>updating to accomidate for the change in the ring<commit_after>package common

import (
	"compress/gzip"
	"crypto/md5"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
)

type Ring interface {
	GetNodes(partition uint64) (response []*Device)
	GetJobNodes(partition uint64, localDevice int) (response []*Device, handoff bool)
	GetPartition(account string, container string, object string) uint64
	LocalDevices(localPort int) (devs []*Device)
	GetMoreNodes(partition uint64) MoreNodes
}

type MoreNodes interface {
	Next() *Device
}

type Device struct {
	Id              int     `json:"id"`
	Device          string  `json:"device"`
	Ip              string  `json:"ip"`
	Meta            string  `json:"meta"`
	Port            int     `json:"port"`
	Region          int     `json:"region"`
	ReplicationIp   string  `json:"replication_ip"`
	ReplicationPort int     `json:"replication_port"`
	Weight          float64 `json:"weight"`
	Zone            int     `json:"zone"`
}

type hashRing struct {
	Devs                                []Device `json:"devs"`
	ReplicaCount                        int      `json:"replica_count"`
	PartShift                           uint64   `json:"part_shift"`
	replica2part2devId                  [][]uint16
	prefix                              string
	suffix                              string
	regionCount, zoneCount, ipPortCount int
}

type regionZone struct {
	region, zone int
}

type ipPort struct {
	region, zone, port int
	ip                 string
}

type hashMoreNodes struct {
	r                 *hashRing
	used, sameRegions map[int]bool
	sameZones         map[regionZone]bool
	sameIpPorts       map[ipPort]bool
	parts, start, inc int
	partition         uint64
}

func (d *Device) String() string {
	return fmt.Sprintf("Device{Id: %d, Device: %s, Ip: %s, Port: %d}", d.Id, d.Device, d.Ip, d.Port)
}

func (r *hashRing) GetNodes(partition uint64) (response []*Device) {
	for i := 0; i < r.ReplicaCount; i++ {
		response = append(response, &r.Devs[r.replica2part2devId[i][partition]])
	}
	return response
}

func (r *hashRing) GetJobNodes(partition uint64, localDevice int) (response []*Device, handoff bool) {
	handoff = true
	for i := 0; i < r.ReplicaCount; i++ {
		dev := &r.Devs[r.replica2part2devId[i][partition]]
		if dev.Id == localDevice {
			handoff = false
		} else {
			response = append(response, dev)
		}
	}
	return response, handoff
}

func (r *hashRing) GetPartition(account string, container string, object string) uint64 {
	hash := md5.New()
	hash.Write([]byte(r.prefix + "/" + account + "/"))
	if container != "" {
		hash.Write([]byte(container + "/"))
		if object != "" {
			hash.Write([]byte(object + "/"))
		}
	}
	// treat as big endian unsigned int
	hash.Write([]byte(r.suffix))
	digest := hash.Sum(nil)
	val := uint64(digest[0])<<24 | uint64(digest[1])<<16 | uint64(digest[2])<<8 | uint64(digest[3])
	return val >> r.PartShift
}

func (r *hashRing) LocalDevices(localPort int) (devs []*Device) {
	var localIPs = make(map[string]bool)

	localAddrs, _ := net.InterfaceAddrs()
	for _, addr := range localAddrs {
		localIPs[strings.Split(addr.String(), "/")[0]] = true
	}

	for _, dev := range r.Devs {
		if localIPs[dev.ReplicationIp] && dev.ReplicationPort == localPort {
			devs = append(devs, &dev)
		}
	}
	return devs
}

func (r *hashRing) GetMoreNodes(partition uint64) MoreNodes {
	return &hashMoreNodes{r: r, partition: partition, used: nil}
}

func (m *hashMoreNodes) addDevice(d *Device) {
	m.used[d.Id] = true
	m.sameRegions[d.Region] = true
	m.sameZones[regionZone{d.Region, d.Zone}] = true
	m.sameIpPorts[ipPort{d.Region, d.Zone, d.Port, d.Ip}] = true
}

func (m *hashMoreNodes) initialize() {
	m.parts = len(m.r.replica2part2devId[0])
	m.used = make(map[int]bool)
	m.sameRegions = make(map[int]bool)
	m.sameZones = make(map[regionZone]bool)
	m.sameIpPorts = make(map[ipPort]bool)
	for _, mp := range m.r.replica2part2devId {
		m.addDevice(&m.r.Devs[mp[m.partition]])
	}
	hash := md5.New()
	hash.Write([]byte(strconv.FormatUint(m.partition, 10)))
	digest := hash.Sum(nil)
	m.start = int((uint64(digest[0])<<24 | uint64(digest[1])<<16 | uint64(digest[2])<<8 | uint64(digest[3])) >> m.r.PartShift)
	m.inc = m.parts / 65536
	if m.inc == 0 {
		m.inc = 1
	}
}

func (m *hashMoreNodes) Next() *Device {
	if m.used == nil {
		m.initialize()
	}
	var check func(d *Device) bool
	if len(m.sameRegions) < m.r.regionCount {
		check = func(d *Device) bool { return !m.sameRegions[d.Region] }
	} else if len(m.sameZones) < m.r.zoneCount {
		check = func(d *Device) bool { return !m.sameZones[regionZone{d.Region, d.Zone}] }
	} else if len(m.sameIpPorts) < m.r.ipPortCount {
		check = func(d *Device) bool { return !m.sameIpPorts[ipPort{d.Region, d.Zone, d.Port, d.Ip}] }
	} else {
		check = func(d *Device) bool { return !m.used[d.Id] }
	}
	for i := 0; i < m.parts; i += m.inc {
		handoffPart := (i + m.start) % m.parts
		for _, part2devId := range m.r.replica2part2devId {
			if handoffPart < len(part2devId) {
				if check(&m.r.Devs[part2devId[handoffPart]]) {
					m.addDevice(&m.r.Devs[part2devId[handoffPart]])
					return &m.r.Devs[part2devId[handoffPart]]
				}
			}
		}
	}
	return nil
}

func LoadRing(path string, prefix string, suffix string) (Ring, error) {
	fp, err := os.Open(path)
	if err != nil {
		if os.IsNotExist(err) {
			errMsg := fmt.Sprintf("File at %s doesn't exists", path)
			return nil, errors.New(errMsg)
		} else {
			return nil, err
		}
	}
	gz, _ := gzip.NewReader(fp)
	magicBuf := make([]byte, 4)
	io.ReadFull(gz, magicBuf)
	if string(magicBuf) != "R1NG" {
		return nil, errors.New("Bad magic string")
	}
	var ringVersion uint16
	binary.Read(gz, binary.BigEndian, &ringVersion)
	if ringVersion != 1 {
		return nil, errors.New(fmt.Sprintf("Unknown ring version %d", ringVersion))
	}
	// TODO: assert ringVersion == 1
	var json_len uint32
	binary.Read(gz, binary.BigEndian, &json_len)
	jsonBuf := make([]byte, json_len)
	io.ReadFull(gz, jsonBuf)
	var ring hashRing
	json.Unmarshal(jsonBuf, &ring)
	ring.prefix = prefix
	ring.suffix = suffix
	partitionCount := 1 << (32 - ring.PartShift)
	for i := 0; i < ring.ReplicaCount; i++ {
		part2dev := make([]uint16, partitionCount)
		binary.Read(gz, binary.LittleEndian, &part2dev)
		ring.replica2part2devId = append(ring.replica2part2devId, part2dev)
	}
	regionCount := make(map[int]bool)
	zoneCount := make(map[regionZone]bool)
	ipPortCount := make(map[ipPort]bool)
	for _, d := range ring.Devs {
		regionCount[d.Region] = true
		zoneCount[regionZone{d.Region, d.Zone}] = true
		ipPortCount[ipPort{d.Region, d.Zone, d.Port, d.Ip}] = true
	}
	ring.regionCount = len(regionCount)
	ring.zoneCount = len(zoneCount)
	ring.ipPortCount = len(ipPortCount)
	return &ring, nil
}

// GetRing returns the current ring given the ring_type ("account", "container", "object"),
// hash path prefix, and hash path suffix. An error is raised if the requested ring does
// not exist.
func GetRing(ring_type, prefix, suffix string) (Ring, error) {
	var ring Ring
	var err error
	if ring, err = LoadRing(fmt.Sprintf("/etc/hummingbird/%s.ring.gz", ring_type), prefix, suffix); err != nil {
		if ring, err = LoadRing(fmt.Sprintf("/etc/swift/%s.ring.gz", ring_type), prefix, suffix); err != nil {
			return nil, errors.New(fmt.Sprintf("Error loading %s ring", ring_type))
		}
	}
	return ring, nil
}
<|endoftext|>


<commit_before>package ari

// Sound represents a communication path to
// the asterisk server for Sound resources
type Sound interface {

	// List returns available sounds limited by the provided filters.
	// Valid filters are "lang", "format", and nil (no filter)
	List(filters map[string]string) ([]*SoundHandle, error)

	// Get returns a handle pointer to the sound for further interaction
	Get(name string) *SoundHandle

	// Data returns the Sound's data
	Data(name string) (SoundData, error)
}

// SoundHandle provides a wrapper to a Sound interface for
// operations on a specific Sound
type SoundHandle struct {
	name string
	s    Sound
}

// SoundData describes a media file which may be played back
type SoundData struct {
	Formats []FormatLangPair `json:"formats"`
	ID      string           `json:"id"`
	Text    string           `json:"text,omitempty"`
}

// FormatLangPair describes the format and language of a sound file
type FormatLangPair struct {
	Format   string `json:"format"`
	Language string `json:"language"`
}

// NewSoundHandle creates a new handle to the sound name
func NewSoundHandle(name string, snd Sound) *SoundHandle {
	return &SoundHandle{
		name: name,
		s:    snd,
	}
}

// Data retrieves the data for the Sound
func (sh *SoundHandle) Data() (sd SoundData, err error) {
	sd, err = sh.s.Data(sh.name)
	return sd, err
}
<commit_msg>v3 - sound - Add ID() to handle<commit_after>package ari

// Sound represents a communication path to
// the asterisk server for Sound resources
type Sound interface {

	// List returns available sounds limited by the provided filters.
	// Valid filters are "lang", "format", and nil (no filter)
	List(filters map[string]string) ([]*SoundHandle, error)

	// Get returns a handle pointer to the sound for further interaction
	Get(name string) *SoundHandle

	// Data returns the Sound's data
	Data(name string) (SoundData, error)
}

// SoundHandle provides a wrapper to a Sound interface for
// operations on a specific Sound
type SoundHandle struct {
	name string
	s    Sound
}

// ID returns the identifier for the sound
func (sh *SoundHandle) ID() string {
	return sh.name
}

// SoundData describes a media file which may be played back
type SoundData struct {
	Formats []FormatLangPair `json:"formats"`
	ID      string           `json:"id"`
	Text    string           `json:"text,omitempty"`
}

// FormatLangPair describes the format and language of a sound file
type FormatLangPair struct {
	Format   string `json:"format"`
	Language string `json:"language"`
}

// NewSoundHandle creates a new handle to the sound name
func NewSoundHandle(name string, snd Sound) *SoundHandle {
	return &SoundHandle{
		name: name,
		s:    snd,
	}
}

// Data retrieves the data for the Sound
func (sh *SoundHandle) Data() (sd SoundData, err error) {
	sd, err = sh.s.Data(sh.name)
	return sd, err
}
<|endoftext|>


<commit_before>package gogame

/*
#cgo pkg-config: sdl2
#cgo LDFLAGS: -lm
#include "SDL.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int FREQUENCY = 44100;

float vvs[100];
int amplitudesCallback[100];
int freqsCallback[100];

void audioCallback(void* userdata, Uint8* stream, int len) {
	int *id = (int*) userdata;
	float v = freqsCallback[*id];
	float *data = (float*) stream;
	for(int i=0; i<len / 4; i++) {
		data[i] = amplitudesCallback[*id] * sin(v * 2 * M_PI / FREQUENCY);
		v += freqsCallback[*id];
	}
}

SDL_AudioDeviceID newAudioDevice() {
	int *id = (int*) malloc(sizeof(int));
    SDL_AudioSpec want, have;
    SDL_AudioDeviceID dev;
    SDL_memset(&want, 0, sizeof(want));
    want.freq = FREQUENCY;
    want.format = AUDIO_F32;
    want.channels = 1;
    want.samples = 4096;
    want.callback = audioCallback;
	want.userdata = id;

    dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
    if (dev == 0) {
        SDL_Log("Failed to open audio: %s", SDL_GetError());
    }
    printf("freq: %d\n", have.freq);

	*id = dev;
    return dev;
}

*/
import "C"
import "errors"

type SoundDevice struct {
	dev C.SDL_AudioDeviceID
}

func NewSoundDevice() (*SoundDevice, error) {
	dev := C.newAudioDevice()
	if dev == 0 {
		return nil, errors.New("Can't open audio device")
	}
	sd := new(SoundDevice)
	sd.dev = dev
	return sd, nil
}

func (self *SoundDevice) Start() {
	C.SDL_PauseAudioDevice(self.dev, 0)
}

func (self *SoundDevice) Stop() {
	C.SDL_PauseAudioDevice(self.dev, 1)
}

func (self *SoundDevice) SetFreq(freq int) {
	C.freqsCallback[self.dev] = C.int(freq)
}

func (self *SoundDevice) SetAmplitude(amp int) {
	C.amplitudesCallback[self.dev] = C.int(amp)
}

func (self *SoundDevice) Close() {
	C.SDL_CloseAudioDevice(self.dev)
}
<commit_msg>Anem fent<commit_after>package gogame

/*
#cgo pkg-config: sdl2
#cgo LDFLAGS: -lm
#include "SDL.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int FREQUENCY = 44100;

float vvs[100];
int amplitudesCallback[100];
int freqsCallback[100];

void audioCallback(void* userdata, Uint8* stream, int len) {
	int *id = (int*) userdata;
	float v = vvs[*id];
	float *data = (float*) stream;
	for(int i=0; i<len / 4; i++) {
		data[i] = amplitudesCallback[*id] * sin((v) * 2 * M_PI / FREQUENCY);
		//if (abs(((v) * 2 * M_PI / FREQUENCY) - 2*M_PI) < 0.01) v = 0;
		(v) += freqsCallback[*id];
	}
	vvs[*id] = v;
}

SDL_AudioDeviceID newAudioDevice() {
	int *id = (int*) malloc(sizeof(int));
    SDL_AudioSpec want, have;
    SDL_AudioDeviceID dev;
    SDL_memset(&want, 0, sizeof(want));
    want.freq = FREQUENCY;
    want.format = AUDIO_F32;
    want.channels = 1;
    want.samples = 4096;
    want.callback = audioCallback;
	want.userdata = id;

    dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
    if (dev == 0) {
        SDL_Log("Failed to open audio: %s", SDL_GetError());
    }
    printf("freq: %d\n", have.freq);

	*id = dev;
    return dev;
}

*/
import "C"
import "errors"

type SoundDevice struct {
	dev C.SDL_AudioDeviceID
}

func NewSoundDevice() (*SoundDevice, error) {
	dev := C.newAudioDevice()
	if dev == 0 {
		return nil, errors.New("Can't open audio device")
	}
	sd := new(SoundDevice)
	sd.dev = dev
	return sd, nil
}

func (self *SoundDevice) Start() {
	C.SDL_PauseAudioDevice(self.dev, 0)
}

func (self *SoundDevice) Stop() {
	C.SDL_PauseAudioDevice(self.dev, 1)
}

func (self *SoundDevice) SetFreq(freq int) {
	C.freqsCallback[self.dev] = C.int(freq)
}

func (self *SoundDevice) SetAmplitude(amp int) {
	C.amplitudesCallback[self.dev] = C.int(amp)
}

func (self *SoundDevice) Close() {
	C.SDL_CloseAudioDevice(self.dev)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
)

func printMtl(w io.Writer, blockId uint16) {
	if !noColor {
		if blockId&0xff == blockId {
			fmt.Fprintln(w, "usemtl", blockId)
		} else {
			fmt.Fprintf(w, "usemtl %d_%d", blockId&0xff, blockId>>8)
		}
	}
}

func writeMtlFile(filename string) os.Error {
	if noColor {
		return nil
	}

	var outFile, outErr = os.Open(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if outErr != nil {
		return outErr
	}
	defer outFile.Close()

	var p = 0

	for i := 0; i < 256; i++ {
		var matched = false

		for p < len(colors) && colors[p].blockId == byte(i) {
			matched = true
			colors[p].Print(outFile)
			p++
		}

		if !matched {
			var mtl = MTL{byte(i), 255, 0x7f7f7f, "Unknown"}
			mtl.Print(outFile)
		}
	}

	return nil
}

type MTL struct {
	blockId  byte
	metadata byte
	color    uint32
	name     string
}

func (mtl *MTL) Print(w io.Writer) {
	var (
		r = mtl.color >> 24
		g = mtl.color >> 16 & 0xff
		b = mtl.color >> 8 & 0xff
		a = mtl.color & 0xff
	)

	if mtl.metadata == 255 {
		fmt.Fprintf(w, "# %s\nnewmtl %d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	} else {
		fmt.Fprintf(w, "# %s\nnewmtl %d_%d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, mtl.metadata, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	}
}

func (mtl *MTL) colorId() uint16 {
	var id = uint16(mtl.blockId)
	if mtl.metadata != 255 {
		id += uint16(mtl.metadata) << 8
	}
	return id
}

var (
	colors = []MTL{
		MTL{0, 255, 0xff0000ff, "Air"},
		MTL{1, 255, 0x7f7f7fff, "Stone"},
		MTL{2, 255, 0x509026ff, "Grass"},
		MTL{3, 255, 0x79553aff, "Dirt"},
		MTL{4, 255, 0xa8a8a8ff, "Cobblestone"},
		MTL{5, 255, 0x9e8052ff, "Wooden Plank"},
		MTL{6, 255, 0x006400ff, "Sapling"},
		MTL{7, 255, 0x575757ff, "Bedrock"},
		MTL{8, 255, 0x009affaa, "Water"},
		MTL{9, 255, 0x002affff, "Stationary water"},
		MTL{10, 255, 0x002affff, "Lava"},
		MTL{11, 255, 0xfc4a00ff, "Stationary lava"},
		MTL{12, 255, 0xcfc393ff, "Sand"},
		MTL{13, 255, 0x9a9b9fff, "Gravel"},
		MTL{14, 255, 0xfff144ff, "Gold ore"},
		MTL{15, 255, 0xe2c0aaff, "Iron ore"},
		MTL{16, 255, 0x454545ff, "Coal ore"},
		MTL{17, 255, 0x695433ff, "Wood"},
		MTL{18, 255, 0x2e6d05ff, "Leaves"},
		MTL{19, 255, 0xe5e54eff, "Sponge"},
		MTL{20, 255, 0xffffff10, "Glass"},
		MTL{21, 255, 0x224da1ff, "Lapis Lazuli Ore"},
		MTL{22, 255, 0x224dffff, "Lapis Lazuli Block"},
		MTL{23, 255, 0x7f7f7fff, "Dispenser"},
		MTL{24, 255, 0xdad2abff, "Sandstone"},
		MTL{25, 255, 0x9b664bff, "Note Block"},
		MTL{35, 0, 0xd1d1d1ff, "Wool - White"},
		MTL{35, 1, 0xe97a2eff, "Wool - Orange"},
		MTL{35, 2, 0xbc3ec7ff, "Wool - Magenta"},
		MTL{35, 3, 0x5980d0ff, "Wool - Light Blue"},
		MTL{35, 4, 0xb6a918ff, "Wool - Yellow"},
		MTL{35, 5, 0x37b32cff, "Wool - Light Green"},
		MTL{35, 6, 0xd57690ff, "Wool - Pink"},
		MTL{35, 7, 0x3f3f3fff, "Wool - Gray"},
		MTL{35, 8, 0x949d9dff, "Wool - Light Gray"},
		MTL{35, 9, 0xbc3ec7ff, "Wool - Cyan"},
		MTL{35, 10, 0x7a2fbcff, "Wool - Purple"},
		MTL{35, 11, 0x243091ff, "Wool - Blue"},
		MTL{35, 12, 0x51301aff, "Wool - Brown"},
		MTL{35, 13, 0x344817ff, "Wool - Dark Green"},
		MTL{35, 14, 0x9b2a26ff, "Wool - Red"},
		MTL{35, 15, 0x171313ff, "Wool - Black"},
		MTL{37, 255, 0xf1f902ff, "Yellow flower"},
		MTL{38, 255, 0xf11102ff, "Red rose"},
		MTL{39, 255, 0xba7038ff, "Brown Mushroom"},
		MTL{40, 255, 0xcf3626ff, "Red Mushroom"},
		MTL{41, 255, 0xfff199ff, "Gold Block"},
		MTL{42, 255, 0xdededeff, "Iron Block"},
		MTL{43, 255, 0xc8c8c8ff, "Double Stone Slab"},
		MTL{44, 255, 0xa8a8a8ff, "Stone Slab"},
		MTL{45, 255, 0xa14f38ff, "Brick"},
		MTL{46, 255, 0xdb441aff, "TNT"},
		MTL{47, 255, 0x9f844dff, "Bookshelf"},
		MTL{48, 255, 0xa7a8a7ff, "Moss Stone"},
		MTL{49, 255, 0x101019ff, "Obsidian"},
		MTL{50, 255, 0xffae0c99, "Torch"},
		MTL{51, 255, 0xff000099, "Fire"},
		MTL{52, 255, 0x929292ff, "Monster Spawner"},
		MTL{53, 255, 0x9c743aff, "Wooden Stairs"},
		MTL{54, 255, 0xab792dff, "Chest"},
		MTL{55, 255, 0xcc0000ff, "Redstone Wire"},
		MTL{56, 255, 0x50aba6ff, "Diamond Ore"},
		MTL{57, 255, 0x69dfdaff, "Diamond Block"},
		MTL{58, 255, 0xab9472ff, "Workbench"},
		MTL{59, 255, 0x1a7508ff, "Crops"},
		MTL{60, 255, 0x573d2aff, "Soil"},
		MTL{61, 255, 0x919191ff, "Furnace"},
		MTL{62, 255, 0x919191ff, "Burning Furnace"},
		MTL{63, 255, 0xd6b88bff, "Sign Post"},
		MTL{64, 255, 0x82592cff, "Wooden Door"},
		MTL{65, 255, 0xab8944ff, "Ladder"},
		MTL{66, 255, 0xc7c7c7ff, "Minecart Tracks"},
		MTL{67, 255, 0x919191ff, "Cobblestone Stairs"}, // Should be Mesh
		MTL{68, 255, 0xd6b88bff, "Wall Sign"},
		MTL{69, 255, 0xd6b88bff, "Lever"},
		MTL{70, 255, 0x919191ff, "Stone Pressure Plate"},
		MTL{71, 255, 0xbababaff, "Iron Door"},
		MTL{72, 255, 0x7a6340ff, "Wooden Pressure Plate"},
		MTL{73, 255, 0xbd0000ff, "Redstone Ore"},
		MTL{74, 255, 0xff0000ff, "Glowing Redstone Ore"},
		MTL{75, 255, 0xbd0000ff, "Redstone torch (\"off\" state)"},
		MTL{76, 255, 0xff0000ff, "Redstone torch (\"on\" state)"},
		MTL{77, 255, 0x919191ff, "Stone Button"},
		MTL{78, 255, 0xfefefeff, "Snow"},
		MTL{79, 255, 0x77a9ffff, "Ice"},
		MTL{80, 255, 0xfcfcfcff, "Snow Block"},
		MTL{81, 255, 0x11801eff, "Cactus"},
		MTL{82, 255, 0xaaaebeff, "Clay"},
		MTL{83, 255, 0x3c6e0aff, "Sugar Cane"},
		MTL{84, 255, 0x9b664bff, "Jukebox"},
		MTL{85, 255, 0x7a6340ff, "Fence"},
		MTL{86, 255, 0xa05a0bff, "Pumpkin"},
		MTL{87, 255, 0xb66b6bff, "Netherrack"},
		MTL{88, 255, 0x453125ff, "Soul Sand"},
		MTL{89, 255, 0xfff894ff, "Glowstone"},
		MTL{90, 255, 0x381d55ff, "Portal"},
		MTL{91, 255, 0xe9b416ff, "Jack-O-Lantern"},
		MTL{92, 255, 0xbd9075ff, "Cake Block"},
	}
)
<commit_msg>Fix bug: colors missing on blocks with extra data<commit_after>package main

import (
	"fmt"
	"io"
	"os"
)

func printMtl(w io.Writer, blockId uint16) {
	if !noColor {
		var idByte = byte(blockId & 0xff)
		var extraValue, extraPresent = extraData[idByte]
		if extraValue && extraPresent {
			fmt.Fprintf(w, "usemtl %d_%d", idByte, blockId>>8)
		} else {
			fmt.Fprintln(w, "usemtl", idByte)
		}
	}
}

func writeMtlFile(filename string) os.Error {
	if noColor {
		return nil
	}

	var outFile, outErr = os.Open(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if outErr != nil {
		return outErr
	}
	defer outFile.Close()

	var p = 0

	for i := 0; i < 256; i++ {
		var matched = false

		for p < len(colors) && colors[p].blockId == byte(i) {
			matched = true
			colors[p].Print(outFile)
			p++
		}

		if !matched {
			var mtl = MTL{byte(i), 255, 0x7f7f7f, "Unknown"}
			mtl.Print(outFile)
		}
	}

	return nil
}

type MTL struct {
	blockId  byte
	metadata byte
	color    uint32
	name     string
}

func (mtl *MTL) Print(w io.Writer) {
	var (
		r = mtl.color >> 24
		g = mtl.color >> 16 & 0xff
		b = mtl.color >> 8 & 0xff
		a = mtl.color & 0xff
	)

	if mtl.metadata == 255 {
		fmt.Fprintf(w, "# %s\nnewmtl %d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	} else {
		fmt.Fprintf(w, "# %s\nnewmtl %d_%d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, mtl.metadata, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	}
}

func (mtl *MTL) colorId() uint16 {
	var id = uint16(mtl.blockId)
	if mtl.metadata != 255 {
		id += uint16(mtl.metadata) << 8
	}
	return id
}

func init() {
	extraData = make(map[byte]bool)
	for _, mtl := range colors {
		if mtl.metadata != 255 {
			extraData[mtl.blockId] = true
		}
	}
}

var (
	extraData map[byte]bool

	colors = []MTL{
		MTL{0, 255, 0xff0000ff, "Air"},
		MTL{1, 255, 0x7f7f7fff, "Stone"},
		MTL{2, 255, 0x509026ff, "Grass"},
		MTL{3, 255, 0x79553aff, "Dirt"},
		MTL{4, 255, 0xa8a8a8ff, "Cobblestone"},
		MTL{5, 255, 0x9e8052ff, "Wooden Plank"},
		MTL{6, 255, 0x006400ff, "Sapling"},
		MTL{7, 255, 0x575757ff, "Bedrock"},
		MTL{8, 255, 0x009affaa, "Water"},
		MTL{9, 255, 0x002affff, "Stationary water"},
		MTL{10, 255, 0x002affff, "Lava"},
		MTL{11, 255, 0xfc4a00ff, "Stationary lava"},
		MTL{12, 255, 0xcfc393ff, "Sand"},
		MTL{13, 255, 0x9a9b9fff, "Gravel"},
		MTL{14, 255, 0xfff144ff, "Gold ore"},
		MTL{15, 255, 0xe2c0aaff, "Iron ore"},
		MTL{16, 255, 0x454545ff, "Coal ore"},
		MTL{17, 255, 0x695433ff, "Wood"},
		MTL{18, 255, 0x2e6d05ff, "Leaves"},
		MTL{19, 255, 0xe5e54eff, "Sponge"},
		MTL{20, 255, 0xffffff10, "Glass"},
		MTL{21, 255, 0x224da1ff, "Lapis Lazuli Ore"},
		MTL{22, 255, 0x224dffff, "Lapis Lazuli Block"},
		MTL{23, 255, 0x7f7f7fff, "Dispenser"},
		MTL{24, 255, 0xdad2abff, "Sandstone"},
		MTL{25, 255, 0x9b664bff, "Note Block"},
		MTL{35, 0, 0xd1d1d1ff, "Wool - White"},
		MTL{35, 1, 0xe97a2eff, "Wool - Orange"},
		MTL{35, 2, 0xbc3ec7ff, "Wool - Magenta"},
		MTL{35, 3, 0x5980d0ff, "Wool - Light Blue"},
		MTL{35, 4, 0xb6a918ff, "Wool - Yellow"},
		MTL{35, 5, 0x37b32cff, "Wool - Light Green"},
		MTL{35, 6, 0xd57690ff, "Wool - Pink"},
		MTL{35, 7, 0x3f3f3fff, "Wool - Gray"},
		MTL{35, 8, 0x949d9dff, "Wool - Light Gray"},
		MTL{35, 9, 0xbc3ec7ff, "Wool - Cyan"},
		MTL{35, 10, 0x7a2fbcff, "Wool - Purple"},
		MTL{35, 11, 0x243091ff, "Wool - Blue"},
		MTL{35, 12, 0x51301aff, "Wool - Brown"},
		MTL{35, 13, 0x344817ff, "Wool - Dark Green"},
		MTL{35, 14, 0x9b2a26ff, "Wool - Red"},
		MTL{35, 15, 0x171313ff, "Wool - Black"},
		MTL{37, 255, 0xf1f902ff, "Yellow flower"},
		MTL{38, 255, 0xf11102ff, "Red rose"},
		MTL{39, 255, 0xba7038ff, "Brown Mushroom"},
		MTL{40, 255, 0xcf3626ff, "Red Mushroom"},
		MTL{41, 255, 0xfff199ff, "Gold Block"},
		MTL{42, 255, 0xdededeff, "Iron Block"},
		MTL{43, 255, 0xc8c8c8ff, "Double Stone Slab"},
		MTL{44, 255, 0xa8a8a8ff, "Stone Slab"},
		MTL{45, 255, 0xa14f38ff, "Brick"},
		MTL{46, 255, 0xdb441aff, "TNT"},
		MTL{47, 255, 0x9f844dff, "Bookshelf"},
		MTL{48, 255, 0xa7a8a7ff, "Moss Stone"},
		MTL{49, 255, 0x101019ff, "Obsidian"},
		MTL{50, 255, 0xffae0c99, "Torch"},
		MTL{51, 255, 0xff000099, "Fire"},
		MTL{52, 255, 0x929292ff, "Monster Spawner"},
		MTL{53, 255, 0x9c743aff, "Wooden Stairs"},
		MTL{54, 255, 0xab792dff, "Chest"},
		MTL{55, 255, 0xcc0000ff, "Redstone Wire"},
		MTL{56, 255, 0x50aba6ff, "Diamond Ore"},
		MTL{57, 255, 0x69dfdaff, "Diamond Block"},
		MTL{58, 255, 0xab9472ff, "Workbench"},
		MTL{59, 255, 0x1a7508ff, "Crops"},
		MTL{60, 255, 0x573d2aff, "Soil"},
		MTL{61, 255, 0x919191ff, "Furnace"},
		MTL{62, 255, 0x919191ff, "Burning Furnace"},
		MTL{63, 255, 0xd6b88bff, "Sign Post"},
		MTL{64, 255, 0x82592cff, "Wooden Door"},
		MTL{65, 255, 0xab8944ff, "Ladder"},
		MTL{66, 255, 0xc7c7c7ff, "Minecart Tracks"},
		MTL{67, 255, 0x919191ff, "Cobblestone Stairs"},
		MTL{68, 255, 0xd6b88bff, "Wall Sign"},
		MTL{69, 255, 0xd6b88bff, "Lever"},
		MTL{70, 255, 0x919191ff, "Stone Pressure Plate"},
		MTL{71, 255, 0xbababaff, "Iron Door"},
		MTL{72, 255, 0x7a6340ff, "Wooden Pressure Plate"},
		MTL{73, 255, 0xbd0000ff, "Redstone Ore"},
		MTL{74, 255, 0xff0000ff, "Glowing Redstone Ore"},
		MTL{75, 255, 0xbd0000ff, "Redstone torch (\"off\" state)"},
		MTL{76, 255, 0xff0000ff, "Redstone torch (\"on\" state)"},
		MTL{77, 255, 0x919191ff, "Stone Button"},
		MTL{78, 255, 0xfefefeff, "Snow"},
		MTL{79, 255, 0x77a9ffff, "Ice"},
		MTL{80, 255, 0xfcfcfcff, "Snow Block"},
		MTL{81, 255, 0x11801eff, "Cactus"},
		MTL{82, 255, 0xaaaebeff, "Clay"},
		MTL{83, 255, 0x3c6e0aff, "Sugar Cane"},
		MTL{84, 255, 0x9b664bff, "Jukebox"},
		MTL{85, 255, 0x7a6340ff, "Fence"},
		MTL{86, 255, 0xa05a0bff, "Pumpkin"},
		MTL{87, 255, 0xb66b6bff, "Netherrack"},
		MTL{88, 255, 0x453125ff, "Soul Sand"},
		MTL{89, 255, 0xfff894ff, "Glowstone"},
		MTL{90, 255, 0x381d55ff, "Portal"},
		MTL{91, 255, 0xe9b416ff, "Jack-O-Lantern"},
		MTL{92, 255, 0xbd9075ff, "Cake Block"},
	}
)
<|endoftext|>


<commit_before>package main

import (
	"github.com/sorcix/irc"
	"log"
	"net"
	"time"
)

type IrcBot struct {
	server string
	login  string
	pass   string
	conn   net.Conn
	reader *irc.Decoder
	writer *irc.Encoder
	data   chan *irc.Message
}

func (b *IrcBot) loop() {
	for {
		b.conn.SetDeadline(time.Now().Add(300 * time.Second))
		msg, err := b.reader.Decode()
		if err != nil {
			log.Print("IRC channel closed", err)
			close(b.data)
		}
		b.data <- msg
	}
}

func (b *IrcBot) connect() error {
	b.data = make(chan *irc.Message)
	var err error
	b.conn, err = net.Dial("tcp", b.server)
	if err != nil {
		return err
	}

	b.writer = irc.NewEncoder(b.conn)
	b.reader = irc.NewDecoder(b.conn)

	loginMessages := []irc.Message{
		irc.Message{
			Command: irc.PASS,
			Params:  []string{b.pass},
		},
		irc.Message{
			Command: irc.NICK,
			Params:  []string{b.login},
		},
		irc.Message{
			Command:  irc.USER,
			Params:   []string{b.login, "0", "*"},
			Trailing: b.login,
		},
	}

	for _, v := range loginMessages {
		err := b.writer.Encode(&v)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Fix bug in irc_bot.go<commit_after>package main

import (
	"github.com/sorcix/irc"
	"log"
	"net"
	"time"
)

type IrcBot struct {
	server string
	login  string
	pass   string
	conn   net.Conn
	reader *irc.Decoder
	writer *irc.Encoder
	data   chan *irc.Message
}

func (b *IrcBot) loop() {
	for {
		b.conn.SetDeadline(time.Now().Add(300 * time.Second))
		msg, err := b.reader.Decode()
		if err != nil {
			log.Print("IRC channel closed", err)
			close(b.data)
		}
		b.data <- msg
	}
}

func (b *IrcBot) connect() error {
	b.data = make(chan *irc.Message)
	var err error
	b.conn, err = net.Dial("tcp", b.server)
	if err != nil {
		return err
	}

	b.writer = irc.NewEncoder(b.conn)
	b.reader = irc.NewDecoder(b.conn)

	loginMessages := []irc.Message{
		irc.Message{
			Command: irc.PASS,
			Params:  []string{b.pass},
		},
		irc.Message{
			Command: irc.NICK,
			Params:  []string{b.login},
		},
		irc.Message{
			Command:  irc.USER,
			Params:   []string{b.login, "0", "*"},
			Trailing: b.login,
		},
	}

	for _, v := range loginMessages {
		err := b.writer.Encode(&v)
		if err != nil {
			return err
		}
	}

	go b.loop()

	return nil
}
<|endoftext|>