<commit_before>package cf

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	helpersCF "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
	"github.com/pivotal-cf/on-demand-service-broker/system_tests/cf_helpers"
)

//CF is a testing wrapper around the cf cli
type CF struct {
	ShortTimeout time.Duration
	LongTimeout  time.Duration
}

//API is equivalent to `cf api {endpoint} [--skip-ssl-validation]`
func (cf *CF) API(endpoint string, skipSSLValidation bool) func() {
	return func() {
		apiCmd := []string{"api", endpoint}

		if skipSSLValidation {
			apiCmd = append(apiCmd, "--skip-ssl-validation")
		}

		Eventually(helpersCF.Cf(apiCmd...), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to target Cloud Foundry"}`,
		)
	}
}

//Auth is equivalent to `cf auth {user} {password}`
func (cf *CF) Auth(user, password string) func() {
	return func() {
		Eventually(helpersCF.Cf("auth", user, password), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf auth` with target Cloud Foundry\"}",
		)
	}
}

//CreateQuota is equivalent to `cf create-quota {name} [args...]`
func (cf *CF) CreateQuota(name string, args ...string) func() {
	return func() {
		cfArgs := []string{"create-quota", name}
		cfArgs = append(cfArgs, args...)
		Eventually(helpersCF.Cf(cfArgs...), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf create-quota` with target Cloud Foundry\"}",
		)
	}
}

//CreateOrg is equivalent to `cf create-org {org} -q {quota}`
func (cf *CF) CreateOrg(org, quota string) func() {
	return func() {
		Eventually(helpersCF.Cf("create-org", org, "-q", quota), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to create CF test org"}`,
		)
	}
}

//EnableServiceAccess is equivalent to `cf enable-service-access -o {org} {service-offering}`
//In order to run enable-service-access idempotently we disable-service-access before.
func (cf *CF) EnableServiceAccess(org, service string) func() {
	return func() {
		Eventually(helpersCF.Cf("disable-service-access", "-o", org, service), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to disable service access for CF test org"}`,
		)
		Eventually(helpersCF.Cf("enable-service-access", "-o", org, service), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to enable service access for CF test org"}`,
		)
	}
}

//TargetOrg is equivalent to `cf target -o {org}`
func (cf *CF) TargetOrg(org string) func() {
	return func() {
		Eventually(helpersCF.Cf("target", "-o", org), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to target test org"}`,
		)
	}
}

//TargetOrgAndSpace is equivalent to `cf target -o {org} -s {space}`
func (cf *CF) TargetOrgAndSpace(org, space string) func() {
	return func() {
		Eventually(helpersCF.Cf("target", "-o", org, "-s", space), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to target test org"}`,
		)
	}
}

//CreateSpace is equivalent to `cf create-space {space}`
func (cf *CF) CreateSpace(space string) func() {
	return func() {
		Eventually(helpersCF.Cf("create-space", space), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to create CF test space"}`,
		)
	}
}

//CreateSecurityGroup is equivalent to `cf create-security-group {securityGroup} {configPath}`
func (cf *CF) CreateAndBindSecurityGroup(securityGroup, appName, org, space string) func() {
	return func() {
		appGuid := cf.getAppGuid(appName)

		host, port := cf.getBindingCredentials(appGuid)

		sgFile, err := ioutil.TempFile("", "smoke-test-security-group-")
		Expect(err).NotTo(HaveOccurred())
		defer sgFile.Close()
		defer os.Remove(sgFile.Name())

		sgs := []struct {
			Protocol    string `json:"protocol"`
			Destination string `json:"destination"`
			Ports       string `json:"ports"`
		}{
			{"tcp", host, port},
		}

		err = json.NewEncoder(sgFile).Encode(sgs)
		Expect(err).NotTo(HaveOccurred(), `{"FailReason": "Failed to encode security groups"}`)

		Eventually(helpersCF.Cf("create-security-group", securityGroup, sgFile.Name()), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to create security group"}`,
		)

		Eventually(helpersCF.Cf("bind-security-group", securityGroup, org, space), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to bind security group to space"}`,
		)
	}
}

//DeleteSecurityGroup is equivalent to `cf delete-security-group {securityGroup} -f`
func (cf *CF) DeleteSecurityGroup(securityGroup string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete-security-group", securityGroup, "-f"), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to delete security group"}`,
		)
	}
}

//CreateUser is equivalent to `cf create-user {name} {password}`
func (cf *CF) CreateUser(name, password string) func() {
	return func() {
		createUserCmd := helpersCF.Cf("create-user", name, password)
		Eventually(createUserCmd, cf.ShortTimeout).Should(gexec.Exit())
		if createUserCmd.ExitCode() != 0 {
			Expect(createUserCmd.Out).To(
				gbytes.Say("scim_resource_already_exists"),
				`{"FailReason": "Failed to create user"}`,
			)
		}
	}
}

//DeleteUser is equivalent to `cf delete-user -f {name}`
func (cf *CF) DeleteUser(name string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete-user", "-f", name), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to delete user"}`,
		)
	}
}

//SetSpaceRole is equivalent to `cf set-space-role {name} {org} {space} {role}`
func (cf *CF) SetSpaceRole(name, org, space, role string) func() {
	return func() {
		Eventually(helpersCF.Cf("set-space-role", name, org, space, role), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to set space role"}`,
		)
	}
}

//Push is equivalent to `cf push {appName} [args...]`
func (cf *CF) Push(appName string, args ...string) func() {
	pushArgs := []string{"push", appName}
	pushArgs = append(pushArgs, args...)
	return func() {
		Eventually(helpersCF.Cf(pushArgs...), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf push` test app\"}",
		)
	}
}

//Delete is equivalent to `cf delete {appName} -f`
func (cf *CF) Delete(appName string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete", appName, "-f", "-r"), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf delete` test app\"}",
		)
	}
}

//CreateService is equivalent to `cf create-service {serviceName} {planName} {instanceName}`
func (cf *CF) CreateService(serviceName, planName, instanceName string, skip *bool) func() {
	return func() {
		session := helpersCF.Cf("create-service", serviceName, planName, instanceName)
		session.Wait(cf.ShortTimeout)
		createServiceStdout := session.Out

		defer createServiceStdout.CancelDetects()
		select {
		case <-createServiceStdout.Detect("FAILED"):
			Eventually(session, cf.ShortTimeout).Should(
				gbytes.Say("instance limit for this service has been reached"),
				`{"FailReason": "Failed to bind Redis service instance to test app"}`,
			)
			Eventually(session, cf.ShortTimeout).Should(gexec.Exit(1))
			fmt.Printf("No Plan Instances available for testing %s plan\n", planName)
			*skip = true
		case <-createServiceStdout.Detect("OK"):
			Eventually(session, cf.ShortTimeout).Should(
				gexec.Exit(0),
				`{"FailReason": "Failed to create Redis service instance"}`,
			)
			cf_helpers.AwaitServiceCreation(instanceName)
		}
	}
}

//DeleteService is equivalent to `cf delete-service {instanceName} -f`
func (cf *CF) DeleteService(instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete-service", "-f", instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			fmt.Sprintf(`{"FailReason": "Failed to delete service %s"}`, instanceName),
		)
	}
}

//BindService is equivalent to `cf bind-service {appName} {instanceName}`
func (cf *CF) BindService(appName, instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("bind-service", appName, instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to bind Redis service instance to test app"}`,
		)
	}
}

//UnbindService is equivalent to `cf unbind-service {appName} {instanceName}`
func (cf *CF) UnbindService(appName, instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("unbind-service", appName, instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			fmt.Sprintf(`{"FailReason": "Failed to unbind %s instance from %s"}`, instanceName, appName),
		)
	}
}

//Start is equivalent to `cf start {appName}`
func (cf *CF) Start(appName string) func() {
	return func() {
		Eventually(helpersCF.Cf("start", appName), cf.LongTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to start test app"}`,
		)
	}
}

//SetEnv is equivalent to `cf set-env {appName} {envVarName} {instanceName}`
func (cf *CF) SetEnv(appName, environmentVariable, instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("set-env", appName, environmentVariable, instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to set environment variable for test app"}`,
		)
	}
}

//Logout is equivalent to `cf logout`
func (cf *CF) Logout() func() {
	return func() {
		Eventually(helpersCF.Cf("logout")).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to logout"}`,
		)
	}
}

func (cf *CF) getAppGuid(appName string) string {
	session := helpersCF.Cf("app", "--guid", appName)
	Eventually(session, cf.ShortTimeout).Should(gexec.Exit(0), `{"FailReason": "Failed to retrieve GUID for app"}`)

	return strings.Trim(string(session.Out.Contents()), " \n")
}

func (cf *CF) getBindingCredentials(appGuid string) (string, string) {
	session := helpersCF.Cf("curl", fmt.Sprintf("/v2/apps/%s/service_bindings", appGuid))
	Eventually(session, cf.ShortTimeout).Should(gexec.Exit(0), `{"FailReason": "Failed to retrieve service bindings for app"}`)

	var resp = new(struct {
		Resources []struct {
			Entity struct {
				Credentials struct {
					Host string
					Port string
				}
			}
		}
	})

	err := json.NewDecoder(bytes.NewBuffer(session.Out.Contents())).Decode(resp)
	Expect(err).NotTo(HaveOccurred(), `{"FailReason": "Failed to decode service binding response"}`)
	Expect(resp.Resources).To(HaveLen(1), `{"FailReason": "Invalid binding response, expected exactly one binding"}`)

	host, port := resp.Resources[0].Entity.Credentials.Host, resp.Resources[0].Entity.Credentials.Port
	Expect(host).NotTo(BeEmpty(), `{"FailReason": "Invalid binding, missing host"}`)
	Expect(port).NotTo(BeEmpty(), `{"FailReason": "Invalid binding, missing port"}`)
	return host, port
}
<commit_msg>Port in Redis bindings is an int<commit_after>package cf

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	helpersCF "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
	"github.com/pivotal-cf/on-demand-service-broker/system_tests/cf_helpers"
)

//CF is a testing wrapper around the cf cli
type CF struct {
	ShortTimeout time.Duration
	LongTimeout  time.Duration
}

//API is equivalent to `cf api {endpoint} [--skip-ssl-validation]`
func (cf *CF) API(endpoint string, skipSSLValidation bool) func() {
	return func() {
		apiCmd := []string{"api", endpoint}

		if skipSSLValidation {
			apiCmd = append(apiCmd, "--skip-ssl-validation")
		}

		Eventually(helpersCF.Cf(apiCmd...), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to target Cloud Foundry"}`,
		)
	}
}

//Auth is equivalent to `cf auth {user} {password}`
func (cf *CF) Auth(user, password string) func() {
	return func() {
		Eventually(helpersCF.Cf("auth", user, password), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf auth` with target Cloud Foundry\"}",
		)
	}
}

//CreateQuota is equivalent to `cf create-quota {name} [args...]`
func (cf *CF) CreateQuota(name string, args ...string) func() {
	return func() {
		cfArgs := []string{"create-quota", name}
		cfArgs = append(cfArgs, args...)
		Eventually(helpersCF.Cf(cfArgs...), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf create-quota` with target Cloud Foundry\"}",
		)
	}
}

//CreateOrg is equivalent to `cf create-org {org} -q {quota}`
func (cf *CF) CreateOrg(org, quota string) func() {
	return func() {
		Eventually(helpersCF.Cf("create-org", org, "-q", quota), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to create CF test org"}`,
		)
	}
}

//EnableServiceAccess is equivalent to `cf enable-service-access -o {org} {service-offering}`
//In order to run enable-service-access idempotently we disable-service-access before.
func (cf *CF) EnableServiceAccess(org, service string) func() {
	return func() {
		Eventually(helpersCF.Cf("disable-service-access", "-o", org, service), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to disable service access for CF test org"}`,
		)
		Eventually(helpersCF.Cf("enable-service-access", "-o", org, service), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to enable service access for CF test org"}`,
		)
	}
}

