<commit_before>// Package hyperloglog implements the HyperLogLog algorithm for
// cardinality estimation. In English: it counts things. It counts
// things using very small amounts of memory compared to the number of
// objects it is counting.
//
// For a full description of the algorithm, see the paper HyperLogLog:
// the analysis of a near-optimal cardinality estimation algorithm by
// Flajolet, et. al.
package hyperloglog

import (
	"fmt"
	"math"
)

var (
	exp32 = math.Pow(2, 32)
)

// A HyperLogLog is a deterministic cardinality estimator.  This version
// exports its fields so that it is suitable for saving eg. to a database.
type HyperLogLog struct {
	M         uint    // Number of registers
	B         uint32  // Number of bits used to determine register index
	Alpha     float64 // Bias correction constant
	Registers []uint8
}

// Compute bias correction alpha_m.
func getAlpha(m uint) (result float64) {
	switch m {
	case 16:
		result = 0.673
	case 32:
		result = 0.697
	case 64:
		result = 0.709
	default:
		result = 0.7213 / (1.0 + 1.079/float64(m))
	}
	return result
}

// New creates a HyperLogLog with the given number of registers. More
// registers leads to lower error in your estimated count, at the
// expense of memory.
//
// Choose a power of two number of registers, depending on the amount
// of memory you're willing to use and the error you're willing to
// tolerate. Each register uses one byte of memory.
//
// Standard error will be: σ ≈ 1.04 / sqrt(registers)
// The estimates provided by hyperloglog are expected to be within σ, 2σ, 3σ
// of the exact count in respectively 65%, 95%, 99% of all the cases.
func New(registers uint) (*HyperLogLog, error) {
	if (registers & (registers - 1)) != 0 {
		return nil, fmt.Errorf("number of registers %d not a power of two", registers)
	}
	h := &HyperLogLog{}
	h.M = registers
	h.B = uint32(math.Ceil(math.Log2(float64(registers))))
	h.Alpha = getAlpha(registers)
	h.Reset()
	return h, nil
}

// Reset all internal variables and set the count to zero.
func (h *HyperLogLog) Reset() {
	h.Registers = make([]uint8, h.M)
}

// Calculate the position of the leftmost 1-bit.
func rho(val uint32, max uint32) uint8 {
	r := uint32(1)
	for val&0x80000000 == 0 && r <= max {
		r++
		val <<= 1
	}
	return uint8(r)
}

// Add to the count. val should be a 32 bit unsigned integer from a
// good hash function.
func (h *HyperLogLog) Add(val uint32) {
	k := 32 - h.B
	r := rho(val<<h.B, k)
	j := val >> uint(k)
	if r > h.Registers[j] {
		h.Registers[j] = r
	}
}

// Count returns the estimated cardinality.
func (h *HyperLogLog) Count() uint64 {
	sum := 0.0
	m := float64(h.M)
	for _, val := range h.Registers {
		sum += 1.0 / math.Pow(2.0, float64(val))
	}
	estimate := h.Alpha * m * m / sum
	if estimate <= 5.0/2.0*m {
		// Small range correction
		v := 0
		for _, r := range h.Registers {
			if r == 0 {
				v++
			}
		}
		if v > 0 {
			estimate = m * math.Log(m/float64(v))
		}
	} else if estimate > 1.0/30.0*exp32 {
		// Large range correction
		estimate = -exp32 * math.Log(1-estimate/exp32)
	}
	return uint64(estimate)
}

// Merge another HyperLogLog into this one. The number of registers in
// each must be the same.
func (h *HyperLogLog) Merge(other *HyperLogLog) error {
	if h.M != other.M {
		return fmt.Errorf("number of registers doesn't match: %d != %d",
			h.M, other.M)
	}
	for j, r := range other.Registers {
		if r > h.Registers[j] {
			h.Registers[j] = r
		}
	}
	return nil
}
<commit_msg>Reset registers instead of making them<commit_after>// Package hyperloglog implements the HyperLogLog algorithm for
// cardinality estimation. In English: it counts things. It counts
// things using very small amounts of memory compared to the number of
// objects it is counting.
//
// For a full description of the algorithm, see the paper HyperLogLog:
// the analysis of a near-optimal cardinality estimation algorithm by
// Flajolet, et. al.
package hyperloglog

import (
	"fmt"
	"math"
)

var (
	exp32 = math.Pow(2, 32)
)

// A HyperLogLog is a deterministic cardinality estimator.  This version
// exports its fields so that it is suitable for saving eg. to a database.
type HyperLogLog struct {
	M         uint    // Number of registers
	B         uint32  // Number of bits used to determine register index
	Alpha     float64 // Bias correction constant
	Registers []uint8
}

// Compute bias correction alpha_m.
func getAlpha(m uint) (result float64) {
	switch m {
	case 16:
		result = 0.673
	case 32:
		result = 0.697
	case 64:
		result = 0.709
	default:
		result = 0.7213 / (1.0 + 1.079/float64(m))
	}
	return result
}

// New creates a HyperLogLog with the given number of registers. More
// registers leads to lower error in your estimated count, at the
// expense of memory.
//
// Choose a power of two number of registers, depending on the amount
// of memory you're willing to use and the error you're willing to
// tolerate. Each register uses one byte of memory.
//
// Standard error will be: σ ≈ 1.04 / sqrt(registers)
// The estimates provided by hyperloglog are expected to be within σ, 2σ, 3σ
// of the exact count in respectively 65%, 95%, 99% of all the cases.
func New(registers uint) (*HyperLogLog, error) {
	if (registers & (registers - 1)) != 0 {
		return nil, fmt.Errorf("number of registers %d not a power of two", registers)
	}
	h := &HyperLogLog{}
	h.M = registers
	h.B = uint32(math.Ceil(math.Log2(float64(registers))))
	h.Alpha = getAlpha(registers)
	h.Reset()
	return h, nil
}

// Reset all internal variables and set the count to zero.
func (h *HyperLogLog) Reset() {
	for i := range h.Registers {
		h.Registers[i] = 0
	}
}

// Calculate the position of the leftmost 1-bit.
func rho(val uint32, max uint32) uint8 {
	r := uint32(1)
	for val&0x80000000 == 0 && r <= max {
		r++
		val <<= 1
	}
	return uint8(r)
}

// Add to the count. val should be a 32 bit unsigned integer from a
// good hash function.
func (h *HyperLogLog) Add(val uint32) {
	k := 32 - h.B
	r := rho(val<<h.B, k)
	j := val >> uint(k)
	if r > h.Registers[j] {
		h.Registers[j] = r
	}
}

// Count returns the estimated cardinality.
func (h *HyperLogLog) Count() uint64 {
	sum := 0.0
	m := float64(h.M)
	for _, val := range h.Registers {
		sum += 1.0 / math.Pow(2.0, float64(val))
	}
	estimate := h.Alpha * m * m / sum
	if estimate <= 5.0/2.0*m {
		// Small range correction
		v := 0
		for _, r := range h.Registers {
			if r == 0 {
				v++
			}
		}
		if v > 0 {
			estimate = m * math.Log(m/float64(v))
		}
	} else if estimate > 1.0/30.0*exp32 {
		// Large range correction
		estimate = -exp32 * math.Log(1-estimate/exp32)
	}
	return uint64(estimate)
}

// Merge another HyperLogLog into this one. The number of registers in
// each must be the same.
func (h *HyperLogLog) Merge(other *HyperLogLog) error {
	if h.M != other.M {
		return fmt.Errorf("number of registers doesn't match: %d != %d",
			h.M, other.M)
	}
	for j, r := range other.Registers {
		if r > h.Registers[j] {
			h.Registers[j] = r
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bufio"
	stderrors "errors"
	"fmt"
	"io"
	"strings"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/configstore"
	"github.com/juju/juju/juju"
)

var NoEnvironmentError = stderrors.New("no environment specified")
var DoubleEnvironmentError = stderrors.New("you cannot supply both -e and the envname as a positional argument")

// DestroyEnvironmentCommand destroys an environment.
type DestroyEnvironmentCommand struct {
	cmd.CommandBase
	envName   string
	assumeYes bool
	force     bool
}

func (c *DestroyEnvironmentCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "destroy-environment",
		Args:    "<environment name>",
		Purpose: "terminate all machines and other associated resources for an environment",
	}
}

func (c *DestroyEnvironmentCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.assumeYes, "y", false, "Do not ask for confirmation")
	f.BoolVar(&c.assumeYes, "yes", false, "")
	f.BoolVar(&c.force, "force", false, "Forcefully destroy the environment, directly through the environment provider")
	f.StringVar(&c.envName, "e", "", "juju environment to operate in")
	f.StringVar(&c.envName, "environment", "", "juju environment to operate in")
}

func (c *DestroyEnvironmentCommand) Init(args []string) error {
	if c.envName != "" {
		logger.Warningf("-e/--environment flag is deprecated in 1.18, " +
			"please supply environment as a positional parameter")
		// They supplied the -e flag
		if len(args) == 0 {
			// We're happy, we have enough information
			return nil
		}
		// You can't supply -e ENV and ENV as a positional argument
		return DoubleEnvironmentError
	}
	// No -e flag means they must supply the environment positionally
	switch len(args) {
	case 0:
		return NoEnvironmentError
	case 1:
		c.envName = args[0]
		return nil
	default:
		return cmd.CheckEmpty(args[1:])
	}
}

func (c *DestroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) {
	store, err := configstore.Default()
	if err != nil {
		return fmt.Errorf("cannot open environment info storage: %v", err)
	}
	environ, err := environs.NewFromName(c.envName, store)
	if err != nil {
		if environs.IsEmptyConfig(err) {
			// Delete the .jenv file and call it done.
			ctx.Infof("removing empty environment file")
			return environs.DestroyInfo(c.envName, store)
		}
		return err
	}
	if !c.assumeYes {
		fmt.Fprintf(ctx.Stdout, destroyEnvMsg, c.envName, environ.Config().Type())

		scanner := bufio.NewScanner(ctx.Stdin)
		scanner.Scan()
		err := scanner.Err()
		if err != nil && err != io.EOF {
			return fmt.Errorf("Environment destruction aborted: %s", err)
		}
		answer := strings.ToLower(scanner.Text())
		if answer != "y" && answer != "yes" {
			return stderrors.New("environment destruction aborted")
		}
	}
	// If --force is supplied, then don't attempt to use the API.
	// This is necessary to destroy broken environments, where the
	// API server is inaccessible or faulty.
	if !c.force {
		defer func() {
			result = c.ensureUserFriendlyErrorLog(result)
		}()
		apiclient, err := juju.NewAPIClientFromName(c.envName)
		if err != nil {
			return errors.Annotate(err, "cannot connect to API")
		}
		defer apiclient.Close()
		err = apiclient.DestroyEnvironment()
		if cmdErr := processDestroyError(err); cmdErr != nil {
			return cmdErr
		}
	}
	return environs.Destroy(environ, store)
}