//TargetOrg is equivalent to `cf target -o {org}`
func (cf *CF) TargetOrg(org string) func() {
	return func() {
		Eventually(helpersCF.Cf("target", "-o", org), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to target test org"}`,
		)
	}
}

//TargetOrgAndSpace is equivalent to `cf target -o {org} -s {space}`
func (cf *CF) TargetOrgAndSpace(org, space string) func() {
	return func() {
		Eventually(helpersCF.Cf("target", "-o", org, "-s", space), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to target test org"}`,
		)
	}
}

//CreateSpace is equivalent to `cf create-space {space}`
func (cf *CF) CreateSpace(space string) func() {
	return func() {
		Eventually(helpersCF.Cf("create-space", space), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to create CF test space"}`,
		)
	}
}

//CreateSecurityGroup is equivalent to `cf create-security-group {securityGroup} {configPath}`
func (cf *CF) CreateAndBindSecurityGroup(securityGroup, appName, org, space string) func() {
	return func() {
		appGuid := cf.getAppGuid(appName)

		host, port := cf.getBindingCredentials(appGuid)

		sgFile, err := ioutil.TempFile("", "smoke-test-security-group-")
		Expect(err).NotTo(HaveOccurred())
		defer sgFile.Close()
		defer os.Remove(sgFile.Name())

		sgs := []struct {
			Protocol    string `json:"protocol"`
			Destination string `json:"destination"`
			Ports       string `json:"ports"`
		}{
			{"tcp", host, fmt.Sprintf("%d", port)},
		}

		err = json.NewEncoder(sgFile).Encode(sgs)
		Expect(err).NotTo(HaveOccurred(), `{"FailReason": "Failed to encode security groups"}`)

		Eventually(helpersCF.Cf("create-security-group", securityGroup, sgFile.Name()), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to create security group"}`,
		)

		Eventually(helpersCF.Cf("bind-security-group", securityGroup, org, space), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to bind security group to space"}`,
		)
	}
}

//DeleteSecurityGroup is equivalent to `cf delete-security-group {securityGroup} -f`
func (cf *CF) DeleteSecurityGroup(securityGroup string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete-security-group", securityGroup, "-f"), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to delete security group"}`,
		)
	}
}

//CreateUser is equivalent to `cf create-user {name} {password}`
func (cf *CF) CreateUser(name, password string) func() {
	return func() {
		createUserCmd := helpersCF.Cf("create-user", name, password)
		Eventually(createUserCmd, cf.ShortTimeout).Should(gexec.Exit())
		if createUserCmd.ExitCode() != 0 {
			Expect(createUserCmd.Out).To(
				gbytes.Say("scim_resource_already_exists"),
				`{"FailReason": "Failed to create user"}`,
			)
		}
	}
}

//DeleteUser is equivalent to `cf delete-user -f {name}`
func (cf *CF) DeleteUser(name string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete-user", "-f", name), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to delete user"}`,
		)
	}
}

//SetSpaceRole is equivalent to `cf set-space-role {name} {org} {space} {role}`
func (cf *CF) SetSpaceRole(name, org, space, role string) func() {
	return func() {
		Eventually(helpersCF.Cf("set-space-role", name, org, space, role), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to set space role"}`,
		)
	}
}

//Push is equivalent to `cf push {appName} [args...]`
func (cf *CF) Push(appName string, args ...string) func() {
	pushArgs := []string{"push", appName}
	pushArgs = append(pushArgs, args...)
	return func() {
		Eventually(helpersCF.Cf(pushArgs...), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf push` test app\"}",
		)
	}
}

//Delete is equivalent to `cf delete {appName} -f`
func (cf *CF) Delete(appName string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete", appName, "-f", "-r"), cf.ShortTimeout).Should(
			gexec.Exit(0),
			"{\"FailReason\": \"Failed to `cf delete` test app\"}",
		)
	}
}

//CreateService is equivalent to `cf create-service {serviceName} {planName} {instanceName}`
func (cf *CF) CreateService(serviceName, planName, instanceName string, skip *bool) func() {
	return func() {
		session := helpersCF.Cf("create-service", serviceName, planName, instanceName)
		session.Wait(cf.ShortTimeout)
		createServiceStdout := session.Out

		defer createServiceStdout.CancelDetects()
		select {
		case <-createServiceStdout.Detect("FAILED"):
			Eventually(session, cf.ShortTimeout).Should(
				gbytes.Say("instance limit for this service has been reached"),
				`{"FailReason": "Failed to bind Redis service instance to test app"}`,
			)
			Eventually(session, cf.ShortTimeout).Should(gexec.Exit(1))
			fmt.Printf("No Plan Instances available for testing %s plan\n", planName)
			*skip = true
		case <-createServiceStdout.Detect("OK"):
			Eventually(session, cf.ShortTimeout).Should(
				gexec.Exit(0),
				`{"FailReason": "Failed to create Redis service instance"}`,
			)
			cf_helpers.AwaitServiceCreation(instanceName)
		}
	}
}

//DeleteService is equivalent to `cf delete-service {instanceName} -f`
func (cf *CF) DeleteService(instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("delete-service", "-f", instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			fmt.Sprintf(`{"FailReason": "Failed to delete service %s"}`, instanceName),
		)
	}
}

//BindService is equivalent to `cf bind-service {appName} {instanceName}`
func (cf *CF) BindService(appName, instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("bind-service", appName, instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to bind Redis service instance to test app"}`,
		)
	}
}

//UnbindService is equivalent to `cf unbind-service {appName} {instanceName}`
func (cf *CF) UnbindService(appName, instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("unbind-service", appName, instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			fmt.Sprintf(`{"FailReason": "Failed to unbind %s instance from %s"}`, instanceName, appName),
		)
	}
}

//Start is equivalent to `cf start {appName}`
func (cf *CF) Start(appName string) func() {
	return func() {
		Eventually(helpersCF.Cf("start", appName), cf.LongTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to start test app"}`,
		)
	}
}

//SetEnv is equivalent to `cf set-env {appName} {envVarName} {instanceName}`
func (cf *CF) SetEnv(appName, environmentVariable, instanceName string) func() {
	return func() {
		Eventually(helpersCF.Cf("set-env", appName, environmentVariable, instanceName), cf.ShortTimeout).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to set environment variable for test app"}`,
		)
	}
}

//Logout is equivalent to `cf logout`
func (cf *CF) Logout() func() {
	return func() {
		Eventually(helpersCF.Cf("logout")).Should(
			gexec.Exit(0),
			`{"FailReason": "Failed to logout"}`,
		)
	}
}

func (cf *CF) getAppGuid(appName string) string {
	session := helpersCF.Cf("app", "--guid", appName)
	Eventually(session, cf.ShortTimeout).Should(gexec.Exit(0), `{"FailReason": "Failed to retrieve GUID for app"}`)

	return strings.Trim(string(session.Out.Contents()), " \n")
}

func (cf *CF) getBindingCredentials(appGuid string) (string, int) {
	session := helpersCF.Cf("curl", fmt.Sprintf("/v2/apps/%s/service_bindings", appGuid))
	Eventually(session, cf.ShortTimeout).Should(gexec.Exit(0), `{"FailReason": "Failed to retrieve service bindings for app"}`)

	var resp = new(struct {
		Resources []struct {
			Entity struct {
				Credentials struct {
					Host string
					Port int
				}
			}
		}
	})

	err := json.NewDecoder(bytes.NewBuffer(session.Out.Contents())).Decode(resp)
	Expect(err).NotTo(HaveOccurred(), `{"FailReason": "Failed to decode service binding response"}`)
	Expect(resp.Resources).To(HaveLen(1), `{"FailReason": "Invalid binding response, expected exactly one binding"}`)

	host, port := resp.Resources[0].Entity.Credentials.Host, resp.Resources[0].Entity.Credentials.Port
	Expect(host).NotTo(BeEmpty(), `{"FailReason": "Invalid binding, missing host"}`)
	Expect(port).NotTo(BeZero(), `{"FailReason": "Invalid binding, missing port"}`)
	return host, port
}
<|endoftext|>


<commit_before>package objx

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/url"
	"strings"
)

// MSIConvertable is an interface that defines methods for converting your
// custom types to a map[string]interface{} representation.
type MSIConvertable interface {
	// ConvertToMap is called by objx.New when it is given a
	// non map[string]interface{} argument.
	MSI() map[string]interface{}
}

// Map provides extended functionality for working with
// untyped data, particularly map[string]interface{},
// []interface{} and interface{}.
type Map map[string]interface{}

// Value returns the internal value instance
func (m Map) Value() *Value {
	return &Value{data: m}
}

// Nil represents a nil Map.
var Nil Map = New(nil)

// New creates a new Map containing the map[string]interface{} in the data argument.
// If the data argument is not a map[string]interface, New attempts to call the
// MSI() method on the MSIConvertable interface to create one.
func New(data interface{}) Map {
	if _, ok := data.(map[string]interface{}); !ok {
		if converter, ok := data.(MSIConvertable); ok {
			data = converter.MSI()
		} else {
			return nil
		}
	}
	return Map(data.(map[string]interface{}))
}

// MSI creates a map[string]interface{} and puts it inside a new Map.
//
// The arguments follow a key, value pattern.
//
// Panics
//
// Panics if any key arugment is non-string or if there are an odd number of arguments.
//
// Example
//
// To easily create Maps:
//
//     m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
//
//     // creates an Map equivalent to
//     m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
func MSI(keyAndValuePairs ...interface{}) Map {

	newMap := make(map[string]interface{})
	keyAndValuePairsLen := len(keyAndValuePairs)

	if keyAndValuePairsLen%2 != 0 {
		panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
	}

	for i := 0; i < keyAndValuePairsLen; i = i + 2 {

		key := keyAndValuePairs[i]
		value := keyAndValuePairs[i+1]

		// make sure the key is a string
		keyString, keyStringOK := key.(string)
		if !keyStringOK {
			panic("objx: MSI must follow 'string, interface{}' pattern.  " + keyString + " is not a valid key.")
		}

		newMap[keyString] = value

	}

	return New(newMap)
}

// ****** Conversion Constructors

// MustFromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Panics if the JSON is invalid.
func MustFromJSON(jsonString string) Map {
	o, err := FromJSON(jsonString)

	if err != nil {
		panic("objx: MustFromJSON failed with error: " + err.Error())
	}

	return o
}

// FromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Returns an error if the JSON is invalid.
func FromJSON(jsonString string) (Map, error) {

	var data interface{}
	err := json.Unmarshal([]byte(jsonString), &data)

	if err != nil {
		return Nil, err
	}

	return New(data), nil

}

// FromBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by Base64
func FromBase64(base64String string) (Map, error) {

	decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))

	decoded, err := ioutil.ReadAll(decoder)
	if err != nil {
		return nil, err
	}

	return FromJSON(string(decoded))
}

// MustFromBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromBase64(base64String string) Map {

	result, err := FromBase64(base64String)

	if err != nil {
		panic("objx: MustFromBase64 failed with error: " + err.Error())
	}

	return result
}

// FromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by SignedBase64
func FromSignedBase64(base64String, key string) (Map, error) {
	parts := strings.Split(base64String, SignatureSeparator)
	if len(parts) != 2 {
		return nil, errors.New("objx: Signed base64 string is malformed.")
	}

	sig := HashWithKey(parts[0], key)
	if parts[1] != sig {
		return nil, errors.New("objx: Signature for base64 data does not match.")
	}

	return FromBase64(parts[0])
}

// MustFromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromSignedBase64(base64String, key string) Map {

	result, err := FromSignedBase64(base64String, key)

	if err != nil {
		panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
	}

	return result
}

// FromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
func FromURLQuery(query string) (Map, error) {

	vals, err := url.ParseQuery(query)

	if err != nil {
		return nil, err
	}

	m := make(map[string]interface{})
	for k, vals := range vals {
		m[k] = vals[0]
	}

	return New(m), nil
}

// MustFromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
//
// Panics if it encounters an error
func MustFromURLQuery(query string) Map {

	o, err := FromURLQuery(query)

	if err != nil {
		panic("objx: MustFromURLQuery failed with error: " + err.Error())
	}

	return o

}
<commit_msg>tweaked docs<commit_after>package objx

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/url"
	"strings"
)

// MSIConvertable is an interface that defines methods for converting your
// custom types to a map[string]interface{} representation.
type MSIConvertable interface {
	// MSI gets a map[string]interface{} (msi) representing the
	// object.
	MSI() map[string]interface{}
}

// Map provides extended functionality for working with
// untyped data, in particular map[string]interface (msi).
type Map map[string]interface{}

// Value returns the internal value instance
func (m Map) Value() *Value {
	return &Value{data: m}
}

// Nil represents a nil Map.
var Nil Map = New(nil)

// New creates a new Map containing the map[string]interface{} in the data argument.
// If the data argument is not a map[string]interface, New attempts to call the
// MSI() method on the MSIConvertable interface to create one.
func New(data interface{}) Map {
	if _, ok := data.(map[string]interface{}); !ok {
		if converter, ok := data.(MSIConvertable); ok {
			data = converter.MSI()
		} else {
			return nil
		}
	}
	return Map(data.(map[string]interface{}))
}

// MSI creates a map[string]interface{} and puts it inside a new Map.
//
// The arguments follow a key, value pattern.
//
// Panics
//
// Panics if any key arugment is non-string or if there are an odd number of arguments.
//
// Example
//
// To easily create Maps:
//
//     m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
//
//     // creates an Map equivalent to
//     m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
func MSI(keyAndValuePairs ...interface{}) Map {

	newMap := make(map[string]interface{})
	keyAndValuePairsLen := len(keyAndValuePairs)

	if keyAndValuePairsLen%2 != 0 {
		panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
	}

	for i := 0; i < keyAndValuePairsLen; i = i + 2 {

		key := keyAndValuePairs[i]
		value := keyAndValuePairs[i+1]

		// make sure the key is a string
		keyString, keyStringOK := key.(string)
		if !keyStringOK {
			panic("objx: MSI must follow 'string, interface{}' pattern.  " + keyString + " is not a valid key.")
		}

		newMap[keyString] = value

	}

	return New(newMap)
}

// ****** Conversion Constructors

// MustFromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Panics if the JSON is invalid.
func MustFromJSON(jsonString string) Map {
	o, err := FromJSON(jsonString)

	if err != nil {
		panic("objx: MustFromJSON failed with error: " + err.Error())
	}

	return o
}

// FromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Returns an error if the JSON is invalid.
func FromJSON(jsonString string) (Map, error) {

	var data interface{}
	err := json.Unmarshal([]byte(jsonString), &data)

	if err != nil {
		return Nil, err
	}

	return New(data), nil

}

// FromBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by Base64
func FromBase64(base64String string) (Map, error) {

	decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))

	decoded, err := ioutil.ReadAll(decoder)
	if err != nil {
		return nil, err
	}

	return FromJSON(string(decoded))
}

// MustFromBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromBase64(base64String string) Map {

	result, err := FromBase64(base64String)

	if err != nil {
		panic("objx: MustFromBase64 failed with error: " + err.Error())
	}

	return result
}

// FromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by SignedBase64
func FromSignedBase64(base64String, key string) (Map, error) {
	parts := strings.Split(base64String, SignatureSeparator)
	if len(parts) != 2 {
		return nil, errors.New("objx: Signed base64 string is malformed.")
	}

	sig := HashWithKey(parts[0], key)
	if parts[1] != sig {
		return nil, errors.New("objx: Signature for base64 data does not match.")
	}

	return FromBase64(parts[0])
}

// MustFromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromSignedBase64(base64String, key string) Map {

	result, err := FromSignedBase64(base64String, key)

	if err != nil {
		panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
	}

	return result
}

// FromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
func FromURLQuery(query string) (Map, error) {

	vals, err := url.ParseQuery(query)

	if err != nil {
		return nil, err
	}

	m := make(map[string]interface{})
	for k, vals := range vals {
		m[k] = vals[0]
	}

	return New(m), nil
}

// MustFromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
//
// Panics if it encounters an error
func MustFromURLQuery(query string) Map {

	o, err := FromURLQuery(query)

	if err != nil {
		panic("objx: MustFromURLQuery failed with error: " + err.Error())
	}

	return o

}
<|endoftext|>


<commit_before>// Fully persistent data structures. A persistent data structure is a data
// structure that always preserves the previous version of itself when
// it is modified. Such data structures are effectively immutable,
// as their operations do not update the structure in-place, but instead
// always yield a new structure.
//
// Persistent
// data structures typically share structure among themselves.  This allows
// operations to avoid copying the entire data structure.
package ps

import (
	"bytes"
	"fmt"
)

// A Map associates unique keys (type string) with values (type Any).
type Map interface {
	// IsNil returns true if the Map is empty
	IsNil() bool

	// Set returns a new map in which key and value are associated.
	// If the key didn't exist before, it's created; otherwise, the
	// associated value is changed.
	// This operation is O(log N) in the number of keys.
	Set(key string, value interface{}) Map

	// Delete returns a new map with the association for key, if any, removed.
	// This operation is O(log N) in the number of keys.
	Delete(key string) Map

	// Lookup returns the value associated with a key, if any.  If the key
	// exists, the second return value is true; otherwise, false.
	// This operation is O(log N) in the number of keys.
	Lookup(key string) (interface{}, bool)

	// Size returns the number of key value pairs in the map.
	// This takes O(1) time.
	Size() int

	// ForEach executes a callback on each key value pair in the map.
	ForEach(f func(key string, val interface{}))

	// Keys returns a slice with all keys in this map.
	// This operation is O(N) in the number of keys.
	Keys() []string

	String() string
}

// Immutable (i.e. persistent) associative array
const childCount = 8
const shiftSize = 3

type tree struct {
	count    int
	hash     uint64 // hash of the key (used for tree balancing)
	key      string
	value    interface{}
	children [childCount]*tree
}

var nilMap = &tree{}

// Recursively set nilMap's subtrees to point at itself.
// This eliminates all nil pointers in the map structure.
// All map nodes are created by cloning this structure so
// they avoid the problem too.
func init() {
	for i := range nilMap.children {
		nilMap.children[i] = nilMap
	}
}

// NewMap allocates a new, persistent map from strings to values of
// any type.
// This is currently implemented as a path-copying binary tree.
func NewMap() Map {
	return nilMap
}

func (self *tree) IsNil() bool {
	return self == nilMap
}

// clone returns an exact duplicate of a tree node
func (self *tree) clone() *tree {
	var m tree
	m = *self
	return &m
}

// constants for FNV-1a hash algorithm
const (
	offset64 uint64 = 14695981039346656037
	prime64  uint64 = 1099511628211
)

// hashKey returns a hash code for a given string
func hashKey(key string) uint64 {
	hash := offset64
	for _, codepoint := range key {
		hash ^= uint64(codepoint)
		hash *= prime64
	}
	return hash
}

// Set returns a new map similar to this one but with key and value
// associated.  If the key didn't exist, it's created; otherwise, the
// associated value is changed.
func (self *tree) Set(key string, value interface{}) Map {
	hash := hashKey(key)
	return setLowLevel(self, hash, hash, key, value)
}

func setLowLevel(self *tree, partialHash, hash uint64, key string, value interface{}) *tree {
	if self.IsNil() { // an empty tree is easy
		m := self.clone()
		m.count = 1
		m.hash = hash
		m.key = key
		m.value = value
		return m
	}

	if hash != self.hash {
		m := self.clone()
		i := partialHash % childCount
		m.children[i] = setLowLevel(self.children[i], partialHash>>shiftSize, hash, key, value)
		recalculateCount(m)
		return m
	}

	// did we find a hash collision?
	if key != self.key {
		oops := fmt.Sprintf("Hash collision between: '%s' and '%s'.  Please report to https://github.com/mndrix/ps/issues/new", self.key, key)
		panic(oops)
	}

	// replacing a key's previous value
	m := self.clone()
	m.value = value
	return m
}

// modifies a map by recalculating its key count based on the counts
// of its subtrees
func recalculateCount(m *tree) {
	count := 0
	for _, t := range m.children {
		count += t.Size()
	}
	m.count = count + 1 // add one to count ourself
}

func (m *tree) Delete(key string) Map {
	hash := hashKey(key)
	newMap, _ := deleteLowLevel(m, hash, hash)
	return newMap
}

func deleteLowLevel(self *tree, partialHash, hash uint64) (*tree, bool) {
	// empty trees are easy
	if self.IsNil() {
		return self, false
	}

	if hash != self.hash {
		i := partialHash % childCount
		child, found := deleteLowLevel(self.children[i], partialHash>>shiftSize, hash)
		if !found {
			return self, false
		}
		newMap := self.clone()
		newMap.children[i] = child
		recalculateCount(newMap)
		return newMap, true // ? this wasn't in the original code
	}

	// we must delete our own node
	if self.isLeaf() { // we have no children
		return nilMap, true
	}
	/*
	   if self.subtreeCount() == 1 { // only one subtree
	       for _, t := range self.children {
	           if t != nilMap {
	               return t, true
	           }
	       }
	       panic("Tree with 1 subtree actually had no subtrees")
	   }
	*/

	// find a node to replace us
	i := -1
	size := -1
	for j, t := range self.children {
		if t.Size() > size {
			i = j
			size = t.Size()
		}
	}

	// make chosen leaf smaller
	replacement, child := self.children[i].deleteLeftmost()
	newMap := replacement.clone()
	for j := range self.children {
		if j == i {
			newMap.children[j] = child
		} else {
			newMap.children[j] = self.children[j]
		}
	}
	recalculateCount(newMap)
	return newMap, true
}

// delete the leftmost node in a tree returning the node that
// was deleted and the tree left over after its deletion
func (m *tree) deleteLeftmost() (*tree, *tree) {
	if m.isLeaf() {
		return m, nilMap
	}

	for i, t := range m.children {
		if t != nilMap {
			deleted, child := t.deleteLeftmost()
			newMap := m.clone()
			newMap.children[i] = child
			recalculateCount(newMap)
			return deleted, newMap
		}
	}
	panic("Tree isn't a leaf but also had no children. How does that happen?")
}

// isLeaf returns true if this is a leaf node
func (m *tree) isLeaf() bool {
	return m.Size() == 1
}

// returns the number of child subtrees we have
func (m *tree) subtreeCount() int {
	count := 0
	for _, t := range m.children {
		if t != nilMap {
			count++
		}
	}
	return count
}

func (m *tree) Lookup(key string) (interface{}, bool) {
	hash := hashKey(key)
	return lookupLowLevel(m, hash, hash)
}

func lookupLowLevel(self *tree, partialHash, hash uint64) (interface{}, bool) {
	if self.IsNil() { // an empty tree is easy
		return nil, false
	}

	if hash != self.hash {
		i := partialHash % childCount
		return lookupLowLevel(self.children[i], partialHash>>shiftSize, hash)
	}

	// we found it
	return self.value, true
}

func (m *tree) Size() int {
	return m.count
}

func (m *tree) ForEach(f func(key string, val interface{})) {
	if m.IsNil() {
		return
	}

	// ourself
	f(m.key, m.value)

	// children
	for _, t := range m.children {
		if t != nilMap {
			t.ForEach(f)
		}
	}
}

func (m *tree) Keys() []string {
	keys := make([]string, m.Size())
	i := 0
	m.ForEach(func(k string, v interface{}) {
		keys[i] = k
		i++
	})
	return keys
}

// make it easier to display maps for debugging
func (m *tree) String() string {
	keys := m.Keys()
	buf := bytes.NewBufferString("{")
	for _, key := range keys {
		val, _ := m.Lookup(key)
		fmt.Fprintf(buf, "%s: %s, ", key, val)
	}
	fmt.Fprintf(buf, "}\n")
	return buf.String()
}
<commit_msg>Improve performance of maps<commit_after>// Fully persistent data structures. A persistent data structure is a data
// structure that always preserves the previous version of itself when
// it is modified. Such data structures are effectively immutable,
// as their operations do not update the structure in-place, but instead
// always yield a new structure.
//
// Persistent
// data structures typically share structure among themselves.  This allows
// operations to avoid copying the entire data structure.
package ps