// processDestroyError determines how to format error message based on its code.
// Note that CodeNotImplemented errors have not be propogated in previous implementation.
// This behaviour was preserved.
func processDestroyError(err error) error {
	if err == nil {
		return nil
	}
	if params.IsCodeOperationBlocked(err) {
		return err
	}
	if !params.IsCodeNotImplemented(err) {
		return errors.Annotate(err, "destroying environment")
	}
	return nil
}

// ensureUserFriendlyErrorLog ensures that error will be logged and displayed
// in a user-friendly manner with readable and digestable error message.
func (c *DestroyEnvironmentCommand) ensureUserFriendlyErrorLog(err error) error {
	if err == nil {
		return nil
	}
	errMsg := stdFailureMsg
	if params.IsCodeOperationBlocked(err) {
		errMsg = blockedOperationMsg
		err = cmd.ErrSilent
	}
	logger.Errorf(errMsg, c.envName)
	return err
}

var destroyEnvMsg = `
WARNING! this command will destroy the %q environment (type: %s)
This includes all machines, services, data and other resources.

Continue [y/N]? `[1:]

var stdFailureMsg = `failed to destroy environment %q

If the environment is unusable, then you may run

    juju destroy-environment --force

to forcefully destroy the environment. Upon doing so, review
your environment provider console for any resources that need
to be cleaned up. Using force will also by-pass destroy-envrionment block.

`
var blockedOperationMsg = `
destroy-environment operation has been blocked for environment %q.
To remove the block run

    juju unblock destroy-environment

`
<commit_msg>Code readability improvement.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bufio"
	stderrors "errors"
	"fmt"
	"io"
	"strings"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/configstore"
	"github.com/juju/juju/juju"
)

var NoEnvironmentError = stderrors.New("no environment specified")
var DoubleEnvironmentError = stderrors.New("you cannot supply both -e and the envname as a positional argument")

// DestroyEnvironmentCommand destroys an environment.
type DestroyEnvironmentCommand struct {
	cmd.CommandBase
	envName   string
	assumeYes bool
	force     bool
}

func (c *DestroyEnvironmentCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "destroy-environment",
		Args:    "<environment name>",
		Purpose: "terminate all machines and other associated resources for an environment",
	}
}

func (c *DestroyEnvironmentCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.assumeYes, "y", false, "Do not ask for confirmation")
	f.BoolVar(&c.assumeYes, "yes", false, "")
	f.BoolVar(&c.force, "force", false, "Forcefully destroy the environment, directly through the environment provider")
	f.StringVar(&c.envName, "e", "", "juju environment to operate in")
	f.StringVar(&c.envName, "environment", "", "juju environment to operate in")
}

func (c *DestroyEnvironmentCommand) Init(args []string) error {
	if c.envName != "" {
		logger.Warningf("-e/--environment flag is deprecated in 1.18, " +
			"please supply environment as a positional parameter")
		// They supplied the -e flag
		if len(args) == 0 {
			// We're happy, we have enough information
			return nil
		}
		// You can't supply -e ENV and ENV as a positional argument
		return DoubleEnvironmentError
	}
	// No -e flag means they must supply the environment positionally
	switch len(args) {
	case 0:
		return NoEnvironmentError
	case 1:
		c.envName = args[0]
		return nil
	default:
		return cmd.CheckEmpty(args[1:])
	}
}

func (c *DestroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) {
	store, err := configstore.Default()
	if err != nil {
		return fmt.Errorf("cannot open environment info storage: %v", err)
	}
	environ, err := environs.NewFromName(c.envName, store)
	if err != nil {
		if environs.IsEmptyConfig(err) {
			// Delete the .jenv file and call it done.
			ctx.Infof("removing empty environment file")
			return environs.DestroyInfo(c.envName, store)
		}
		return err
	}
	if !c.assumeYes {
		fmt.Fprintf(ctx.Stdout, destroyEnvMsg, c.envName, environ.Config().Type())

		scanner := bufio.NewScanner(ctx.Stdin)
		scanner.Scan()
		err := scanner.Err()
		if err != nil && err != io.EOF {
			return fmt.Errorf("Environment destruction aborted: %s", err)
		}
		answer := strings.ToLower(scanner.Text())
		if answer != "y" && answer != "yes" {
			return stderrors.New("environment destruction aborted")
		}
	}
	// If --force is supplied, then don't attempt to use the API.
	// This is necessary to destroy broken environments, where the
	// API server is inaccessible or faulty.
	if !c.force {
		defer func() {
			result = c.ensureUserFriendlyErrorLog(result)
		}()
		apiclient, err := juju.NewAPIClientFromName(c.envName)
		if err != nil {
			return errors.Annotate(err, "cannot connect to API")
		}
		defer apiclient.Close()
		err = apiclient.DestroyEnvironment()
		if cmdErr := processDestroyError(err); cmdErr != nil {
			return cmdErr
		}
	}
	return environs.Destroy(environ, store)
}

// processDestroyError determines how to format error message based on its code.
// Note that CodeNotImplemented errors have not be propogated in previous implementation.
// This behaviour was preserved.
func processDestroyError(err error) error {
	if err == nil || params.IsCodeNotImplemented(err) {
		return nil
	}
	if params.IsCodeOperationBlocked(err) {
		return err
	}
	return errors.Annotate(err, "destroying environment")
}

// ensureUserFriendlyErrorLog ensures that error will be logged and displayed
// in a user-friendly manner with readable and digestable error message.
func (c *DestroyEnvironmentCommand) ensureUserFriendlyErrorLog(err error) error {
	if err == nil {
		return nil
	}
	errMsg := stdFailureMsg
	if params.IsCodeOperationBlocked(err) {
		errMsg = blockedOperationMsg
		err = cmd.ErrSilent
	}
	logger.Errorf(errMsg, c.envName)
	return err
}

var destroyEnvMsg = `
WARNING! this command will destroy the %q environment (type: %s)
This includes all machines, services, data and other resources.

Continue [y/N]? `[1:]

var stdFailureMsg = `failed to destroy environment %q

If the environment is unusable, then you may run

    juju destroy-environment --force

to forcefully destroy the environment. Upon doing so, review
your environment provider console for any resources that need
to be cleaned up. Using force will also by-pass destroy-envrionment block.

`
var blockedOperationMsg = `
destroy-environment operation has been blocked for environment %q.
To remove the block run

    juju unblock destroy-environment

`
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

// Part of this code is heavily inspired/copied by the following file:
// github.com/docker/machine/commands/env.go

package cmd

import (
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"

	lib_shell "github.com/docker/machine/libmachine/shell"
	"github.com/golang/glog"
	"github.com/spf13/cobra"
	"k8s.io/minikube/pkg/drivers/kic/oci"
	"k8s.io/minikube/pkg/minikube/command"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/driver"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/minikube/mustload"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/shell"
	"k8s.io/minikube/pkg/minikube/sysinit"
)

var dockerEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}", constants.DockerTLSVerifyEnv, constants.DockerHostEnv, constants.DockerCertPathEnv, constants.MinikubeActiveDockerdEnv)

// DockerShellConfig represents the shell config for Docker
type DockerShellConfig struct {
	shell.Config
	DockerCertPath         string
	DockerHost             string
	DockerTLSVerify        string
	MinikubeDockerdProfile string
	NoProxyVar             string
	NoProxyValue           string
}

var (
	noProxy              bool
	dockerUnset          bool
	defaultNoProxyGetter NoProxyGetter
)

// NoProxyGetter gets the no_proxy variable
type NoProxyGetter interface {
	GetNoProxyVar() (string, string)
}

// EnvNoProxyGetter gets the no_proxy variable, using environment
type EnvNoProxyGetter struct{}

// dockerShellCfgSet generates context variables for "docker-env"
func dockerShellCfgSet(ec DockerEnvConfig, envMap map[string]string) *DockerShellConfig {
	profile := ec.profile
	const usgPlz = "To point your shell to minikube's docker-daemon, run:"
	var usgCmd = fmt.Sprintf("minikube -p %s docker-env", profile)
	s := &DockerShellConfig{
		Config: *shell.CfgSet(ec.EnvConfig, usgPlz, usgCmd),
	}
	s.DockerCertPath = envMap[constants.DockerCertPathEnv]
	s.DockerHost = envMap[constants.DockerHostEnv]
	s.DockerTLSVerify = envMap[constants.DockerTLSVerifyEnv]
	s.MinikubeDockerdProfile = envMap[constants.MinikubeActiveDockerdEnv]

	if ec.noProxy {
		noProxyVar, noProxyValue := defaultNoProxyGetter.GetNoProxyVar()

		// add the docker host to the no_proxy list idempotently
		switch {
		case noProxyValue == "":
			noProxyValue = ec.hostIP
		case strings.Contains(noProxyValue, ec.hostIP):
		// ip already in no_proxy list, nothing to do
		default:
			noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ec.hostIP)
		}

		s.NoProxyVar = noProxyVar
		s.NoProxyValue = noProxyValue
	}

	return s
}

// GetNoProxyVar gets the no_proxy var
func (EnvNoProxyGetter) GetNoProxyVar() (string, string) {
	// first check for an existing lower case no_proxy var
	noProxyVar := "no_proxy"
	noProxyValue := os.Getenv("no_proxy")

	// otherwise default to allcaps HTTP_PROXY
	if noProxyValue == "" {
		noProxyVar = "NO_PROXY"
		noProxyValue = os.Getenv("NO_PROXY")
	}
	return noProxyVar, noProxyValue
}

// isDockerActive checks if Docker is active
func isDockerActive(r command.Runner) bool {
	return sysinit.New(r).Active("docker")
}