import (
	"bytes"
	"fmt"
	"unsafe"
)

// A Map associates unique keys (type string) with values (type Any).
type Map interface {
	// IsNil returns true if the Map is empty
	IsNil() bool

	// Set returns a new map in which key and value are associated.
	// If the key didn't exist before, it's created; otherwise, the
	// associated value is changed.
	// This operation is O(log N) in the number of keys.
	Set(key string, value interface{}) Map

	// UnsafeMutableSet returns the same map in which key and value are associated in-place.
	// If the key didn't exist before, it's created; otherwise, the
	// associated value is changed.
	// This operation is O(log N) in the number of keys.
	// Only use UnsafeMutableSet if you are the only reference-holder of the Map.
	UnsafeMutableSet(key string, value interface{}) Map

	// Delete returns a new map with the association for key, if any, removed.
	// This operation is O(log N) in the number of keys.
	Delete(key string) Map

	// Lookup returns the value associated with a key, if any.  If the key
	// exists, the second return value is true; otherwise, false.
	// This operation is O(log N) in the number of keys.
	Lookup(key string) (interface{}, bool)

	// Size returns the number of key value pairs in the map.
	// This takes O(1) time.
	Size() int

	// ForEach executes a callback on each key value pair in the map.
	ForEach(f func(key string, val interface{}))

	// Keys returns a slice with all keys in this map.
	// This operation is O(N) in the number of keys.
	Keys() []string

	String() string
}

// Immutable (i.e. persistent) associative array
const childCount = 8
const shiftSize = 3

type tree struct {
	count    int
	hash     uint64 // hash of the key (used for tree balancing)
	key      string
	value    interface{}
	children [childCount]*tree
}

var nilMap = &tree{}

// Recursively set nilMap's subtrees to point at itself.
// This eliminates all nil pointers in the map structure.
// All map nodes are created by cloning this structure so
// they avoid the problem too.
func init() {
	for i := range nilMap.children {
		nilMap.children[i] = nilMap
	}
}

// NewMap allocates a new, persistent map from strings to values of
// any type.
// This is currently implemented as a path-copying binary tree.
func NewMap() Map {
	return nilMap
}

func (self *tree) IsNil() bool {
	return self == nilMap
}

// clone returns an exact duplicate of a tree node
func (self *tree) clone() *tree {
	var m tree
	m = *self
	return &m
}

// constants for FNV-1a hash algorithm
const (
	offset64 uint64 = 14695981039346656037
	prime64  uint64 = 1099511628211
)

type unsafeString struct {
	Data uintptr
	Len  int
}

type unsafeSlice struct {
	Data uintptr
	Len  int
	Cap  int
}

var zeroByteSlice = []byte{}

// bytesView returns a view of the string as a []byte.
// It doesn't incur allocation and copying caused by conversion but it's
// unsafe, use with care.
func bytesView(v string) []byte {
	if len(v) == 0 {
		return zeroByteSlice
	}

	sx := (*unsafeString)(unsafe.Pointer(&v))
	bx := unsafeSlice{sx.Data, sx.Len, sx.Len}
	return *(*[]byte)(unsafe.Pointer(&bx))
}

// hashKey returns a hash code for a given string
func hashKey(key string) uint64 {
	hash := offset64

	for _, b := range bytesView(key) {
		hash ^= uint64(b)
		hash *= prime64
	}
	return hash
}

// Set returns a new map similar to this one but with key and value
// associated.  If the key didn't exist, it's created; otherwise, the
// associated value is changed.
func (self *tree) Set(key string, value interface{}) Map {
	hash := hashKey(key)
	return setLowLevel(self, hash, hash, key, value)
}

func setLowLevel(self *tree, partialHash, hash uint64, key string, value interface{}) *tree {
	if self.IsNil() { // an empty tree is easy
		m := self.clone()
		m.count = 1
		m.hash = hash
		m.key = key
		m.value = value
		return m
	}

	if hash != self.hash {
		m := self.clone()
		i := partialHash % childCount
		m.children[i] = setLowLevel(self.children[i], partialHash>>shiftSize, hash, key, value)
		// update count if we added a new object
		if m.children[i].count > self.children[i].count {
			m.count++
		}
		return m
	}

	// did we find a hash collision?
	if key != self.key {
		oops := fmt.Sprintf("Hash collision between: '%s' and '%s'.  Please report to https://github.com/mndrix/ps/issues/new", self.key, key)
		panic(oops)
	}

	// replacing a key's previous value
	m := self.clone()
	m.value = value
	return m
}

// UnsafeMutableSet is the in-place mutable version of Set. Only use if
// you are the only reference-holder of the Map.
func (self *tree) UnsafeMutableSet(key string, value interface{}) Map {
	hash := hashKey(key)
	return mutableSetLowLevel(self, hash, hash, key, value)
}

func mutableSetLowLevel(self *tree, partialHash, hash uint64, key string, value interface{}) *tree {
	if self.IsNil() { // an empty tree is easy
		m := self.clone()
		m.count = 1
		m.hash = hash
		m.key = key
		m.value = value
		return m
	}

	if hash != self.hash {
		i := partialHash % childCount
		oldChildCount := self.children[i].count
		self.children[i] = mutableSetLowLevel(self.children[i], partialHash>>shiftSize, hash, key, value)
		// update count if we added a new object
		if oldChildCount < self.children[i].count {
			self.count++
		}
		return self
	}

	// did we find a hash collision?
	if key != self.key {
		oops := fmt.Sprintf("Hash collision between: '%s' and '%s'.  Please report to https://github.com/mndrix/ps/issues/new", self.key, key)
		panic(oops)
	}

	// replacing a key's previous value
	self.value = value
	return self
}

// modifies a map by recalculating its key count based on the counts
// of its subtrees
func recalculateCount(m *tree) {
	count := 0
	for _, t := range m.children {
		count += t.Size()
	}
	m.count = count + 1 // add one to count ourself
}

func (m *tree) Delete(key string) Map {
	hash := hashKey(key)
	newMap, _ := deleteLowLevel(m, hash, hash)
	return newMap
}

func deleteLowLevel(self *tree, partialHash, hash uint64) (*tree, bool) {
	// empty trees are easy
	if self.IsNil() {
		return self, false
	}

	if hash != self.hash {
		i := partialHash % childCount
		child, found := deleteLowLevel(self.children[i], partialHash>>shiftSize, hash)
		if !found {
			return self, false
		}
		newMap := self.clone()
		newMap.children[i] = child
		recalculateCount(newMap)
		return newMap, true // ? this wasn't in the original code
	}

	// we must delete our own node
	if self.isLeaf() { // we have no children
		return nilMap, true
	}
	/*
	   if self.subtreeCount() == 1 { // only one subtree
	       for _, t := range self.children {
	           if t != nilMap {
	               return t, true
	           }
	       }
	       panic("Tree with 1 subtree actually had no subtrees")
	   }
	*/

	// find a node to replace us
	i := -1
	size := -1
	for j, t := range self.children {
		if t.Size() > size {
			i = j
			size = t.Size()
		}
	}

	// make chosen leaf smaller
	replacement, child := self.children[i].deleteLeftmost()
	newMap := replacement.clone()
	for j := range self.children {
		if j == i {
			newMap.children[j] = child
		} else {
			newMap.children[j] = self.children[j]
		}
	}
	recalculateCount(newMap)
	return newMap, true
}

// delete the leftmost node in a tree returning the node that
// was deleted and the tree left over after its deletion
func (m *tree) deleteLeftmost() (*tree, *tree) {
	if m.isLeaf() {
		return m, nilMap
	}

	for i, t := range m.children {
		if t != nilMap {
			deleted, child := t.deleteLeftmost()
			newMap := m.clone()
			newMap.children[i] = child
			recalculateCount(newMap)
			return deleted, newMap
		}
	}
	panic("Tree isn't a leaf but also had no children. How does that happen?")
}

// isLeaf returns true if this is a leaf node
func (m *tree) isLeaf() bool {
	return m.Size() == 1
}

// returns the number of child subtrees we have
func (m *tree) subtreeCount() int {
	count := 0
	for _, t := range m.children {
		if t != nilMap {
			count++
		}
	}
	return count
}

func (m *tree) Lookup(key string) (interface{}, bool) {
	hash := hashKey(key)
	return lookupLowLevel(m, hash, hash)
}

func lookupLowLevel(self *tree, partialHash, hash uint64) (interface{}, bool) {
	if self.IsNil() { // an empty tree is easy
		return nil, false
	}

	if hash != self.hash {
		i := partialHash % childCount
		return lookupLowLevel(self.children[i], partialHash>>shiftSize, hash)
	}

	// we found it
	return self.value, true
}

func (m *tree) Size() int {
	return m.count
}

func (m *tree) ForEach(f func(key string, val interface{})) {
	if m.IsNil() {
		return
	}

	// ourself
	f(m.key, m.value)

	// children
	for _, t := range m.children {
		if t != nilMap {
			t.ForEach(f)
		}
	}
}

func (m *tree) Keys() []string {
	keys := make([]string, m.Size())
	i := 0
	m.ForEach(func(k string, v interface{}) {
		keys[i] = k
		i++
	})
	return keys
}

// make it easier to display maps for debugging
func (m *tree) String() string {
	keys := m.Keys()
	buf := bytes.NewBufferString("{")
	for _, key := range keys {
		val, _ := m.Lookup(key)
		fmt.Fprintf(buf, "%s: %s, ", key, val)
	}
	fmt.Fprintf(buf, "}\n")
	return buf.String()
}
<|endoftext|>


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

package interfacer

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"os"
	"strings"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"

	"github.com/kisielk/gotool"
	"github.com/mvdan/lint"
)

func toDiscard(usage *varUsage) bool {
	if usage.discard {
		return true
	}
	for to := range usage.assigned {
		if toDiscard(to) {
			return true
		}
	}
	return false
}

func allCalls(usage *varUsage, all, ftypes map[string]string) {
	for fname := range usage.calls {
		all[fname] = ftypes[fname]
	}
	for to := range usage.assigned {
		allCalls(to, all, ftypes)
	}
}

func (v *visitor) interfaceMatching(param *types.Var, usage *varUsage) (string, string) {
	if toDiscard(usage) {
		return "", ""
	}
	ftypes := typeFuncMap(param.Type())
	called := make(map[string]string, len(usage.calls))
	allCalls(usage, called, ftypes)
	s := funcMapString(called)
	return v.ifaces[s], s
}

type varUsage struct {
	calls   map[string]struct{}
	discard bool

	assigned map[*varUsage]struct{}
}

type funcDecl struct {
	name    string
	sign    *types.Signature
	astType *ast.FuncType
}

type visitor struct {
	pkgTypes
	*loader.PackageInfo

	fset  *token.FileSet
	funcs []*funcDecl

	discardFuncs map[*types.Signature]struct{}

	vars map[*types.Var]*varUsage
}

// CheckArgs checks the packages specified by their import paths in
// args.
func CheckArgs(args []string) ([]string, error) {
	paths := gotool.ImportPaths(args)
	conf := loader.Config{}
	conf.AllowErrors = true
	conf.TypeChecker.Error = func(e error) {}
	rest, err := conf.FromArgs(paths, false)
	if err != nil {
		return nil, err
	}
	if len(rest) > 0 {
		return nil, fmt.Errorf("unwanted extra args: %v", rest)
	}
	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}
	prog := ssautil.CreateProgram(lprog, 0)
	prog.Build()
	issues, err := new(Checker).Check(lprog, prog)
	if err != nil {
		return nil, err
	}
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	lines := make([]string, len(issues))
	for i, issue := range issues {
		fpos := prog.Fset.Position(issue.Pos()).String()
		if strings.HasPrefix(fpos, wd) {
			fpos = fpos[len(wd)+1:]
		}
		lines[i] = fmt.Sprintf("%s: %s", fpos, issue.Message())
	}
	return lines, nil
}

type Checker struct{}

func (*Checker) Check(lprog *loader.Program, prog *ssa.Program) ([]lint.Issue, error) {
	v := &visitor{
		fset: lprog.Fset,
	}
	var total []lint.Issue
	for _, pinfo := range lprog.InitialPackages() {
		pkg := pinfo.Pkg
		v.getTypes(pkg)
		total = append(total, v.checkPkg(lprog.AllPackages[pkg])...)
	}
	return total, nil
}

func (v *visitor) checkPkg(info *loader.PackageInfo) []lint.Issue {
	v.PackageInfo = info
	v.discardFuncs = make(map[*types.Signature]struct{})
	v.vars = make(map[*types.Var]*varUsage)
	for _, f := range info.Files {
		ast.Walk(v, f)
	}
	return v.packageIssues()
}

func paramVarAndType(sign *types.Signature, i int) (*types.Var, types.Type) {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil, nil
		}
		vr := params.At(i)
		return vr, vr.Type()
	}
	last := params.At(params.Len() - 1)
	switch x := last.Type().(type) {
	case *types.Slice:
		return nil, x.Elem()
	default:
		return nil, x
	}
}

func (v *visitor) varUsage(e ast.Expr) *varUsage {
	id, ok := e.(*ast.Ident)
	if !ok {
		return nil
	}
	param, ok := v.ObjectOf(id).(*types.Var)
	if !ok {
		// not a variable
		return nil
	}
	if usage, e := v.vars[param]; e {
		return usage
	}
	if !interesting(param.Type()) {
		return nil
	}
	usage := &varUsage{
		calls:    make(map[string]struct{}),
		assigned: make(map[*varUsage]struct{}),
	}
	v.vars[param] = usage
	return usage
}

func (v *visitor) addUsed(e ast.Expr, as types.Type) {
	if as == nil {
		return
	}
	if usage := v.varUsage(e); usage != nil {
		// using variable
		iface, ok := as.Underlying().(*types.Interface)
		if !ok {
			usage.discard = true
			return
		}
		for i := 0; i < iface.NumMethods(); i++ {
			m := iface.Method(i)
			usage.calls[m.Name()] = struct{}{}
		}
	} else if t, ok := v.TypeOf(e).(*types.Signature); ok {
		// using func
		v.discardFuncs[t] = struct{}{}
	}
}

func (v *visitor) addAssign(to, from ast.Expr) {
	pto := v.varUsage(to)
	pfrom := v.varUsage(from)
	if pto == nil || pfrom == nil {
		// either isn't interesting
		return
	}
	pfrom.assigned[pto] = struct{}{}
}

func (v *visitor) discard(e ast.Expr) {
	if usage := v.varUsage(e); usage != nil {
		usage.discard = true
	}
}

func (v *visitor) comparedWith(e, with ast.Expr) {
	if _, ok := with.(*ast.BasicLit); ok {
		v.discard(e)
	}
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	var fd *funcDecl
	switch x := node.(type) {
	case *ast.FuncDecl:
		fd = &funcDecl{
			name:    x.Name.Name,
			sign:    v.Defs[x.Name].Type().(*types.Signature),
			astType: x.Type,
		}
		if v.funcSigns[signString(fd.sign)] {
			// implements interface
			return nil
		}
	case *ast.SelectorExpr:
		if _, ok := v.TypeOf(x.Sel).(*types.Signature); !ok {
			v.discard(x.X)
		}
	case *ast.StarExpr:
		v.discard(x.X)
	case *ast.UnaryExpr:
		v.discard(x.X)
	case *ast.IndexExpr:
		v.discard(x.X)
	case *ast.IncDecStmt:
		v.discard(x.X)
	case *ast.BinaryExpr:
		switch x.Op {
		case token.EQL, token.NEQ:
			v.comparedWith(x.X, x.Y)
			v.comparedWith(x.Y, x.X)
		default:
			v.discard(x.X)
			v.discard(x.Y)
		}
	case *ast.ValueSpec:
		for _, val := range x.Values {
			v.addUsed(val, v.TypeOf(x.Type))
		}
	case *ast.AssignStmt:
		for i, val := range x.Rhs {
			left := x.Lhs[i]
			if x.Tok == token.ASSIGN {
				v.addUsed(val, v.TypeOf(left))
			}
			v.addAssign(left, val)
		}
	case *ast.CompositeLit:
		for i, e := range x.Elts {
			switch y := e.(type) {
			case *ast.KeyValueExpr:
				v.addUsed(y.Key, v.TypeOf(y.Value))
				v.addUsed(y.Value, v.TypeOf(y.Key))
			case *ast.Ident:
				v.addUsed(y, compositeIdentType(v.TypeOf(x), i))
			}
		}
	case *ast.CallExpr:
		switch y := v.TypeOf(x.Fun).Underlying().(type) {
		case *types.Signature:
			v.onMethodCall(x, y)
		default:
			// type conversion
			if len(x.Args) == 1 {
				v.addUsed(x.Args[0], y)
			}
		}
	}
	if fd != nil {
		v.funcs = append(v.funcs, fd)
	}
	return v
}

func compositeIdentType(t types.Type, i int) types.Type {
	switch x := t.(type) {
	case *types.Named:
		return compositeIdentType(x.Underlying(), i)
	case *types.Struct:
		return x.Field(i).Type()
	case *types.Array:
		return x.Elem()
	case *types.Slice:
		return x.Elem()
	}
	return nil
}

func (v *visitor) onMethodCall(ce *ast.CallExpr, sign *types.Signature) {
	for i, e := range ce.Args {
		paramObj, t := paramVarAndType(sign, i)
		// Don't if this is a parameter being re-used as itself
		// in a recursive call
		if id, ok := e.(*ast.Ident); ok {
			if paramObj == v.ObjectOf(id) {
				continue
			}
		}
		v.addUsed(e, t)
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	// receiver func call on the left side
	if usage := v.varUsage(sel.X); usage != nil {
		usage.calls[sel.Sel.Name] = struct{}{}
	}
}

func (fd *funcDecl) paramGroups() [][]*types.Var {
	astList := fd.astType.Params.List
	groups := make([][]*types.Var, len(astList))
	signIndex := 0
	for i, field := range astList {
		group := make([]*types.Var, len(field.Names))
		for j := range field.Names {
			group[j] = fd.sign.Params().At(signIndex)
			signIndex++
		}
		groups[i] = group
	}
	return groups
}

func (v *visitor) packageIssues() []lint.Issue {
	var issues []lint.Issue
	for _, fd := range v.funcs {
		if _, e := v.discardFuncs[fd.sign]; e {
			continue
		}
		for _, group := range fd.paramGroups() {
			issues = append(issues, v.groupIssues(fd, group)...)
		}
	}
	return issues
}

type Issue struct {
	pos token.Pos
	msg string
}

func (i Issue) Pos() token.Pos  { return i.pos }
func (i Issue) Message() string { return i.msg }

func (v *visitor) groupIssues(fd *funcDecl, group []*types.Var) []lint.Issue {
	var issues []lint.Issue
	for _, param := range group {
		usage := v.vars[param]
		if usage == nil {
			return nil
		}
		newType := v.paramNewType(fd.name, param, usage)
		if newType == "" {
			return nil
		}
		issues = append(issues, Issue{
			pos: param.Pos(),
			msg: fmt.Sprintf("%s can be %s", param.Name(), newType),
		})
	}
	return issues
}

func willAddAllocation(t types.Type) bool {
	switch t.Underlying().(type) {
	case *types.Pointer, *types.Interface:
		return false
	}
	return true
}

func (v *visitor) paramNewType(funcName string, param *types.Var, usage *varUsage) string {
	t := param.Type()
	if !ast.IsExported(funcName) && willAddAllocation(t) {
		return ""
	}
	if named := typeNamed(t); named != nil {
		tname := named.Obj().Name()
		vname := param.Name()
		if mentionsName(funcName, tname) || mentionsName(funcName, vname) {
			return ""
		}
	}
	ifname, iftype := v.interfaceMatching(param, usage)
	if ifname == "" {
		return ""
	}
	if types.IsInterface(t.Underlying()) {
		if have := funcMapString(typeFuncMap(t)); have == iftype {
			return ""
		}
	}
	return ifname
}
<commit_msg>Remove unused types.Config.Error func<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interfacer

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"os"
	"strings"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"

	"github.com/kisielk/gotool"
	"github.com/mvdan/lint"
)

func toDiscard(usage *varUsage) bool {
	if usage.discard {
		return true
	}
	for to := range usage.assigned {
		if toDiscard(to) {
			return true
		}
	}
	return false
}

func allCalls(usage *varUsage, all, ftypes map[string]string) {
	for fname := range usage.calls {
		all[fname] = ftypes[fname]
	}
	for to := range usage.assigned {
		allCalls(to, all, ftypes)
	}
}

func (v *visitor) interfaceMatching(param *types.Var, usage *varUsage) (string, string) {
	if toDiscard(usage) {
		return "", ""
	}
	ftypes := typeFuncMap(param.Type())
	called := make(map[string]string, len(usage.calls))
	allCalls(usage, called, ftypes)
	s := funcMapString(called)
	return v.ifaces[s], s
}

type varUsage struct {
	calls   map[string]struct{}
	discard bool

	assigned map[*varUsage]struct{}
}

type funcDecl struct {
	name    string
	sign    *types.Signature
	astType *ast.FuncType
}

type visitor struct {
	pkgTypes
	*loader.PackageInfo

	fset  *token.FileSet
	funcs []*funcDecl

	discardFuncs map[*types.Signature]struct{}

	vars map[*types.Var]*varUsage
}

// CheckArgs checks the packages specified by their import paths in
// args.
func CheckArgs(args []string) ([]string, error) {
	paths := gotool.ImportPaths(args)
	conf := loader.Config{}
	conf.AllowErrors = true
	rest, err := conf.FromArgs(paths, false)
	if err != nil {
		return nil, err
	}
	if len(rest) > 0 {
		return nil, fmt.Errorf("unwanted extra args: %v", rest)
	}
	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}
	prog := ssautil.CreateProgram(lprog, 0)
	prog.Build()
	issues, err := new(Checker).Check(lprog, prog)
	if err != nil {
		return nil, err
	}
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	lines := make([]string, len(issues))
	for i, issue := range issues {
		fpos := prog.Fset.Position(issue.Pos()).String()
		if strings.HasPrefix(fpos, wd) {
			fpos = fpos[len(wd)+1:]
		}
		lines[i] = fmt.Sprintf("%s: %s", fpos, issue.Message())
	}
	return lines, nil
}

type Checker struct{}

func (*Checker) Check(lprog *loader.Program, prog *ssa.Program) ([]lint.Issue, error) {
	v := &visitor{
		fset: lprog.Fset,
	}
	var total []lint.Issue
	for _, pinfo := range lprog.InitialPackages() {
		pkg := pinfo.Pkg
		v.getTypes(pkg)
		total = append(total, v.checkPkg(lprog.AllPackages[pkg])...)
	}
	return total, nil
}

func (v *visitor) checkPkg(info *loader.PackageInfo) []lint.Issue {
	v.PackageInfo = info
	v.discardFuncs = make(map[*types.Signature]struct{})
	v.vars = make(map[*types.Var]*varUsage)
	for _, f := range info.Files {
		ast.Walk(v, f)
	}
	return v.packageIssues()
}

func paramVarAndType(sign *types.Signature, i int) (*types.Var, types.Type) {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil, nil
		}
		vr := params.At(i)
		return vr, vr.Type()
	}
	last := params.At(params.Len() - 1)
	switch x := last.Type().(type) {
	case *types.Slice:
		return nil, x.Elem()
	default:
		return nil, x
	}
}