// dockerEnvCmd represents the docker-env command
var dockerEnvCmd = &cobra.Command{
	Use:   "docker-env",
	Short: "Sets up docker env variables; similar to '$(docker-machine env)'",
	Long:  `Sets up docker env variables; similar to '$(docker-machine env)'.`,
	Run: func(cmd *cobra.Command, args []string) {
		cname := ClusterFlagValue()
		co := mustload.Running(cname)
		driverName := co.CP.Host.DriverName

		if driverName == driver.None {
			exit.UsageT(`'none' driver does not support 'minikube docker-env' command`)
		}

		if co.Config.KubernetesConfig.ContainerRuntime != "docker" {
			exit.WithCodeT(exit.BadUsage, `The docker-env command is only compatible with the "docker" runtime, but this cluster was configured to use the "{{.runtime}}" runtime.`,
				out.V{"runtime": co.Config.KubernetesConfig.ContainerRuntime})
		}

		if ok := isDockerActive(co.CP.Runner); !ok {
			exit.WithCodeT(exit.Unavailable, `The docker service within '{{.name}}' is not active`, out.V{"name": cname})
		}

		sh := shell.EnvConfig{
			Shell: shell.ForceShell,
		}

		var err error
		port := constants.DockerDaemonPort
		if driver.NeedsPortForward(driverName) {
			port, err = oci.ForwardedPort(driverName, cname, port)
			if err != nil {
				exit.WithCodeT(exit.Failure, "Error getting port binding for '{{.driver_name}} driver: {{.error}}", out.V{"driver_name": driverName, "error": err})
			}
		}

		ec := DockerEnvConfig{
			EnvConfig: sh,
			profile:   cname,
			driver:    driverName,
			hostIP:    co.CP.IP.String(),
			port:      port,
			certsDir:  localpath.MakeMiniPath("certs"),
			noProxy:   noProxy,
		}

		if ec.Shell == "" {
			ec.Shell, err = shell.Detect()
			if err != nil {
				// if we can't detect it could be bash. for example github actions
				if err == lib_shell.ErrUnknownShell {
					ec.Shell = "bash"
					glog.Warningf("couldn't detect shell type, will default to bash: %v", err)
				} else {
					exit.WithError("Error detecting shell", err)
				}

			}
		}

		if dockerUnset {
			if err := dockerUnsetScript(ec, os.Stdout); err != nil {
				exit.WithError("Error generating unset output", err)
			}
			return
		}

		if err := dockerSetScript(ec, os.Stdout); err != nil {
			exit.WithError("Error generating set output", err)
		}
	},
}

// DockerEnvConfig encapsulates all external inputs into shell generation for Docker
type DockerEnvConfig struct {
	shell.EnvConfig
	profile  string
	driver   string
	hostIP   string
	port     int
	certsDir string
	noProxy  bool
}

// dockerSetScript writes out a shell-compatible 'docker-env' script
func dockerSetScript(ec DockerEnvConfig, w io.Writer) error {
	envVars := dockerEnvVars(ec)
	return shell.SetScript(ec.EnvConfig, w, dockerEnvTmpl, dockerShellCfgSet(ec, envVars))
}

// dockerSetScript writes out a shell-compatible 'docker-env unset' script
func dockerUnsetScript(ec DockerEnvConfig, w io.Writer) error {
	vars := []string{
		constants.DockerTLSVerifyEnv,
		constants.DockerHostEnv,
		constants.DockerCertPathEnv,
		constants.MinikubeActiveDockerdEnv,
	}

	if ec.noProxy {
		k, _ := defaultNoProxyGetter.GetNoProxyVar()
		if k != "" {
			vars = append(vars, k)
		}
	}

	return shell.UnsetScript(ec.EnvConfig, w, vars)
}

// dockerURL returns a the docker endpoint URL for an ip/port pair.
func dockerURL(ip string, port int) string {
	return fmt.Sprintf("tcp://%s", net.JoinHostPort(ip, strconv.Itoa(port)))
}

// dockerEnvVars gets the necessary docker env variables to allow the use of minikube's docker daemon
func dockerEnvVars(ec DockerEnvConfig) map[string]string {
	env := map[string]string{
		constants.DockerTLSVerifyEnv:       "1",
		constants.DockerHostEnv:            dockerURL(ec.hostIP, ec.port),
		constants.DockerCertPathEnv:        ec.certsDir,
		constants.MinikubeActiveDockerdEnv: ec.profile,
	}

	return env
}

func init() {
	defaultNoProxyGetter = &EnvNoProxyGetter{}
	dockerEnvCmd.Flags().BoolVar(&noProxy, "no-proxy", false, "Add machine IP to NO_PROXY environment variable")
	dockerEnvCmd.Flags().StringVar(&shell.ForceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
	dockerEnvCmd.Flags().BoolVarP(&dockerUnset, "unset", "u", false, "Unset variables instead of setting them")
}
<commit_msg>Revert "docker-env: fall back to bash if can not detect shell."<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

// Part of this code is heavily inspired/copied by the following file:
// github.com/docker/machine/commands/env.go

package cmd

import (
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/spf13/cobra"
	"k8s.io/minikube/pkg/drivers/kic/oci"
	"k8s.io/minikube/pkg/minikube/command"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/driver"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/minikube/mustload"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/shell"
	"k8s.io/minikube/pkg/minikube/sysinit"
)

var dockerEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}", constants.DockerTLSVerifyEnv, constants.DockerHostEnv, constants.DockerCertPathEnv, constants.MinikubeActiveDockerdEnv)

// DockerShellConfig represents the shell config for Docker
type DockerShellConfig struct {
	shell.Config
	DockerCertPath         string
	DockerHost             string
	DockerTLSVerify        string
	MinikubeDockerdProfile string
	NoProxyVar             string
	NoProxyValue           string
}

var (
	noProxy              bool
	dockerUnset          bool
	defaultNoProxyGetter NoProxyGetter
)

// NoProxyGetter gets the no_proxy variable
type NoProxyGetter interface {
	GetNoProxyVar() (string, string)
}

// EnvNoProxyGetter gets the no_proxy variable, using environment
type EnvNoProxyGetter struct{}

// dockerShellCfgSet generates context variables for "docker-env"
func dockerShellCfgSet(ec DockerEnvConfig, envMap map[string]string) *DockerShellConfig {
	profile := ec.profile
	const usgPlz = "To point your shell to minikube's docker-daemon, run:"
	var usgCmd = fmt.Sprintf("minikube -p %s docker-env", profile)
	s := &DockerShellConfig{
		Config: *shell.CfgSet(ec.EnvConfig, usgPlz, usgCmd),
	}
	s.DockerCertPath = envMap[constants.DockerCertPathEnv]
	s.DockerHost = envMap[constants.DockerHostEnv]
	s.DockerTLSVerify = envMap[constants.DockerTLSVerifyEnv]
	s.MinikubeDockerdProfile = envMap[constants.MinikubeActiveDockerdEnv]

	if ec.noProxy {
		noProxyVar, noProxyValue := defaultNoProxyGetter.GetNoProxyVar()

		// add the docker host to the no_proxy list idempotently
		switch {
		case noProxyValue == "":
			noProxyValue = ec.hostIP
		case strings.Contains(noProxyValue, ec.hostIP):
		// ip already in no_proxy list, nothing to do
		default:
			noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ec.hostIP)
		}

		s.NoProxyVar = noProxyVar
		s.NoProxyValue = noProxyValue
	}

	return s
}

// GetNoProxyVar gets the no_proxy var
func (EnvNoProxyGetter) GetNoProxyVar() (string, string) {
	// first check for an existing lower case no_proxy var
	noProxyVar := "no_proxy"
	noProxyValue := os.Getenv("no_proxy")

	// otherwise default to allcaps HTTP_PROXY
	if noProxyValue == "" {
		noProxyVar = "NO_PROXY"
		noProxyValue = os.Getenv("NO_PROXY")
	}
	return noProxyVar, noProxyValue
}

// isDockerActive checks if Docker is active
func isDockerActive(r command.Runner) bool {
	return sysinit.New(r).Active("docker")
}

// dockerEnvCmd represents the docker-env command
var dockerEnvCmd = &cobra.Command{
	Use:   "docker-env",
	Short: "Sets up docker env variables; similar to '$(docker-machine env)'",
	Long:  `Sets up docker env variables; similar to '$(docker-machine env)'.`,
	Run: func(cmd *cobra.Command, args []string) {
		cname := ClusterFlagValue()
		co := mustload.Running(cname)
		driverName := co.CP.Host.DriverName

		if driverName == driver.None {
			exit.UsageT(`'none' driver does not support 'minikube docker-env' command`)
		}

		if co.Config.KubernetesConfig.ContainerRuntime != "docker" {
			exit.WithCodeT(exit.BadUsage, `The docker-env command is only compatible with the "docker" runtime, but this cluster was configured to use the "{{.runtime}}" runtime.`,
				out.V{"runtime": co.Config.KubernetesConfig.ContainerRuntime})
		}

		if ok := isDockerActive(co.CP.Runner); !ok {
			exit.WithCodeT(exit.Unavailable, `The docker service within '{{.name}}' is not active`, out.V{"name": cname})
		}

		sh := shell.EnvConfig{
			Shell: shell.ForceShell,
		}

		var err error
		port := constants.DockerDaemonPort
		if driver.NeedsPortForward(driverName) {
			port, err = oci.ForwardedPort(driverName, cname, port)
			if err != nil {
				exit.WithCodeT(exit.Failure, "Error getting port binding for '{{.driver_name}} driver: {{.error}}", out.V{"driver_name": driverName, "error": err})
			}
		}

		ec := DockerEnvConfig{
			EnvConfig: sh,
			profile:   cname,
			driver:    driverName,
			hostIP:    co.CP.IP.String(),
			port:      port,
			certsDir:  localpath.MakeMiniPath("certs"),
			noProxy:   noProxy,
		}

		if ec.Shell == "" {
			ec.Shell, err = shell.Detect()
			if err != nil {
				exit.WithError("Error detecting shell", err)
			}
		}

		if dockerUnset {
			if err := dockerUnsetScript(ec, os.Stdout); err != nil {
				exit.WithError("Error generating unset output", err)
			}
			return
		}

		if err := dockerSetScript(ec, os.Stdout); err != nil {
			exit.WithError("Error generating set output", err)
		}
	},
}

// DockerEnvConfig encapsulates all external inputs into shell generation for Docker
type DockerEnvConfig struct {
	shell.EnvConfig
	profile  string
	driver   string
	hostIP   string
	port     int
	certsDir string
	noProxy  bool
}

// dockerSetScript writes out a shell-compatible 'docker-env' script
func dockerSetScript(ec DockerEnvConfig, w io.Writer) error {
	envVars := dockerEnvVars(ec)
	return shell.SetScript(ec.EnvConfig, w, dockerEnvTmpl, dockerShellCfgSet(ec, envVars))
}

// dockerSetScript writes out a shell-compatible 'docker-env unset' script
func dockerUnsetScript(ec DockerEnvConfig, w io.Writer) error {
	vars := []string{
		constants.DockerTLSVerifyEnv,
		constants.DockerHostEnv,
		constants.DockerCertPathEnv,
		constants.MinikubeActiveDockerdEnv,
	}

	if ec.noProxy {
		k, _ := defaultNoProxyGetter.GetNoProxyVar()
		if k != "" {
			vars = append(vars, k)
		}
	}

	return shell.UnsetScript(ec.EnvConfig, w, vars)
}

// dockerURL returns a the docker endpoint URL for an ip/port pair.
func dockerURL(ip string, port int) string {
	return fmt.Sprintf("tcp://%s", net.JoinHostPort(ip, strconv.Itoa(port)))
}

// dockerEnvVars gets the necessary docker env variables to allow the use of minikube's docker daemon
func dockerEnvVars(ec DockerEnvConfig) map[string]string {
	env := map[string]string{
		constants.DockerTLSVerifyEnv:       "1",
		constants.DockerHostEnv:            dockerURL(ec.hostIP, ec.port),
		constants.DockerCertPathEnv:        ec.certsDir,
		constants.MinikubeActiveDockerdEnv: ec.profile,
	}

	return env
}