func (v *visitor) varUsage(e ast.Expr) *varUsage {
	id, ok := e.(*ast.Ident)
	if !ok {
		return nil
	}
	param, ok := v.ObjectOf(id).(*types.Var)
	if !ok {
		// not a variable
		return nil
	}
	if usage, e := v.vars[param]; e {
		return usage
	}
	if !interesting(param.Type()) {
		return nil
	}
	usage := &varUsage{
		calls:    make(map[string]struct{}),
		assigned: make(map[*varUsage]struct{}),
	}
	v.vars[param] = usage
	return usage
}

func (v *visitor) addUsed(e ast.Expr, as types.Type) {
	if as == nil {
		return
	}
	if usage := v.varUsage(e); usage != nil {
		// using variable
		iface, ok := as.Underlying().(*types.Interface)
		if !ok {
			usage.discard = true
			return
		}
		for i := 0; i < iface.NumMethods(); i++ {
			m := iface.Method(i)
			usage.calls[m.Name()] = struct{}{}
		}
	} else if t, ok := v.TypeOf(e).(*types.Signature); ok {
		// using func
		v.discardFuncs[t] = struct{}{}
	}
}

func (v *visitor) addAssign(to, from ast.Expr) {
	pto := v.varUsage(to)
	pfrom := v.varUsage(from)
	if pto == nil || pfrom == nil {
		// either isn't interesting
		return
	}
	pfrom.assigned[pto] = struct{}{}
}

func (v *visitor) discard(e ast.Expr) {
	if usage := v.varUsage(e); usage != nil {
		usage.discard = true
	}
}

func (v *visitor) comparedWith(e, with ast.Expr) {
	if _, ok := with.(*ast.BasicLit); ok {
		v.discard(e)
	}
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	var fd *funcDecl
	switch x := node.(type) {
	case *ast.FuncDecl:
		fd = &funcDecl{
			name:    x.Name.Name,
			sign:    v.Defs[x.Name].Type().(*types.Signature),
			astType: x.Type,
		}
		if v.funcSigns[signString(fd.sign)] {
			// implements interface
			return nil
		}
	case *ast.SelectorExpr:
		if _, ok := v.TypeOf(x.Sel).(*types.Signature); !ok {
			v.discard(x.X)
		}
	case *ast.StarExpr:
		v.discard(x.X)
	case *ast.UnaryExpr:
		v.discard(x.X)
	case *ast.IndexExpr:
		v.discard(x.X)
	case *ast.IncDecStmt:
		v.discard(x.X)
	case *ast.BinaryExpr:
		switch x.Op {
		case token.EQL, token.NEQ:
			v.comparedWith(x.X, x.Y)
			v.comparedWith(x.Y, x.X)
		default:
			v.discard(x.X)
			v.discard(x.Y)
		}
	case *ast.ValueSpec:
		for _, val := range x.Values {
			v.addUsed(val, v.TypeOf(x.Type))
		}
	case *ast.AssignStmt:
		for i, val := range x.Rhs {
			left := x.Lhs[i]
			if x.Tok == token.ASSIGN {
				v.addUsed(val, v.TypeOf(left))
			}
			v.addAssign(left, val)
		}
	case *ast.CompositeLit:
		for i, e := range x.Elts {
			switch y := e.(type) {
			case *ast.KeyValueExpr:
				v.addUsed(y.Key, v.TypeOf(y.Value))
				v.addUsed(y.Value, v.TypeOf(y.Key))
			case *ast.Ident:
				v.addUsed(y, compositeIdentType(v.TypeOf(x), i))
			}
		}
	case *ast.CallExpr:
		switch y := v.TypeOf(x.Fun).Underlying().(type) {
		case *types.Signature:
			v.onMethodCall(x, y)
		default:
			// type conversion
			if len(x.Args) == 1 {
				v.addUsed(x.Args[0], y)
			}
		}
	}
	if fd != nil {
		v.funcs = append(v.funcs, fd)
	}
	return v
}

func compositeIdentType(t types.Type, i int) types.Type {
	switch x := t.(type) {
	case *types.Named:
		return compositeIdentType(x.Underlying(), i)
	case *types.Struct:
		return x.Field(i).Type()
	case *types.Array:
		return x.Elem()
	case *types.Slice:
		return x.Elem()
	}
	return nil
}

func (v *visitor) onMethodCall(ce *ast.CallExpr, sign *types.Signature) {
	for i, e := range ce.Args {
		paramObj, t := paramVarAndType(sign, i)
		// Don't if this is a parameter being re-used as itself
		// in a recursive call
		if id, ok := e.(*ast.Ident); ok {
			if paramObj == v.ObjectOf(id) {
				continue
			}
		}
		v.addUsed(e, t)
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	// receiver func call on the left side
	if usage := v.varUsage(sel.X); usage != nil {
		usage.calls[sel.Sel.Name] = struct{}{}
	}
}

func (fd *funcDecl) paramGroups() [][]*types.Var {
	astList := fd.astType.Params.List
	groups := make([][]*types.Var, len(astList))
	signIndex := 0
	for i, field := range astList {
		group := make([]*types.Var, len(field.Names))
		for j := range field.Names {
			group[j] = fd.sign.Params().At(signIndex)
			signIndex++
		}
		groups[i] = group
	}
	return groups
}

func (v *visitor) packageIssues() []lint.Issue {
	var issues []lint.Issue
	for _, fd := range v.funcs {
		if _, e := v.discardFuncs[fd.sign]; e {
			continue
		}
		for _, group := range fd.paramGroups() {
			issues = append(issues, v.groupIssues(fd, group)...)
		}
	}
	return issues
}

type Issue struct {
	pos token.Pos
	msg string
}

func (i Issue) Pos() token.Pos  { return i.pos }
func (i Issue) Message() string { return i.msg }

func (v *visitor) groupIssues(fd *funcDecl, group []*types.Var) []lint.Issue {
	var issues []lint.Issue
	for _, param := range group {
		usage := v.vars[param]
		if usage == nil {
			return nil
		}
		newType := v.paramNewType(fd.name, param, usage)
		if newType == "" {
			return nil
		}
		issues = append(issues, Issue{
			pos: param.Pos(),
			msg: fmt.Sprintf("%s can be %s", param.Name(), newType),
		})
	}
	return issues
}

func willAddAllocation(t types.Type) bool {
	switch t.Underlying().(type) {
	case *types.Pointer, *types.Interface:
		return false
	}
	return true
}

func (v *visitor) paramNewType(funcName string, param *types.Var, usage *varUsage) string {
	t := param.Type()
	if !ast.IsExported(funcName) && willAddAllocation(t) {
		return ""
	}
	if named := typeNamed(t); named != nil {
		tname := named.Obj().Name()
		vname := param.Name()
		if mentionsName(funcName, tname) || mentionsName(funcName, vname) {
			return ""
		}
	}
	ifname, iftype := v.interfaceMatching(param, usage)
	if ifname == "" {
		return ""
	}
	if types.IsInterface(t.Underlying()) {
		if have := funcMapString(typeFuncMap(t)); have == iftype {
			return ""
		}
	}
	return ifname
}
<|endoftext|>


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

package interfacer

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/tools/go/loader"
)

func toDiscard(vu *varUsage) bool {
	if vu.discard {
		return true
	}
	for to := range vu.assigned {
		if toDiscard(to) {
			return true
		}
	}
	return false
}

func (v *visitor) interfaceMatching(vr *types.Var, vu *varUsage) (string, string) {
	if toDiscard(vu) {
		return "", ""
	}
	allFuncs := typeFuncMap(vr.Type())
	if allFuncs == nil {
		return "", ""
	}
	called := make(map[string]string, len(vu.calls))
	for fname := range vu.calls {
		called[fname] = allFuncs[fname]
	}
	s := funcMapString(called)
	name := v.ifaceOf(s)
	if name == "" {
		return "", ""
	}
	return name, s
}

func orderedPkgs(prog *loader.Program) ([]*types.Package, error) {
	// InitialPackages() is not in the order that we passed to it
	// via Import() calls.
	// For now, make it deterministic by sorting import paths
	// alphabetically.
	unordered := prog.InitialPackages()
	paths := make([]string, 0, len(unordered))
	byPath := make(map[string]*types.Package, len(unordered))
	for _, info := range unordered {
		if info.Errors != nil {
			return nil, info.Errors[0]
		}
		path := info.Pkg.Path()
		paths = append(paths, path)
		byPath[path] = info.Pkg
	}
	sort.Sort(ByAlph(paths))
	pkgs := make([]*types.Package, 0, len(unordered))
	for _, path := range paths {
		pkgs = append(pkgs, byPath[path])
	}
	return pkgs, nil
}

// relPathErr converts errors by go/types and go/loader that use
// absolute paths into errors with relative paths
func relPathErr(err error, wd string) error {
	errStr := fmt.Sprintf("%v", err)
	if strings.HasPrefix(errStr, wd) {
		return fmt.Errorf(errStr[len(wd)+1:])
	}
	return err
}

// CheckArgs checks the packages specified by their import paths in
// args, and writes the results in w. Can give verbose output if
// specified, printing each package as it is checked.
func CheckArgs(args []string, w io.Writer, verbose bool) error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}
	paths, err := recurse(args)
	if err != nil {
		return err
	}
	c := newCache()
	rest, err := c.FromArgs(paths, false)
	if err != nil {
		return err
	}
	if len(rest) > 0 {
		return fmt.Errorf("unwanted extra args: %v", rest)
	}
	prog, err := c.Load()
	if err != nil {
		return err
	}
	pkgs, err := orderedPkgs(prog)
	if err != nil {
		return relPathErr(err, wd)
	}
	c.typesGet(pkgs)
	for _, pkg := range pkgs {
		info := prog.AllPackages[pkg]
		if verbose {
			fmt.Fprintln(w, info.Pkg.Path())
		}
		v := &visitor{
			cache:       c,
			PackageInfo: info,
			wd:          wd,
			w:           w,
			fset:        prog.Fset,
			vars:        make(map[*types.Var]*varUsage),
		}
		for _, f := range info.Files {
			ast.Walk(v, f)
		}
	}
	return nil
}

type varUsage struct {
	calls   map[string]struct{}
	discard bool

	assigned map[*varUsage]struct{}
}

type visitor struct {
	*cache
	*loader.PackageInfo

	wd    string
	w     io.Writer
	fset  *token.FileSet
	signs []*types.Signature
	warns [][]string
	level int

	vars map[*types.Var]*varUsage
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	last := params.At(params.Len() - 1)
	switch x := last.Type().(type) {
	case *types.Slice:
		return x.Elem()
	default:
		return x
	}
}

func (v *visitor) varUsage(id *ast.Ident) *varUsage {
	vr, ok := v.ObjectOf(id).(*types.Var)
	if !ok {
		return nil
	}
	if vu, e := v.vars[vr]; e {
		return vu
	}
	vu := &varUsage{
		calls:    make(map[string]struct{}),
		assigned: make(map[*varUsage]struct{}),
	}
	v.vars[vr] = vu
	return vu
}

func (v *visitor) addUsed(id *ast.Ident, as types.Type) {
	if as == nil {
		return
	}
	vu := v.varUsage(id)
	if vu == nil {
		// not a variable
		return
	}
	iface, ok := as.Underlying().(*types.Interface)
	if !ok {
		vu.discard = true
		return
	}
	for i := 0; i < iface.NumMethods(); i++ {
		m := iface.Method(i)
		vu.calls[m.Name()] = struct{}{}
	}
}

func (v *visitor) addAssign(to, from *ast.Ident) {
	pto := v.varUsage(to)
	pfrom := v.varUsage(from)
	if pto == nil || pfrom == nil {
		// either isn't a variable
		return
	}
	pfrom.assigned[pto] = struct{}{}
}

func (v *visitor) discard(e ast.Expr) {
	id, ok := e.(*ast.Ident)
	if !ok {
		return
	}
	vu := v.varUsage(id)
	if vu == nil {
		// not a variable
		return
	}
	vu.discard = true
}

func (v *visitor) comparedWith(e ast.Expr, with ast.Expr) {
	if _, ok := with.(*ast.BasicLit); ok {
		v.discard(e)
	}
}

func (v *visitor) implementsIface(sign *types.Signature) bool {
	s := signString(sign)
	return v.funcOf(s) != ""
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	var sign *types.Signature
	switch x := node.(type) {
	case *ast.FuncLit:
		sign = v.Types[x].Type.(*types.Signature)
		if v.implementsIface(sign) {
			return nil
		}
	case *ast.FuncDecl:
		sign = v.Defs[x.Name].Type().(*types.Signature)
		if v.implementsIface(sign) {
			return nil
		}
	case *ast.SelectorExpr:
		if _, ok := v.TypeOf(x.Sel).(*types.Signature); !ok {
			v.discard(x.X)
		}
	case *ast.UnaryExpr:
		v.discard(x.X)
	case *ast.IndexExpr:
		v.discard(x.X)
	case *ast.IncDecStmt:
		v.discard(x.X)
	case *ast.BinaryExpr:
		v.onBinary(x)
	case *ast.AssignStmt:
		v.onAssign(x)
	case *ast.KeyValueExpr:
		v.onKeyValue(x)
	case *ast.CompositeLit:
		v.onComposite(x)
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		if top := v.signs[len(v.signs)-1]; top != nil {
			v.funcEnded(top)
		}
		v.signs = v.signs[:len(v.signs)-1]
	}
	if node != nil {
		v.signs = append(v.signs, sign)
		if sign != nil {
			v.level++
		}
	}
	return v
}

func (v *visitor) onBinary(be *ast.BinaryExpr) {
	switch be.Op {
	case token.EQL, token.NEQ:
	default:
		v.discard(be.X)
		v.discard(be.Y)
		return
	}
	v.comparedWith(be.X, be.Y)
	v.comparedWith(be.Y, be.X)
}

func (v *visitor) onAssign(as *ast.AssignStmt) {
	for i, e := range as.Rhs {
		id, ok := e.(*ast.Ident)
		if !ok {
			continue
		}
		left := as.Lhs[i]
		v.addUsed(id, v.Types[left].Type)
		if lid, ok := left.(*ast.Ident); ok {
			v.addAssign(lid, id)
		}
	}
}

func (v *visitor) onKeyValue(kv *ast.KeyValueExpr) {
	if id, ok := kv.Key.(*ast.Ident); ok {
		v.addUsed(id, v.TypeOf(kv.Value))
	}
	if id, ok := kv.Value.(*ast.Ident); ok {
		v.addUsed(id, v.TypeOf(kv.Key))
	}
}

func (v *visitor) onComposite(cl *ast.CompositeLit) {
	for _, e := range cl.Elts {
		if kv, ok := e.(*ast.KeyValueExpr); ok {
			v.onKeyValue(kv)
		}
	}
}

func (v *visitor) onCall(ce *ast.CallExpr) {
	if sign, ok := v.TypeOf(ce.Fun).(*types.Signature); ok {
		v.onMethodCall(ce, sign)
		return
	}
	if len(ce.Args) == 1 {
		v.discard(ce.Args[0])
	}
}

func (v *visitor) onMethodCall(ce *ast.CallExpr, sign *types.Signature) {
	for i, e := range ce.Args {
		if id, ok := e.(*ast.Ident); ok {
			v.addUsed(id, paramType(sign, i))
		}
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vu := v.varUsage(left)
	if vu == nil {
		// not a variable
		return
	}
	vu.calls[sel.Sel.Name] = struct{}{}
}

func (v *visitor) funcEnded(sign *types.Signature) {
	v.level--
	v.warns = append(v.warns, v.funcWarns(sign))
	if v.level > 0 {
		return
	}
	for i := len(v.warns) - 1; i >= 0; i-- {
		warns := v.warns[i]
		for _, warn := range warns {
			fmt.Fprintln(v.w, warn)
		}
	}
	v.warns = nil
	v.vars = make(map[*types.Var]*varUsage)
}

func (v *visitor) funcWarns(sign *types.Signature) []string {
	var warns []string
	params := sign.Params()
	for i := 0; i < params.Len(); i++ {
		vr := params.At(i)
		vu := v.vars[vr]
		if vu == nil {
			continue
		}
		warn := v.paramWarn(vr, vu)
		if warn == "" {
			continue
		}
		pos := v.fset.Position(vr.Pos())
		fname := pos.Filename
		// go/loader seems to like absolute paths
		if rel, err := filepath.Rel(v.wd, fname); err == nil {
			fname = rel
		}
		warns = append(warns, fmt.Sprintf("%s:%d:%d: %s",
			fname, pos.Line, pos.Column, warn))
	}
	return warns
}

func (v *visitor) paramWarn(vr *types.Var, vu *varUsage) string {
	ifname, iftype := v.interfaceMatching(vr, vu)
	if ifname == "" {
		return ""
	}
	t := vr.Type()
	if _, ok := t.Underlying().(*types.Interface); ok {
		if ifname == t.String() {
			return ""
		}
		if have := funcMapString(typeFuncMap(t)); have == iftype {
			return ""
		}
	}
	pname := v.Pkg.Path()
	if strings.HasPrefix(ifname, pname+".") {
		ifname = ifname[len(pname)+1:]
	}
	return fmt.Sprintf("%s can be %s", vr.Name(), ifname)
}
<commit_msg>Separate package stripping into a function<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interfacer

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/tools/go/loader"
)

func toDiscard(vu *varUsage) bool {
	if vu.discard {
		return true
	}
	for to := range vu.assigned {
		if toDiscard(to) {
			return true
		}
	}
	return false
}

func (v *visitor) interfaceMatching(vr *types.Var, vu *varUsage) (string, string) {
	if toDiscard(vu) {
		return "", ""
	}
	allFuncs := typeFuncMap(vr.Type())
	if allFuncs == nil {
		return "", ""
	}
	called := make(map[string]string, len(vu.calls))
	for fname := range vu.calls {
		called[fname] = allFuncs[fname]
	}
	s := funcMapString(called)
	name := v.ifaceOf(s)
	if name == "" {
		return "", ""
	}
	return name, s
}

func orderedPkgs(prog *loader.Program) ([]*types.Package, error) {
	// InitialPackages() is not in the order that we passed to it
	// via Import() calls.
	// For now, make it deterministic by sorting import paths
	// alphabetically.
	unordered := prog.InitialPackages()
	paths := make([]string, 0, len(unordered))
	byPath := make(map[string]*types.Package, len(unordered))
	for _, info := range unordered {
		if info.Errors != nil {
			return nil, info.Errors[0]
		}
		path := info.Pkg.Path()
		paths = append(paths, path)
		byPath[path] = info.Pkg
	}
	sort.Sort(ByAlph(paths))
	pkgs := make([]*types.Package, 0, len(unordered))
	for _, path := range paths {
		pkgs = append(pkgs, byPath[path])
	}
	return pkgs, nil
}

// relPathErr converts errors by go/types and go/loader that use
// absolute paths into errors with relative paths
func relPathErr(err error, wd string) error {
	errStr := fmt.Sprintf("%v", err)
	if strings.HasPrefix(errStr, wd) {
		return fmt.Errorf(errStr[len(wd)+1:])
	}
	return err
}

// CheckArgs checks the packages specified by their import paths in
// args, and writes the results in w. Can give verbose output if
// specified, printing each package as it is checked.
func CheckArgs(args []string, w io.Writer, verbose bool) error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}
	paths, err := recurse(args)
	if err != nil {
		return err
	}
	c := newCache()
	rest, err := c.FromArgs(paths, false)
	if err != nil {
		return err
	}
	if len(rest) > 0 {
		return fmt.Errorf("unwanted extra args: %v", rest)
	}
	prog, err := c.Load()
	if err != nil {
		return err
	}
	pkgs, err := orderedPkgs(prog)
	if err != nil {
		return relPathErr(err, wd)
	}
	c.typesGet(pkgs)
	for _, pkg := range pkgs {
		info := prog.AllPackages[pkg]
		if verbose {
			fmt.Fprintln(w, info.Pkg.Path())
		}
		v := &visitor{
			cache:       c,
			PackageInfo: info,
			wd:          wd,
			w:           w,
			fset:        prog.Fset,
			vars:        make(map[*types.Var]*varUsage),
		}
		for _, f := range info.Files {
			ast.Walk(v, f)
		}
	}
	return nil
}

type varUsage struct {
	calls   map[string]struct{}
	discard bool

	assigned map[*varUsage]struct{}
}

type visitor struct {
	*cache
	*loader.PackageInfo

	wd    string
	w     io.Writer
	fset  *token.FileSet
	signs []*types.Signature
	warns [][]string
	level int

	vars map[*types.Var]*varUsage
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	last := params.At(params.Len() - 1)
	switch x := last.Type().(type) {
	case *types.Slice:
		return x.Elem()
	default:
		return x
	}
}

func (v *visitor) varUsage(id *ast.Ident) *varUsage {
	vr, ok := v.ObjectOf(id).(*types.Var)
	if !ok {
		return nil
	}
	if vu, e := v.vars[vr]; e {
		return vu
	}
	vu := &varUsage{
		calls:    make(map[string]struct{}),
		assigned: make(map[*varUsage]struct{}),
	}
	v.vars[vr] = vu
	return vu
}

func (v *visitor) addUsed(id *ast.Ident, as types.Type) {
	if as == nil {
		return
	}
	vu := v.varUsage(id)
	if vu == nil {
		// not a variable
		return
	}
	iface, ok := as.Underlying().(*types.Interface)
	if !ok {
		vu.discard = true
		return
	}
	for i := 0; i < iface.NumMethods(); i++ {
		m := iface.Method(i)
		vu.calls[m.Name()] = struct{}{}
	}
}

func (v *visitor) addAssign(to, from *ast.Ident) {
	pto := v.varUsage(to)
	pfrom := v.varUsage(from)
	if pto == nil || pfrom == nil {
		// either isn't a variable
		return
	}
	pfrom.assigned[pto] = struct{}{}
}

func (v *visitor) discard(e ast.Expr) {
	id, ok := e.(*ast.Ident)
	if !ok {
		return
	}
	vu := v.varUsage(id)
	if vu == nil {
		// not a variable
		return
	}
	vu.discard = true
}

func (v *visitor) comparedWith(e ast.Expr, with ast.Expr) {
	if _, ok := with.(*ast.BasicLit); ok {
		v.discard(e)
	}
}

func (v *visitor) implementsIface(sign *types.Signature) bool {
	s := signString(sign)
	return v.funcOf(s) != ""
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	var sign *types.Signature
	switch x := node.(type) {
	case *ast.FuncLit:
		sign = v.Types[x].Type.(*types.Signature)
		if v.implementsIface(sign) {
			return nil
		}
	case *ast.FuncDecl:
		sign = v.Defs[x.Name].Type().(*types.Signature)
		if v.implementsIface(sign) {
			return nil
		}
	case *ast.SelectorExpr:
		if _, ok := v.TypeOf(x.Sel).(*types.Signature); !ok {
			v.discard(x.X)
		}
	case *ast.UnaryExpr:
		v.discard(x.X)
	case *ast.IndexExpr:
		v.discard(x.X)
	case *ast.IncDecStmt:
		v.discard(x.X)
	case *ast.BinaryExpr:
		v.onBinary(x)
	case *ast.AssignStmt:
		v.onAssign(x)
	case *ast.KeyValueExpr:
		v.onKeyValue(x)
	case *ast.CompositeLit:
		v.onComposite(x)
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		if top := v.signs[len(v.signs)-1]; top != nil {
			v.funcEnded(top)
		}
		v.signs = v.signs[:len(v.signs)-1]
	}
	if node != nil {
		v.signs = append(v.signs, sign)
		if sign != nil {
			v.level++
		}
	}
	return v
}

func (v *visitor) onBinary(be *ast.BinaryExpr) {
	switch be.Op {
	case token.EQL, token.NEQ:
	default:
		v.discard(be.X)
		v.discard(be.Y)
		return
	}
	v.comparedWith(be.X, be.Y)
	v.comparedWith(be.Y, be.X)
}