func init() {
	defaultNoProxyGetter = &EnvNoProxyGetter{}
	dockerEnvCmd.Flags().BoolVar(&noProxy, "no-proxy", false, "Add machine IP to NO_PROXY environment variable")
	dockerEnvCmd.Flags().StringVar(&shell.ForceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
	dockerEnvCmd.Flags().BoolVarP(&dockerUnset, "unset", "u", false, "Unset variables instead of setting them")
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"os"
	"time"

	"code.cloudfoundry.org/debugserver"
	"code.cloudfoundry.org/durationjson"
	"code.cloudfoundry.org/lager/lagerflags"
)

type SSHProxyConfig struct {
	lagerflags.LagerConfig
	debugserver.DebugServerConfig
	Address                   string                `json:"address,omitempty"`
	HealthCheckAddress        string                `json:"health_check_address,omitempty"`
	HostKey                   string                `json:"host_key"`
	BBSAddress                string                `json:"bbs_address"`
	CCAPIURL                  string                `json:"cc_api_url"`
	UAATokenURL               string                `json:"uaa_token_url"`
	UAAPassword               string                `json:"uaa_password"`
	UAAUsername               string                `json:"uaa_username"`
	UAACACert                 string                `json:"uaa_ca_cert"`
	SkipCertVerify            bool                  `json:"skip_cert_verify"`
	DropsondePort             int                   `json:"dropsonde_port,omitempty"`
	EnableCFAuth              bool                  `json:"enable_cf_auth"`
	EnableDiegoAuth           bool                  `json:"enable_diego_auth"`
	DiegoCredentials          string                `json:"diego_credentials"`
	BBSCACert                 string                `json:"bbs_ca_cert"`
	BBSClientCert             string                `json:"bbs_client_cert"`
	BBSClientKey              string                `json:"bbs_client_key"`
	BBSClientSessionCacheSize int                   `json:"bbs_client_session_cache_size"`
	BBSMaxIdleConnsPerHost    int                   `json:"bbs_max_idle_conns_per_host"`
	ConsulCluster             string                `json:"consul_cluster"`
	AllowedCiphers            string                `json:"allowed_ciphers"`
	AllowedMACs               string                `json:"allowed_macs"`
	AllowedKeyExchanges       string                `json:"allowed_key_exchanges"`
	CommunicationTimeout      durationjson.Duration `json:"communication_timeout,omitempty"`
}

func defaultConfig() SSHProxyConfig {
	return SSHProxyConfig{
		Address:              ":2222",
		HealthCheckAddress:   ":2223",
		CommunicationTimeout: durationjson.Duration(10 * time.Second),
		DropsondePort:        3457,
		LagerConfig:          lagerflags.DefaultLagerConfig(),
	}
}

func NewSSHProxyConfig(configPath string) (SSHProxyConfig, error) {
	proxyConfig := defaultConfig()

	configFile, err := os.Open(configPath)
	if err != nil {
		return SSHProxyConfig{}, err
	}
	decoder := json.NewDecoder(configFile)

	err = decoder.Decode(&proxyConfig)
	if err != nil {
		return SSHProxyConfig{}, err
	}

	return proxyConfig, nil
}
<commit_msg>Close config file after reading.<commit_after>package config

import (
	"encoding/json"
	"os"
	"time"

	"code.cloudfoundry.org/debugserver"
	"code.cloudfoundry.org/durationjson"
	"code.cloudfoundry.org/lager/lagerflags"
)

type SSHProxyConfig struct {
	lagerflags.LagerConfig
	debugserver.DebugServerConfig
	Address                   string                `json:"address,omitempty"`
	HealthCheckAddress        string                `json:"health_check_address,omitempty"`
	HostKey                   string                `json:"host_key"`
	BBSAddress                string                `json:"bbs_address"`
	CCAPIURL                  string                `json:"cc_api_url"`
	UAATokenURL               string                `json:"uaa_token_url"`
	UAAPassword               string                `json:"uaa_password"`
	UAAUsername               string                `json:"uaa_username"`
	UAACACert                 string                `json:"uaa_ca_cert"`
	SkipCertVerify            bool                  `json:"skip_cert_verify"`
	DropsondePort             int                   `json:"dropsonde_port,omitempty"`
	EnableCFAuth              bool                  `json:"enable_cf_auth"`
	EnableDiegoAuth           bool                  `json:"enable_diego_auth"`
	DiegoCredentials          string                `json:"diego_credentials"`
	BBSCACert                 string                `json:"bbs_ca_cert"`
	BBSClientCert             string                `json:"bbs_client_cert"`
	BBSClientKey              string                `json:"bbs_client_key"`
	BBSClientSessionCacheSize int                   `json:"bbs_client_session_cache_size"`
	BBSMaxIdleConnsPerHost    int                   `json:"bbs_max_idle_conns_per_host"`
	ConsulCluster             string                `json:"consul_cluster"`
	AllowedCiphers            string                `json:"allowed_ciphers"`
	AllowedMACs               string                `json:"allowed_macs"`
	AllowedKeyExchanges       string                `json:"allowed_key_exchanges"`
	CommunicationTimeout      durationjson.Duration `json:"communication_timeout,omitempty"`
}

func defaultConfig() SSHProxyConfig {
	return SSHProxyConfig{
		Address:              ":2222",
		HealthCheckAddress:   ":2223",
		CommunicationTimeout: durationjson.Duration(10 * time.Second),
		DropsondePort:        3457,
		LagerConfig:          lagerflags.DefaultLagerConfig(),
	}
}

func NewSSHProxyConfig(configPath string) (SSHProxyConfig, error) {
	proxyConfig := defaultConfig()

	configFile, err := os.Open(configPath)
	if err != nil {
		return SSHProxyConfig{}, err
	}

	defer configFile.Close()

	decoder := json.NewDecoder(configFile)

	err = decoder.Decode(&proxyConfig)
	if err != nil {
		return SSHProxyConfig{}, err
	}

	return proxyConfig, nil
}
<|endoftext|>


<commit_before>package telegram

import (
	"encoding/base64"
	"fmt"
	"strconv"
	"strings"

	"github.com/everpcpc/yubari/elasticsearch"

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
)

var (
	page = 5
)

func onSearch(b *Bot, message *tgbotapi.Message) {
	idx := getIndex(message)
	q := message.CommandArguments()

	exists, err := elasticsearch.CheckIndexExist(b.es, idx)
	if err != nil {
		b.logger.Errorf("check es index exists error: %+v", err)
		return
	}
	if !exists {
		msg := tgbotapi.NewMessage(message.Chat.ID, "还没有启用哦")
		msg.ReplyToMessageID = message.MessageID
		b.Client.Send(msg)
	}
	res, err := elasticsearch.SearchMessage(b.es, idx, q, 0, page)
	if err != nil {
		b.logger.Errorf("es search error: %+v", err)
		return
	}

	msg := tgbotapi.NewMessage(message.Chat.ID, buildSearchResponse(res, 0))
	msg.ParseMode = tgbotapi.ModeHTML
	msg.ReplyMarkup = buildSearchResponseButton(res, 0, q)

	_, err = b.Client.Send(msg)
	if err != nil {
		b.logger.Errorf("%+v", err)
	}
}

func getIndex(message *tgbotapi.Message) string {
	return fmt.Sprintf("%s-%d", message.Chat.Type, message.Chat.ID)
}

func buildSearchResponse(res *elasticsearch.SearchResponse, from int) string {
	total := res.Hits.Total.Value
	respond := fmt.Sprintf("(%d) results: \n", total)
	for i, hit := range res.Hits.Hits {
		var content string
		if len(hit.Highlight.Content) == 0 {
			content = hit.Source.Content[:15]
		} else {
			content = hit.Highlight.Content[0]
		}
		// TODO:(everpcpc) send link to target message
		// respond += fmt.Sprintf("%d. %s\n", from+i+1, hit.Source.MessageID, content)
		respond += fmt.Sprintf("%d. %s\n", from+i+1, content)
	}
	respond += fmt.Sprintf("duration %.3fs", float64(res.Took)/1000)
	return respond
}

func buildSearchResponseButton(res *elasticsearch.SearchResponse, from int, q string) tgbotapi.InlineKeyboardMarkup {
	total := res.Hits.Total.Value
	if total == 0 {
		total = 1
	}
	encodedQ := base64.StdEncoding.EncodeToString([]byte(q))
	row := tgbotapi.NewInlineKeyboardRow(
		tgbotapi.NewInlineKeyboardButtonData("⬅", fmt.Sprintf("search:%d:%s", max(int64(from-5), 0), encodedQ)),
		tgbotapi.NewInlineKeyboardButtonData("❎", fmt.Sprintf("search:%d:%s", -1, encodedQ)),
		tgbotapi.NewInlineKeyboardButtonData("➡", fmt.Sprintf("search:%d:%s", min(int64(from+5), int64(total-1)), encodedQ)),
	)
	return tgbotapi.NewInlineKeyboardMarkup(row)
}

func onReactionSearch(b *Bot, callbackQuery *tgbotapi.CallbackQuery) {
	token := strings.Split(callbackQuery.Data, ":")
	if len(token) != 3 {
		b.logger.Errorf("react data error: %s", callbackQuery.Data)
		return
	}

	from, err := strconv.ParseInt(token[1], 10, 0)
	if err != nil {
		b.logger.Errorf("react search from error: %s", callbackQuery.Data)
	}
	if from < 0 {
		delMsg := tgbotapi.DeleteMessageConfig{
			ChatID:    callbackQuery.Message.Chat.ID,
			MessageID: callbackQuery.Message.MessageID,
		}
		_, err = b.Client.DeleteMessage(delMsg)
		if err != nil {
			b.logger.Errorf("delete search error: %s", callbackQuery.Data)
		}
		return
	}

	q, err := base64.StdEncoding.DecodeString(token[2])
	if err != nil {
		b.logger.Errorf("react search q error: %s", callbackQuery.Data)
		return
	}

	idx := getIndex(callbackQuery.Message)

	res, err := elasticsearch.SearchMessage(b.es, idx, string(q), int(from), page)
	if err != nil {
		b.logger.Errorf("es search error: %+v", err)
		return
	}

	msg := tgbotapi.NewEditMessageText(
		callbackQuery.Message.Chat.ID,
		callbackQuery.Message.MessageID,
		buildSearchResponse(res, int(from)),
	)
	button := buildSearchResponseButton(res, int(from), string(q))
	msg.ParseMode = tgbotapi.ModeHTML
	msg.ReplyMarkup = &button

	_, err = b.Client.Send(msg)
	if err != nil {
		b.logger.Errorf("search reaction reply error: %+v", err)
	}

	callbackMsg := tgbotapi.NewCallback(callbackQuery.ID, "OK")
	_, err = b.Client.AnswerCallbackQuery(callbackMsg)
	if err != nil {
		b.logger.Errorf("%+v", err)
	}
}
<commit_msg>reject empty query<commit_after>package telegram

import (
	"encoding/base64"
	"fmt"
	"strconv"
	"strings"

	"github.com/everpcpc/yubari/elasticsearch"

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
)

var (
	page = 5
)

func onSearch(b *Bot, message *tgbotapi.Message) {
	idx := getIndex(message)
	q := message.CommandArguments()
	q = strings.TrimSpace(q)
	if q == "" {
		msg := tgbotapi.NewMessage(message.Chat.ID, "直接发送你要搜索的内容即可。搜索支持 Lucene 语法")
		msg.ReplyToMessageID = message.MessageID
		b.Client.Send(msg)
	}

	exists, err := elasticsearch.CheckIndexExist(b.es, idx)
	if err != nil {
		b.logger.Errorf("check es index exists error: %+v", err)
		return
	}
	if !exists {
		msg := tgbotapi.NewMessage(message.Chat.ID, "还没有启用哦")
		msg.ReplyToMessageID = message.MessageID
		b.Client.Send(msg)
	}
	res, err := elasticsearch.SearchMessage(b.es, idx, q, 0, page)
	if err != nil {
		b.logger.Errorf("es search error: %+v", err)
		return
	}

	msg := tgbotapi.NewMessage(message.Chat.ID, buildSearchResponse(res, 0))
	msg.ParseMode = tgbotapi.ModeHTML
	msg.ReplyMarkup = buildSearchResponseButton(res, 0, q)

	_, err = b.Client.Send(msg)
	if err != nil {
		b.logger.Errorf("%+v", err)
	}
}

func getIndex(message *tgbotapi.Message) string {
	return fmt.Sprintf("%s-%d", message.Chat.Type, message.Chat.ID)
}

func buildSearchResponse(res *elasticsearch.SearchResponse, from int) string {
	total := res.Hits.Total.Value
	respond := fmt.Sprintf("(%d) results: \n", total)
	for i, hit := range res.Hits.Hits {
		var content string
		if len(hit.Highlight.Content) == 0 {
			content = hit.Source.Content[:15]
		} else {
			content = hit.Highlight.Content[0]
		}
		// TODO:(everpcpc) send link to target message
		// respond += fmt.Sprintf("%d. %s\n", from+i+1, hit.Source.MessageID, content)
		respond += fmt.Sprintf("%d. %s\n", from+i+1, content)
	}
	respond += fmt.Sprintf("duration %.3fs", float64(res.Took)/1000)
	return respond
}

func buildSearchResponseButton(res *elasticsearch.SearchResponse, from int, q string) tgbotapi.InlineKeyboardMarkup {
	total := res.Hits.Total.Value
	if total == 0 {
		total = 1
	}
	encodedQ := base64.StdEncoding.EncodeToString([]byte(q))
	row := tgbotapi.NewInlineKeyboardRow(
		tgbotapi.NewInlineKeyboardButtonData("⬅", fmt.Sprintf("search:%d:%s", max(int64(from-5), 0), encodedQ)),
		tgbotapi.NewInlineKeyboardButtonData("❎", fmt.Sprintf("search:%d:%s", -1, encodedQ)),
		tgbotapi.NewInlineKeyboardButtonData("➡", fmt.Sprintf("search:%d:%s", min(int64(from+5), int64(total-1)), encodedQ)),
	)
	return tgbotapi.NewInlineKeyboardMarkup(row)
}

func onReactionSearch(b *Bot, callbackQuery *tgbotapi.CallbackQuery) {
	token := strings.Split(callbackQuery.Data, ":")
	if len(token) != 3 {
		b.logger.Errorf("illegal react data: %s", callbackQuery.Data)
		return
	}

	from, err := strconv.ParseInt(token[1], 10, 0)
	if err != nil {
		b.logger.Errorf("illegal react search from: %s", callbackQuery.Data)
		return
	}
	q, err := base64.StdEncoding.DecodeString(token[2])
	if err != nil {
		b.logger.Errorf("illegal react search q: %s", callbackQuery.Data)
		return
	}

	var reply string
	defer func() {
		callbackMsg := tgbotapi.NewCallback(callbackQuery.ID, reply)
		_, err = b.Client.AnswerCallbackQuery(callbackMsg)
		if err != nil {
			b.logger.Errorf("answer callback error: %+v", err)
		}
	}()

	if from < 0 {
		delMsg := tgbotapi.DeleteMessageConfig{
			ChatID:    callbackQuery.Message.Chat.ID,
			MessageID: callbackQuery.Message.MessageID,
		}
		_, err = b.Client.DeleteMessage(delMsg)
		if err != nil {
			reply = fmt.Sprintf("delete error: %+v", err)
		} else {
			reply = "delete OK"
		}
		return
	}

	idx := getIndex(callbackQuery.Message)

	res, err := elasticsearch.SearchMessage(b.es, idx, string(q), int(from), page)
	if err != nil {
		reply = fmt.Sprintf("search error: %+v", err)
		return
	}

	msg := tgbotapi.NewEditMessageText(
		callbackQuery.Message.Chat.ID,
		callbackQuery.Message.MessageID,
		buildSearchResponse(res, int(from)),
	)
	button := buildSearchResponseButton(res, int(from), string(q))
	msg.ParseMode = tgbotapi.ModeHTML
	msg.ReplyMarkup = &button

	_, err = b.Client.Send(msg)
	if err != nil {
		reply = fmt.Sprintf("update result error: %+v", err)
	} else {
		reply = "OK"
	}
}
<|endoftext|>


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

package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/codegangsta/cli"
)