func (v *visitor) onAssign(as *ast.AssignStmt) {
	for i, e := range as.Rhs {
		id, ok := e.(*ast.Ident)
		if !ok {
			continue
		}
		left := as.Lhs[i]
		v.addUsed(id, v.Types[left].Type)
		if lid, ok := left.(*ast.Ident); ok {
			v.addAssign(lid, id)
		}
	}
}

func (v *visitor) onKeyValue(kv *ast.KeyValueExpr) {
	if id, ok := kv.Key.(*ast.Ident); ok {
		v.addUsed(id, v.TypeOf(kv.Value))
	}
	if id, ok := kv.Value.(*ast.Ident); ok {
		v.addUsed(id, v.TypeOf(kv.Key))
	}
}

func (v *visitor) onComposite(cl *ast.CompositeLit) {
	for _, e := range cl.Elts {
		if kv, ok := e.(*ast.KeyValueExpr); ok {
			v.onKeyValue(kv)
		}
	}
}

func (v *visitor) onCall(ce *ast.CallExpr) {
	if sign, ok := v.TypeOf(ce.Fun).(*types.Signature); ok {
		v.onMethodCall(ce, sign)
		return
	}
	if len(ce.Args) == 1 {
		v.discard(ce.Args[0])
	}
}

func (v *visitor) onMethodCall(ce *ast.CallExpr, sign *types.Signature) {
	for i, e := range ce.Args {
		if id, ok := e.(*ast.Ident); ok {
			v.addUsed(id, paramType(sign, i))
		}
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vu := v.varUsage(left)
	if vu == nil {
		// not a variable
		return
	}
	vu.calls[sel.Sel.Name] = struct{}{}
}

func (v *visitor) funcEnded(sign *types.Signature) {
	v.level--
	v.warns = append(v.warns, v.funcWarns(sign))
	if v.level > 0 {
		return
	}
	for i := len(v.warns) - 1; i >= 0; i-- {
		warns := v.warns[i]
		for _, warn := range warns {
			fmt.Fprintln(v.w, warn)
		}
	}
	v.warns = nil
	v.vars = make(map[*types.Var]*varUsage)
}

func (v *visitor) funcWarns(sign *types.Signature) []string {
	var warns []string
	params := sign.Params()
	for i := 0; i < params.Len(); i++ {
		vr := params.At(i)
		vu := v.vars[vr]
		if vu == nil {
			continue
		}
		warn := v.paramWarn(vr, vu)
		if warn == "" {
			continue
		}
		pos := v.fset.Position(vr.Pos())
		fname := pos.Filename
		// go/loader seems to like absolute paths
		if rel, err := filepath.Rel(v.wd, fname); err == nil {
			fname = rel
		}
		warns = append(warns, fmt.Sprintf("%s:%d:%d: %s",
			fname, pos.Line, pos.Column, warn))
	}
	return warns
}

func (v *visitor) stripPkg(fullName string) string {
	pname := v.Pkg.Path()
	if strings.HasPrefix(fullName, pname+".") {
		return fullName[len(pname)+1:]
	}
	return fullName
}

func (v *visitor) paramWarn(vr *types.Var, vu *varUsage) string {
	ifname, iftype := v.interfaceMatching(vr, vu)
	if ifname == "" {
		return ""
	}
	t := vr.Type()
	if _, ok := t.Underlying().(*types.Interface); ok {
		if ifname == t.String() {
			return ""
		}
		if have := funcMapString(typeFuncMap(t)); have == iftype {
			return ""
		}
	}
	return fmt.Sprintf("%s can be %s", vr.Name(), v.stripPkg(ifname))
}
<|endoftext|>


<commit_before>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 12, 1, 11, 0, 0, 0, time.Local)
	motto := "Just Go"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now, countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<commit_msg>reset to midnight<commit_after>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 12, 1, 0, 0, 0, 0, time.Local)
	motto := "Just Go"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now, countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<|endoftext|>


<commit_before><commit_msg>Proxy: Fix updating refresh token in OAuth pass-thru (#26885)<commit_after><|endoftext|>


<commit_before><commit_msg>Make conversion function names match expected values<commit_after><|endoftext|>


<commit_before><commit_msg>Name outer loop and break from it<commit_after><|endoftext|>


<commit_before>// Package mem is an example REST backend storage that stores everything in memory.
package mem

import (
	"sort"
	"sync"
	"time"

	"github.com/rs/rest-layer"
	"golang.org/x/net/context"
)

// MemoryHandler is an example handler storing data in memory
type MemoryHandler struct {
	sync.RWMutex
	// If latency is set, the handler will introduce an artificial latency on
	// all operations
	Latency time.Duration
	items   map[interface{}]*rest.Item
	ids     []interface{}
}

// NewHandler creates an empty memory handler
func NewHandler() *MemoryHandler {
	return &MemoryHandler{
		items: map[interface{}]*rest.Item{},
		ids:   []interface{}{},
	}
}

// NewSlowHandler creates an empty memory handler with specified latency
func NewSlowHandler(latency time.Duration) *MemoryHandler {
	return &MemoryHandler{
		Latency: latency,
		items:   map[interface{}]*rest.Item{},
		ids:     []interface{}{},
	}
}

// Insert inserts new items in memory
func (m *MemoryHandler) Insert(ctx context.Context, items []*rest.Item) (err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		for _, item := range items {
			if _, found := m.items[item.ID]; found {
				return rest.ConflictError
			}
		}
		for _, item := range items {
			// Store ids in ordered slice for sorting
			m.ids = append(m.ids, item.ID)
			m.items[item.ID] = item
		}
		return nil
	})
	return err
}

// Update replace an item by a new one in memory
func (m *MemoryHandler) Update(ctx context.Context, item *rest.Item, original *rest.Item) (err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		o, found := m.items[original.ID]
		if !found {
			return rest.NotFoundError
		}
		if original.Etag != o.Etag {
			return rest.ConflictError
		}
		m.items[item.ID] = item
		return nil
	})
	return err
}

// Delete deletes an item from memory
func (m *MemoryHandler) Delete(ctx context.Context, item *rest.Item) (err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		o, found := m.items[item.ID]
		if !found {
			return rest.NotFoundError
		}
		if item.Etag != o.Etag {
			return rest.ConflictError
		}
		m.delete(item.ID)
		return nil
	})
	return err
}

// Clear clears all items from the memory store matching the lookup
func (m *MemoryHandler) Clear(ctx context.Context, lookup *rest.Lookup) (total int, err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		for _, id := range m.ids {
			item := m.items[id]
			if !lookup.Match(item.Payload) {
				continue
			}
			m.delete(item.ID)
			total++
		}
		return nil
	})
	return total, err
}

// delete removes an item by this id with no look
func (m *MemoryHandler) delete(id interface{}) {
	delete(m.items, id)
	// Remove id from id list
	for i, _id := range m.ids {
		if _id == id {
			if i >= len(m.ids)-1 {
				m.ids = m.ids[:i]
			} else {
				m.ids = append(m.ids[:i], m.ids[i+1:]...)
			}
		}
	}
}

// Find items from memory matching the provided lookup
func (m *MemoryHandler) Find(ctx context.Context, lookup *rest.Lookup, page, perPage int) (list *rest.ItemList, err *rest.Error) {
	m.RLock()
	defer m.RUnlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		items := []*rest.Item{}
		// Apply filter
		for _, id := range m.ids {
			item := m.items[id]
			if !lookup.Match(item.Payload) {
				continue
			}
			items = append(items, item)
		}
		// Apply sort
		if len(lookup.Sort) > 0 {
			s := sortableItems{lookup.Sort, items}
			sort.Sort(s)
		}
		// Apply pagination
		total := len(items)
		start := (page - 1) * perPage
		end := total
		if perPage > 0 {
			end = start + perPage
			if start > total-1 {
				start = 0
				end = 0
			} else if end > total-1 {
				end = total
			}
		}
		list = &rest.ItemList{total, page, items[start:end]}
		return nil
	})
	return list, err
}
<commit_msg>Apply last rest layer changes<commit_after>// Package mem is an example REST backend storage that stores everything in memory.
package mem

import (
	"sort"
	"sync"
	"time"

	"github.com/rs/rest-layer"
	"golang.org/x/net/context"
)

// MemoryHandler is an example handler storing data in memory
type MemoryHandler struct {
	sync.RWMutex
	// If latency is set, the handler will introduce an artificial latency on
	// all operations
	Latency time.Duration
	items   map[interface{}]*rest.Item
	ids     []interface{}
}

// NewHandler creates an empty memory handler
func NewHandler() *MemoryHandler {
	return &MemoryHandler{
		items: map[interface{}]*rest.Item{},
		ids:   []interface{}{},
	}
}

// NewSlowHandler creates an empty memory handler with specified latency
func NewSlowHandler(latency time.Duration) *MemoryHandler {
	return &MemoryHandler{
		Latency: latency,
		items:   map[interface{}]*rest.Item{},
		ids:     []interface{}{},
	}
}

// Insert inserts new items in memory
func (m *MemoryHandler) Insert(ctx context.Context, items []*rest.Item) (err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		for _, item := range items {
			if _, found := m.items[item.ID]; found {
				return rest.ConflictError
			}
		}
		for _, item := range items {
			// Store ids in ordered slice for sorting
			m.ids = append(m.ids, item.ID)
			m.items[item.ID] = item
		}
		return nil
	})
	return err
}

// Update replace an item by a new one in memory
func (m *MemoryHandler) Update(ctx context.Context, item *rest.Item, original *rest.Item) (err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		o, found := m.items[original.ID]
		if !found {
			return rest.NotFoundError
		}
		if original.ETag != o.ETag {
			return rest.ConflictError
		}
		m.items[item.ID] = item
		return nil
	})
	return err
}

// Delete deletes an item from memory
func (m *MemoryHandler) Delete(ctx context.Context, item *rest.Item) (err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		o, found := m.items[item.ID]
		if !found {
			return rest.NotFoundError
		}
		if item.ETag != o.ETag {
			return rest.ConflictError
		}
		m.delete(item.ID)
		return nil
	})
	return err
}

// Clear clears all items from the memory store matching the lookup
func (m *MemoryHandler) Clear(ctx context.Context, lookup rest.Lookup) (total int, err *rest.Error) {
	m.Lock()
	defer m.Unlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		for _, id := range m.ids {
			item := m.items[id]
			if !lookup.Filter().Match(item.Payload) {
				continue
			}
			m.delete(item.ID)
			total++
		}
		return nil
	})
	return total, err
}

// delete removes an item by this id with no look
func (m *MemoryHandler) delete(id interface{}) {
	delete(m.items, id)
	// Remove id from id list
	for i, _id := range m.ids {
		if _id == id {
			if i >= len(m.ids)-1 {
				m.ids = m.ids[:i]
			} else {
				m.ids = append(m.ids[:i], m.ids[i+1:]...)
			}
		}
	}
}

// Find items from memory matching the provided lookup
func (m *MemoryHandler) Find(ctx context.Context, lookup rest.Lookup, page, perPage int) (list *rest.ItemList, err *rest.Error) {
	m.RLock()
	defer m.RUnlock()
	err = handleWithLatency(m.Latency, ctx, func() *rest.Error {
		items := []*rest.Item{}
		// Apply filter
		for _, id := range m.ids {
			item := m.items[id]
			if !lookup.Filter().Match(item.Payload) {
				continue
			}
			items = append(items, item)
		}
		// Apply sort
		if len(lookup.Sort()) > 0 {
			s := sortableItems{lookup.Sort(), items}
			sort.Sort(s)
		}
		// Apply pagination
		total := len(items)
		start := (page - 1) * perPage
		end := total
		if perPage > 0 {
			end = start + perPage
			if start > total-1 {
				start = 0
				end = 0
			} else if end > total-1 {
				end = total
			}
		}
		list = &rest.ItemList{total, page, items[start:end]}
		return nil
	})
	return list, err
}
<|endoftext|>