func testContext(force bool) *cli.Context {
	set := flag.NewFlagSet("test", 0)
	set.Bool("force", force, "doc")
	return cli.NewContext(nil, set, nil)
}

func TestImagesCmdFail(t *testing.T) {
	dockerClient = &mockClient{listFail: true}

	buffer := bytes.NewBuffer([]byte{})
	log.SetOutput(buffer)
	imagesCmd(testContext(false))

	lines := strings.Split(buffer.String(), "\n")
	if len(lines) != 2 {
		t.Fatal("Wrong number of lines")
	}
	if !strings.Contains(buffer.String(), "List Failed") {
		t.Fatal("It should've logged something expected\n")
	}
}

func TestImagesListEmpty(t *testing.T) {
	dockerClient = &mockClient{listEmpty: true}

	temp, err := ioutil.TempFile("", "zypper")
	if err != nil {
		t.Fatal("Could not setup test")
	}
	original := os.Stdout
	os.Stdout = temp

	imagesCmd(testContext(false))
	b, err := ioutil.ReadFile(temp.Name())
	if err != nil {
		t.Fatal("Could not read temporary file")
	}

	_ = temp.Close()
	_ = os.Remove(temp.Name())
	os.Stdout = original

	lines := strings.Split(string(b), "\n")
	if len(lines) != 2 {
		t.Fatal("Wrong number of lines")
	}
	if !strings.HasPrefix(lines[0], "REPOSITORY") {
		t.Fatal("Wrong contents")
	}
}

func TestImagesListOk(t *testing.T) {
	dockerClient = &mockClient{waitSleep: 100 * time.Millisecond}

	buffer := bytes.NewBuffer([]byte{})
	log.SetOutput(buffer)
	temp, err := ioutil.TempFile("", "zypper")
	if err != nil {
		t.Fatal("Could not setup test")
	}
	original := os.Stdout
	os.Stdout = temp

	imagesCmd(testContext(false))
	b, err := ioutil.ReadFile(temp.Name())
	if err != nil {
		os.Stdout = original
		t.Fatal("Could not read temporary file")
	}

	_ = temp.Close()
	_ = os.Remove(temp.Name())
	os.Stdout = original

	lines := strings.Split(string(b), "\n")
	if len(lines) != 4 {
		t.Fatal("Wrong number of lines")
	}
	if !strings.HasPrefix(lines[0], "REPOSITORY") {
		t.Fatal("Wrong contents")
	}
	str := "opensuse            latest              1                   Less than a second ago   254.5 MB"
	if lines[1] != str {
		t.Fatal("Wrong contents")
	}
	str = "opensuse            13.2                2                   Less than a second ago   254.5 MB"
	if lines[2] != str {
		t.Fatal("Wrong contents")
	}
}

func TestImagesForce(t *testing.T) {
	dockerClient = &mockClient{waitSleep: 100 * time.Millisecond}

	temp, err := ioutil.TempFile("", "zypper")
	if err != nil {
		t.Fatal("Could not setup test")
	}
	original := os.Stdout
	os.Stdout = temp

	cache := os.Getenv("XDG_CACHE_HOME")
	abs, _ := filepath.Abs(".")
	test := filepath.Join(abs, "test")

	defer func() {
		_ = os.Setenv("XDG_CACHE_HOME", cache)
		_ = os.Remove(filepath.Join(test, cacheName))
	}()
	_ = os.Setenv("XDG_CACHE_HOME", test)

	// Dump some dummy value.
	cd := getCacheFile()
	cd.Suse = []string{"1234"}
	cd.flush()

	// Check that they are really written there.
	cd = getCacheFile()
	if len(cd.Suse) != 1 || cd.Suse[0] != "1234" {
		t.Fatal("Unexpected value")
	}

	// Luke, use the force!
	imagesCmd(testContext(true))
	cd = getCacheFile()

	if !cd.Valid {
		t.Fatal("It should be valid")
	}
	for i, v := range []string{"1", "2", "4"} {
		if cd.Suse[i] != v {
			t.Fatal("Unexpected value")
		}
	}
	if len(cd.Other) != 1 || cd.Other[0] != "3" {
		t.Fatal("Unexpected value")
	}

	_ = temp.Close()
	_ = os.Remove(temp.Name())
	os.Stdout = original
}
<commit_msg>Fixed tests<commit_after>// Copyright (c) 2015 SUSE LLC. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/codegangsta/cli"
)

func testContext(force bool) *cli.Context {
	set := flag.NewFlagSet("test", 0)
	set.Bool("force", force, "doc")
	return cli.NewContext(nil, set, nil)
}

func TestImagesCmdFail(t *testing.T) {
	dockerClient = &mockClient{listFail: true}

	buffer := bytes.NewBuffer([]byte{})
	log.SetOutput(buffer)
	imagesCmd(testContext(false))

	lines := strings.Split(buffer.String(), "\n")
	if len(lines) != 2 {
		t.Fatal("Wrong number of lines")
	}
	if !strings.Contains(buffer.String(), "List Failed") {
		t.Fatal("It should've logged something expected\n")
	}
}

func TestImagesListEmpty(t *testing.T) {
	dockerClient = &mockClient{listEmpty: true}

	temp, err := ioutil.TempFile("", "zypper")
	if err != nil {
		t.Fatal("Could not setup test")
	}
	original := os.Stdout
	os.Stdout = temp

	imagesCmd(testContext(false))
	b, err := ioutil.ReadFile(temp.Name())
	if err != nil {
		t.Fatal("Could not read temporary file")
	}

	_ = temp.Close()
	_ = os.Remove(temp.Name())
	os.Stdout = original

	lines := strings.Split(string(b), "\n")
	if len(lines) != 3 {
		t.Fatal("Wrong number of lines")
	}
	if !strings.HasPrefix(lines[1], "REPOSITORY") {
		t.Fatal("Wrong contents")
	}
}

func TestImagesListOk(t *testing.T) {
	dockerClient = &mockClient{waitSleep: 100 * time.Millisecond}

	buffer := bytes.NewBuffer([]byte{})
	log.SetOutput(buffer)
	temp, err := ioutil.TempFile("", "zypper")
	if err != nil {
		t.Fatal("Could not setup test")
	}
	original := os.Stdout
	os.Stdout = temp

	imagesCmd(testContext(false))
	b, err := ioutil.ReadFile(temp.Name())
	if err != nil {
		os.Stdout = original
		t.Fatal("Could not read temporary file")
	}

	_ = temp.Close()
	_ = os.Remove(temp.Name())
	os.Stdout = original

	lines := strings.Split(string(b), "\n")
	if len(lines) != 5 {
		t.Fatal("Wrong number of lines")
	}
	if !strings.HasPrefix(lines[1], "REPOSITORY") {
		t.Fatal("Wrong contents")
	}
	str := "opensuse            latest              1                   Less than a second ago   254.5 MB"
	if lines[2] != str {
		t.Fatal("Wrong contents")
	}
	str = "opensuse            13.2                2                   Less than a second ago   254.5 MB"
	if lines[3] != str {
		t.Fatal("Wrong contents")
	}
}

func TestImagesForce(t *testing.T) {
	dockerClient = &mockClient{waitSleep: 100 * time.Millisecond}

	temp, err := ioutil.TempFile("", "zypper")
	if err != nil {
		t.Fatal("Could not setup test")
	}
	original := os.Stdout
	os.Stdout = temp

	cache := os.Getenv("XDG_CACHE_HOME")
	abs, _ := filepath.Abs(".")
	test := filepath.Join(abs, "test")

	defer func() {
		_ = os.Setenv("XDG_CACHE_HOME", cache)
		_ = os.Remove(filepath.Join(test, cacheName))
	}()
	_ = os.Setenv("XDG_CACHE_HOME", test)

	// Dump some dummy value.
	cd := getCacheFile()
	cd.Suse = []string{"1234"}
	cd.flush()

	// Check that they are really written there.
	cd = getCacheFile()
	if len(cd.Suse) != 1 || cd.Suse[0] != "1234" {
		t.Fatal("Unexpected value")
	}

	// Luke, use the force!
	imagesCmd(testContext(true))
	cd = getCacheFile()

	if !cd.Valid {
		t.Fatal("It should be valid")
	}
	for i, v := range []string{"1", "2", "4"} {
		if cd.Suse[i] != v {
			t.Fatal("Unexpected value")
		}
	}
	if len(cd.Other) != 1 || cd.Other[0] != "3" {
		t.Fatal("Unexpected value")
	}

	_ = temp.Close()
	_ = os.Remove(temp.Name())
	os.Stdout = original
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package util

import (
	"errors"
	"strconv"
	"strings"

	"github.com/TheThingsNetwork/ttn/core/account"
)

func ParseLocation(locationStr string) (*account.Location, error) {
	parts := strings.Split(locationStr, ",")
	if len(parts) != 2 {
		return nil, errors.New("Location should be on the <latitude>,<longitude> format")
	}

	lat, err := strconv.ParseFloat(parts[0], 64)
	if err != nil {
		return nil, err
	}

	if lat < 0 || lat > 90 {
		return nil, errors.New("Latitude should be in range [0, 90]")
	}

	lng, err := strconv.ParseFloat(parts[1], 64)
	if err != nil {
		return nil, err
	}

	if lng < 0 || lng > 180 {
		return nil, errors.New("Longitude should be in range [0, 180]")
	}

	return &account.Location{
		Latitude:  lat,
		Longitude: lng,
	}, nil
}
<commit_msg>Correct latittude longitude ranges<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package util

import (
	"errors"
	"strconv"
	"strings"

	"github.com/TheThingsNetwork/ttn/core/account"
)

func ParseLocation(locationStr string) (*account.Location, error) {
	parts := strings.Split(locationStr, ",")
	if len(parts) != 2 {
		return nil, errors.New("Location should be on the <latitude>,<longitude> format")
	}

	lat, err := strconv.ParseFloat(parts[0], 64)
	if err != nil {
		return nil, err
	}

	if lat < -90 || lat > 90 {
		return nil, errors.New("Latitude should be in range [90, 90]")
	}

	lng, err := strconv.ParseFloat(parts[1], 64)
	if err != nil {
		return nil, err
	}

	if lng < -180 || lng > 180 {
		return nil, errors.New("Longitude should be in range [-180, 180]")
	}

	return &account.Location{
		Latitude:  lat,
		Longitude: lng,
	}, nil
}
<|endoftext|>


<commit_before>package requests

import (
	"errors"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
)

var multipartMem int64 = 2 << 20 * 10

// MultipartMem returns the current memory limit for multipart form
// data.
func MultipartMem() int64 {
	return multipartMem
}

// SetMultipartMem sets the memory limit for multipart form data.
func SetMultipartMem(mem int64) {
	multipartMem = mem
}

// Body returns the result of ParseBody for this request.  ParseBody
// will only be called the first time Body is called; subsequent calls
// will return the same value as the first call.
func (request *Request) Body() (interface{}, error) {
	if request.body == nil {
		body, err := ParseBody(request.httpRequest)
		if err != nil {
			return nil, err
		}
		request.body = body
	}
	return request.body, nil
}

// Params returns the result of ParseParams for this request.
// ParseParams will only be called the first time Params is called;
// subsequent calls will return the same value as the first call.
func (request *Request) Params() (map[string]interface{}, error) {
	if request.params == nil {
		body, err := request.Body()
		if err != nil {
			return nil, err
		}
		params, err := convertToParams(body)
		if err != nil {
			return nil, err
		}
		request.params = params
	}
	return request.params, nil
}

// ParseBody locates a codec matching the request's Content-Type
// header, then Unmarshals the request's body to an interface{} type.
// The resulting type is unpredictable and will be heavily based on
// the actual data in the request.
//
// There are two exceptions to the above, where no codec lookup is
// used:
//
// * application/x-www-form-urlencoded (or an empty Content-Type)
//   * The return value for this type will be the same as
//   "net/http".Request.PostForm after calling ParseForm.
// * multipart/form-data
//   * The return value for this type will be the same as
//   "net/http".Request.MultipartForm after calling
//   ParseMultipartForm.
func ParseBody(request *http.Request) (interface{}, error) {
	// Handle form data types
	contentType, _, err := mime.ParseMediaType(request.Header.Get("Content-Type"))
	if err != nil {
		return nil, err
	}
	switch contentType {
	case "application/x-www-form-urlencoded", "":
		if err := request.ParseForm(); err != nil {
			return nil, err
		}
		return request.PostForm, nil
	case "multipart/form-data":
		if err := request.ParseMultipartForm(MultipartMem()); err != nil {
			return nil, err
		}
		return request.MultipartForm, nil
	}

	// Now the general case
	codec, err := Codecs().GetCodec(contentType)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(request.Body)
	if err != nil {
		return nil, err
	}
	var response interface{}
	if err = codec.Unmarshal(body, &response); err != nil {
		return nil, err
	}
	return response, nil
}

// ParseParams returns a map[string]interface{} of values found in a
// request body.  In most cases, this is the equivalent of
// ParseBody(request).(map[string]interface{}).  However, there are
// two exceptions:
//
// * application/x-www-form-urlencoded (or an empty Content-Type)
//   * Each value in request.PostForm that has a len() of 1 will be
//   stored instead as the zeroeth index of the value.
// * multipart/form-data
//   * In addition to the above, files will be stored at the same
//   level as values.  Each value in the resulting map could contain
//   both string and *"mime/multipart".FileHeader values.
//
// The resulting code to parse a form may look like the following:
//
//     params, err := ParseParams(request)
//     // handle err
//     for key, value := range params {
//         switch v := value.(type) {
//         case string:
//             // Do stuff with single string value
//         case *multipart.FileHeader:
//             // Do stuff with single file
//         case []interface{}:
//             // There were multiple string and/or file values at
//             // this key, so deal with that.
//         }
//     }
//
// To be honest, I *hate* dealing with urlencoded or multipart form
// data.  The ParseParams function here is designed solely to unify
// form data behavior with json and other types, so that I don't need
// specialized code to handle all the []string and
// []*multipart.FileHeader values when *most* of them are length 1.
func ParseParams(request *http.Request) (map[string]interface{}, error) {
	if request.Body == nil {
		return nil, nil
	}
	body, err := ParseBody(request)
	if err != nil {
		return nil, err
	}
	return convertToParams(body)
}

func convertToParams(body interface{}) (map[string]interface{}, error) {
	switch body.(type) {
	case url.Values, *multipart.Form:
		return convertForm(body), nil
	}
	m, ok := body.(map[string]interface{})
	if !ok {
		return nil, errors.New("The unmarshalled body is not of type map[string]interface{} " +
			"and cannot be converted to params")
	}
	return m, nil
}

func convertForm(body interface{}) map[string]interface{} {
	var (
		params = make(map[string]interface{})
		values map[string][]string
		files  map[string][]*multipart.FileHeader
	)
	switch form := body.(type) {
	case url.Values:
		values = map[string][]string(form)
	case *multipart.Form:
		values = form.Value
		files = form.File
	}
	for key, valueList := range values {
		if len(valueList) == 1 {
			params[key] = valueList[0]
		} else {
			values := make([]interface{}, len(valueList))
			for idx, value := range valueList {
				values[idx] = value
			}
			params[key] = values
		}
	}
	for key, fileList := range files {
		param, ok := params[key]
		if ok || len(fileList) > 1 {
			values := make([]interface{}, 0, len(params)+len(fileList))
			switch params := param.(type) {
			case []interface{}:
				values = append(values, params...)
			default:
				values = append(values, param)
			}
			for _, file := range fileList {
				values = append(values, file)
			}
			param = values
		} else {
			param = fileList[0]
		}
		params[key] = param
	}
	return params
}
<commit_msg>Documentation update, part 3<commit_after>package requests

import (
	"errors"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
)

var multipartMem int64 = 2 << 20 * 10

// MultipartMem returns the current memory limit for multipart form
// data.
func MultipartMem() int64 {
	return multipartMem
}

// SetMultipartMem sets the memory limit for multipart form data.
func SetMultipartMem(mem int64) {
	multipartMem = mem
}

// Body returns the result of ParseBody for this request.  ParseBody
// will only be called the first time Body is called; subsequent calls
// will return the same value as the first call.
func (request *Request) Body() (interface{}, error) {
	if request.body == nil {
		body, err := ParseBody(request.httpRequest)
		if err != nil {
			return nil, err
		}
		request.body = body
	}
	return request.body, nil
}

// Params returns the result of ParseParams for this request.
// ParseParams will only be called the first time Params is called;
// subsequent calls will return the same value as the first call.
func (request *Request) Params() (map[string]interface{}, error) {
	if request.params == nil {
		body, err := request.Body()
		if err != nil {
			return nil, err
		}
		params, err := convertToParams(body)
		if err != nil {
			return nil, err
		}
		request.params = params
	}
	return request.params, nil
}

// ParseBody locates a codec matching the request's Content-Type
// header, then Unmarshals the request's body to an interface{} type.
// The resulting type is unpredictable and will be heavily based on
// the actual data in the request.
//
// There are two exceptions to the above, where no codec lookup is
// used:
//
// * application/x-www-form-urlencoded (or an empty Content-Type)
//
// ** The return value for this type will be the same as
//    "net/http".Request.PostForm after calling ParseForm.
//
// * multipart/form-data
//
// ** The return value for this type will be the same as
//    "net/http".Request.MultipartForm after calling
//    ParseMultipartForm.
func ParseBody(request *http.Request) (interface{}, error) {
	// Handle form data types
	contentType, _, err := mime.ParseMediaType(request.Header.Get("Content-Type"))
	if err != nil {
		return nil, err
	}
	switch contentType {
	case "application/x-www-form-urlencoded", "":
		if err := request.ParseForm(); err != nil {
			return nil, err
		}
		return request.PostForm, nil
	case "multipart/form-data":
		if err := request.ParseMultipartForm(MultipartMem()); err != nil {
			return nil, err
		}
		return request.MultipartForm, nil
	}

	// Now the general case
	codec, err := Codecs().GetCodec(contentType)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(request.Body)
	if err != nil {
		return nil, err
	}
	var response interface{}
	if err = codec.Unmarshal(body, &response); err != nil {
		return nil, err
	}
	return response, nil
}

// ParseParams returns a map[string]interface{} of values found in a
// request body.  In most cases, this is the equivalent of
// ParseBody(request).(map[string]interface{}).  However, there are
// two exceptions:
//
// * application/x-www-form-urlencoded (or an empty Content-Type)
//
// ** Each value in request.PostForm that has a len() of 1 will be
//    stored instead as the zeroeth index of the value.
//
// * multipart/form-data
//
// ** In addition to the above, files will be stored at the same
//    level as values.  Each value in the resulting map could contain
//    both string and *"mime/multipart".FileHeader values.
//
// The resulting code to parse a form may look like the following:
//
//     params, err := ParseParams(request)
//     // handle err
//     for key, value := range params {
//         switch v := value.(type) {
//         case string:
//             // Do stuff with single string value
//         case *multipart.FileHeader:
//             // Do stuff with single file
//         case []interface{}:
//             // There were multiple string and/or file values at
//             // this key, so deal with that.
//         }
//     }
//
func ParseParams(request *http.Request) (map[string]interface{}, error) {
	if request.Body == nil {
		return nil, nil
	}
	body, err := ParseBody(request)
	if err != nil {
		return nil, err
	}
	return convertToParams(body)
}

func convertToParams(body interface{}) (map[string]interface{}, error) {
	switch body.(type) {
	case url.Values, *multipart.Form:
		return convertForm(body), nil
	}
	m, ok := body.(map[string]interface{})
	if !ok {
		return nil, errors.New("The unmarshalled body is not of type map[string]interface{} " +
			"and cannot be converted to params")
	}
	return m, nil
}

func convertForm(body interface{}) map[string]interface{} {
	var (
		params = make(map[string]interface{})
		values map[string][]string
		files  map[string][]*multipart.FileHeader
	)
	switch form := body.(type) {
	case url.Values:
		values = map[string][]string(form)
	case *multipart.Form:
		values = form.Value
		files = form.File
	}
	for key, valueList := range values {
		if len(valueList) == 1 {
			params[key] = valueList[0]
		} else {
			values := make([]interface{}, len(valueList))
			for idx, value := range valueList {
				values[idx] = value
			}
			params[key] = values
		}
	}
	for key, fileList := range files {
		param, ok := params[key]
		if ok || len(fileList) > 1 {
			values := make([]interface{}, 0, len(params)+len(fileList))
			switch params := param.(type) {
			case []interface{}:
				values = append(values, params...)
			default:
				values = append(values, param)
			}
			for _, file := range fileList {
				values = append(values, file)
			}
			param = values
		} else {
			param = fileList[0]
		}
		params[key] = param
	}
	return params
}
<|endoftext|>


<commit_before>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements the parser.

package golisp

import (
	"errors"
	"fmt"
	"io/ioutil"
	"unsafe"
)

func makeInteger(str string) (n *Data, err error) {
	var i int64
	_, err = fmt.Sscanf(str, "%d", &i)
	if err != nil {
		return
	}
	n = IntegerWithValue(i)
	return
}

func makeHexInteger(str string) (n *Data, err error) {
	var i int64
	_, err = fmt.Sscanf(str, "%v", &i)
	if err != nil {
		return
	}
	n = IntegerWithValue(i)
	return
}

func makeFloat(str string) (n *Data, err error) {
	var i float32
	_, err = fmt.Sscanf(str, "%f", &i)
	if err != nil {
		return
	}
	n = FloatWithValue(i)
	return
}

func makeString(str string) (s *Data, err error) {
	s = StringWithValue(str)
	return
}

func makeSymbol(str string) (s *Data, err error) {
	s = Intern(str)
	return
}

func parseConsCell(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	tok, _ := s.NextToken()
	if tok == RPAREN {
		s.ConsumeToken()
		sexpr = nil
		return
	}

	var car *Data
	var cdr *Data
	cells := make([]*Data, 0, 10)
	for tok != RPAREN {
		if tok == PERIOD {
			s.ConsumeToken()
			cdr, eof, err = parseExpression(s)
			if eof || err != nil {
				return
			}
			tok, _ = s.NextToken()
			if tok != RPAREN {
				err = errors.New("Expected ')'")
				return
			}
			s.ConsumeToken()
			sexpr = ArrayToListWithTail(cells, cdr)
			return
		} else {
			car, eof, err = parseExpression(s)
			if eof {
				err = errors.New("Unexpected EOF (expected closing parenthesis)")
				return
			}
			if err != nil {
				return
			}
			cells = append(cells, car)
		}
		tok, _ = s.NextToken()
	}

	s.ConsumeToken()
	sexpr = ArrayToList(cells)
	return
}

func allIntegers(data []*Data) bool {
	for _, n := range data {
		if !IntegerP(n) {
			return false
		}
	}
	return true
}

func listToBytearray(cells []*Data) *Data {
	bytes := make([]byte, 0, len(cells))
	for _, cell := range cells {
		b := IntegerValue(cell)
		bytes = append(bytes, byte(b))
	}
	return ObjectWithTypeAndValue("[]byte", unsafe.Pointer(&bytes))
}

func parseBytearray(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	tok, _ := s.NextToken()
	if tok == RBRACKET {
		s.ConsumeToken()
		bytes := make([]byte, 0)
		sexpr = ObjectWithTypeAndValue("[]byte", unsafe.Pointer(&bytes))
		return
	}

	var element *Data
	cells := make([]*Data, 0, 10)
	for tok != RBRACKET {
		element, eof, err = parseExpression(s)
		if eof {
			err = errors.New("Unexpected EOF (expected closing bracket)")
			return
		}
		if err != nil {
			return
		}
		if IntegerP(element) && IntegerValue(element) > 255 {
			err = errors.New(fmt.Sprintf("Numeric literals in a bytearray must be bytes. Encountered %s.", String(element)))
			return
		}
		if !IntegerP(element) && !SymbolP(element) && !ListP(element) {
			err = errors.New(fmt.Sprintf("Bytearray elements must be numbers, symbols, or lists (function calls). Encountered %s.", String(element)))
			return
		}
		cells = append(cells, element)
		tok, _ = s.NextToken()
	}

	s.ConsumeToken()
	if allIntegers(cells) {
		sexpr = listToBytearray(cells)
	} else {
		sexpr = InternalMakeList(Intern("list-to-bytearray"), QuoteIt(ArrayToList(cells)))
	}
	return
}

func parseFrame(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	tok, _ := s.NextToken()
	if tok == RBRACKET {
		s.ConsumeToken()
		f := make(FrameMap)
		sexpr = FrameWithValue(&f)
		return
	}

	var element *Data
	cells := make([]*Data, 0, 10)
	for tok != RBRACE {
		element, eof, err = parseExpression(s)
		if eof {
			err = errors.New("Unexpected EOF (expected closing brace)")
			return
		}
		if err != nil {
			return
		}
		cells = append(cells, element)
		tok, _ = s.NextToken()
	}

	s.ConsumeToken()
	sexpr = Cons(Intern("make-frame"), ArrayToList(cells))
	return
}

func parseExpression(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	for {
		tok, lit := s.NextToken()
		switch tok {
		case EOF:
			eof = true
			err = nil
			return
		case COMMENT:
			s.ConsumeToken()
			break
		case NUMBER:
			s.ConsumeToken()
			sexpr, err = makeInteger(lit)
			return
		case HEXNUMBER:
			s.ConsumeToken()
			sexpr, err = makeHexInteger(lit)
			return
		case FLOAT:
			s.ConsumeToken()
			sexpr, err = makeFloat(lit)
			return
		case STRING:
			s.ConsumeToken()
			sexpr, err = makeString(lit)
			return
		case LPAREN:
			s.ConsumeToken()
			sexpr, eof, err = parseConsCell(s)
			return
		case LBRACKET:
			s.ConsumeToken()
			sexpr, eof, err = parseBytearray(s)
			return
		case LBRACE:
			s.ConsumeToken()
			sexpr, eof, err = parseFrame(s)
			return
		case SYMBOL:
			s.ConsumeToken()
			sexpr, err = makeSymbol(lit)
			return
		case FALSE:
			s.ConsumeToken()
			sexpr = LispFalse
			return
		case TRUE:
			s.ConsumeToken()
			sexpr = LispTrue
			return
		case QUOTE:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("quote"), Cons(sexpr, nil))
			}
			return
		case BACKQUOTE:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("quasiquote"), Cons(sexpr, nil))
			}
			return
		case COMMA:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("unquote"), Cons(sexpr, nil))
			}
			return
		case COMMAAT:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("unquote-splicing"), Cons(sexpr, nil))
			}
			return
		case ILLEGAL:
			err = errors.New(fmt.Sprintf("Illegal character: %s", lit))
			return
		default:
			s.ConsumeToken()
			sexpr, err = makeSymbol(lit)
			return
		}
	}
}

func Parse(src string) (sexpr *Data, err error) {
	s := NewTokenizer(src)
	sexpr, _, err = parseExpression(s)
	return
}

func ParseAll(src string) (result []*Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	var eof bool
	for {
		sexpr, eof, err = parseExpression(s)
		if err != nil || eof {
			break
		}
		result = append(result, sexpr)
	}
	return
}

func ReadFile(filename string) (s string, err error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	s = *(*string)(unsafe.Pointer(&contents))
	return
}

func ProcessFile(filename string) (result *Data, err error) {
	src, err := ReadFile(filename)
	if err != nil {
		return
	}
	result, err = ParseAndEvalAll(src)
	return
}

func ParseAndEvalAll(src string) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	var eof bool
	for {
		sexpr, eof, err = parseExpression(s)
		if err != nil {
			return
		}
		if eof {
			return
		}
		if NilP(sexpr) {
			return
		}
		result, err = Eval(sexpr, Global)
		if err != nil {
			return
		}
	}
	return
}

func ParseAndEval(src string) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	sexpr, _, err = parseExpression(s)
	if err != nil {
		return
	}
	if NilP(sexpr) {
		return
	}
	result, err = Eval(sexpr, Global)
	if err != nil {
		return
	}
	return
}

func ParseAndEvalAllInEnvironment(src string, env *SymbolTableFrame) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	var eof bool
	for {
		sexpr, eof, err = parseExpression(s)
		if err != nil {
			return
		}
		if eof {
			return
		}
		if NilP(sexpr) {
			return
		}
		result, err = Eval(sexpr, env)
		if err != nil {
			return
		}
	}
	return
}

func ParseAndEvalInEnvironment(src string, env *SymbolTableFrame) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	sexpr, _, err = parseExpression(s)
	if err != nil {
		return
	}
	if NilP(sexpr) {
		return
	}
	result, err = Eval(sexpr, env)
	if err != nil {
		return
	}
	return
}<commit_msg>Added ProcessFileInEnvironment<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements the parser.

package golisp

import (
	"errors"
	"fmt"
	"io/ioutil"
	"unsafe"
)

func makeInteger(str string) (n *Data, err error) {
	var i int64
	_, err = fmt.Sscanf(str, "%d", &i)
	if err != nil {
		return
	}
	n = IntegerWithValue(i)
	return
}

func makeHexInteger(str string) (n *Data, err error) {
	var i int64
	_, err = fmt.Sscanf(str, "%v", &i)
	if err != nil {
		return
	}
	n = IntegerWithValue(i)
	return
}

func makeFloat(str string) (n *Data, err error) {
	var i float32
	_, err = fmt.Sscanf(str, "%f", &i)
	if err != nil {
		return
	}
	n = FloatWithValue(i)
	return
}

func makeString(str string) (s *Data, err error) {
	s = StringWithValue(str)
	return
}

func makeSymbol(str string) (s *Data, err error) {
	s = Intern(str)
	return
}

func parseConsCell(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	tok, _ := s.NextToken()
	if tok == RPAREN {
		s.ConsumeToken()
		sexpr = nil
		return
	}

	var car *Data
	var cdr *Data
	cells := make([]*Data, 0, 10)
	for tok != RPAREN {
		if tok == PERIOD {
			s.ConsumeToken()
			cdr, eof, err = parseExpression(s)
			if eof || err != nil {
				return
			}
			tok, _ = s.NextToken()
			if tok != RPAREN {
				err = errors.New("Expected ')'")
				return
			}
			s.ConsumeToken()
			sexpr = ArrayToListWithTail(cells, cdr)
			return
		} else {
			car, eof, err = parseExpression(s)
			if eof {
				err = errors.New("Unexpected EOF (expected closing parenthesis)")
				return
			}
			if err != nil {
				return
			}
			cells = append(cells, car)
		}
		tok, _ = s.NextToken()
	}

	s.ConsumeToken()
	sexpr = ArrayToList(cells)
	return
}

func allIntegers(data []*Data) bool {
	for _, n := range data {
		if !IntegerP(n) {
			return false
		}
	}
	return true
}

func listToBytearray(cells []*Data) *Data {
	bytes := make([]byte, 0, len(cells))
	for _, cell := range cells {
		b := IntegerValue(cell)
		bytes = append(bytes, byte(b))
	}
	return ObjectWithTypeAndValue("[]byte", unsafe.Pointer(&bytes))
}

func parseBytearray(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	tok, _ := s.NextToken()
	if tok == RBRACKET {
		s.ConsumeToken()
		bytes := make([]byte, 0)
		sexpr = ObjectWithTypeAndValue("[]byte", unsafe.Pointer(&bytes))
		return
	}

	var element *Data
	cells := make([]*Data, 0, 10)
	for tok != RBRACKET {
		element, eof, err = parseExpression(s)
		if eof {
			err = errors.New("Unexpected EOF (expected closing bracket)")
			return
		}
		if err != nil {
			return
		}
		if IntegerP(element) && IntegerValue(element) > 255 {
			err = errors.New(fmt.Sprintf("Numeric literals in a bytearray must be bytes. Encountered %s.", String(element)))
			return
		}
		if !IntegerP(element) && !SymbolP(element) && !ListP(element) {
			err = errors.New(fmt.Sprintf("Bytearray elements must be numbers, symbols, or lists (function calls). Encountered %s.", String(element)))
			return
		}
		cells = append(cells, element)
		tok, _ = s.NextToken()
	}

	s.ConsumeToken()
	if allIntegers(cells) {
		sexpr = listToBytearray(cells)
	} else {
		sexpr = InternalMakeList(Intern("list-to-bytearray"), QuoteIt(ArrayToList(cells)))
	}
	return
}

func parseFrame(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	tok, _ := s.NextToken()
	if tok == RBRACKET {
		s.ConsumeToken()
		f := make(FrameMap)
		sexpr = FrameWithValue(&f)
		return
	}

	var element *Data
	cells := make([]*Data, 0, 10)
	for tok != RBRACE {
		element, eof, err = parseExpression(s)
		if eof {
			err = errors.New("Unexpected EOF (expected closing brace)")
			return
		}
		if err != nil {
			return
		}
		cells = append(cells, element)
		tok, _ = s.NextToken()
	}

	s.ConsumeToken()
	sexpr = Cons(Intern("make-frame"), ArrayToList(cells))
	return
}

func parseExpression(s *Tokenizer) (sexpr *Data, eof bool, err error) {
	for {
		tok, lit := s.NextToken()
		switch tok {
		case EOF:
			eof = true
			err = nil
			return
		case COMMENT:
			s.ConsumeToken()
			break
		case NUMBER:
			s.ConsumeToken()
			sexpr, err = makeInteger(lit)
			return
		case HEXNUMBER:
			s.ConsumeToken()
			sexpr, err = makeHexInteger(lit)
			return
		case FLOAT:
			s.ConsumeToken()
			sexpr, err = makeFloat(lit)
			return
		case STRING:
			s.ConsumeToken()
			sexpr, err = makeString(lit)
			return
		case LPAREN:
			s.ConsumeToken()
			sexpr, eof, err = parseConsCell(s)
			return
		case LBRACKET:
			s.ConsumeToken()
			sexpr, eof, err = parseBytearray(s)
			return
		case LBRACE:
			s.ConsumeToken()
			sexpr, eof, err = parseFrame(s)
			return
		case SYMBOL:
			s.ConsumeToken()
			sexpr, err = makeSymbol(lit)
			return
		case FALSE:
			s.ConsumeToken()
			sexpr = LispFalse
			return
		case TRUE:
			s.ConsumeToken()
			sexpr = LispTrue
			return
		case QUOTE:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("quote"), Cons(sexpr, nil))
			}
			return
		case BACKQUOTE:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("quasiquote"), Cons(sexpr, nil))
			}
			return
		case COMMA:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("unquote"), Cons(sexpr, nil))
			}
			return
		case COMMAAT:
			s.ConsumeToken()
			sexpr, eof, err = parseExpression(s)
			if sexpr != nil {
				sexpr = Cons(Intern("unquote-splicing"), Cons(sexpr, nil))
			}
			return
		case ILLEGAL:
			err = errors.New(fmt.Sprintf("Illegal character: %s", lit))
			return
		default:
			s.ConsumeToken()
			sexpr, err = makeSymbol(lit)
			return
		}
	}
}

func Parse(src string) (sexpr *Data, err error) {
	s := NewTokenizer(src)
	sexpr, _, err = parseExpression(s)
	return
}

func ParseAll(src string) (result []*Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	var eof bool
	for {
		sexpr, eof, err = parseExpression(s)
		if err != nil || eof {
			break
		}
		result = append(result, sexpr)
	}
	return
}

func ReadFile(filename string) (s string, err error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	s = *(*string)(unsafe.Pointer(&contents))
	return
}

func ProcessFile(filename string) (result *Data, err error) {
	src, err := ReadFile(filename)
	if err != nil {
		return
	}
	result, err = ParseAndEvalAll(src)
	return
}

func ParseAndEvalAll(src string) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	var eof bool
	for {
		sexpr, eof, err = parseExpression(s)
		if err != nil {
			return
		}
		if eof {
			return
		}
		if NilP(sexpr) {
			return
		}
		result, err = Eval(sexpr, Global)
		if err != nil {
			return
		}
	}
	return
}

func ParseAndEval(src string) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	sexpr, _, err = parseExpression(s)
	if err != nil {
		return
	}
	if NilP(sexpr) {
		return
	}
	result, err = Eval(sexpr, Global)
	if err != nil {
		return
	}
	return
}

func ProcessFileInEnvironment(filename string, env *SymbolTableFrame) (result *Data, err error) {
	src, err := ReadFile(filename)
	if err != nil {
		return
	}
	result, err = ParseAndEvalAllInEnvironment(src, env)
	return
}

func ParseAndEvalAllInEnvironment(src string, env *SymbolTableFrame) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	var eof bool
	for {
		sexpr, eof, err = parseExpression(s)
		if err != nil {
			return
		}
		if eof {
			return
		}
		if NilP(sexpr) {
			return
		}
		result, err = Eval(sexpr, env)
		if err != nil {
			return
		}
	}
	return
}

func ParseAndEvalInEnvironment(src string, env *SymbolTableFrame) (result *Data, err error) {
	s := NewTokenizer(src)
	var sexpr *Data
	sexpr, _, err = parseExpression(s)
	if err != nil {
		return
	}
	if NilP(sexpr) {
		return
	}
	result, err = Eval(sexpr, env)
	if err != nil {
		return
	}
	return
}<|endoftext|>